diff --git a/msvc/zznop.vcxproj b/msvc/zznop.vcxproj index 3a60550..8ecb892 100644 --- a/msvc/zznop.vcxproj +++ b/msvc/zznop.vcxproj @@ -69,7 +69,6 @@ $(OutDir)zznop.pdb Console MachineX86 - false @@ -91,7 +90,6 @@ true true MachineX86 - false @@ -106,4 +104,4 @@ - \ No newline at end of file + diff --git a/src/myfork.c b/src/myfork.c index 52a41ca..e8a15ab 100644 --- a/src/myfork.c +++ b/src/myfork.c @@ -73,9 +73,7 @@ static int run_process(struct child *child, struct opts *, int[][2]); #if defined HAVE_WINDOWS_H static void rep32(uint8_t *buf, void *addr); -static int dll_inject(PROCESS_INFORMATION *, void *, char const *); -static intptr_t get_base_address(DWORD); -static intptr_t get_entry_point(char const *name, DWORD pid); +static int dll_inject(PROCESS_INFORMATION *, char const *); static intptr_t get_proc_address(void *, DWORD, char const *); #endif @@ -158,7 +156,6 @@ static int run_process(struct child *child, struct opts *opts, int pipes[][2]) PROCESS_INFORMATION pinfo; STARTUPINFO sinfo; HANDLE pid; - void *epaddr; int ret; #endif @@ -275,14 +272,8 @@ static int run_process(struct child *child, struct opts *opts, int pipes[][2]) if(!ret) return -1; - /* Get the child process's entry point address */ - epaddr = (void *)get_entry_point(child->newargv[0], - pinfo.dwProcessId); - if(!epaddr) - return -1; - /* Insert the replacement code */ - ret = dll_inject(&pinfo, epaddr, SONAME); + ret = dll_inject(&pinfo, SONAME); if(ret < 0) { TerminateProcess(pinfo.hProcess, -1); @@ -296,7 +287,6 @@ static int run_process(struct child *child, struct opts *opts, int pipes[][2]) return -1; } -Sleep(5000); return (long int)pinfo.hProcess; #endif } @@ -312,8 +302,7 @@ static void rep32(uint8_t *buf, void *addr) } } -static int dll_inject(PROCESS_INFORMATION *pinfo, - void *epaddr, char const *lib) +static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib) { static uint8_t const loader[] = /* Load the injected DLL into memory */ @@ -347,8 +336,10 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, "\xb8____" /* mov eax, */ "\xff\xe0"; /* jmp eax */ + CONTEXT ctx; void *process = pinfo->hProcess; void *thread = pinfo->hThread; + void *epaddr; DWORD pid = pinfo->dwProcessId; /* code: @@ -396,6 +387,11 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, memcpy(code, loader, loaderlen); memcpy(code + loaderlen + jumperlen, lib, liblen); + /* Find the entry point address. It's simply in EAX. */ + ctx.ContextFlags = CONTEXT_FULL; + GetThreadContext(thread, &ctx); + epaddr = (void *)(uintptr_t)ctx.Eax; + /* Backup the old entry point code */ ReadProcessMemory(process, epaddr, code + loaderlen, jumperlen, &tmp); if(tmp != jumperlen) @@ -411,15 +407,15 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, ResumeThread(thread); /* Wait until the entry point is reached */ - for (tmp = 0; tmp < 100; tmp++) - { - CONTEXT ctx; - ctx.ContextFlags = CONTEXT_FULL; - GetThreadContext(thread, &ctx); - if ((uintptr_t)ctx.Eip == (uintptr_t)epaddr) - break; - Sleep(10); - } + for (tmp = 0; tmp < 100; tmp++) + { + CONTEXT ctx; + ctx.ContextFlags = CONTEXT_FULL; + GetThreadContext(thread, &ctx); + if ((uintptr_t)ctx.Eip == (uintptr_t)epaddr) + break; + Sleep(10); + } SuspendThread(thread); if (tmp == 100) return -1; @@ -428,12 +424,12 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, * of the functions we need. This can only be done because we advanced * the target's execution to the entry point. */ rep32(code, loaderaddr + loaderlen + jumperlen); - rep32(code, (uintptr_t)get_proc_address(process, pid, "LoadLibraryA")); + rep32(code, (void *)get_proc_address(process, pid, "LoadLibraryA")); rep32(code, (void *)(uintptr_t)jumperlen); rep32(code, loaderaddr + loaderlen); rep32(code, epaddr); - rep32(code, (uintptr_t)get_proc_address(process, pid, "GetCurrentProcess")); - rep32(code, (uintptr_t)get_proc_address(process, pid, "WriteProcessMemory")); + rep32(code, (void *)get_proc_address(process, pid, "GetCurrentProcess")); + rep32(code, (void *)get_proc_address(process, pid, "WriteProcessMemory")); rep32(code, epaddr); /* Write our shellcodes into the target process */ @@ -451,148 +447,69 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, return 0; } -/* Find the process's entry point address offset. The information is in - * the file's PE header. */ -static intptr_t get_entry_point(char const *name, DWORD pid) +static intptr_t get_proc_address(void *process, DWORD pid, const char *func) { - PIMAGE_DOS_HEADER dos; - PIMAGE_NT_HEADERS nt; - intptr_t ret = 0; - void *file, *map, *base; + char buf[1024]; + size_t buflen = strlen(func) + 1; - file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, 0, NULL); - if(file == INVALID_HANDLE_VALUE) - return ret; - - map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); - if(!map) - { - CloseHandle(file); - return ret; - } - - base = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); - if(!base) - { - CloseHandle(map); - CloseHandle(file); - return ret; - } - - /* Sanity checks */ - dos = (PIMAGE_DOS_HEADER)base; - nt = (PIMAGE_NT_HEADERS)((char *)base + dos->e_lfanew); - if(dos->e_magic == IMAGE_DOS_SIGNATURE /* 0x5A4D */ - && nt->Signature == IMAGE_NT_SIGNATURE /* 0x00004550 */ - && nt->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 - && nt->OptionalHeader.Magic == 0x10b /* IMAGE_NT_OPTIONAL_HDR32_MAGIC */) - { - ret = get_base_address(pid); - /* Base address not found in the running process. Falling back - * to the header's information, which is unreliable because of - * Vista's address space randomisation. */ - if (!ret) - ret = (intptr_t)nt->OptionalHeader.ImageBase; - - ret += (intptr_t)nt->OptionalHeader.AddressOfEntryPoint; - } - - UnmapViewOfFile(base); - CloseHandle(map); - CloseHandle(file); - - return ret; -} - -/* FIXME: this could probably be merged with get_entry_point */ -static intptr_t get_proc_address(void *process, DWORD pid, const char *func) -{ - char buf[1024]; - size_t buflen = strlen(func) + 1; - - MODULEENTRY32 entry; - intptr_t ret = 0; - DWORD tmp; - void *list; - int i, k; - - list = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); - entry.dwSize = sizeof(entry); - for(k = Module32First(list, &entry); k; k = Module32Next(list, &entry)) - { - IMAGE_DOS_HEADER dos; - IMAGE_NT_HEADERS nt; - IMAGE_EXPORT_DIRECTORY expdir; - - uint32_t exportaddr; - uint8_t const *base = entry.modBaseAddr; - - if (strcmp("kernel32.dll", entry.szModule)) - continue; - - ReadProcessMemory(process, base, &dos, sizeof(dos), &tmp); - ReadProcessMemory(process, base + dos.e_lfanew, &nt, sizeof(nt), &tmp); - - exportaddr = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - if (!exportaddr) - continue; - - ReadProcessMemory(process, base + exportaddr, &expdir, sizeof(expdir), &tmp); - - for (i = 0; i < (int)expdir.NumberOfNames; i++) - { - uint32_t nameaddr, funcaddr; - uint16_t j; - - /* Look for our function name in the list of names */ - ReadProcessMemory(process, base + expdir.AddressOfNames - + i * sizeof(DWORD), - &nameaddr, sizeof(nameaddr), &tmp); - ReadProcessMemory(process, base + nameaddr, buf, buflen, &tmp); - - if (strcmp(buf, func)) - continue; - - /* If we found a function with this name, return its address */ - ReadProcessMemory(process, base + expdir.AddressOfNameOrdinals - + i * sizeof(WORD), - &j, sizeof(j), &tmp); - ReadProcessMemory(process, base + expdir.AddressOfFunctions - + j * sizeof(DWORD), - &funcaddr, sizeof(funcaddr), &tmp); - - ret = (intptr_t)base + funcaddr; - goto _finished; - } - } - -_finished: - CloseHandle(list); - return ret; -} - -/* Find the process's base address once it is loaded in memory (the header - * information is unreliable because of Vista's ASLR). - * FIXME: this does not work properly because CreateToolhelp32Snapshot() - * requires a certain level of initialisation. */ -static intptr_t get_base_address(DWORD pid) -{ MODULEENTRY32 entry; intptr_t ret = 0; - + DWORD tmp; void *list; - int k; + int i, k; list = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); entry.dwSize = sizeof(entry); for(k = Module32First(list, &entry); k; k = Module32Next(list, &entry)) { - /* FIXME: how do we select the correct module? */ - ret = (intptr_t)entry.modBaseAddr; - } - CloseHandle(list); + IMAGE_DOS_HEADER dos; + IMAGE_NT_HEADERS nt; + IMAGE_EXPORT_DIRECTORY expdir; + uint32_t exportaddr; + uint8_t const *base = entry.modBaseAddr; + + if (strcmp("kernel32.dll", entry.szModule)) + continue; + + ReadProcessMemory(process, base, &dos, sizeof(dos), &tmp); + ReadProcessMemory(process, base + dos.e_lfanew, &nt, sizeof(nt), &tmp); + + exportaddr = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (!exportaddr) + continue; + + ReadProcessMemory(process, base + exportaddr, &expdir, sizeof(expdir), &tmp); + + for (i = 0; i < (int)expdir.NumberOfNames; i++) + { + uint32_t nameaddr, funcaddr; + uint16_t j; + + /* Look for our function name in the list of names */ + ReadProcessMemory(process, base + expdir.AddressOfNames + + i * sizeof(DWORD), + &nameaddr, sizeof(nameaddr), &tmp); + ReadProcessMemory(process, base + nameaddr, buf, buflen, &tmp); + + if (strcmp(buf, func)) + continue; + + /* If we found a function with this name, return its address */ + ReadProcessMemory(process, base + expdir.AddressOfNameOrdinals + + i * sizeof(WORD), + &j, sizeof(j), &tmp); + ReadProcessMemory(process, base + expdir.AddressOfFunctions + + j * sizeof(DWORD), + &funcaddr, sizeof(funcaddr), &tmp); + + ret = (intptr_t)base + funcaddr; + goto _finished; + } + } + +_finished: + CloseHandle(list); return ret; }