Cleanup of data and assembly patches
Now encapsulates patched memory differently to Cheat Engine which doesn't actually support auto-assembly like I assumed
This commit is contained in:
parent
5012078a35
commit
e0e2c434d2
|
@ -1,210 +0,0 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CxbxDebugger.CheatEngine;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
class CheatEngineManager
|
||||
{
|
||||
public CheatTable Cheats;
|
||||
|
||||
public bool RefreshAll(DebuggerProcess Process)
|
||||
{
|
||||
bool Changed = false;
|
||||
|
||||
for (int i = 0; i < Cheats.CheatEntries.Count; ++i)
|
||||
{
|
||||
CheatEntry Entry = Cheats.CheatEntries[i];
|
||||
|
||||
//if (Entry.LastState.Activated)
|
||||
{
|
||||
string last = Entry.LastState.Value;
|
||||
Entry.LastState.Value = Read(Process, i);
|
||||
|
||||
if(Entry.LastState.Value != last )
|
||||
{
|
||||
Changed = true;
|
||||
}
|
||||
|
||||
Cheats.CheatEntries[i] = Entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
public string Read(DebuggerProcess Process, int CheatIndex)
|
||||
{
|
||||
string printed_value = "??";
|
||||
CheatEntry entry = Cheats.CheatEntries[CheatIndex];
|
||||
|
||||
int addr = 0;
|
||||
if (!ReadHexInt(entry.Address, ref addr))
|
||||
{
|
||||
return printed_value;
|
||||
}
|
||||
|
||||
switch (entry.VariableType)
|
||||
{
|
||||
case Variable.Byte:
|
||||
{
|
||||
var data = Process.ReadMemoryBlock(new IntPtr(addr), 1);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
if (entry.ShowAsHex)
|
||||
{
|
||||
printed_value = string.Format("0x{0:x}", data[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_value = string.Format("{0}", data[0]);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Variable.Bytes2:
|
||||
{
|
||||
var data = Process.ReadMemoryBlock(new IntPtr(addr), 2);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
ushort val = BitConverter.ToUInt16(data, 0);
|
||||
|
||||
if (entry.ShowAsHex)
|
||||
{
|
||||
printed_value = string.Format("0x{0:x}", val);
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_value = string.Format("{0}", val);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Variable.Bytes4:
|
||||
{
|
||||
var data = Process.ReadMemoryBlock(new IntPtr(addr), 4);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
uint val = BitConverter.ToUInt32(data, 0);
|
||||
|
||||
if (entry.ShowAsHex)
|
||||
{
|
||||
printed_value = string.Format("0x{0:x}", val);
|
||||
}
|
||||
else
|
||||
{
|
||||
printed_value = string.Format("{0}", val);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Variable.Float:
|
||||
{
|
||||
var data = Process.ReadMemoryBlock(new IntPtr(addr), 4);
|
||||
if (data != null)
|
||||
{
|
||||
if (entry.ShowAsHex)
|
||||
{
|
||||
uint val = BitConverter.ToUInt32(data, 0);
|
||||
printed_value = string.Format("{0:x8}", val);
|
||||
}
|
||||
else
|
||||
{
|
||||
float flt = BitConverter.ToSingle(data, 0);
|
||||
printed_value = string.Format("{0}", flt);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return printed_value;
|
||||
}
|
||||
|
||||
public void Write(DebuggerProcess Process, int CheatIndex, string Value)
|
||||
{
|
||||
CheatEntry entry = Cheats.CheatEntries[CheatIndex];
|
||||
|
||||
int addr = 0;
|
||||
if (!ReadHexInt(entry.Address, ref addr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (entry.VariableType)
|
||||
{
|
||||
case Variable.Byte:
|
||||
{
|
||||
uint byte_val = 0;
|
||||
ReadAddress(Value, ref byte_val);
|
||||
|
||||
byte val = (byte)(byte_val & 0xFF);
|
||||
Process.WriteMemory(new IntPtr(addr), val);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Variable.Float:
|
||||
{
|
||||
float flt_val = 0.0f;
|
||||
ReadFloat(Value, ref flt_val);
|
||||
|
||||
Process.WriteMemory(new IntPtr(addr), flt_val);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private bool ReadHexInt(string HexSource, ref int Out)
|
||||
{
|
||||
if (int.TryParse(HexSource, System.Globalization.NumberStyles.HexNumber, null, out Out))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static private bool ReadAddress(string Source, ref uint Out)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Source.StartsWith("0x"))
|
||||
{
|
||||
Out = Convert.ToUInt32(Source.Substring(2), 16);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uint.TryParse(Source, out Out))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static private bool ReadFloat(string Source, ref float Out)
|
||||
{
|
||||
return float.TryParse(Source, out Out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,7 +67,6 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CheatEngineManager.cs" />
|
||||
<Compile Include="DebuggerExtras\CheatTable.cs" />
|
||||
<Compile Include="DebuggerExtras\CheatTableReader.cs" />
|
||||
<Compile Include="DebuggerSymbols\Kernel\KernelSymbolProvider.cs" />
|
||||
|
@ -93,6 +92,7 @@
|
|||
<Compile Include="DebuggerSymbols\HLECache\HLECacheFile.cs" />
|
||||
<Compile Include="DebuggerSymbols\HLECache\HLECacheProvider.cs" />
|
||||
<Compile Include="DebuggerSymbols\HLECache\Utils\INIReader.cs" />
|
||||
<Compile Include="PatchManager.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RicherTextBox.cs">
|
||||
|
|
|
@ -225,6 +225,18 @@ namespace CxbxDebugger
|
|||
Data = new byte[] { (byte)GenericValue };
|
||||
break;
|
||||
|
||||
case TypeCode.Int16:
|
||||
Data = BitConverter.GetBytes((short)GenericValue);
|
||||
break;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
Data = BitConverter.GetBytes((ushort)GenericValue);
|
||||
break;
|
||||
|
||||
case TypeCode.Int32:
|
||||
Data = BitConverter.GetBytes((int)GenericValue);
|
||||
break;
|
||||
|
||||
case TypeCode.UInt32:
|
||||
Data = BitConverter.GetBytes((uint)GenericValue);
|
||||
break;
|
||||
|
@ -242,5 +254,13 @@ namespace CxbxDebugger
|
|||
WriteMemoryInternal(Address, Data);
|
||||
}
|
||||
}
|
||||
|
||||
public bool WriteMemoryBlock(IntPtr Address, byte[] Data)
|
||||
{
|
||||
if (Address == IntPtr.Zero)
|
||||
return false;
|
||||
|
||||
return WriteMemoryInternal(Address, Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,11 @@ namespace CxbxDebugger
|
|||
public enum Variable
|
||||
{
|
||||
Unsupported,
|
||||
Binary,
|
||||
Byte,
|
||||
Bytes2,
|
||||
Bytes4,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
}
|
||||
|
||||
public struct CheatEntry
|
||||
|
@ -43,9 +41,9 @@ namespace CxbxDebugger
|
|||
public uint Address;
|
||||
public string ModuleName;
|
||||
public uint ModuleNameOffset;
|
||||
public byte[] Before;
|
||||
public byte[] Actual;
|
||||
public byte[] After;
|
||||
public byte[] Before; // 5 bytes before 'Actual'
|
||||
public byte[] Actual; // with a length of the opcode
|
||||
public byte[] After; // 5 bytes after 'Actual'
|
||||
};
|
||||
|
||||
public class CheatTable
|
||||
|
@ -61,5 +59,29 @@ namespace CxbxDebugger
|
|||
CodeEntires = new List<CodeEntry>();
|
||||
}
|
||||
};
|
||||
|
||||
class Helpers
|
||||
{
|
||||
public static int VariableSize(Variable Var)
|
||||
{
|
||||
switch (Var)
|
||||
{
|
||||
case Variable.Unsupported:
|
||||
return 0;
|
||||
case Variable.Byte:
|
||||
return 1;
|
||||
case Variable.Bytes2:
|
||||
return 2;
|
||||
case Variable.Bytes4:
|
||||
return 4;
|
||||
case Variable.Float:
|
||||
return 4;
|
||||
case Variable.Double:
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using cs_x86;
|
||||
using CxbxDebugger.CheatEngine;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
|
@ -23,10 +22,11 @@ namespace CxbxDebugger
|
|||
|
||||
List<DebuggerThread> DebugThreads = new List<DebuggerThread>();
|
||||
List<DebuggerModule> DebugModules = new List<DebuggerModule>();
|
||||
DebuggerProcess MainProcess = null;
|
||||
|
||||
FileWatchManager fileWatchMan;
|
||||
DebugOutputManager debugStrMan;
|
||||
CheatEngineManager cheatMan;
|
||||
PatchManager patchMan;
|
||||
|
||||
List<DebuggerMessages.FileOpened> FileHandles = new List<DebuggerMessages.FileOpened>();
|
||||
|
||||
|
@ -65,17 +65,17 @@ namespace CxbxDebugger
|
|||
|
||||
cbAction.SelectedIndex = 0;
|
||||
|
||||
foreach (string VariableEnum in Enum.GetNames(typeof(Variable)))
|
||||
foreach (string VariableEnum in Enum.GetNames(typeof(PatchType)))
|
||||
{
|
||||
cbDataFormat.Items.Add(VariableEnum);
|
||||
}
|
||||
|
||||
// Default to byte
|
||||
cbDataFormat.SelectedIndex = 2;
|
||||
|
||||
cbDataFormat.SelectedIndex = 0;
|
||||
InvokePatchTypeChange();
|
||||
|
||||
fileWatchMan = new FileWatchManager(clbBreakpoints);
|
||||
debugStrMan = new DebugOutputManager(lbDebug);
|
||||
cheatMan = new CheatEngineManager();
|
||||
patchMan = new PatchManager();
|
||||
}
|
||||
|
||||
private void OnDisassemblyNavigation(object sender, InlineLinkClickedEventArgs e)
|
||||
|
@ -105,6 +105,7 @@ namespace CxbxDebugger
|
|||
// Create debugger instance
|
||||
DebuggerInst = new Debugger(CachedArgs);
|
||||
DebuggerInst.RegisterEventInterfaces(DebugEvents);
|
||||
DebuggerInst.RegisterEventInterfaces(patchMan);
|
||||
|
||||
// Setup new debugger thread
|
||||
DebuggerWorkerThread = new Thread(x =>
|
||||
|
@ -124,7 +125,7 @@ namespace CxbxDebugger
|
|||
{
|
||||
cbItems.Items.Clear();
|
||||
|
||||
uint AutoThreadId= DebugThreads[0].OwningProcess.MainThread.ThreadID;
|
||||
uint AutoThreadId = DebugThreads[0].OwningProcess.MainThread.ThreadID;
|
||||
if (FocusThread != null)
|
||||
AutoThreadId = FocusThread.ThreadID;
|
||||
|
||||
|
@ -292,7 +293,8 @@ namespace CxbxDebugger
|
|||
|
||||
Text = string.Format("{0} - Cxbx-Reloaded Debugger", CachedTitle);
|
||||
|
||||
LoadCheatTable(string.Format("{0}.ct", CachedTitle));
|
||||
// This is done too late - modules are already loaded
|
||||
//LoadCheatTable(string.Format("{0}.ct", CachedTitle));
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -378,6 +380,7 @@ namespace CxbxDebugger
|
|||
public void OnProcessCreate(DebuggerProcess Process)
|
||||
{
|
||||
frm.DebugModules.Add(Process);
|
||||
frm.MainProcess = Process;
|
||||
}
|
||||
|
||||
public void OnProcessExit(DebuggerProcess Process, uint ExitCode)
|
||||
|
@ -609,6 +612,11 @@ namespace CxbxDebugger
|
|||
|
||||
static private bool ReadHexInt(string HexSource, ref int Out)
|
||||
{
|
||||
if (HexSource.StartsWith("0x"))
|
||||
{
|
||||
HexSource = HexSource.Substring(2);
|
||||
}
|
||||
|
||||
if (int.TryParse(HexSource, System.Globalization.NumberStyles.HexNumber, null, out Out))
|
||||
{
|
||||
return true;
|
||||
|
@ -1052,48 +1060,68 @@ namespace CxbxDebugger
|
|||
HandleDisasmGo();
|
||||
}
|
||||
|
||||
private static System.Drawing.Color MakeColor(uint RGB)
|
||||
{
|
||||
int r = (int)(RGB & 0xFF);
|
||||
int g = (int)((RGB >> 8) & 0xFF);
|
||||
int b = (int)((RGB >> 16) & 0xFF);
|
||||
|
||||
return System.Drawing.Color.FromArgb(r, g, b);
|
||||
}
|
||||
|
||||
private void RefreshCheatTableDisplay()
|
||||
private void RefreshPatches()
|
||||
{
|
||||
lvCEMemory.BeginUpdate();
|
||||
lvCEMemory.Items.Clear();
|
||||
|
||||
foreach (var code in cheatMan.Cheats.CheatEntries)
|
||||
foreach (Patch DataPatch in patchMan.Data)
|
||||
{
|
||||
var li = lvCEMemory.Items.Add("");
|
||||
li.SubItems.Add(code.Description);
|
||||
li.SubItems.Add(string.Format("{0:x8}", code.Address));
|
||||
li.SubItems.Add(code.VariableType.ToString());
|
||||
li.SubItems.Add(code.LastState.Value);
|
||||
|
||||
li.Checked = code.LastState.Activated;
|
||||
li.ForeColor = MakeColor(code.Color);
|
||||
var li = lvCEMemory.Items.Add(string.Format("{0} 0x{1:x}", DataPatch.Module, DataPatch.Offset));
|
||||
li.SubItems.Add(DataPatch.Name);
|
||||
li.SubItems.Add(string.Format("{0} byte(s)", DataPatch.Patched.Length));
|
||||
if (MainProcess != null)
|
||||
{
|
||||
li.SubItems.Add(patchMan.Read(MainProcess, DataPatch));
|
||||
}
|
||||
else
|
||||
{
|
||||
li.SubItems.Add("??");
|
||||
}
|
||||
}
|
||||
|
||||
lvCEMemory.EndUpdate();
|
||||
|
||||
// Code entries are not supported at the moment
|
||||
|
||||
lvCEAssembly.BeginUpdate();
|
||||
lvCEAssembly.Items.Clear();
|
||||
|
||||
foreach (var code in cheatMan.Cheats.CodeEntires)
|
||||
foreach (Patch patch in patchMan.Assembly)
|
||||
{
|
||||
var li = lvCEAssembly.Items.Add(string.Format("{0} +{1:X}", code.ModuleName, code.ModuleNameOffset));
|
||||
li.SubItems.Add(code.Description);
|
||||
var li = lvCEAssembly.Items.Add(string.Format("{0} 0x{1:x}", patch.Module, patch.Offset));
|
||||
li.SubItems.Add(patch.Name);
|
||||
li.SubItems.Add(PrettyPrint(patch.Original));
|
||||
li.SubItems.Add(PrettyPrint(patch.Patched));
|
||||
}
|
||||
|
||||
lvCEAssembly.EndUpdate();
|
||||
}
|
||||
|
||||
static private byte[] Fill(int Count, byte Val)
|
||||
{
|
||||
List<byte> ByteList = new List<byte>(Count);
|
||||
for (int i = 0; i < Count; ++i) ByteList.Add(Val);
|
||||
return ByteList.ToArray();
|
||||
}
|
||||
|
||||
static private byte[] Nops(int Count)
|
||||
{
|
||||
return Fill(Count, 0x90);
|
||||
}
|
||||
|
||||
static private string PrettyPrint(byte[] Bytes)
|
||||
{
|
||||
if (Bytes == null)
|
||||
return "??";
|
||||
|
||||
string Str = "";
|
||||
int Max = Math.Min(5, Bytes.Length);
|
||||
for (int i = 0; i < Max; ++i)
|
||||
{
|
||||
Str += string.Format("{0:X2} ", Bytes[i]);
|
||||
}
|
||||
return Str;
|
||||
}
|
||||
|
||||
private void LoadCheatTable(string filename)
|
||||
{
|
||||
string path = Directory.GetCurrentDirectory();
|
||||
|
@ -1101,73 +1129,81 @@ namespace CxbxDebugger
|
|||
if (File.Exists(filename))
|
||||
{
|
||||
DebugLog(string.Format("Attempting to load \"{0}\"", filename));
|
||||
|
||||
CheatTable ct_data = CheatTableReader.FromFile(filename);
|
||||
|
||||
CheatEngine.CheatTable ct_data = CheatEngine.CheatTableReader.FromFile(filename);
|
||||
if (ct_data != null)
|
||||
{
|
||||
cheatMan.Cheats = ct_data;
|
||||
foreach(CheatEngine.CheatEntry Entry in ct_data.CheatEntries)
|
||||
{
|
||||
int addr = 0;
|
||||
if(ReadHexInt(Entry.Address, ref addr))
|
||||
{
|
||||
Patch DataPatch = new Patch();
|
||||
|
||||
DataPatch.DisplayAs = PatchType.Array;
|
||||
DataPatch.Name = Entry.Description;
|
||||
DataPatch.Module = "";
|
||||
DataPatch.Offset = (uint)addr;
|
||||
DataPatch.Original = null;
|
||||
DataPatch.Patched = Nops(CheatEngine.Helpers.VariableSize(Entry.VariableType));
|
||||
|
||||
patchMan.Data.Add(DataPatch);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(CheatEngine.CodeEntry Entry in ct_data.CodeEntires)
|
||||
{
|
||||
Patch DataPatch = new Patch();
|
||||
|
||||
DataPatch.DisplayAs = PatchType.Array;
|
||||
DataPatch.Name = Entry.Description;
|
||||
DataPatch.Module = Entry.ModuleName;
|
||||
DataPatch.Offset = Entry.ModuleNameOffset;
|
||||
DataPatch.Original = Entry.Actual;
|
||||
DataPatch.Patched = Nops(Entry.Actual.Length);
|
||||
|
||||
patchMan.Assembly.Add(DataPatch);
|
||||
}
|
||||
|
||||
DebugLog(string.Format("Loaded {0} auto-assembler entries", ct_data.CodeEntires.Count));
|
||||
DebugLog(string.Format("Loaded {0} cheat entries", ct_data.CheatEntries.Count));
|
||||
|
||||
RefreshPatches();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void button2_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
if( diagBrowseCT.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string filename = diagBrowseCT.FileNames[0];
|
||||
LoadCheatTable(filename);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCEMemory()
|
||||
{
|
||||
if (DebugThreads.Count == 0)
|
||||
return;
|
||||
|
||||
if (cheatMan.RefreshAll(DebugThreads[0].OwningProcess))
|
||||
{
|
||||
RefreshCheatTableDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private void button3_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
if (DebugThreads.Count == 0)
|
||||
return;
|
||||
|
||||
if (lvCEMemory.SelectedIndices.Count == 1)
|
||||
{
|
||||
int selected = lvCEMemory.SelectedIndices[0];
|
||||
|
||||
cheatMan.Write(DebugThreads[0].OwningProcess, selected, textBox1.Text);
|
||||
}
|
||||
}
|
||||
|
||||
private void button4_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
RefreshCEMemory();
|
||||
}
|
||||
|
||||
|
||||
private void button5_Click(object sender, EventArgs e)
|
||||
{
|
||||
CheatEntry ce = new CheatEntry();
|
||||
PatchType PatchType = (PatchType)cbDataFormat.SelectedIndex;
|
||||
|
||||
ce.ID = 0;
|
||||
ce.Description = "Automatic";
|
||||
ce.ShowAsHex = false;
|
||||
ce.LastState.Activated = false;
|
||||
ce.LastState.RealAddress = 0;
|
||||
ce.LastState.Value = "";
|
||||
ce.VariableType = (Variable)cbDataFormat.SelectedIndex;
|
||||
|
||||
if(txAddress.Text.StartsWith("0x"))
|
||||
int PatchSize = PatchManager.PatchTypeLength(PatchType);
|
||||
if(PatchSize == 0 )
|
||||
{
|
||||
ce.Address = txAddress.Text.Substring(2);
|
||||
}
|
||||
if (!ReadInt(textBox2, ref PatchSize))
|
||||
return;
|
||||
|
||||
cheatMan.Cheats.CheatEntries.Add(ce);
|
||||
if (PatchSize < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshCEMemory();
|
||||
int addr = 0;
|
||||
if(ReadHexInt(txAddress.Text, ref addr))
|
||||
{
|
||||
Patch DataPatch = new Patch();
|
||||
|
||||
DataPatch.DisplayAs = PatchType;
|
||||
DataPatch.Name = string.Format("Patched {0}", cbDataFormat.SelectedText);
|
||||
DataPatch.Module = "";
|
||||
DataPatch.Offset = (uint)addr;
|
||||
|
||||
// TODO: Read original memory at this location
|
||||
DataPatch.Original = Nops(PatchSize);
|
||||
DataPatch.Patched = Nops(PatchSize);
|
||||
patchMan.Data.Add(DataPatch);
|
||||
|
||||
RefreshPatches();
|
||||
}
|
||||
}
|
||||
|
||||
private void button6_Click(object sender, EventArgs e)
|
||||
|
@ -1179,5 +1215,48 @@ namespace CxbxDebugger
|
|||
tabContainer.SelectedTab = tabMemory;
|
||||
}
|
||||
}
|
||||
|
||||
private void button2_Click_2(object sender, EventArgs e)
|
||||
{
|
||||
if (diagBrowseCT.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string filename = diagBrowseCT.FileNames[0];
|
||||
LoadCheatTable(filename);
|
||||
}
|
||||
}
|
||||
|
||||
private void button1_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
RefreshPatches();
|
||||
}
|
||||
|
||||
private void InvokePatchTypeChange()
|
||||
{
|
||||
PatchType Type = (PatchType)cbDataFormat.SelectedIndex;
|
||||
|
||||
textBox2.Text = PatchManager.PatchTypeLength(Type).ToString();
|
||||
textBox2.Enabled = (Type == PatchType.Array);
|
||||
}
|
||||
|
||||
private void cbDataFormat_SelectionChangeCommitted(object sender, EventArgs e)
|
||||
{
|
||||
InvokePatchTypeChange();
|
||||
}
|
||||
|
||||
private void button3_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
if (lvCEMemory.SelectedIndices.Count != 1)
|
||||
return;
|
||||
|
||||
string Value = txNewValue.Text;
|
||||
if(Value.Length != 0 )
|
||||
{
|
||||
Patch DataPatch = patchMan.Data[lvCEMemory.SelectedIndices[0]];
|
||||
if( patchMan.Write(MainProcess, DataPatch, Value))
|
||||
{
|
||||
RefreshPatches();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
enum PatchType
|
||||
{
|
||||
Byte,
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Float,
|
||||
Array
|
||||
};
|
||||
|
||||
struct Patch
|
||||
{
|
||||
public PatchType DisplayAs { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Module { get; set; }
|
||||
public uint Offset { get; set; }
|
||||
public byte[] Original { get; set; }
|
||||
public byte[] Patched { get; set; }
|
||||
};
|
||||
|
||||
class PatchManager : IDebuggerProcessEvents, IDebuggerModuleEvents
|
||||
{
|
||||
public List<Patch> Data = new List<Patch>();
|
||||
public List<Patch> Assembly = new List<Patch>();
|
||||
|
||||
public void OnProcessCreate(DebuggerProcess Process)
|
||||
{
|
||||
// TODO: apply pending patches
|
||||
}
|
||||
|
||||
public void OnProcessExit(DebuggerProcess Process, uint ExitCode) { }
|
||||
|
||||
public void OnModuleLoaded(DebuggerModule Module)
|
||||
{
|
||||
// TODO: apply pending patches
|
||||
}
|
||||
|
||||
public void OnModuleUnloaded(DebuggerModule Module) { }
|
||||
|
||||
static int PatchSize(Patch PatchItem)
|
||||
{
|
||||
if (PatchItem.Original != null)
|
||||
return PatchItem.Original.Length;
|
||||
|
||||
if (PatchItem.Patched != null)
|
||||
return PatchItem.Patched.Length;
|
||||
|
||||
return PatchTypeLength(PatchItem.DisplayAs);
|
||||
}
|
||||
|
||||
private static string Format(PatchType Type, byte[] Data)
|
||||
{
|
||||
string Result = "";
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case PatchType.Byte:
|
||||
{
|
||||
Result = string.Format("{0}", Data[0]);
|
||||
}
|
||||
break;
|
||||
case PatchType.Short:
|
||||
{
|
||||
var Value = BitConverter.ToInt16(Data, 0);
|
||||
Result = string.Format("{0}", Value);
|
||||
}
|
||||
break;
|
||||
case PatchType.UShort:
|
||||
{
|
||||
var Value = BitConverter.ToUInt16(Data, 0);
|
||||
Result = string.Format("{0}", Value);
|
||||
}
|
||||
break;
|
||||
case PatchType.Int:
|
||||
{
|
||||
var Value = BitConverter.ToInt32(Data, 0);
|
||||
Result = string.Format("{0}", Value);
|
||||
}
|
||||
break;
|
||||
case PatchType.UInt:
|
||||
{
|
||||
var Value = BitConverter.ToUInt32(Data, 0);
|
||||
Result = string.Format("{0}", Value);
|
||||
}
|
||||
break;
|
||||
case PatchType.Float:
|
||||
{
|
||||
var Value = BitConverter.ToSingle(Data, 0);
|
||||
Result = string.Format("{0}", Value);
|
||||
}
|
||||
break;
|
||||
case PatchType.Array:
|
||||
{
|
||||
foreach (byte B in Data)
|
||||
{
|
||||
Result += string.Format("{0:X2} ", B);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public string Read(DebuggerProcess OwningProcess, Patch PatchItem)
|
||||
{
|
||||
int Size = PatchSize(PatchItem);
|
||||
if (Size == 0)
|
||||
return "";
|
||||
|
||||
byte[] Current = OwningProcess.ReadMemoryBlock(new IntPtr(PatchItem.Offset), (uint)Size);
|
||||
return Format(PatchItem.DisplayAs, Current);
|
||||
}
|
||||
|
||||
public bool Write(DebuggerProcess OwningProcess, Patch PatchItem, string NewValue)
|
||||
{
|
||||
switch (PatchItem.DisplayAs)
|
||||
{
|
||||
case PatchType.Byte:
|
||||
{
|
||||
byte Value;
|
||||
if( byte.TryParse(NewValue, out Value) )
|
||||
{
|
||||
OwningProcess.WriteMemory(new IntPtr(PatchItem.Offset), Value);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static public int PatchTypeLength(PatchType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case PatchType.Byte:
|
||||
return 1;
|
||||
case PatchType.Short:
|
||||
return 2;
|
||||
case PatchType.UShort:
|
||||
return 2;
|
||||
case PatchType.Int:
|
||||
return 4;
|
||||
case PatchType.UInt:
|
||||
return 4;
|
||||
case PatchType.Float:
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue