Skip to content

Commit 496a0ce

Browse files
committed
Added RemoteGetFunctionStartAddress.
1 parent 1b229ce commit 496a0ce

File tree

1 file changed

+89
-32
lines changed

1 file changed

+89
-32
lines changed

Memory/Disassembler.cs

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,22 @@ public Disassembler(NativeHelper nativeHelper)
1919
this.nativeHelper = nativeHelper;
2020
}
2121

22-
/// <summary>
23-
/// Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) in the remote process.
24-
/// </summary>
22+
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) in the remote process.</summary>
2523
/// <param name="process">The process to read from.</param>
2624
/// <param name="address">The address of the code.</param>
2725
/// <param name="length">The length of the code.</param>
2826
/// <returns>A list of <see cref="DisassembledInstruction"/>.</returns>
29-
public List<DisassembledInstruction> RemoteDisassembleCode(RemoteProcess process, IntPtr address, int length)
27+
public IEnumerable<DisassembledInstruction> RemoteDisassembleCode(RemoteProcess process, IntPtr address, int length)
3028
{
3129
Contract.Requires(process != null);
32-
Contract.Ensures(Contract.Result<List<DisassembledInstruction>>() != null);
30+
Contract.Ensures(Contract.Result<IEnumerable<DisassembledInstruction>>() != null);
3331

3432
var buffer = process.ReadRemoteMemory(address, length);
3533

3634
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
3735
try
3836
{
39-
return DisassembleCode(handle.AddrOfPinnedObject(), length, address).ToList();
37+
return DisassembleCode(handle.AddrOfPinnedObject(), length, address);
4038
}
4139
finally
4240
{
@@ -47,9 +45,7 @@ public List<DisassembledInstruction> RemoteDisassembleCode(RemoteProcess process
4745
}
4846
}
4947

50-
/// <summary>
51-
/// Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>).
52-
/// </summary>
48+
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>).</summary>
5349
/// <param name="address">The address of the code.</param>
5450
/// <param name="length">The length of the code.</param>
5551
/// <param name="virtualAddress">The virtual address of the code. This allows to decode instructions located anywhere in memory even if they are not at their original place.</param>
@@ -64,7 +60,7 @@ public IEnumerable<DisassembledInstruction> DisassembleCode(IntPtr address, int
6460
var instruction = new InstructionData();
6561
while (eip.CompareTo(end) == -1)
6662
{
67-
var res = nativeHelper.DisassembleCode(eip, end.Sub(eip).ToInt32(), virtualAddress, out instruction);
63+
var res = nativeHelper.DisassembleCode(eip, end.Sub(eip).ToInt32() + 1, virtualAddress, out instruction);
6864
if (!res)
6965
{
7066
break;
@@ -83,24 +79,22 @@ public IEnumerable<DisassembledInstruction> DisassembleCode(IntPtr address, int
8379
}
8480
}
8581

86-
/// <summary>
87-
/// Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) in the remote process until the first 0xCC instruction.
88-
/// </summary>
82+
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="maxLength"/>) in the remote process until the first 0xCC instruction.</summary>
8983
/// <param name="process">The process to read from.</param>
9084
/// <param name="address">The address of the code.</param>
91-
/// <param name="length">The length of the code.</param>
85+
/// <param name="maxLength">The maximum maxLength of the code.</param>
9286
/// <returns>A list of <see cref="DisassembledInstruction"/>.</returns>
93-
public List<DisassembledInstruction> RemoteDisassembleFunction(RemoteProcess process, IntPtr address, int length)
87+
public IEnumerable<DisassembledInstruction> RemoteDisassembleFunction(RemoteProcess process, IntPtr address, int maxLength)
9488
{
9589
Contract.Requires(process != null);
96-
Contract.Ensures(Contract.Result<List<DisassembledInstruction>>() != null);
90+
Contract.Ensures(Contract.Result<IEnumerable<DisassembledInstruction>>() != null);
9791

98-
var buffer = process.ReadRemoteMemory(address, length);
92+
var buffer = process.ReadRemoteMemory(address, maxLength);
9993

10094
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
10195
try
10296
{
103-
return DisassembleFunction(handle.AddrOfPinnedObject(), length, address).ToList();
97+
return DisassembleFunction(handle.AddrOfPinnedObject(), maxLength, address);
10498
}
10599
finally
106100
{
@@ -111,25 +105,21 @@ public List<DisassembledInstruction> RemoteDisassembleFunction(RemoteProcess pro
111105
}
112106
}
113107

114-
/// <summary>
115-
/// Disassembles the code in the given range (<paramref name="address"/>, <paramref name="length"/>) until the first 0xCC instruction.
116-
/// </summary>
108+
/// <summary>Disassembles the code in the given range (<paramref name="address"/>, <paramref name="maxLength"/>) until the first 0xCC instruction.</summary>
117109
/// <param name="address">The address of the code.</param>
118-
/// <param name="length">The length of the code.</param>
110+
/// <param name="maxLength">The maxLength of the code.</param>
119111
/// <param name="virtualAddress">The virtual address of the code. This allows to decode instructions located anywhere in memory even if they are not at their original place.</param>
120112
/// <returns>A list of <see cref="DisassembledInstruction"/>.</returns>
121-
public IEnumerable<DisassembledInstruction> DisassembleFunction(IntPtr address, int length, IntPtr virtualAddress)
113+
public IEnumerable<DisassembledInstruction> DisassembleFunction(IntPtr address, int maxLength, IntPtr virtualAddress)
122114
{
123115
Contract.Ensures(Contract.Result<IEnumerable<DisassembledInstruction>>() != null);
124116

125117
// Read until first CC.
126-
return DisassembleCode(address, length, virtualAddress)
118+
return DisassembleCode(address, maxLength, virtualAddress)
127119
.TakeWhile(i => !(i.Length == 1 && i.Data[0] == 0xCC));
128120
}
129121

130-
/// <summary>
131-
/// Disassembles the instruction prior to the given address.
132-
/// </summary>
122+
/// <summary>Tries to find and disassembles the instruction prior to the given address.</summary>
133123
/// <param name="process">The process to read from.</param>
134124
/// <param name="address">The address of the code.</param>
135125
/// <returns>The prior instruction.</returns>
@@ -151,6 +141,10 @@ public DisassembledInstruction RemoteGetPreviousInstruction(RemoteProcess proces
151141
}
152142
}
153143

144+
/// <summary>Gets the previous instruction.</summary>
145+
/// <param name="address">The address of the code.</param>
146+
/// <param name="virtualAddress">The virtual address of the code. This allows to decode instructions located anywhere in memory even if they are not at their original place.</param>
147+
/// <returns>The previous instruction.</returns>
154148
private DisassembledInstruction GetPreviousInstruction(IntPtr address, IntPtr virtualAddress)
155149
{
156150
var end = address + 80;
@@ -169,12 +163,15 @@ private DisassembledInstruction GetPreviousInstruction(IntPtr address, IntPtr vi
169163
x = GetPreviousInstructionHelper(end, 10, virtualAddress, ref instruction);
170164
if (x != end)
171165
{
172-
for (var i = 1; i < 20; ++i)
166+
for (var i = 1; i < 15; ++i)
173167
{
174-
x = end - i;
175-
if (nativeHelper.DisassembleCode(x, end.Sub(x).ToInt32(), virtualAddress, out instruction))
168+
x = address + 65 + i;
169+
if (nativeHelper.DisassembleCode(x, end.Sub(x).ToInt32() + 1, virtualAddress, out instruction))
176170
{
177-
break;
171+
if (x + instruction.Length == end)
172+
{
173+
break;
174+
}
178175
}
179176
}
180177
}
@@ -186,6 +183,7 @@ private DisassembledInstruction GetPreviousInstruction(IntPtr address, IntPtr vi
186183
{
187184
Address = virtualAddress - instruction.Length,
188185
Length = instruction.Length,
186+
Data = instruction.Data,
189187
Instruction = instruction.Instruction
190188
};
191189
}
@@ -196,7 +194,7 @@ private IntPtr GetPreviousInstructionHelper(IntPtr address, int distance, IntPtr
196194
var y = virtualAddress - distance;
197195
while (x.CompareTo(address) == -1) // aka x < address
198196
{
199-
if (nativeHelper.DisassembleCode(x, address.Sub(x).ToInt32(), y, out instruction))
197+
if (nativeHelper.DisassembleCode(x, address.Sub(x).ToInt32() + 1, y, out instruction))
200198
{
201199
x += instruction.Length;
202200
y += instruction.Length;
@@ -208,6 +206,63 @@ private IntPtr GetPreviousInstructionHelper(IntPtr address, int distance, IntPtr
208206
}
209207
return x;
210208
}
209+
210+
/// <summary>Tries to find the start address of the function <paramref name="address"/> points into.</summary>
211+
/// <param name="process">The process to read from.</param>
212+
/// <param name="address">The address inside the function.</param>
213+
/// <returns>The start address of the function (maybe) or <see cref="IntPtr.Zero"/> if no start address could be found.</returns>
214+
public IntPtr RemoteGetFunctionStartAddress(RemoteProcess process, IntPtr address)
215+
{
216+
const int BufferLength = 512;
217+
218+
var buffer = new byte[2 + BufferLength + 2 + 1];
219+
220+
for (var i = 1; i <= 10; ++i)
221+
{
222+
if (!process.ReadRemoteMemoryIntoBuffer(address - i * BufferLength - 2, ref buffer))
223+
{
224+
return IntPtr.Zero;
225+
}
226+
227+
for (var o = BufferLength + 4; o >= 0; --o)
228+
{
229+
// Search for two CC in a row.
230+
if (buffer[o] == 0xCC && buffer[o - 1] == 0xCC)
231+
{
232+
var start = address - i * BufferLength + o - 1;
233+
234+
// Check if the two previous instructions are really a CC.
235+
var prevInstruction = RemoteGetPreviousInstruction(process, start);
236+
if (prevInstruction.Length == 1 && prevInstruction.Data[0] == 0xCC)
237+
{
238+
prevInstruction = RemoteGetPreviousInstruction(process, start - 1);
239+
if (prevInstruction.Length == 1 && prevInstruction.Data[0] == 0xCC)
240+
{
241+
// Disassemble the code from the start and check if the instructions sum up to address.
242+
var length = RemoteDisassembleCode(process, start, address.Sub(start).ToInt32())
243+
.Select(inst => inst.Length)
244+
.Sum();
245+
246+
if (start + length == address)
247+
{
248+
return start;
249+
}
250+
}
251+
else
252+
{
253+
o -= prevInstruction.Length;
254+
}
255+
}
256+
else
257+
{
258+
o -= prevInstruction.Length;
259+
}
260+
}
261+
}
262+
}
263+
264+
return IntPtr.Zero;
265+
}
211266
}
212267

213268
public class DisassembledInstruction
@@ -217,6 +272,8 @@ public class DisassembledInstruction
217272
public byte[] Data;
218273
public string Instruction;
219274

275+
public bool IsValid => Length > 0;
276+
220277
public override string ToString() => $"{Address.ToString(Constants.StringHexFormat)} - {Instruction}";
221278
}
222279
}

0 commit comments

Comments
 (0)