Changeset 4648 for zzuf


Ignore:
Timestamp:
Sep 20, 2010, 3:16:36 AM (9 years ago)
Author:
Sam Hocevar
Message:

Improve the DLL injection code. Now seems to work rather
well under Windows. But it needs a lot of polishing.

Location:
zzuf/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • zzuf/trunk/src/libzzuf/sys.c

    r4645 r4648  
    3939
    4040/* TODO: get rid of this later */
    41 HINSTANCE (__stdcall *LoadLibraryA_orig)(LPCSTR);
    42 HINSTANCE __stdcall LoadLibraryA_new(LPCSTR path)
     41HINSTANCE (WINAPI *LoadLibraryA_orig)(LPCSTR);
     42HINSTANCE WINAPI LoadLibraryA_new(LPCSTR path)
    4343{
    4444    void *ret;
  • zzuf/trunk/src/myfork.c

    r4645 r4648  
    7474#if defined HAVE_WINDOWS_H
    7575static void rep32(uint8_t *buf, void *addr);
    76 static int dll_inject(void *, void *, char const *);
     76static int dll_inject(PROCESS_INFORMATION *, void *, char const *);
    7777static intptr_t get_base_address(DWORD);
    78 static intptr_t get_entry_point_offset(char const *);
     78static intptr_t get_entry_point(char const *name, DWORD pid);
     79static intptr_t get_proc_address(void *, DWORD, char const *);
    7980#endif
    8081
     
    261262    memset(&sinfo, 0, sizeof(sinfo));
    262263    sinfo.cb = sizeof(sinfo);
     264#if 0
    263265    DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[0][1]), pid,
    264266        /* FIXME */ &sinfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
     
    268270                    &sinfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    269271    sinfo.dwFlags = STARTF_USESTDHANDLES;
     272#endif
    270273    ret = CreateProcess(NULL, child->newargv[0], NULL, NULL, FALSE,
    271274                        CREATE_SUSPENDED, NULL, NULL, &sinfo, &pinfo);
     
    280283
    281284    /* Insert the replacement code */
    282     ret = dll_inject(pinfo.hProcess, epaddr, SONAME);
     285    ret = dll_inject(&pinfo, epaddr, SONAME);
    283286    if(ret < 0)
    284287    {
     
    294297    }
    295298
     299Sleep(5000);
    296300    return (long int)pinfo.hProcess;
    297301#endif
     
    309313}
    310314
    311 static int dll_inject(void *process, void *epaddr, char const *lib)
     315static int dll_inject(PROCESS_INFORMATION *pinfo,
     316                      void *epaddr, char const *lib)
    312317{
    313318    static uint8_t const loader[] =
     
    335340        "\xff\xe0";      /* jmp %eax */
    336341
     342    static uint8_t const waiter[] =
     343        "\xeb\xfe";      /* jmp <current> */
     344
    337345    static uint8_t const jumper[] =
    338346        /* Jump to the injected loader */
    339347        "\xb8____"       /* mov eax, <loader_address> */
    340348        "\xff\xe0";      /* jmp eax */
     349
     350    void *process = pinfo->hProcess;
     351    void *thread = pinfo->hThread;
     352    DWORD pid = pinfo->dwProcessId;
    341353
    342354    /* code:
     
    347359    uint8_t code[1024];
    348360
    349     void *kernel32;
    350361    uint8_t *loaderaddr;
    351     size_t liblen, loaderlen, jumperlen;
     362    size_t liblen, loaderlen, waiterlen, jumperlen;
    352363    DWORD tmp;
    353364
    354365    liblen = strlen(lib) + 1;
    355366    loaderlen = sizeof(loader) - 1;
     367    waiterlen = sizeof(waiter) - 1;
    356368    jumperlen = sizeof(jumper) - 1;
    357369    if (loaderlen + jumperlen + liblen > 1024)
     
    390402        return -1;
    391403
    392     /* XXX: at this point, the StarCraft 2 hack replaces the entry point
    393      * contents with a jump to self, then waits until the program counter
    394      * actually reaches the entry point. Not sure whether it is needed. */
    395 
    396     /* FIXME: the GetProcAddress calls assume the library was loaded at
    397      * the same address in the child process. This is wrong since Vista
    398      * and its address space randomisation. The StarCraft 2 hack remotely
    399      * parses the target process's module list in order to find the
    400      * kernel32.dll address. Have a look at _RemoteGetProcAddress(). */
    401     kernel32 = LoadLibrary("kernel32.dll");
    402     if(!kernel32)
    403         return -1;
    404 
     404    /* Replace the entry point code with a short jump to self, then resume
     405     * the thread. This is necessary for CreateToolhelp32Snapshot() to
     406     * work. */
     407    WriteProcessMemory(process, epaddr, waiter, waiterlen, &tmp);
     408    if(tmp != waiterlen)
     409        return -1;
     410    FlushInstructionCache(process, epaddr, waiterlen);
     411    ResumeThread(thread);
     412
     413    /* Wait until the entry point is reached */
     414    for (tmp = 0; tmp < 100; tmp++)
     415    {
     416        CONTEXT ctx;
     417        ctx.ContextFlags = CONTEXT_FULL;
     418        GetThreadContext(thread, &ctx);
     419        if ((uintptr_t)ctx.Eip == (uintptr_t)epaddr)
     420            break;
     421        Sleep(10);
     422    }
     423    SuspendThread(thread);
     424    if (tmp == 100)
     425        return -1;
     426
     427    /* Remotely parse the target process's module list to get the addresses
     428     * of the functions we need. This can only be done because we advanced
     429     * the target's execution to the entry point. */
    405430    rep32(code, loaderaddr + loaderlen + jumperlen);
    406     rep32(code, GetProcAddress(kernel32, "LoadLibraryA"));
     431    rep32(code, (uintptr_t)get_proc_address(process, pid, "LoadLibraryA"));
    407432    rep32(code, (void *)(uintptr_t)jumperlen);
    408433    rep32(code, loaderaddr + loaderlen);
    409434    rep32(code, epaddr);
    410     rep32(code, GetProcAddress(kernel32, "GetCurrentProcess"));
    411     rep32(code, GetProcAddress(kernel32, "WriteProcessMemory"));
     435    rep32(code, (uintptr_t)get_proc_address(process, pid, "GetCurrentProcess"));
     436    rep32(code, (uintptr_t)get_proc_address(process, pid, "WriteProcessMemory"));
    412437    rep32(code, epaddr);
    413     FreeLibrary(kernel32);
    414438
    415439    /* Write our shellcodes into the target process */
     
    418442    if(tmp != jumperlen)
    419443        return -1;
     444    FlushInstructionCache(process, epaddr, waiterlen);
    420445
    421446    WriteProcessMemory(process, loaderaddr, code,
     
    469494         * Vista's address space randomisation. */
    470495        if (!ret)
    471             ret = (intptr_t)nt->OptionalHeader.BaseOfCode;
     496            ret = (intptr_t)nt->OptionalHeader.ImageBase;
    472497
    473498        ret += (intptr_t)nt->OptionalHeader.AddressOfEntryPoint;
     
    481506}
    482507
    483 /* Find the process's base address once it is loaded in memory (the header
    484  * information is unreliable because of Vista's ASLR). */
    485 static intptr_t get_base_address(DWORD pid)
    486 {
     508/* FIXME: this could probably be merged with get_entry_point */
     509static intptr_t get_proc_address(void *process, DWORD pid, const char *func)
     510{
     511    char buf[1024];
     512    size_t buflen = strlen(func) + 1;
     513
    487514    MODULEENTRY32 entry;
    488515    intptr_t ret = 0;
     516    DWORD tmp;
    489517    void *list;
    490     int k;
     518    int i, k;
    491519
    492520    list = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
     
    494522    for(k = Module32First(list, &entry); k; k = Module32Next(list, &entry))
    495523    {
     524        IMAGE_DOS_HEADER dos;
     525        IMAGE_NT_HEADERS nt;
     526        IMAGE_EXPORT_DIRECTORY expdir;
     527
     528        uint32_t exportaddr;
     529        uint8_t const *base = entry.modBaseAddr;
     530
     531        if (strcmp("kernel32.dll", entry.szModule))
     532            continue;
     533
     534        ReadProcessMemory(process, base, &dos, sizeof(dos), &tmp);
     535        ReadProcessMemory(process, base + dos.e_lfanew, &nt, sizeof(nt), &tmp);
     536
     537        exportaddr = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
     538        if (!exportaddr)
     539            continue;
     540
     541        ReadProcessMemory(process, base + exportaddr, &expdir, sizeof(expdir), &tmp);
     542
     543        for (i = 0; i < (int)expdir.NumberOfNames; i++)
     544        {
     545            uint32_t nameaddr, funcaddr;
     546            uint16_t j;
     547
     548            /* Look for our function name in the list of names */
     549            ReadProcessMemory(process, base + expdir.AddressOfNames
     550                                            + i * sizeof(DWORD),
     551                              &nameaddr, sizeof(nameaddr), &tmp);
     552            ReadProcessMemory(process, base + nameaddr, buf, buflen, &tmp);
     553
     554            if (strcmp(buf, func))
     555                continue;
     556
     557            /* If we found a function with this name, return its address */
     558            ReadProcessMemory(process, base + expdir.AddressOfNameOrdinals
     559                                            + i * sizeof(WORD),
     560                                &j, sizeof(j), &tmp);
     561            ReadProcessMemory(process, base + expdir.AddressOfFunctions
     562                                            + j * sizeof(DWORD),
     563                                &funcaddr, sizeof(funcaddr), &tmp);
     564
     565            ret = (intptr_t)base + funcaddr;
     566            goto _finished;
     567        }
     568    }
     569
     570_finished:
     571    CloseHandle(list);
     572    return ret;
     573}
     574
     575/* Find the process's base address once it is loaded in memory (the header
     576 * information is unreliable because of Vista's ASLR).
     577 * FIXME: this does not work properly because CreateToolhelp32Snapshot()
     578 * requires a certain level of initialisation. */
     579static intptr_t get_base_address(DWORD pid)
     580{
     581    MODULEENTRY32 entry;
     582    intptr_t ret = 0;
     583
     584    void *list;
     585    int k;
     586
     587    list = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
     588    entry.dwSize = sizeof(entry);
     589    for(k = Module32First(list, &entry); k; k = Module32Next(list, &entry))
     590    {
    496591        /* FIXME: how do we select the correct module? */
    497592        ret = (intptr_t)entry.modBaseAddr;
  • zzuf/trunk/test/zznop.c

    r4253 r4648  
    2626
    2727    fprintf(stderr, "About to call LoadLibraryA()\n");
    28     //LoadLibraryA("whatever");
     28    LoadLibraryA("whatever");
    2929    fprintf(stderr, "Finished calling LoadLibraryA()\n");
    3030
Note: See TracChangeset for help on using the changeset viewer.