Changeset 4116 for zzuf/trunk


Ignore:
Timestamp:
Dec 12, 2009, 11:20:16 PM (10 years ago)
Author:
Sam Hocevar
Message:

Refactor the shellcode generation to remove all hardcoded values.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • zzuf/trunk/src/myfork.c

    r4115 r4116  
    5151
    5252#if defined HAVE_WINDOWS_H
    53 static int dll_inject(void *, void *);
     53static void rep32(uint8_t *buf, void *addr);
     54static int dll_inject(void *, void *, char const *);
    5455static intptr_t get_base_address(DWORD);
    5556static intptr_t get_entry_point_offset(char const *);
    56 #endif
    57 
    58 #if defined HAVE_WINDOWS_H
    59 static inline void addcpy(void *buf, void *x)
    60 {
    61     memcpy(buf, &x, 4);
    62 }
    6357#endif
    6458
     
    259253
    260254    /* Insert the replacement code */
    261     ret = dll_inject(pinfo.hProcess, epaddr);
     255    ret = dll_inject(pinfo.hProcess, epaddr, SONAME);
    262256    if(ret < 0)
    263257    {
     
    278272
    279273#if defined HAVE_WINDOWS_H
    280 static int dll_inject(void *process, void *epaddr)
    281 {
    282     uint8_t code1[] =                  /* LIBZZUF: */
    283                       "libzzuf.dll\0"
    284                                        /* OLDEP: */
    285                       "_______"
    286                                        /* START: */
    287                       "\xb8____"       /* mov eax,<libzzuf.dll> */
    288                       "\x50"           /* push eax */
    289                       "\xb8____"       /* mov eax,<LoadLibraryA> */
    290                       "\xff\xd0"       /* call eax */
    291                       "\xb8\0\0\0\0"   /* mov eax,0 */
    292                       "\x50"           /* push eax */
    293                       "\xb8\x07\0\0\0" /* mov eax,7 */
    294                       "\x50"           /* push eax */
    295                       "\xb8____"       /* mov eax,<OLDEP> */
    296                       "\x50"           /* push eax */
    297                       "\xb8____"       /* mov eax,<NEWEP> */
    298                       "\x50"           /* push eax */
    299                       "\xb8____"       /* mov eax,<GetCurrentProcess> */
    300                       "\xff\xd0"       /* call eax */
    301                       "\x50"           /* push eax */
    302                       "\xb8____"       /* mov eax,<WriteProcessMemory> */
    303                       "\xff\xd0"       /* call eax */
    304                       "\xb8____"       /* mov eax,<NEWEP> */
    305                       "\xff\xe0";      /* jmp eax */
    306     uint8_t code2[] =                  /* NEWEP: */
    307                       "\xb8____"       /* mov eax,<START> */
    308                       "\xff\xe0";      /* jmp eax */
    309     void *lib;
     274static void rep32(uint8_t *buf, void *addr)
     275{
     276    while(buf++)
     277        if (memcmp(buf, "____", 4) == 0)
     278        {
     279            memcpy(buf, &addr, 4);
     280            return;
     281        }
     282}
     283
     284static int dll_inject(void *process, void *epaddr, char const *lib)
     285{
     286    static uint8_t const loader[] =
     287        /* Load the injected DLL into memory */
     288        "\xb8____"       /* mov %eax, <library_name_address> */
     289        "\x50"           /* push %eax */
     290        "\xb8____"       /* mov %eax, <LoadLibraryA> */
     291        "\xff\xd0"       /* call %eax */
     292        /* Restore the clobbered entry point code using our backup */
     293        "\xb8\0\0\0\0"   /* mov %eax,0 */
     294        "\x50"           /* push %eax */
     295        "\xb8____"       /* mov %eax, <jumper_length> */
     296        "\x50"           /* push %eax */
     297        "\xb8____"       /* mov %eax, <backuped_entry_point_address> */
     298        "\x50"           /* push %eax */
     299        "\xb8____"       /* mov %eax, <original_entry_point_address> */
     300        "\x50"           /* push %eax */
     301        "\xb8____"       /* mov %eax, <GetCurrentProcess> */
     302        "\xff\xd0"       /* call %eax */
     303        "\x50"           /* push %eax */
     304        "\xb8____"       /* mov %eax, <WriteProcessMemory> */
     305        "\xff\xd0"       /* call %eax */
     306        /* Jump to the original entry point */
     307        "\xb8____"       /* mov %eax, <original_entry_point_address> */
     308        "\xff\xe0";      /* jmp %eax */
     309
     310    static uint8_t const jumper[] =
     311        /* Jump to the injected loader */
     312        "\xb8____"       /* mov eax, <loader_address> */
     313        "\xff\xe0";      /* jmp eax */
     314
     315    /* code:
     316     * +---------------+--------------------+--------------+-------------+
     317     * |     loader    | entry point backup | library name |   jumper    |
     318     * |  len(loader)  |    len(jumper)     |   len(lib)   | len(jumper) |
     319     * +---------------+--------------------+--------------+-------------+ */
     320    uint8_t code[1024];
     321
     322    void *kernel32;
    310323    uint8_t *loaderaddr;
     324    size_t liblen, loaderlen, jumperlen;
    311325    DWORD tmp;
    312326
    313     /* Backup the old entry-point code */
    314     ReadProcessMemory(process, epaddr, code1 + 0x0c, 7, &tmp);
    315     if(tmp != 7)
    316         return -1;
    317 
    318     /* Copy the first shell code to a freshly allocated memory area. */
    319     loaderaddr = VirtualAllocEx(process, NULL, sizeof(code1), MEM_COMMIT,
    320                                 PAGE_EXECUTE_READWRITE);
     327    liblen = strlen(lib) + 1;
     328    loaderlen = sizeof(loader) - 1;
     329    jumperlen = sizeof(jumper) - 1;
     330    if (loaderlen + jumperlen + liblen > 1024)
     331        return -1;
     332
     333    /* Allocate memory in the child for our injected code */
     334    loaderaddr = VirtualAllocEx(process, NULL, loaderlen + jumperlen + liblen,
     335                                MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    321336    if(!loaderaddr)
    322337        return -1;
    323338
    324     lib = LoadLibrary("kernel32.dll");
    325     if(!lib)
    326         return -1;
    327 
    328     addcpy(code1 + 0x14, loaderaddr + 0x00); /* offset for dll string */
    329     addcpy(code1 + 0x1a, GetProcAddress(lib, "LoadLibraryA"));
    330     addcpy(code1 + 0x2d, loaderaddr + 0x0c);
    331     addcpy(code1 + 0x33, epaddr);
    332     addcpy(code1 + 0x39, GetProcAddress(lib, "GetCurrentProcess"));
    333     addcpy(code1 + 0x41, GetProcAddress(lib, "WriteProcessMemory"));
    334     addcpy(code1 + 0x48, epaddr);
    335     FreeLibrary(lib);
    336 
    337     WriteProcessMemory(process, loaderaddr, code1, sizeof(code1), &tmp);
    338     if(tmp != sizeof(code1))
    339         return -1;
    340 
    341     /* Copy the second shell code where the old entry point was. */
    342     addcpy(code2 + 0x01, loaderaddr + 12 + 7);
    343     WriteProcessMemory(process, epaddr, code2, 7, &tmp);
    344     if(tmp != 7)
     339    /* Create the first shellcode (jumper).
     340     *
     341     * The jumper's job is simply to jump at the second shellcode's location.
     342     * It is written at the original entry point's location, which will in
     343     * turn be restored by the second shellcode.
     344     */
     345    memcpy(code + loaderlen + jumperlen + liblen, jumper, jumperlen);
     346    rep32(code + loaderlen + jumperlen + liblen, loaderaddr);
     347
     348    /* Create the second shellcode (loader, backuped entry point, and library
     349     * name).
     350     *
     351     * The loader's job is to load the library by calling LoadLibraryA(),
     352     * restore the original entry point using the backup copy, and jump
     353     * back to the original entry point as if the process had just started.
     354     *
     355     * The second shellcode is written at a freshly allocated memory location.
     356     */
     357    memcpy(code, loader, loaderlen);
     358    memcpy(code + loaderlen + jumperlen, lib, liblen);
     359
     360    /* Backup the old entry point code */
     361    ReadProcessMemory(process, epaddr, code + loaderlen,
     362                      jumperlen, &tmp);
     363    if(tmp != jumperlen)
     364        return -1;
     365
     366    /* FIXME: the GetProcAddress calls assume the library was loaded at
     367     * the same address in the child process. This is wrong since Vista
     368     * and its address space randomisation. */
     369    kernel32 = LoadLibrary("kernel32.dll");
     370    if(!kernel32)
     371        return -1;
     372
     373    rep32(code, loaderaddr + loaderlen + jumperlen);
     374    rep32(code, GetProcAddress(kernel32, "LoadLibraryA"));
     375    rep32(code, (void *)(uintptr_t)jumperlen);
     376    rep32(code, loaderaddr + loaderlen);
     377    rep32(code, epaddr);
     378    rep32(code, GetProcAddress(kernel32, "GetCurrentProcess"));
     379    rep32(code, GetProcAddress(kernel32, "WriteProcessMemory"));
     380    rep32(code, epaddr);
     381    FreeLibrary(kernel32);
     382
     383    /* Write our shellcodes into the target process */
     384    WriteProcessMemory(process, epaddr, code + loaderlen + jumperlen + liblen,
     385                       jumperlen, &tmp);
     386    if(tmp != jumperlen)
     387        return -1;
     388
     389    WriteProcessMemory(process, loaderaddr, code,
     390                       loaderlen + jumperlen + liblen, &tmp);
     391    if(tmp != loaderlen + jumperlen + liblen)
    345392        return -1;
    346393
Note: See TracChangeset for help on using the changeset viewer.