Skip to content

Commit 37f91bb

Browse files
committed
Disassemble multiple instructions at once.
1 parent 13315c2 commit 37f91bb

File tree

8 files changed

+116
-100
lines changed

8 files changed

+116
-100
lines changed

NativeCore/Shared/DistormHelper.cpp

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ extern "C"
77
#include <../src/instructions.h>
88
}
99

10-
bool AreOperandsStatic(_DInst *instruction, const int prefixLength)
10+
bool AreOperandsStatic(const _DInst &instruction, const int prefixLength)
1111
{
12-
const auto fc = META_GET_FC(instruction->meta);
12+
const auto fc = META_GET_FC(instruction.meta);
1313
if (fc == FC_UNC_BRANCH || fc == FC_CND_BRANCH)
1414
{
15-
if (instruction->size - prefixLength < 5)
15+
if (instruction.size - prefixLength < 5)
1616
{
1717
return true;
1818
}
1919
}
2020

21-
const auto ops = instruction->ops;
21+
const auto ops = instruction.ops;
2222
for (auto i = 0; i < OPERANDS_NO; i++)
2323
{
2424
switch (ops[i].type)
@@ -37,7 +37,7 @@ bool AreOperandsStatic(_DInst *instruction, const int prefixLength)
3737
case O_DISP:
3838
case O_SMEM:
3939
case O_MEM:
40-
if (instruction->dispSize < 32)
40+
if (instruction.dispSize < 32)
4141
{
4242
continue;
4343
}
@@ -58,12 +58,12 @@ bool AreOperandsStatic(_DInst *instruction, const int prefixLength)
5858
return true;
5959
}
6060

61-
int GetStaticInstructionBytes(_DInst *instruction, const uint8_t *data)
61+
int GetStaticInstructionBytes(const _DInst &instruction, const uint8_t *data)
6262
{
6363
_CodeInfo info = {};
6464
info.codeOffset = reinterpret_cast<_OffsetType>(data);
6565
info.code = data;
66-
info.codeLen = instruction->size;
66+
info.codeLen = instruction.size;
6767
info.features = DF_NONE;
6868
#ifdef RECLASSNET32
6969
info.dt = Decode32Bits;
@@ -88,13 +88,13 @@ int GetStaticInstructionBytes(_DInst *instruction, const uint8_t *data)
8888

8989
if (AreOperandsStatic(instruction, prefixLength))
9090
{
91-
return instruction->size;
91+
return instruction.size;
9292
}
9393

94-
return instruction->size - info.codeLen;
94+
return instruction.size - info.codeLen;
9595
}
9696

97-
bool DisassembleCodeImpl(const RC_Pointer address, const RC_Size length, const RC_Pointer virtualAddress, const bool determineStaticInstructionBytes, InstructionData* instruction)
97+
_CodeInfo CreateCodeInfo(const RC_Pointer address, const RC_Size length, const RC_Pointer virtualAddress)
9898
{
9999
_CodeInfo info = {};
100100
info.codeOffset = reinterpret_cast<_OffsetType>(virtualAddress);
@@ -108,50 +108,85 @@ bool DisassembleCodeImpl(const RC_Pointer address, const RC_Size length, const R
108108
info.dt = Decode64Bits;
109109
#endif
110110

111-
_DInst decodedInstructions[1] = {};
112-
unsigned int instructionCount = 0;
113-
114-
const auto res = distorm_decompose(&info, decodedInstructions, 1, &instructionCount);
115-
if (res == DECRES_INPUTERR || !(res == DECRES_SUCCESS || res == DECRES_MEMORYERR) || instructionCount != 1)
116-
{
117-
return false;
118-
}
119-
120-
_DecodedInst instructionInfo = {};
121-
distorm_format(&info, &decodedInstructions[0], &instructionInfo);
111+
return info;
112+
}
122113

123-
instruction->Length = instructionInfo.size;
124-
std::memcpy(instruction->Data, address, instructionInfo.size);
114+
void FillInstructionData(const RC_Pointer address, const _DInst& instruction, const _DecodedInst& instructionInfo, const bool determineStaticInstructionBytes, InstructionData* data)
115+
{
116+
data->Length = instructionInfo.size;
117+
std::memcpy(data->Data, address, instructionInfo.size);
125118

126119
MultiByteToUnicode(
127120
reinterpret_cast<const char*>(instructionInfo.mnemonic.p),
128-
instruction->Instruction,
121+
data->Instruction,
129122
instructionInfo.mnemonic.length
130123
);
131124
if (instructionInfo.operands.length != 0)
132125
{
133-
instruction->Instruction[instructionInfo.mnemonic.length] = ' ';
126+
data->Instruction[instructionInfo.mnemonic.length] = ' ';
134127

135128
MultiByteToUnicode(
136129
reinterpret_cast<const char*>(instructionInfo.operands.p),
137130
0,
138-
instruction->Instruction,
131+
data->Instruction,
139132
instructionInfo.mnemonic.length + 1,
140133
std::min<int>(64 - 1 - instructionInfo.mnemonic.length, instructionInfo.operands.length)
141134
);
142135
}
143136

144137
if (determineStaticInstructionBytes)
145138
{
146-
instruction->StaticInstructionBytes = GetStaticInstructionBytes(
147-
&decodedInstructions[0],
139+
data->StaticInstructionBytes = GetStaticInstructionBytes(
140+
instruction,
148141
reinterpret_cast<const uint8_t*>(address)
149142
);
150143
}
151144
else
152145
{
153-
instruction->StaticInstructionBytes = -1;
146+
data->StaticInstructionBytes = -1;
154147
}
148+
}
155149

156-
return true;
150+
bool DisassembleInstructionsImpl(const RC_Pointer address, const RC_Size length, const RC_Pointer virtualAddress, const bool determineStaticInstructionBytes, EnumerateInstructionCallback callback)
151+
{
152+
auto info = CreateCodeInfo(address, length, virtualAddress);
153+
154+
const unsigned MaxInstructions = 50;
155+
156+
_DInst decodedInstructions[MaxInstructions] = {};
157+
unsigned count = 0;
158+
159+
while (true)
160+
{
161+
const auto res = distorm_decompose(&info, decodedInstructions, MaxInstructions, &count);
162+
if (res == DECRES_INPUTERR)
163+
{
164+
return false;
165+
}
166+
167+
for (auto i = 0u; i < count; ++i)
168+
{
169+
_DecodedInst instructionInfo = {};
170+
distorm_format(&info, &decodedInstructions[i], &instructionInfo);
171+
172+
InstructionData data;
173+
FillInstructionData(address, decodedInstructions[i], instructionInfo, determineStaticInstructionBytes, &data);
174+
175+
if (callback(&data) == false)
176+
{
177+
return true;
178+
}
179+
}
180+
181+
if (res == DECRES_SUCCESS || count == 0)
182+
{
183+
return true;
184+
}
185+
186+
const auto offset = decodedInstructions[count - 1].addr - info.codeOffset;
187+
188+
info.codeOffset += offset;
189+
info.code += offset;
190+
info.codeLen -= offset;
191+
}
157192
}

NativeCore/Shared/DistormHelper.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22

33
#include "../ReClassNET_Plugin.hpp"
44

5-
bool DisassembleCodeImpl(const RC_Pointer address, const RC_Size length, const RC_Pointer virtualAddress, const bool determineStaticInstructionBytes, InstructionData* instruction);
5+
typedef bool(RC_CallConv EnumerateInstructionCallback)(InstructionData* data);
6+
7+
bool DisassembleInstructionsImpl(const RC_Pointer address, const RC_Size length, const RC_Pointer virtualAddress, const bool determineStaticInstructionBytes, EnumerateInstructionCallback callback);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "../Shared/DistormHelper.hpp"
22

3-
extern "C" bool RC_CallConv DisassembleCode(RC_Pointer address, RC_Size length, RC_Pointer virtualAddress, bool determineStaticInstructionBytes, InstructionData* instruction)
3+
extern "C" bool RC_CallConv DisassembleCode(RC_Pointer address, RC_Size length, RC_Pointer virtualAddress, bool determineStaticInstructionBytes, EnumerateInstructionCallback callback)
44
{
5-
return DisassembleCodeImpl(address, length, virtualAddress, determineStaticInstructionBytes, instruction);
5+
return DisassembleInstructionsImpl(address, length, virtualAddress, determineStaticInstructionBytes, callback);
66
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "../Shared/DistormHelper.hpp"
22

3-
bool RC_CallConv DisassembleCode(RC_Pointer address, RC_Size length, RC_Pointer virtualAddress, bool determineStaticInstructionBytes, InstructionData* instruction)
3+
bool RC_CallConv DisassembleCode(RC_Pointer address, RC_Size length, RC_Pointer virtualAddress, bool determineStaticInstructionBytes, EnumerateInstructionCallback callback)
44
{
5-
return DisassembleCodeImpl(address, length, virtualAddress, determineStaticInstructionBytes, instruction);
5+
return DisassembleInstructionsImpl(address, length, virtualAddress, determineStaticInstructionBytes, callback);
66
}

ReClass.NET/Core/CoreFunctionsManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ public bool SetHardwareBreakpoint(IntPtr id, IntPtr address, HardwareBreakpointR
174174

175175
#region Internal Core Functions
176176

177-
public bool DisassembleCode(IntPtr address, int length, IntPtr virtualAddress, bool determineStaticInstructionBytes, out InstructionData instruction)
177+
public bool DisassembleCode(IntPtr address, int length, IntPtr virtualAddress, bool determineStaticInstructionBytes, EnumerateInstructionCallback callback)
178178
{
179-
return internalCoreFunctions.DisassembleCode(address, length, virtualAddress, determineStaticInstructionBytes, out instruction);
179+
return internalCoreFunctions.DisassembleCode(address, length, virtualAddress, determineStaticInstructionBytes, callback);
180180
}
181181

182182
public IntPtr InitializeInput()

ReClass.NET/Core/InternalCoreFunctions.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace ReClassNET.Core
99
{
10+
public delegate bool EnumerateInstructionCallback(ref InstructionData data);
11+
1012
internal class InternalCoreFunctions : NativeCoreWrapper, IDisposable
1113
{
1214
private const string CoreFunctionsModuleWindows = "NativeCore.dll";
@@ -15,7 +17,7 @@ internal class InternalCoreFunctions : NativeCoreWrapper, IDisposable
1517
private readonly IntPtr handle;
1618

1719
[return: MarshalAs(UnmanagedType.I1)]
18-
private delegate bool DisassembleCodeDelegate(IntPtr address, IntPtr length, IntPtr virtualAddress, [MarshalAs(UnmanagedType.I1)] bool determineStaticInstructionBytes, out InstructionData instruction);
20+
private delegate bool DisassembleCodeDelegate(IntPtr address, IntPtr length, IntPtr virtualAddress, [MarshalAs(UnmanagedType.I1)] bool determineStaticInstructionBytes, [MarshalAs(UnmanagedType.FunctionPtr)] EnumerateInstructionCallback callback);
1921

2022
private delegate IntPtr InitializeInputDelegate();
2123

@@ -76,9 +78,9 @@ public void Dispose()
7678

7779
#endregion
7880

79-
public bool DisassembleCode(IntPtr address, int length, IntPtr virtualAddress, bool determineStaticInstructionBytes, out InstructionData instruction)
81+
public bool DisassembleCode(IntPtr address, int length, IntPtr virtualAddress, bool determineStaticInstructionBytes, EnumerateInstructionCallback callback)
8082
{
81-
return disassembleCodeDelegate(address, (IntPtr)length, virtualAddress, determineStaticInstructionBytes, out instruction);
83+
return disassembleCodeDelegate(address, (IntPtr)length, virtualAddress, determineStaticInstructionBytes, callback);
8284
}
8385

8486
public IntPtr InitializeInput()

ReClass.NET/Memory/Disassembler.cs

Lines changed: 33 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,15 @@ public IEnumerable<DisassembledInstruction> DisassembleCode(IntPtr address, int
7171

7272
while (eip.CompareTo(end) == -1)
7373
{
74-
var res = coreFunctions.DisassembleCode(eip, end.Sub(eip).ToInt32() + 1, virtualAddress, false, out var instruction);
74+
var instruction = default(InstructionData);
75+
76+
// Grab only one instruction.
77+
var res = coreFunctions.DisassembleCode(eip, end.Sub(eip).ToInt32() + 1, virtualAddress, false, (ref InstructionData data) =>
78+
{
79+
instruction = data;
80+
81+
return false;
82+
});
7583
if (!res)
7684
{
7785
break;
@@ -170,64 +178,40 @@ public DisassembledInstruction RemoteGetPreviousInstruction(RemoteProcess proces
170178
/// <returns>The previous instruction.</returns>
171179
private DisassembledInstruction GetPreviousInstruction(IntPtr address, IntPtr virtualAddress)
172180
{
173-
var end = address + 80;
181+
var instruction = default(InstructionData);
174182

175-
var instruction = new InstructionData();
176-
177-
var x = GetPreviousInstructionHelper(end, 80, virtualAddress, ref instruction);
178-
if (x != end)
183+
foreach (var offset in new[] { 80, 40, 20, 10, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 })
179184
{
180-
x = GetPreviousInstructionHelper(end, 40, virtualAddress, ref instruction);
181-
if (x != end)
185+
var currentAddress = address - offset;
186+
187+
coreFunctions.DisassembleCode(currentAddress, offset + 1, virtualAddress - offset, false, (ref InstructionData data) =>
182188
{
183-
x = GetPreviousInstructionHelper(end, 20, virtualAddress, ref instruction);
184-
if (x != end)
189+
var nextAddress = currentAddress + data.Length;
190+
if (nextAddress.CompareTo(address) > -1)
185191
{
186-
x = GetPreviousInstructionHelper(end, 10, virtualAddress, ref instruction);
187-
if (x != end)
188-
{
189-
for (var i = 1; i < 15; ++i)
190-
{
191-
x = address + 65 + i;
192-
if (coreFunctions.DisassembleCode(x, end.Sub(x).ToInt32() + 1, virtualAddress, false, out instruction))
193-
{
194-
if (x + instruction.Length == end)
195-
{
196-
break;
197-
}
198-
}
199-
}
200-
}
192+
return false;
201193
}
202-
}
203-
}
204194

205-
return new DisassembledInstruction
206-
{
207-
Address = virtualAddress - instruction.Length,
208-
Length = instruction.Length,
209-
Data = instruction.Data,
210-
Instruction = instruction.Instruction
211-
};
212-
}
195+
instruction = data;
213196

214-
private IntPtr GetPreviousInstructionHelper(IntPtr address, int distance, IntPtr virtualAddress, ref InstructionData instruction)
215-
{
216-
var x = address - distance;
217-
var y = virtualAddress - distance;
218-
while (x.CompareTo(address) == -1) // aka x < address
219-
{
220-
if (coreFunctions.DisassembleCode(x, address.Sub(x).ToInt32() + 1, y, false, out instruction))
221-
{
222-
x += instruction.Length;
223-
y += instruction.Length;
224-
}
225-
else
197+
currentAddress = nextAddress;
198+
199+
return true;
200+
});
201+
202+
if (currentAddress == address)
226203
{
227-
break;
204+
return new DisassembledInstruction
205+
{
206+
Address = virtualAddress - instruction.Length,
207+
Length = instruction.Length,
208+
Data = instruction.Data,
209+
Instruction = instruction.Instruction
210+
};
228211
}
229212
}
230-
return x;
213+
214+
return null;
231215
}
232216

233217
/// <summary>Tries to find the start address of the function <paramref name="address"/> points into.</summary>

ReClass.NET/MemoryScanner/PatternScanner.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics.Contracts;
44
using System.Runtime.InteropServices;
5+
using ReClassNET.Core;
56
using ReClassNET.Memory;
67
using ReClassNET.Util;
78

@@ -105,23 +106,15 @@ public static BytePattern CreatePatternFromCode(RemoteProcess process, IntPtr st
105106
try
106107
{
107108
var eip = handle.AddrOfPinnedObject();
108-
var end = eip + size;
109109

110-
while (eip.CompareTo(end) == -1)
110+
process.CoreFunctions.DisassembleCode(eip, size, IntPtr.Zero, true, (ref InstructionData instruction) =>
111111
{
112-
var res = process.CoreFunctions.DisassembleCode(eip, end.Sub(eip).ToInt32() + 1, IntPtr.Zero, true, out var instruction);
113-
if (!res)
114-
{
115-
break;
116-
}
117-
118112
for (var i = 0; i < instruction.Length; ++i)
119113
{
120114
data.Add(Tuple.Create(instruction.Data[i], i >= instruction.StaticInstructionBytes));
121115
}
122-
123-
eip += instruction.Length;
124-
}
116+
return true;
117+
});
125118
}
126119
finally
127120
{

0 commit comments

Comments
 (0)