-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCodeCaveScanner.cpp
164 lines (138 loc) · 4.68 KB
/
CodeCaveScanner.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "CodeCaveScanner.h"
#include "BackendGlobalDef.h"
// CodeCaveScanner default constructor.
CodeCaveScanner::CodeCaveScanner()
{
this->mRunning = false;
}
// CodeCaveScanner default destructor.
CodeCaveScanner::~CodeCaveScanner()
{
}
// ---------------------------------------------------------------------------------------------
// Checks whether a specific address qualifies as a code cave.
const CodeCaveType CodeCaveScanner::QualifyForStartOfCodeCave(const cs_insn* insn) const
{
cs_detail* detail = insn->detail;
// Check for a zero instruction.
if (insn->size == 2 && *(WORD*)insn->bytes == 0)
{
return ZERO_INSTRUCTIONS;
}
// Check for a NOP sled.
else if (insn->id == X86_INS_NOP)
{
return NOP_SLED;
}
// Check for an INT3 sled.
else if (insn->id == X86_INS_INT3)
{
return INT3_SLED;
}
return UNKNOWN;
}
// The private worker function that actually executes the scan logic.
void CodeCaveScanner::DoScanForCodeCaves(const SIZE_T base, const SIZE_T size, const int caveLength, const cs_mode arch)
{
// Query virtual pages inside target process.
Byte* const buffer = new Byte[size];
CrySearchRoutines.CryReadMemoryRoutine(mMemoryScanner->GetHandle(), (void*)base, buffer, size, NULL);
// Open Capstone disassembler in x86 mode, for either x86_32 or x86_64.
csh handle;
cs_open(CS_ARCH_X86, arch, &handle);
// Allocate memory cache for 1 instruction, to be used by cs_disasm_iter later.
cs_insn* insn = cs_malloc(handle);
const Byte* bufIteratorPtr = buffer;
size_t code_size = size;
uint64 iterAddress = base;
uint64 prevAddress = iterAddress;
// Keeps track of the of code cave we started encountering.
CodeCaveType cType = UNKNOWN;
SIZE_T caveAddr = 0;
int currentCaveSize = 0;
// Keep disassembling until we reach the end of the specified input memory block.
do
{
// Disassemble one instruction a time & store the result into @insn variable.
while (cs_disasm_iter(handle, &bufIteratorPtr, &code_size, &iterAddress, insn))
{
// Disassembled succesfully, check whether this instruction would qualify as the
// start or addition of a code cave.
CodeCaveType tempType = this->QualifyForStartOfCodeCave(insn);
if (tempType != UNKNOWN)
{
// Is the code cave starting?
if (cType == UNKNOWN)
{
// Set address and start recording code cave size.
caveAddr = (SIZE_T)prevAddress;
currentCaveSize = insn->size;
}
else
{
// Increment the size of the code cave and continue.
currentCaveSize += insn->size;
}
// Set the code cave type.
cType = tempType;
}
else
{
// Check the size of the code cave, do we have a sufficiently large one?
if (currentCaveSize >= caveLength)
{
// Report the code cave to the user.
this->ScannerResultFound(caveAddr, currentCaveSize);
}
// Reset code cave data.
caveAddr = 0;
currentCaveSize = 0;
cType = tempType;
}
prevAddress = iterAddress;
}
// Check if we encountered an address that Capstone could not disassemble.
if (cs_errno(handle) == CS_ERR_OK && iterAddress < base + size)
{
// We don't want to check anything here, just increment the instruction pointer.
prevAddress = ++iterAddress;
}
}
while (prevAddress < base + size && this->mRunning);
// Release the cache memory when done.
cs_free(insn, 1);
// Close the Capstone handle and clean up used buffer.
cs_close(&handle);
delete[] buffer;
// Indicate that this work is done.
this->mRunning = false;
this->ScannerFinished();
}
// Scans for code caves asynchronously, given some memory block and cave size.
void CodeCaveScanner::ScanForCodeCaves(const SIZE_T base, const SIZE_T size, const int caveLength)
{
// Set the state to running.
this->mRunning = true;
// Signal the user interface that the scanning has started asynchronous.
// This callback does not run on a seperate thread and can be safely executed in the UI thread.
this->ScannerStarted();
// Start the scanning.
#ifdef _WIN64
this->mDisasmThread.Start(THISBACK4(DoScanForCodeCaves, base, size, caveLength, mMemoryScanner->IsX86Process() ? CS_MODE_32 : CS_MODE_64));
#else
this->mDisasmThread.Start(THISBACK4(DoScanForCodeCaves, base, size, caveLength, CS_MODE_32));
#endif
}
// ---------------------------------------------------------------------------------------------
// Gets whether the code cave scanner is running or not.
const bool CodeCaveScanner::IsRunning() const
{
return this->mRunning;
}
// Kills the code cave scanner if it is running in order to shut down operations on a possible crash detection.
void CodeCaveScanner::Kill()
{
this->mRunning = false;
// Block the thread until the disassembler threads has been killed.
this->mDisasmThread.Wait();
}