Changeset 4831


Ignore:
Timestamp:
07/31/12 15:54:47 (11 months ago)
Author:
wisk
Message:

change the method of hooking, now we disassemble the beginning of the targeted function and insert a jump to the new function.

Location:
zzuf/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • zzuf/trunk/AUTHORS

    r4253 r4831  
    99 Sami Liedes <sliedes#cc:hut:fi> (LD_PRELOAD conservation) 
    1010 Corentin Delorme <codelorme@gmail.com> (remote host filtering) 
     11 Kévin Szkudłapski <kszkudlapski@quarkslab.com> (win32 port) 
    1112 
  • zzuf/trunk/src/libzzuf/sys.c

    r4830 r4831  
    4848 
    4949#if defined HAVE_WINDOWS_H 
    50 static void insert_funcs(void *); 
     50static void insert_funcs(void); 
    5151 
    5252/* TODO: get rid of this later */ 
     
    7474#if defined HAVE_WINDOWS_H 
    7575 
    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(); 
    9477 
    9578#elif defined HAVE_DLFCN_H 
     
    11699#define MK_JMP_JD(dst, src) ((dst) - ((src) + 5)) 
    117100 
    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. */ 
     103static 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 */ 
     149static 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; 
    138155    DWORD old_prot; 
    139156 
     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 
    140164    *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; 
    145165 
    146166    jmp_prolog[0] = '\xe9'; /* jmp Jd */ 
    147167    *(uint32_t *)(&jmp_prolog[1]) = MK_JMP_JD(new_api, old_api); 
    148168 
    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); 
    153173 
    154174    /* We must make the trampoline executable, this line is required because of DEP */ 
    155175    /* 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; 
    157177 
    158178    /* 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 */ 
    162182 
    163183    *trampoline_api = trampoline; 
     
    175195    } 
    176196 
     197    if (jmp_prolog != NULL) free(jmp_prolog); 
     198 
    177199    return res; 
    178200} 
    179201 
    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[] =  
     202static void insert_funcs(void) 
     203{ 
     204    static zzuf_table_t *list[] = 
    188205    { 
    189206        table_win32, 
     
    212229            return; 
    213230        } 
    214         if (hook_hotpatch(old_api, diversion->new, &trampoline_api) < 0) 
    215         { 
    216             fprintf(stderr, "hook_hotpatch failed 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); 
    217234            return; 
    218235        } 
    219236        *diversion->old = trampoline_api; 
    220237    } 
    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.