Changeset 4826 for zzuf


Ignore:
Timestamp:
Jul 10, 2012, 12:18:31 PM (7 years 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.