Changeset 4826


Ignore:
Timestamp:
07/10/12 12:18:31 (11 months ago)
Author:
wisk
Message:
 
Location:
zzuf/trunk/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • zzuf/trunk/src/libzzuf/lib-win32.c

    r4813 r4826  
    4141/* Kernel functions that we divert */ 
    4242#if defined HAVE_CREATEFILEA 
    43 static HANDLE (__stdcall *ORIG(CreateFileA))(LPCTSTR, DWORD, DWORD, 
     43static HANDLE (__stdcall *ORIG(CreateFileA))(LPCSTR, DWORD, DWORD, 
    4444                                             LPSECURITY_ATTRIBUTES, 
    4545                                             DWORD, DWORD, HANDLE); 
     
    6767 
    6868#if defined HAVE_CREATEFILEA 
    69 HANDLE __stdcall NEW(CreateFileA)(LPCTSTR lpFileName, DWORD dwDesiredAccess, 
     69HANDLE __stdcall NEW(CreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, 
    7070           DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
    7171           DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, 
     
    7373{ 
    7474    HANDLE ret; 
     75 
    7576    ret = ORIG(CreateFileA)(lpFileName, dwDesiredAccess, dwShareMode, 
    7677                            lpSecurityAttributes, dwCreationDisposition, 
  • zzuf/trunk/src/libzzuf/sys.c

    r4813 r4826  
    155155                continue; 
    156156 
    157             thunk = (thunk_t)((char *)module + import->FirstThunk); 
     157            thunk = (thunk_t)((char *)module + import[j].FirstThunk); 
    158158            for(i = 0; thunk[i].u1.Function; i++) 
    159159            { 
  • zzuf/trunk/src/myfork.c

    r4813 r4826  
    7878static void rep32(uint8_t *buf, void *addr); 
    7979static int dll_inject(PROCESS_INFORMATION *, char const *); 
    80 static intptr_t get_proc_address(void *, DWORD, char const *); 
     80static void *get_proc_address(void *, DWORD, char const *); 
    8181#endif 
    8282 
     
    305305        DWORD err = GetLastError(); 
    306306        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    307                       FORMAT_MESSAGE_FROM_SYSTEM | 
     307                      FORMAT_MESSAGE_FROM_SYSTEM     | 
    308308                      FORMAT_MESSAGE_IGNORE_INSERTS, 
    309309                      NULL, err, 0, (LPTSTR)&buf, 0, NULL); 
     
    333333 
    334334#if defined HAVE_WINDOWS_H 
    335 static void rep32(uint8_t *buf, void *addr) 
    336 { 
    337     while(buf++) 
    338         if (memcmp(buf, "____", 4) == 0) 
    339         { 
    340             memcpy(buf, &addr, 4); 
    341             return; 
    342         } 
    343 } 
    344335 
    345336static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib) 
    346337{ 
    347     static uint8_t const loader[] = 
    348         /* Load the injected DLL into memory */ 
    349         "\xb8____"       /* mov %eax, <library_name_address> */ 
    350         "\x50"           /* push %eax */ 
    351         "\xb8____"       /* mov %eax, <LoadLibraryA> */ 
    352         "\xff\xd0"       /* call %eax */ 
    353         /* Restore the clobbered entry point code using our backup */ 
    354         "\xb8\0\0\0\0"   /* mov %eax,0 */ 
    355         "\x50"           /* push %eax */ 
    356         "\xb8____"       /* mov %eax, <jumper_length> */ 
    357         "\x50"           /* push %eax */ 
    358         "\xb8____"       /* mov %eax, <backuped_entry_point_address> */ 
    359         "\x50"           /* push %eax */ 
    360         "\xb8____"       /* mov %eax, <original_entry_point_address> */ 
    361         "\x50"           /* push %eax */ 
    362         "\xb8____"       /* mov %eax, <GetCurrentProcess> */ 
    363         "\xff\xd0"       /* call %eax */ 
    364         "\x50"           /* push %eax */ 
    365         "\xb8____"       /* mov %eax, <WriteProcessMemory> */ 
    366         "\xff\xd0"       /* call %eax */ 
    367         /* Jump to the original entry point */ 
    368         "\xb8____"       /* mov %eax, <original_entry_point_address> */ 
    369         "\xff\xe0";      /* jmp %eax */ 
    370  
    371     static uint8_t const waiter[] = 
    372         "\xeb\xfe";      /* jmp <current> */ 
    373  
    374     static uint8_t const jumper[] = 
    375         /* Jump to the injected loader */ 
    376         "\xb8____"       /* mov eax, <loader_address> */ 
    377         "\xff\xe0";      /* jmp eax */ 
    378  
    379     CONTEXT ctx; 
    380     void *process = pinfo->hProcess; 
    381     void *thread = pinfo->hThread; 
    382     void *epaddr; 
    383     DWORD pid = pinfo->dwProcessId; 
    384  
    385     /* code: 
    386      * +---------------+--------------------+--------------+-------------+ 
    387      * |     loader    | entry point backup | library name |   jumper    | 
    388      * |  len(loader)  |    len(jumper)     |   len(lib)   | len(jumper) | 
    389      * +---------------+--------------------+--------------+-------------+ */ 
    390     uint8_t code[1024]; 
    391  
    392     uint8_t *loaderaddr; 
    393     size_t liblen, loaderlen, waiterlen, jumperlen; 
    394     DWORD tmp; 
    395  
    396     liblen = strlen(lib) + 1; 
    397     loaderlen = sizeof(loader) - 1; 
    398     waiterlen = sizeof(waiter) - 1; 
    399     jumperlen = sizeof(jumper) - 1; 
    400     if (loaderlen + jumperlen + liblen > 1024) 
    401         return -1; 
    402  
    403     /* Allocate memory in the child for our injected code */ 
    404     loaderaddr = VirtualAllocEx(process, NULL, loaderlen + jumperlen + liblen, 
    405                                 MEM_COMMIT, PAGE_EXECUTE_READWRITE); 
    406     if(!loaderaddr) 
    407         return -1; 
    408  
    409     /* Create the first shellcode (jumper). 
    410      * 
    411      * The jumper's job is simply to jump at the second shellcode's location. 
    412      * It is written at the original entry point's location, which will in 
    413      * turn be restored by the second shellcode. 
    414      */ 
    415     memcpy(code + loaderlen + jumperlen + liblen, jumper, jumperlen); 
    416     rep32(code + loaderlen + jumperlen + liblen, loaderaddr); 
    417  
    418     /* Create the second shellcode (loader, backuped entry point, and library 
    419      * name). 
    420      * 
    421      * The loader's job is to load the library by calling LoadLibraryA(), 
    422      * restore the original entry point using the backup copy, and jump 
    423      * back to the original entry point as if the process had just started. 
    424      * 
    425      * The second shellcode is written at a freshly allocated memory location. 
    426      */ 
    427     memcpy(code, loader, loaderlen); 
    428     memcpy(code + loaderlen + jumperlen, lib, liblen); 
    429  
    430     /* Find the entry point address. It's simply in EAX. */ 
    431     ctx.ContextFlags = CONTEXT_FULL; 
    432     GetThreadContext(thread, &ctx); 
    433     epaddr = (void *)(uintptr_t)ctx.Eax; 
    434  
    435     /* Backup the old entry point code */ 
    436     ReadProcessMemory(process, epaddr, code + loaderlen, jumperlen, &tmp); 
    437     if(tmp != jumperlen) 
    438         return -1; 
    439  
    440     /* Replace the entry point code with a short jump to self, then resume 
    441      * the thread. This is necessary for CreateToolhelp32Snapshot() to 
    442      * work. */ 
    443     WriteProcessMemory(process, epaddr, waiter, waiterlen, &tmp); 
    444     if(tmp != waiterlen) 
    445         return -1; 
    446     FlushInstructionCache(process, epaddr, waiterlen); 
    447     ResumeThread(thread); 
    448  
    449     /* Wait until the entry point is reached */ 
    450     for (tmp = 0; tmp < 100; tmp++) 
    451     { 
    452         CONTEXT ctx; 
    453         ctx.ContextFlags = CONTEXT_FULL; 
    454         GetThreadContext(thread, &ctx); 
    455         if ((uintptr_t)ctx.Eip == (uintptr_t)epaddr) 
    456             break; 
     338    int res = -1; 
     339 
     340    /* This payload allows us to load arbitrary module located at the end of this buffer */ 
     341    static uint8_t const ldr[] = 
     342    { 
     343        "\x60"                  /* pushad               */ 
     344        "\xEB\x0E"              /* jmp short 0x11       */ 
     345        "\xB8____"              /* mov eax,LoadLibraryA */ 
     346        "\xFF\xD0"              /* call eax             */ 
     347        "\x85\xC0"              /* test eax,eax         */ 
     348        "\x75\x01"              /* jnz 0xf              */ 
     349        "\xCC"                  /* int3                 */ 
     350        "\x61"                  /* popad                */ 
     351        "\xC3"                  /* ret                  */ 
     352        "\xE8\xED\xFF\xFF\xFF"  /* call dword 0x3       */ 
     353    }; 
     354 
     355    /* We use this code to make the targeted process waits for us */ 
     356    static uint8_t const wait[] = "\xeb\xfe"; /* jmp $-1 */ 
     357    size_t wait_len             = sizeof(wait) - 1; 
     358    uint8_t orig_data[2]; 
     359 
     360    void *process   = pinfo->hProcess; 
     361    void *thread    = pinfo->hThread; 
     362    DWORD pid       = pinfo->dwProcessId; 
     363    void *rldlib    = NULL; 
     364    DWORD written   = 0; 
     365    DWORD old_prot  = 0; 
     366 
     367    /* Payload */ 
     368    void *rpl       = NULL; 
     369    uint8_t *pl     = NULL; 
     370    size_t pl_len   = sizeof(ldr) - 1 + strlen(lib) + 1; 
     371 
     372    CONTEXT ctxt; 
     373    DWORD oep; /* Original Entry Point */ 
     374 
     375    /* Use the main thread to inject our library */ 
     376    ctxt.ContextFlags = CONTEXT_FULL; 
     377    if (!GetThreadContext(thread, &ctxt)) goto _return; 
     378 
     379    /* Make the target program waits when it reachs the original entry point, because we can't do many thing from the windows loader */ 
     380    oep = ctxt.Eax; 
     381    if (!ReadProcessMemory(process, (LPVOID)oep, orig_data, sizeof(orig_data), &written) || written != sizeof(orig_data)) goto _return; /* save original opcode */ 
     382    if (!WriteProcessMemory(process, (LPVOID)oep, wait, wait_len , &written) || written != wait_len) goto _return;                      /* write jmp short $-1 */ 
     383    if (!FlushInstructionCache(process, (LPVOID)oep, wait_len)) goto _return; 
     384    if (ResumeThread(thread) == (DWORD)-1) goto _return; 
     385 
     386    /* Stop when the program reachs the oep */ 
     387    while (oep != ctxt.Eip) 
     388    { 
     389        if (!GetThreadContext(thread, &ctxt)) goto _return; 
    457390        Sleep(10); 
    458391    } 
    459     SuspendThread(thread); 
    460     if (tmp == 100) 
    461         return -1; 
    462  
    463     /* Remotely parse the target process's module list to get the addresses 
    464      * of the functions we need. This can only be done because we advanced 
    465      * the target's execution to the entry point. */ 
    466     rep32(code, loaderaddr + loaderlen + jumperlen); 
    467     rep32(code, (void *)get_proc_address(process, pid, "LoadLibraryA")); 
    468     rep32(code, (void *)(uintptr_t)jumperlen); 
    469     rep32(code, loaderaddr + loaderlen); 
    470     rep32(code, epaddr); 
    471     rep32(code, (void *)get_proc_address(process, pid, "GetCurrentProcess")); 
    472     rep32(code, (void *)get_proc_address(process, pid, "WriteProcessMemory")); 
    473     rep32(code, epaddr); 
    474  
    475     /* Write our shellcodes into the target process */ 
    476     WriteProcessMemory(process, epaddr, code + loaderlen + jumperlen + liblen, 
    477                        jumperlen, &tmp); 
    478     if(tmp != jumperlen) 
    479         return -1; 
    480     FlushInstructionCache(process, epaddr, waiterlen); 
    481  
    482     WriteProcessMemory(process, loaderaddr, code, 
    483                        loaderlen + jumperlen + liblen, &tmp); 
    484     if(tmp != loaderlen + jumperlen + liblen) 
    485         return -1; 
    486  
    487     return 0; 
     392 
     393    if (SuspendThread(thread) == (DWORD)-1) goto _return; 
     394 
     395    /* Resolve LoadLibraryA from the target process memory context */ 
     396    rldlib = get_proc_address(process, pid, "LoadLibraryA"); 
     397 
     398    if ((rpl = VirtualAllocEx(process, NULL, pl_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL) goto _return; 
     399 
     400    /* Emulate a call to the ldr code, thus the ret instruction from ldr will get eip back to the original entry point */ 
     401    ctxt.Esp -= 4; 
     402    if (!WriteProcessMemory(process, (LPVOID)ctxt.Esp, &oep, sizeof(oep), &written) || written != sizeof(oep)) goto _return; 
     403    ctxt.Eip = (DWORD)rpl; 
     404    if (!SetThreadContext(thread, &ctxt)) goto _return; 
     405 
     406    /* Forge the payload */ 
     407    if ((pl = (uint8_t *)malloc(pl_len)) == NULL) goto _return; 
     408    memcpy(pl, ldr, sizeof(ldr) - 1); 
     409    memcpy(pl + 4, &rldlib, sizeof(rldlib));        /* Write the address of LoadLibraryA         */ 
     410    strcpy((char *)(pl + sizeof(ldr) - 1), lib);    /* Write the first parameter of LoadLibraryA */ 
     411 
     412    if (!WriteProcessMemory(process, rpl, pl, pl_len, &written) || written != pl_len) goto _return; 
     413 
     414    /* Restore original opcode */ 
     415    if (!WriteProcessMemory(process, (LPVOID)oep, orig_data, sizeof(orig_data), &written) || written != sizeof(orig_data)) goto _return; 
     416 
     417    if (!FlushInstructionCache(process, rpl, pl_len)) goto _return; 
     418    if (!FlushInstructionCache(process, (LPVOID)oep, sizeof(orig_data))) goto _return; 
     419 
     420    res = 0; 
     421_return: 
     422    if (pl != NULL) free(pl); 
     423 
     424    /* We must not free remote allocated memory since they will be used after the process will be resumed */ 
     425    return res; 
    488426} 
    489427 
    490 static intptr_t get_proc_address(void *process, DWORD pid, const char *func) 
     428static void *get_proc_address(void *process, DWORD pid, const char *func) 
    491429{ 
    492430    char buf[1024]; 
     
    494432 
    495433    MODULEENTRY32 entry; 
    496     intptr_t ret = 0; 
     434    void *ret = 0; 
    497435    DWORD tmp; 
    498436    void *list; 
     
    508446 
    509447        uint32_t exportaddr; 
    510         uint8_t const *base = entry.modBaseAddr; 
     448        uint8_t *base = entry.modBaseAddr; 
    511449 
    512450        if (strcmp("kernel32.dll", entry.szModule)) 
     
    539477            ReadProcessMemory(process, base + expdir.AddressOfNameOrdinals 
    540478                                            + i * sizeof(WORD), 
    541                                 &j, sizeof(j), &tmp); 
     479                              &j, sizeof(j), &tmp); 
    542480            ReadProcessMemory(process, base + expdir.AddressOfFunctions 
    543481                                            + j * sizeof(DWORD), 
    544                                 &funcaddr, sizeof(funcaddr), &tmp); 
    545  
    546             ret = (intptr_t)base + funcaddr; 
     482                              &funcaddr, sizeof(funcaddr), &tmp); 
     483 
     484            ret = base + funcaddr; 
    547485            goto _finished; 
    548486        } 
Note: See TracChangeset for help on using the changeset viewer.