libPeConv
A library to load, manipulate, dump PE files.
hooks.cpp
Go to the documentation of this file.
1#include "peconv/hooks.h"
2#include "peconv.h"
3#include "peconv/peb_lookup.h"
4
5using namespace peconv;
6
7namespace peconv {
8
9 bool is_pointer_in_ntdll(LPVOID lpAddress)
10 {
11 HMODULE mod = peconv::get_module_via_peb(L"ntdll.dll");
12 size_t module_size = peconv::get_module_size_via_peb(mod);
13 if (peconv::validate_ptr(mod, module_size, lpAddress, sizeof(BYTE))) {
14 return true; //this address lies within NTDLL
15 }
16 return false;
17 }
18
19 BOOL nt_protect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
20 {
21 FARPROC proc = peconv::get_exported_func(
22 peconv::get_module_via_peb(L"ntdll.dll"),
23 "NtProtectVirtualMemory"
24 );
25 if (!proc) {
26 return FALSE;
27 }
28 NTSTATUS(NTAPI *_NtProtectVirtualMemory)(
29 IN HANDLE,
30 IN OUT PVOID*,
31 IN OUT PSIZE_T,
32 IN DWORD,
33 OUT PDWORD) =
34 (NTSTATUS(NTAPI *)(
35 IN HANDLE,
36 IN OUT PVOID*,
37 IN OUT PSIZE_T,
38 IN DWORD,
39 OUT PDWORD)) proc;
40
41 SIZE_T protect_size = dwSize;
42 NTSTATUS status = _NtProtectVirtualMemory(GetCurrentProcess(), &lpAddress, &protect_size, flNewProtect, lpflOldProtect);
43 if (status != S_OK) {
44 return FALSE;
45 }
46 return TRUE;
47 }
48};
49
50bool PatchBackup::makeBackup(BYTE *patch_ptr, size_t patch_size)
51{
52 if (!patch_ptr) {
53 return false;
54 }
56 this->sourcePtr = patch_ptr;
57 this->buffer = new BYTE[patch_size];
58 this->bufferSize = patch_size;
59
60 memcpy(buffer, patch_ptr, patch_size);
61 return true;
62}
63
65{
66 if (!isBackup()) {
67 return false;
68 }
69 DWORD oldProtect = 0;
70 if (!nt_protect((LPVOID)sourcePtr, bufferSize, PAGE_EXECUTE_READWRITE, &oldProtect)) {
71 return false;
72 }
73 memcpy(sourcePtr, buffer, bufferSize);
74 nt_protect((LPVOID)sourcePtr, bufferSize, oldProtect, &oldProtect);
75
76 //flush cache:
77 FlushInstructionCache(GetCurrentProcess(), sourcePtr, bufferSize);
78 return true;
79}
80
81FARPROC peconv::hooking_func_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
82{
83 //the name may be ordinal rather than string, so check if it is a valid pointer:
84 if (!peconv::is_bad_read_ptr(func_name, 1)) {
85 std::map<std::string, FARPROC>::iterator itr = hooks_map.find(func_name);
86 if (itr != hooks_map.end()) {
87 FARPROC hook = itr->second;
88#ifdef _DEBUG
89 std::cout << ">>>>>>Replacing: " << func_name << " by: " << hook << std::endl;
90#endif
91 return hook;
92 }
93 }
94 return peconv::default_func_resolver::resolve_func(lib_name, func_name);
95}
96
97size_t peconv::redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup* backup)
98{
99 if (!ptr) return 0;
100
101 BYTE hook_64[] = {
102 0x48, 0xB8, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xEE, 0xFF, //movabs rax,FFEE998877665544
103 0xFF, 0xE0 //jmp rax
104 };
105 const size_t hook64_size = sizeof(hook_64);
106 if (is_pointer_in_ntdll(ptr)) {
107 std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
108 return 0;
109 }
110 DWORD oldProtect = 0;
111 if (!nt_protect((LPVOID)ptr,
112 hook64_size,
113 PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
114 &oldProtect))
115 {
116 return 0;
117 }
118
119 if (backup != nullptr) {
120 backup->makeBackup((BYTE*)ptr, hook64_size);
121 }
122 memcpy(hook_64 + 2, &new_offset, sizeof(ULONGLONG));
123 memcpy(ptr, hook_64, hook64_size);
124
125 nt_protect((LPVOID)ptr, hook64_size, oldProtect, &oldProtect);
126
127 //flush cache:
128 FlushInstructionCache(GetCurrentProcess(), ptr, hook64_size);
129 return hook64_size;
130}
131
132size_t peconv::redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup* backup)
133{
134 if (!ptr) return 0;
135
136 BYTE hook_32[] = {
137 0xB8, 0xCC, 0xDD, 0xEE, 0xFF, // mov eax,FFEEDDCC
138 0xFF, 0xE0 //jmp eax
139 };
140 const size_t hook32_size = sizeof(hook_32);
141 if (is_pointer_in_ntdll(ptr)) {
142 std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
143 return 0;
144 }
145 DWORD oldProtect = 0;
146 if (!nt_protect((LPVOID)ptr,
147 hook32_size,
148 PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
149 &oldProtect))
150 {
151 return 0;
152 }
153
154 if (backup != nullptr) {
155 backup->makeBackup((BYTE*)ptr, hook32_size);
156 }
157 memcpy(hook_32 + 1, &new_offset, sizeof(DWORD));
158 memcpy(ptr, hook_32, hook32_size);
159
160 nt_protect((LPVOID)ptr, hook32_size, oldProtect, &oldProtect);
161
162 //flush cache:
163 FlushInstructionCache(GetCurrentProcess(), ptr, hook32_size);
164 return hook32_size;
165}
166
167size_t peconv::redirect_to_local(void *ptr, void* new_function_ptr, PatchBackup* backup)
168{
169#ifdef _WIN64
170 return peconv::redirect_to_local64(ptr, (ULONGLONG)new_function_ptr, backup);
171#else
172 return peconv::redirect_to_local32(ptr, (DWORD)new_function_ptr, backup);
173#endif
174}
175
176inline long long int get_jmp_delta(ULONGLONG currVA, int instrLen, ULONGLONG destVA)
177{
178 long long int diff = destVA - (currVA + instrLen);
179 return diff;
180}
181
182inline bool is_valid_delta(long long int delta)
183{
184 DWORD first_dw = delta >> sizeof(DWORD) * 8;
185 if (first_dw == 0) {
186 return true;
187 }
188 const DWORD max_dword = DWORD(-1);
189 if (first_dw != max_dword) {
190 return false;
191 }
192 DWORD delta_dw = DWORD(delta);
193 if (delta_dw & 0x80000000) {
194 return true;
195 }
196 //invalid, sign bit is missing
197 return false;
198}
199
200bool peconv::replace_target(BYTE *patch_ptr, ULONGLONG dest_addr)
201{
202 typedef enum {
203 OP_JMP = 0xE9,
204 OP_CALL_DWORD = 0xE8
205 } t_opcode;
206
207 if (patch_ptr[0] == OP_JMP || patch_ptr[0] == OP_CALL_DWORD) {
208 ULONGLONG delta = get_jmp_delta(ULONGLONG(patch_ptr), 5, dest_addr);
209 if (!is_valid_delta(delta)) {
210#ifdef _DEBUG
211 std::cout << "Cannot replace the target: too big delta: " << std::hex << delta << std::endl;
212#endif
213 //too big delta, cannot be saved in a DWORD
214 return false;
215 }
216 DWORD delta_dw = DWORD(delta);
217 memcpy(patch_ptr + 1, &delta_dw, sizeof(DWORD));
218
219 //flush cache:
220 FlushInstructionCache(GetCurrentProcess(), patch_ptr + 1, sizeof(DWORD));
221 return true;
222 }
223 return false;
224}
size_t bufferSize
Definition: hooks.h:67
bool applyBackup()
Definition: hooks.cpp:64
BYTE * sourcePtr
Definition: hooks.h:69
BYTE * buffer
Definition: hooks.h:66
void deleteBackup()
Definition: hooks.h:38
bool makeBackup(BYTE *patch_ptr, size_t patch_size)
Definition: hooks.cpp:50
bool isBackup()
Definition: hooks.h:60
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name)
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name)
Definition: hooks.cpp:81
long long int get_jmp_delta(ULONGLONG currVA, int instrLen, ULONGLONG destVA)
Definition: hooks.cpp:176
bool is_valid_delta(long long int delta)
Definition: hooks.cpp:182
Functions related to hooking the loaded PE. Reditecting/replacing a functions with another.
bool validate_ptr(IN const void *buffer_bgn, IN SIZE_T buffer_size, IN const void *field_bgn, IN SIZE_T field_size)
Definition: buffer_util.cpp:9
BOOL nt_protect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
Definition: hooks.cpp:19
bool is_pointer_in_ntdll(LPVOID lpAddress)
Definition: hooks.cpp:9
FARPROC get_exported_func(PVOID modulePtr, LPSTR wanted_name)
size_t get_module_size_via_peb(IN OPTIONAL HMODULE hModule=nullptr)
Definition: peb_lookup.cpp:128
bool is_bad_read_ptr(LPCVOID areaStart, SIZE_T areaSize)
Definition: util.cpp:150
HMODULE get_module_via_peb(IN OPTIONAL LPWSTR module_name=nullptr)
Definition: peb_lookup.cpp:97
bool replace_target(BYTE *ptr, ULONGLONG dest_addr)
Definition: hooks.cpp:200
size_t redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup *backup=nullptr)
Definition: hooks.cpp:132
size_t redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup *backup=nullptr)
Definition: hooks.cpp:97
size_t redirect_to_local(void *ptr, void *new_function_ptr, PatchBackup *backup=nullptr)
Definition: hooks.cpp:167
long NTSTATUS
Definition: ntddk.h:28
Functions for retrieving process information from PEB.
Master include file, including everything else.