J'ai fait un petit programme pour injecter une DLL et faire de la surcharge de fonctions en hookant l'API. Il y a 3 fichiers:
- vg.exe
- vg.dll
- test.exe
Je lance vg.exe ainsi :
vg.exe injecte vg.dll dans test.exe. Ce dernier appelle une fonction que je hook dans vg.dll
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 vg.exe test.exe
Voila les différents codes :
Pour vg.exe :
vg.dll :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 #include <stdio.h> #include <string.h> #include <windows.h> #define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ) typedef HMODULE (*_load_library) (const char *); typedef BOOL (*_free_library) (HMODULE); typedef struct _Vg Vg; struct _Vg { _load_library ll; _free_library fl; char *dll_fullname; int dll_length; struct { HANDLE process1; HANDLE thread; HANDLE process2; } child; DWORD exit_code; /* actually the base address of the mapped DLL */ }; FARPROC _vg_symbol_get (const char *module, const char *symbol) { HMODULE mod; FARPROC proc; printf (" * loading library %s... ", module); mod = LoadLibrary(module); if (!mod) { printf("failed\n", module); return NULL; } printf ("done\n"); printf (" * retrieving symbol %s... ", symbol); proc = GetProcAddress(mod, symbol); if (!proc) { printf("failed\n", symbol); goto free_library; } printf ("done\n"); FreeLibrary(mod); return proc; free_library: FreeLibrary(mod); return NULL; } Vg * vg_new() { char buf[MAX_PATH]; Vg *vg; HMODULE kernel32; DWORD length; /* Check if CreateRemoteThread() is available. */ /* MSDN suggests to check the availability of a */ /* function instead of checking the Windows version. */ kernel32 = LoadLibrary("kernel32.dll"); if (!kernel32) { printf("no kernel32.dll found\n"); return 0; } if (!GetProcAddress(kernel32, "CreateRemoteThread")) { printf("no CreateRemoteThread found\n"); goto free_kernel32; } vg = (Vg *)calloc (1, sizeof (Vg)); if (!vg) goto free_kernel32; vg->ll = (_load_library)_vg_symbol_get("kernel32.dll", "LoadLibraryA"); if (!vg->ll) goto free_vg; vg->fl = (_free_library)_vg_symbol_get("kernel32.dll", "FreeLibrary"); if (!vg->fl) goto free_vg; length = GetFullPathName("valgrind_dll.dll", MAX_PATH, buf, NULL); if (!length) { printf ("can't get full path name\n"); goto free_vg; } vg->dll_fullname = _strdup(buf); if (!vg->dll_fullname) goto free_vg; vg->dll_length = length + 1; FreeLibrary(kernel32); return vg; free_vg: free(vg); free_kernel32: FreeLibrary(kernel32); return 0; } void vg_del(Vg *vg) { if (!vg) return; if (vg->child.process2) CloseHandle(vg->child.process2); if (vg->child.thread) CloseHandle(vg->child.thread); if (vg->child.process1) CloseHandle(vg->child.process1); free(vg->dll_fullname); free(vg); } int vg_dll_inject(Vg *vg, const char *prog) { STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE process; HANDLE remote_thread; LPVOID remote_string; DWORD exit_code; /* actually the base address of the mapped DLL */ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); printf (" * creating child process %s... ", prog); if (!CreateProcess(NULL, (char *)prog, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { printf ("failed\n * can't spawn child process %s\n", prog); return 0; } printf ("done\n"); printf (" * waiting for the child process to initialize... "); if (!WaitForInputIdle(pi.hProcess, INFINITE)) { printf("failed\n * no process for %s\n", prog); goto close_handles; } printf ("done\n"); printf (" * opening child process... "); process = OpenProcess(CREATE_THREAD_ACCESS, FALSE, pi.dwProcessId); if (!process) { printf("failed\n * no process for %s\n", prog); goto close_handles; } printf ("done\n"); printf (" * allocating virtual memory... "); remote_string = VirtualAllocEx(process, NULL, vg->dll_length, MEM_COMMIT, PAGE_READWRITE); if (!remote_string) { printf("failed\n"); goto close_process; } printf ("done\n"); printf(" * writing process in virtual memory... "); if (!WriteProcessMemory(process, remote_string, vg->dll_fullname, vg->dll_length, NULL)) { printf("failed\n"); goto virtual_free; } printf ("done\n"); printf (" * execute thread... "); remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)vg->ll, remote_string, 0, NULL); if (!remote_thread) { printf("failed\n"); goto virtual_free; } printf ("done\n"); WaitForSingleObject(remote_thread, INFINITE); printf (" * getting exit code... "); if (!GetExitCodeThread(remote_thread, &exit_code)) { printf("failed\n"); goto close_thread; } printf ("done\n"); CloseHandle(remote_thread); VirtualFreeEx(process, remote_string, vg->dll_length + 1, MEM_RELEASE); printf(" * resume child process\n"); ResumeThread(pi.hThread); vg->child.process1 = pi.hProcess; vg->child.thread = pi.hThread; vg->child.process2 = process; vg->exit_code = exit_code; return 1; close_thread: CloseHandle(remote_thread); virtual_free: VirtualFreeEx(process, remote_string, vg->dll_length, MEM_RELEASE); close_process: CloseHandle(process); close_handles: CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return 0; } void vg_dll_extract(Vg *vg) { HANDLE thread; thread = CreateRemoteThread(vg->child.process2, NULL, 0, (LPTHREAD_START_ROUTINE)vg->fl, (void*)vg->exit_code, 0, NULL ); WaitForSingleObject(thread, INFINITE ); CloseHandle(thread ); } int main(int argc, char *argv[]) { Vg *vg; //if (argc < 2) // { // printf ("Usage: %s file\n\n", argv[0]); // return -1; // } vg = vg_new(); if (!vg) return -1; if (!vg_dll_inject(vg, "valgrind_test.exe"/*argv[1]*/)) { printf(" * injection failed\n * exiting...\n"); goto del_vg; } Sleep(2000); printf(" * fin process\n"); vg_dll_extract(vg); vg_del(vg); printf(" * ressources freed\n"); return 0; del_vg: vg_del(vg); return -1; }
test.exe:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 #include <stdio.h> #include <windows.h> #include <psapi.h> #include <imagehlp.h> typedef struct { char *func_name_old; PROC func_proc_old; PROC func_proc_new; } Vg_Hook; typedef LPVOID (*vgd_heap_alloc_t) (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); typedef BOOL (*vgd_heap_free_t) (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); typedef void (*vgd_get_system_info_t)(LPSYSTEM_INFO lpSystemInfo); typedef void (*vgd_get_system_time_t)(LPSYSTEM_INFO lpSystemTime); Vg_Hook vg_hooks_kernel32[2]; LPVOID WINAPI VG_HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) { vgd_heap_alloc_t *ha; LPVOID data; printf("HeapAlloc !!!\n"); ha = (vgd_heap_alloc_t *)vg_hooks_kernel32[0].func_proc_old; data = (*ha)(hHeap, dwFlags, dwBytes); return data; } BOOL WINAPI VG_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) { vgd_heap_free_t *hf; BOOL res; printf("HeapFree !!!\n"); hf = (vgd_heap_free_t *)vg_hooks_kernel32[1].func_proc_old; res = (*hf)(hHeap, dwFlags, lpMem); return res; } void WINAPI VG_GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { vgd_get_system_info_t *gsi; printf ("GetSystemInfo !!!\n"); gsi = (vgd_get_system_info_t *)vg_hooks_kernel32[0].func_proc_old; (*gsi)(lpSystemInfo); } void WINAPI VG_GetSystemTime(LPSYSTEM_INFO lpSystemTime) { vgd_get_system_time_t *gst; printf ("GetSystemTime !!!\n"); gst = (vgd_get_system_time_t *)vg_hooks_kernel32[1].func_proc_old; (*gst)(lpSystemTime); } #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue)) void _vgd_modules_hook_set(HMODULE module, const char *lib_name, PROC old_function_proc, PROC new_function_proc) { PIMAGE_IMPORT_DESCRIPTOR iid; PIMAGE_THUNK_DATA thunk; ULONG size; iid = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); if (!iid) return; while (iid->Name) { PSTR module_name; module_name = (PSTR)((PBYTE) module + iid->Name); if (_stricmp(module_name, lib_name) == 0) break; iid++; } if (!iid->Name) return; thunk = (PIMAGE_THUNK_DATA)((PBYTE)module + iid->FirstThunk ); while (thunk->u1.Function) { PROC *func; func = (PROC *)&thunk->u1.Function; if (*func == old_function_proc) { MEMORY_BASIC_INFORMATION mbi; DWORD dwOldProtect; VirtualQuery(func, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); if (!VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect)) return; *func = *new_function_proc; VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect); break; } thunk++; } } void _vgd_modules_hook(HMODULE main_module, const char *lib_name) { HMODULE mods[1024]; HMODULE lib_module; DWORD mods_nbr; unsigned int i; unsigned int j; lib_module = LoadLibrary(lib_name); for (j = 0; vg_hooks_kernel32[j].func_name_old; j++) vg_hooks_kernel32[j].func_proc_old = GetProcAddress(lib_module, vg_hooks_kernel32[j].func_name_old); if (!EnumProcessModules(GetCurrentProcess(), mods, sizeof(mods), &mods_nbr)) return; for (i = 0; i < (mods_nbr / sizeof(HMODULE)); i++) { if (mods[i] == main_module) continue; for (j = 0; vg_hooks_kernel32[j].func_name_old; j++) _vgd_modules_hook_set(mods[i], lib_name, vg_hooks_kernel32[j].func_proc_old, vg_hooks_kernel32[j].func_proc_new); } FreeLibrary(lib_module); } void _vgd_modules_unhook(HMODULE main_module, const char *lib_name) { HMODULE mods[1024]; DWORD mods_nbr; unsigned int i; unsigned int j; if (!EnumProcessModules(GetCurrentProcess(), mods, sizeof(mods), &mods_nbr)) return; for (i = 0; i < (mods_nbr / sizeof(HMODULE)); i++) { if (mods[i] == main_module) continue; for (j = 0; vg_hooks_kernel32[j].func_name_old; j++) _vgd_modules_hook_set(mods[i], lib_name, vg_hooks_kernel32[j].func_proc_new, vg_hooks_kernel32[j].func_proc_old); } } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReason, LPVOID lpReserved) { /* vg_hooks_kernel32[0].func_name_old = "HeapAlloc"; */ /* vg_hooks_kernel32[0].func_proc_old = NULL; */ /* vg_hooks_kernel32[0].func_proc_new = (PROC)VG_HeapAlloc; */ /* vg_hooks_kernel32[1].func_name_old = "HeapFree"; */ /* vg_hooks_kernel32[1].func_proc_old = NULL; */ /* vg_hooks_kernel32[1].func_proc_new = (PROC)VG_HeapFree; */ vg_hooks_kernel32[0].func_name_old = "GetSystemInfo"; vg_hooks_kernel32[0].func_proc_old = NULL; vg_hooks_kernel32[0].func_proc_new = (PROC)VG_GetSystemInfo; vg_hooks_kernel32[1].func_name_old = "GetSystemTime"; vg_hooks_kernel32[1].func_proc_old = NULL; vg_hooks_kernel32[1].func_proc_new = (PROC)VG_GetSystemTime; vg_hooks_kernel32[2].func_name_old = NULL; vg_hooks_kernel32[2].func_proc_old = NULL; vg_hooks_kernel32[2].func_proc_new = NULL; switch (ulReason) { case DLL_PROCESS_ATTACH: printf ("DLL attach\n"); printf ("hooking... "); _vgd_modules_hook(hModule, "kernel32.dll"); printf ("finished\n"); break; case DLL_PROCESS_DETACH: printf ("DLL detach\n"); /* _vgd_modules_unhook(hModule, "kernel32.dll"); */ break; } return TRUE; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 #include <stdio.h> #include <windows.h> int main() { SYSTEMTIME st; GetSystemTime(&st); /* Exception non gérée à 0x100115b6 dans test.exe: 0xC0000005: Violation d'accès lors de la lecture de l'emplacement 0x100115b6. */ return 0; }
- Si je ne fait pas d'API hooking dans vg.dll, test.exe s'exécute sans erreur, mais évidemment, pas de surcharge... Au moins, l'injection de DLL marche car des messages dans vg.dll sont affichés.
- Si je ne surcharge qu'une seule fonction dans vg.dll, test.exe ne s'exécute pas
- Si je surcharge 2 fonctions (comme c'est le cas dans le code de vg.dll ci-dessus), test.exe plante avec le message qui se trouve dans son code ci-dessus.
J'ai cherché pendan tout le week-end, sans trouver la solution. Quelqu'un voit-il le problème (qui se trouve certainement dans vg.dll) ?
Merci
PS : pour ceux qui veulent essayer, voici une archive. Il y a un Makefile pour compiler avec MinGW et la solution pour Visua Studio
Partager