Changeset 4831
- Timestamp:
- 07/31/12 15:54:47 (11 months ago)
- Location:
- zzuf/trunk
- Files:
-
- 2 edited
-
AUTHORS (modified) (1 diff)
-
src/libzzuf/sys.c (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
zzuf/trunk/AUTHORS
r4253 r4831 9 9 Sami Liedes <sliedes#cc:hut:fi> (LD_PRELOAD conservation) 10 10 Corentin Delorme <codelorme@gmail.com> (remote host filtering) 11 Kévin Szkudłapski <kszkudlapski@quarkslab.com> (win32 port) 11 12 -
zzuf/trunk/src/libzzuf/sys.c
r4830 r4831 48 48 49 49 #if defined HAVE_WINDOWS_H 50 static void insert_funcs(void *);50 static void insert_funcs(void); 51 51 52 52 /* TODO: get rid of this later */ … … 74 74 #if defined HAVE_WINDOWS_H 75 75 76 MEMORY_BASIC_INFORMATION mbi; 77 MODULEENTRY32 entry; 78 void *list; 79 int k; 80 81 /* Enumerate all loaded objects and overwrite some functions */ 82 VirtualQuery(_zz_sys_init, &mbi, sizeof(mbi)); 83 list = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); 84 entry.dwSize = sizeof(entry); 85 for(k = Module32First(list, &entry); k; k = Module32Next(list, &entry)) 86 { 87 if(entry.hModule == mbi.AllocationBase) 88 continue; /* Don't replace our own functions */ 89 90 fprintf(stderr, "diverting functions from %s\n", entry.szModule); 91 insert_funcs(entry.hModule); 92 } 93 CloseHandle(list); 76 insert_funcs(); 94 77 95 78 #elif defined HAVE_DLFCN_H … … 116 99 #define MK_JMP_JD(dst, src) ((dst) - ((src) + 5)) 117 100 118 /* 119 * This function hooks a windows API using the hotpatch method 120 * old_api must point to the original windows API. 121 * new_api must point to the hook function 122 * trampoline_api is filled by the function and contains the 123 * function to call to call the original API. 124 * 125 * Windows API should start with the following instructions 126 * mov edi, edi 127 * push ebp 128 * mov ebp, esp 129 * which makes a 5 bytes, the perfect size to insert a jmp to the new api 130 */ 131 static int hook_hotpatch(uint8_t *old_api, uint8_t *new_api, uint8_t **trampoline_api) 132 { 133 int res = -1; 134 uint8_t prolog[5]; 135 uint8_t jmp_prolog[5]; 136 static uint8_t const hotpatch_prolog[] = "\x8b\xff\x55\x8b\xec"; 137 uint8_t *trampoline; 101 /* zz_lde is a _very_ simple length disassemble engine. 102 * x64 is not tested and should not work. */ 103 static int zz_lde(uint8_t *code, int required_size) 104 { 105 int insn_size = 0; 106 static uint8_t modrm_size[] = { 0, 1, 4, 0 }; /* [reg ...], [reg ... + sbyte], [reg ... + sdword], reg */ 107 108 while (insn_size < required_size) 109 { 110 uint8_t opcd = code[insn_size++]; 111 112 /* Simple instructions should be placed here */ 113 switch (opcd) 114 { 115 case 0x68: insn_size += 4; continue; /* PUSH Iv */ 116 case 0x6a: insn_size += 1; continue; /* PUSH Ib */ 117 default: break; 118 } 119 120 /* PUSH/POP rv */ 121 if ((opcd & 0xf0) == 0x50) continue; 122 123 /* MOV Ev, Gv or Gv, Ev */ 124 else if (opcd == 0x89 || opcd == 0x8b) 125 { 126 uint8_t modrm = code[insn_size++]; 127 128 /* Does the instruciton have a SIB byte ? */ 129 if (((modrm & 0x7) == 0x4) && ((modrm >> 6) != 0x3)) 130 insn_size++; 131 132 insn_size += modrm_size[modrm >> 6]; 133 134 continue; 135 } 136 137 138 /* If we can't disassemble the current instruction, we give up */ 139 return -1; 140 } 141 142 return insn_size; 143 } 144 145 /* This function allows to hook any API. To do so, it disassembles the beginning of the 146 * targeted function and looks for, at least, 5 bytes (size of JMP Jd). 147 * Then it writes a JMP Jv instruction to make the new_api executed. 148 * Finally, trampoline_api contains a wrapper to call in order to execute the original API */ 149 static int hook_inline(uint8_t *old_api, uint8_t *new_api, uint8_t **trampoline_api) 150 { 151 int res = -1; 152 int patch_size = 0; 153 uint8_t *jmp_prolog = NULL; 154 uint8_t *trampoline = NULL; 138 155 DWORD old_prot; 139 156 157 /* if we can't get enough byte, we quit */ 158 if ((patch_size = zz_lde(old_api, 5)) == -1) 159 return -1; 160 161 if ((jmp_prolog = malloc(patch_size)) == NULL) goto _out; 162 memset(jmp_prolog, '\xcc', patch_size); /* We use 0xcc because the code after the jmp should be executed */ 163 140 164 *trampoline_api = NULL; 141 142 /* Check if the targeted API contains the hotpatch feature */143 memcpy(prolog, old_api, sizeof(prolog));144 if (memcmp(prolog, hotpatch_prolog, sizeof(prolog))) goto _out;145 165 146 166 jmp_prolog[0] = '\xe9'; /* jmp Jd */ 147 167 *(uint32_t *)(&jmp_prolog[1]) = MK_JMP_JD(new_api, old_api); 148 168 149 trampoline = malloc( 10); /* size of hotpatch_prolog+ sizeof of jmp Jd */150 memcpy(trampoline, hotpatch_prolog, sizeof(hotpatch_prolog) - 1);151 trampoline[5]= '\xe9'; /* jmp Jd */152 *(uint32_t *)&trampoline[ 6] = MK_JMP_JD(old_api + sizeof(hotpatch_prolog) - 1, trampoline + sizeof(hotpatch_prolog) - 1);169 trampoline = malloc(patch_size + 5); /* size of old byte + sizeof of jmp Jd */ 170 memcpy(trampoline, old_api, patch_size); 171 *(uint8_t *)&trampoline[patch_size] = '\xe9'; /* jmp Jd */ 172 *(uint32_t *)&trampoline[patch_size + 1] = MK_JMP_JD(old_api + patch_size, trampoline + patch_size); 153 173 154 174 /* We must make the trampoline executable, this line is required because of DEP */ 155 175 /* NOTE: We _must_ set the write protection, otherwise the heap allocator will crash ! */ 156 if (!VirtualProtect(trampoline, 10, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out;176 if (!VirtualProtect(trampoline, patch_size + 5, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out; 157 177 158 178 /* We patch the targeted API, so we must set it as writable */ 159 if (!VirtualProtect(old_api, sizeof(jmp_prolog), PAGE_EXECUTE_READWRITE, &old_prot)) goto _out;160 memcpy(old_api, jmp_prolog, sizeof(jmp_prolog));161 VirtualProtect(old_api, sizeof(jmp_prolog), old_prot, &old_prot); /* we don't care if this functon fails */179 if (!VirtualProtect(old_api, patch_size, PAGE_EXECUTE_READWRITE, &old_prot)) goto _out; 180 memcpy(old_api, jmp_prolog, patch_size); 181 VirtualProtect(old_api, patch_size, old_prot, &old_prot); /* we don't care if this functon fails */ 162 182 163 183 *trampoline_api = trampoline; … … 175 195 } 176 196 197 if (jmp_prolog != NULL) free(jmp_prolog); 198 177 199 return res; 178 200 } 179 201 180 /* 181 * Even if hook_hotpatch is working, it's look that some API don't use it anymore (kernel32!ReadFile) 182 * So we stay with IAT hook at this time 183 */ 184 #if 0 185 static void insert_funcs(void *module) 186 { 187 static zzuf_table_t *list[] = 202 static void insert_funcs(void) 203 { 204 static zzuf_table_t *list[] = 188 205 { 189 206 table_win32, … … 212 229 return; 213 230 } 214 if (hook_ hotpatch(old_api, diversion->new, &trampoline_api) < 0)215 { 216 fprintf(stderr, "hook_ hotpatchfailed while hooking %s!%s\n", diversion->lib, diversion->name);231 if (hook_inline(old_api, diversion->new, &trampoline_api) < 0) 232 { 233 fprintf(stderr, "hook_inline failed while hooking %s!%s\n", diversion->lib, diversion->name); 217 234 return; 218 235 } 219 236 *diversion->old = trampoline_api; 220 237 } 221 222 (void)module; /* not needed anymore */ 223 224 } 225 #endif 226 227 static void insert_funcs(void *module) 228 { 229 static zzuf_table_t *list[] = 230 { 231 table_win32, 232 }; 233 234 zzuf_table_t *diversion; 235 void *lib; 236 unsigned long dummy; 237 import_t import; 238 thunk_t thunk; 239 int k, j, i; 240 241 import = (import_t) 242 ImageDirectoryEntryToData(module, TRUE, 243 IMAGE_DIRECTORY_ENTRY_IMPORT, &dummy); 244 if(!import) 245 return; 246 247 for (k = 0, diversion = NULL; k < sizeof(list) / sizeof(*list); ) 248 { 249 if (!diversion) 250 diversion = list[k]; 251 252 if (!diversion->lib) 253 { 254 k++; 255 diversion = NULL; 256 continue; 257 } 258 259 fprintf(stderr, "diverting method %s (from %s)\n", 260 diversion->name, diversion->lib); 261 262 lib = GetModuleHandleA(diversion->lib); 263 *diversion->old = (void *)GetProcAddress(lib, diversion->name); 264 265 for(j = 0; import[j].Name; j++) 266 { 267 char *name = (char *)module + import[j].Name; 268 if(lstrcmpiA(name, diversion->lib) != 0) 269 continue; 270 271 thunk = (thunk_t)((char *)module + import[j].FirstThunk); 272 for(i = 0; thunk[i].u1.Function; i++) 273 { 274 void **func = (void **)&thunk[i].u1.Function; 275 if(*func != *diversion->old) 276 continue; 277 278 /* FIXME: The StarCraft 2 hack uses two methods for function 279 * diversion. See HookSsdt() and HookHotPatch(). */ 280 VirtualProtect(func, sizeof(func), PAGE_EXECUTE_READWRITE, &dummy); 281 WriteProcessMemory(GetCurrentProcess(), func, &diversion->new, 282 sizeof(diversion->new), NULL); 283 } 284 } 285 286 diversion++; 287 } 288 } 289 #endif 238 } 239 240 #endif
Note: See TracChangeset
for help on using the changeset viewer.
