PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Loading...
Searching...
No Matches
patch_analyzer.cpp
Go to the documentation of this file.
1#include "patch_analyzer.h"
2//---
3using namespace pesieve;
4
5template <typename DELTA_T>
12
14{
15 const size_t instr_size = 2;
16 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, instr_size)) {
17 return 0;
18 }
19 BYTE *lval = (BYTE*)((ULONGLONG)patch_ptr + 1);
21
22 patch.setHookTarget(addr);
23 return instr_size;
24}
25
27{
28 const size_t instr_size = 5;
29 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, instr_size)) {
30 return 0;
31 }
32 DWORD *lval = (DWORD*)((ULONGLONG) patch_ptr + 1);
34
35 patch.setHookTarget(addr);
36 return instr_size;
37}
38
40{
41 const size_t instr_size = 6;
43
44 DWORD *lval = (DWORD*)((ULONGLONG)patch_ptr + 2);
45 if (!isModule64bit) { //32bit
46 patch.setHookTarget(*lval, false);
47 }
48 else { //64bit
50 patch.setHookTarget(addr, false);
51 }
52 return instr_size;
53}
54
56{
57 size_t mov_instr_len = is_long ? 9 : 5;
58 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, mov_instr_len + 2)) {
59 return 0;
60 }
61
62 PBYTE jmp_ptr = patch_ptr + mov_instr_len; // next instruction
63 if (is64Modifier(*patch_ptr)) {
64 patch_ptr++;
65 jmp_ptr++;
66 mov_instr_len++; // add length of modifier
67 }
68
69 DWORD reg_id0 = patch_ptr[0] - 0xB8;
70
71 // before call/jmp there can be also the modifier...
72 if (is64Modifier(*jmp_ptr)) {
73 jmp_ptr++;
74 mov_instr_len++; // add length of modifier
75 }
76 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, jmp_ptr, 2)) {
77 return 0;
78 }
79 DWORD reg_id1 = 0;
80 if (jmp_ptr[0] == 0xFF && jmp_ptr[1] >= 0xE0 && jmp_ptr[1] <= 0xEF ) { // jmp reg
81 //jmp reg
82 reg_id1 = jmp_ptr[1] - 0xE0;
83 } else if (jmp_ptr[0] == 0xFF && jmp_ptr[1] >= 0xD0 && jmp_ptr[1] <= 0xDF ) { // call reg
84 //jmp reg
85 reg_id1 = jmp_ptr[1] - 0xD0;
86 } else {
87#ifdef _DEBUG
88 std::cerr << "It is not MOV->JMP" << std::hex << (DWORD)jmp_ptr[0] << std::endl;
89#endif
90 return NULL;
91 }
92 //TODO: take into account also modifiers
93 if (reg_id1 != reg_id0) {
94#ifdef _DEBUG
95 std::cerr << "MOV->JMP : reg mismatch" << std::endl;
96#endif
97 return NULL;
98 }
101 if (!is_long) { //32bit
102 DWORD *lval = (DWORD*)((ULONGLONG) patch_ptr + 1);
103 addr = *lval;
104 } else { //64bit
106 addr = *lval;
107 }
108 patch_size += 2; //add jump reg size
109 patch.setHookTarget(addr);
110#ifdef _DEBUG
111 std::cout << "----> Target: " << std::hex << addr << std::endl;
112#endif
113 return patch_size;
114}
115
117{
118 size_t instr_size = 5;
119 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, instr_size + 1)) {
120 return 0;
121 }
122 PBYTE ret_ptr = patch_ptr + instr_size; // next instruction
123 if (ret_ptr[0] != 0xC3) {
124 return NULL; // this is not push->ret
125 }
126 instr_size++;
127 DWORD *lval = (DWORD*)((ULONGLONG) patch_ptr + 1);
128 patch.setHookTarget(*lval);
129 return instr_size;
130}
131
133{
134 if (!isModule64bit) return false;
135 if (op >= 0x40 && op <= 0x4F) { // modifier
136 return true;
137 }
138 return false;
139}
140
142{
143 if (!isModule64bit) return false;
144 if (op >= 0x48 && op <= 0x4F) { // modifier
145 return true;
146 }
147 return false;
148}
149
151{
152 BYTE op = patch_ptr[0];
153 if (op == OP_JMP || op == OP_CALL_DWORD) {
154 return parseJmp(patch, patch_ptr, patch_va);
155 }
156 if (op == OP_SHORTJMP) {
157 return parseShortJmp(patch, patch_ptr, patch_va);
158 }
159 if (op == OP_PUSH_DWORD) {
160 return parsePushRet(patch, patch_ptr);
161 }
162 if (op == OP_JMP_VIA_ADDR_B1 && patch_ptr[1] == OP_JMP_VIA_ADDR_B2) {
163 return parseJmpViaAddr(patch, patch_ptr, patch_va);
164 }
165
166 bool is_long = false;
167 if (is64Modifier(op)) { // mov modifier
168 if (isLongModifier(op)) {
169 is_long = true;
170 }
171 op = patch_ptr[1];
172 }
173
174 if (op >= 0xB8 && op <= 0xBF) { // is mov
175 return parseMovJmp(patch, patch_ptr, is_long);
176 }
177 return 0;
178}
179
181{
182 if (this->relocs.find(patch.startRva) == this->relocs.end()) {
183 return 0;
184 }
185 // This patch is a relocated field
186 const size_t fieldSize = (this->moduleData.is64bit()) ? sizeof(ULONGLONG) : sizeof(DWORD);
187 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, fieldSize)) {
188 return 0;
189 }
190 ULONGLONG field = (this->moduleData.is64bit()) ? *((ULONGLONG*)patch_ptr) : *((DWORD*)patch_ptr);
191 patch.setHookTarget(field, true, pesieve::HOOK_ADDR_REPLACEMENT);
192 return fieldSize;
193}
194
196{
197 const ULONGLONG patch_va = moduleData.rvaToVa(patch.startRva);
198 const size_t patch_offset = patch.startRva - sectionRVA;
199 BYTE* patch_ptr = this->patchedCode + patch_offset;
200
201 size_t size = _analyzeRelocated(patch, patch_ptr);
202 if (size) {
203 return size;
204 }
205 const size_t kMinSize = 3;
206 if (!peconv::validate_ptr(this->patchedCode, this->codeSize, patch_ptr, kMinSize)) {
207 return 0;
208 }
209 size = _analyze(patch, patch_ptr, patch_va);
210 if (size == 0 && patch_offset > 0) {
211 //it may happen that the address of an existing JMP/CALL was replaced
212 //try to parse a byte before the patch...
213 size = _analyze(patch, patch_ptr -1, patch_va - 1);
214 if (size > 0) {
215 // substract the added position:
216 size--;
217 }
218 }
219 return size;
220}
221
size_t _analyze(PatchList::Patch &patch, PBYTE patch_ptr, ULONGLONG patch_va)
size_t parseShortJmp(PatchList::Patch &patch, PBYTE patch_ptr, ULONGLONG patch_va)
size_t _analyzeRelocated(PatchList::Patch &patch, BYTE *patch_ptr)
size_t parseJmpViaAddr(PatchList::Patch &patch, PBYTE patch_ptr, ULONGLONG patch_va)
size_t parseJmp(PatchList::Patch &patch, PBYTE patch_ptr, ULONGLONG patch_va)
ULONGLONG getJmpDestAddr(ULONGLONG currVA, int instrLen, DELTA_T lVal)
size_t parseMovJmp(PatchList::Patch &patch, PBYTE patch_ptr, bool is_long)
size_t parsePushRet(PatchList::Patch &patch, PBYTE patch_ptr)
size_t analyze(PatchList::Patch &patch)
@ HOOK_ADDR_REPLACEMENT
Definition patch_list.h:14
size_t fill_iat(BYTE *vBuf, size_t vBufSize, IN const peconv::ExportsMapper *exportsMap, IN OUT IATBlock &iat, IN ThunkFoundCallback *callback)
Definition iat_finder.h:31