Move process creation stuff to a separate myfork.c file.

This commit is contained in:
Sam Hocevar
2009-12-12 22:20:11 +00:00
committed by sam
parent 0715d2e16c
commit 587088d48f
5 changed files with 451 additions and 358 deletions
+3 -3
View File
@@ -4,7 +4,7 @@ bin_PROGRAMS = zzuf
pkglib_LTLIBRARIES = libzzuf.la
ZZUF = \
zzuf.c opts.c opts.h md5.c md5.h timer.c timer.h
zzuf.c opts.c opts.h md5.c md5.h timer.c timer.h myfork.c myfork.h
LIBZZUF = \
libzzuf/libzzuf.c libzzuf/libzzuf.h \
@@ -25,12 +25,12 @@ GETOPT = mygetopt.c mygetopt.h
endif
zzuf_SOURCES = $(ZZUF) $(COMMON) $(GETOPT)
zzuf_CFLAGS = -DLIBDIR=\"$(libdir)/zzuf\" -Icommon/
zzuf_CFLAGS = -DLIBDIR=\"$(libdir)/zzuf\" -I$(srcdir)/common
zzuf_LDFLAGS = $(MATH_LIBS) $(WINSOCK2_LIBS)
zzuf_DEPENDENCIES = libzzuf.la
libzzuf_la_SOURCES = $(LIBZZUF) $(COMMON)
libzzuf_la_CFLAGS = -DLIBZZUF -Ilibzzuf/ -Icommon/
libzzuf_la_CFLAGS = -DLIBZZUF -I$(srcdir)/libzzuf -I$(srcdir)/common
libzzuf_la_LDFLAGS = -avoid-version -no-undefined $(DLL_LDFLAGS)
libzzuf_la_LIBADD = $(GETOPT_LIBS) $(DL_LIBS) $(MATH_LIBS) $(WINSOCK2_LIBS)
+4
View File
@@ -35,6 +35,10 @@
* zzuf may bring a machine down to its knees because of I/O. */
#define DEFAULT_MEM 1024
/* We use file descriptor 17 as the debug channel */
#define DEBUG_FILENO 17
#define DEBUG_FILENO_STR "17"
struct fuzz
{
uint32_t seed;
+418
View File
@@ -0,0 +1,418 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2002, 2007-2009 Sam Hocevar <sam@hocevar.net>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* myfork.c: launcher
*/
#include "config.h"
#define _INCLUDE_POSIX_SOURCE /* for STDERR_FILENO on HP-UX */
#if defined HAVE_STDINT_H
# include <stdint.h>
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if defined HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined HAVE_WINDOWS_H
# include <windows.h>
# include <imagehlp.h>
# include <tlhelp32.h>
#endif
#include <string.h>
#include <fcntl.h> /* for O_BINARY */
#include "common.h"
#include "opts.h"
#include "random.h"
#include "fd.h"
#include "fuzz.h"
#include "myfork.h"
#include "md5.h"
#include "timer.h"
static int run_process(struct opts *, int[][2]);
#if defined HAVE_WINDOWS_H
static int dll_inject(void *, void *);
static intptr_t get_base_address(DWORD);
static intptr_t get_entry_point_offset(char const *);
#endif
#if defined HAVE_WINDOWS_H
static inline void addcpy(void *buf, void *x)
{
memcpy(buf, &x, 4);
}
#endif
int myfork(struct child *child, struct opts *opts)
{
int pipes[3][2];
pid_t pid;
int i;
/* Prepare communication pipe */
for(i = 0; i < 3; i++)
{
int ret;
#if defined HAVE_PIPE
ret = pipe(pipes[i]);
#elif defined HAVE__PIPE
ret = _pipe(pipes[i], 512, _O_BINARY | O_NOINHERIT);
#endif
if(ret < 0)
{
perror("pipe");
return -1;
}
}
pid = run_process(opts, pipes);
if(pid < 0)
{
/* FIXME: close pipes */
fprintf(stderr, "error launching `%s'\n", opts->newargv[0]);
return -1;
}
child->pid = pid;
for(i = 0; i < 3; i++)
{
close(pipes[i][1]);
child->fd[i] = pipes[i][0];
}
return 0;
}
#if !defined HAVE_SETENV
static void setenv(char const *name, char const *value, int overwrite)
{
char *str;
if(!overwrite && getenv(name))
return;
str = malloc(strlen(name) + 1 + strlen(value) + 1);
sprintf(str, "%s=%s", name, value);
putenv(str);
}
#endif
static int run_process(struct opts *opts, int pipes[][2])
{
char buf[64];
#if defined HAVE_FORK
static int const files[] = { DEBUG_FILENO, STDERR_FILENO, STDOUT_FILENO };
char *libpath, *tmp;
int pid, j, len = strlen(opts->oldargv[0]);
# if defined __APPLE__
# define EXTRAINFO ""
# define PRELOAD "DYLD_INSERT_LIBRARIES"
setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
# elif defined __osf__
# define EXTRAINFO ":DEFAULT"
# define PRELOAD "_RLD_LIST"
# else
# define EXTRAINFO ""
# define PRELOAD "LD_PRELOAD"
# endif
#elif HAVE_WINDOWS_H
PROCESS_INFORMATION pinfo;
STARTUPINFO sinfo;
HANDLE pid;
void *epaddr;
int ret;
#endif
#if defined HAVE_FORK
/* Fork and launch child */
pid = fork();
if(pid < -1)
perror("fork");
if(pid != 0)
return pid;
/* We loop in reverse order so that files[0] is done last,
* just in case one of the other dup2()ed fds had the value */
for(j = 3; j--; )
{
close(pipes[j][0]);
if(pipes[j][1] != files[j])
{
dup2(pipes[j][1], files[j]);
close(pipes[j][1]);
}
}
#endif
#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
if(opts->maxmem >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxmem * 1000000;
rlim.rlim_max = opts->maxmem * 1000000;
setrlimit(ZZUF_RLIMIT_MEM, &rlim);
}
#endif
#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
if(opts->maxcpu >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxcpu;
rlim.rlim_max = opts->maxcpu + 5;
setrlimit(ZZUF_RLIMIT_CPU, &rlim);
}
#endif
/* Set environment variables */
sprintf(buf, "%i", opts->seed);
setenv("ZZUF_SEED", buf, 1);
sprintf(buf, "%g", opts->minratio);
setenv("ZZUF_MINRATIO", buf, 1);
sprintf(buf, "%g", opts->maxratio);
setenv("ZZUF_MAXRATIO", buf, 1);
#if defined HAVE_FORK
/* Make sure there is space for everything we might do. */
libpath = malloc(len + strlen(LIBDIR "/" LT_OBJDIR SONAME EXTRAINFO) + 1);
strcpy(libpath, opts->oldargv[0]);
/* If the binary name contains a '/', we look for a libzzuf in the
* same directory. Otherwise, we only look into the system directory
* to avoid shared library attacks. Write the result in libpath. */
tmp = strrchr(libpath, '/');
if(tmp)
{
strcpy(tmp + 1, LT_OBJDIR SONAME);
if(access(libpath, R_OK) < 0)
strcpy(libpath, LIBDIR "/" SONAME);
}
else
strcpy(libpath, LIBDIR "/" SONAME);
/* OSF1 only */
strcat(libpath, EXTRAINFO);
/* Do not clobber previous LD_PRELOAD values */
tmp = getenv(PRELOAD);
if(tmp && *tmp)
{
char *bigbuf = malloc(strlen(tmp) + strlen(libpath) + 2);
sprintf(bigbuf, "%s:%s", tmp, libpath);
free(libpath);
libpath = bigbuf;
}
setenv(PRELOAD, libpath, 1);
free(libpath);
if(execvp(opts->newargv[0], opts->newargv))
{
perror(opts->newargv[0]);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
/* no return */
return 0;
#elif HAVE_WINDOWS_H
pid = GetCurrentProcess();
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[0][1]), pid,
/* FIXME */ &sinfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[1][1]), pid,
&sinfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[2][1]), pid,
&sinfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
sinfo.dwFlags = STARTF_USESTDHANDLES;
ret = CreateProcess(NULL, opts->newargv[0], NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &sinfo, &pinfo);
if(!ret)
return -1;
/* Get the child process's entry point address */
epaddr = (void *)(get_base_address(pinfo.dwProcessId)
+ get_entry_point_offset(opts->newargv[0]));
if(!epaddr)
return -1;
/* Insert the replacement code */
ret = dll_inject(pinfo.hProcess, epaddr);
if(ret < 0)
{
TerminateProcess(pinfo.hProcess, -1);
return -1;
}
ret = ResumeThread(pinfo.hThread);
if(ret < 0)
{
TerminateProcess(pinfo.hProcess, -1);
return -1;
}
return (long int)pinfo.hProcess;
#endif
}
#if defined HAVE_WINDOWS_H
static int dll_inject(void *process, void *epaddr)
{
uint8_t code1[] = /* LIBZZUF: */
"libzzuf.dll\0"
/* OLDEP: */
"_______"
/* START: */
"\xb8____" /* mov eax,<libzzuf.dll> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<LoadLibraryA> */
"\xff\xd0" /* call eax */
"\xb8\0\0\0\0" /* mov eax,0 */
"\x50" /* push eax */
"\xb8\x07\0\0\0" /* mov eax,7 */
"\x50" /* push eax */
"\xb8____" /* mov eax,<OLDEP> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<NEWEP> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<GetCurrentProcess> */
"\xff\xd0" /* call eax */
"\x50" /* push eax */
"\xb8____" /* mov eax,<WriteProcessMemory> */
"\xff\xd0" /* call eax */
"\xb8____" /* mov eax,<NEWEP> */
"\xff\xe0"; /* jmp eax */
uint8_t code2[] = /* NEWEP: */
"\xb8____" /* mov eax,<START> */
"\xff\xe0"; /* jmp eax */
void *lib;
uint8_t *loaderaddr;
DWORD tmp;
/* Backup the old entry-point code */
ReadProcessMemory(process, epaddr, code1 + 0x0c, 7, &tmp);
if(tmp != 7)
return -1;
/* Copy the first shell code to a freshly allocated memory area. */
loaderaddr = VirtualAllocEx(process, NULL, sizeof(code1), MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if(!loaderaddr)
return -1;
lib = LoadLibrary("kernel32.dll");
if(!lib)
return -1;
addcpy(code1 + 0x14, loaderaddr + 0x00); /* offset for dll string */
addcpy(code1 + 0x1a, GetProcAddress(lib, "LoadLibraryA"));
addcpy(code1 + 0x2d, loaderaddr + 0x0c);
addcpy(code1 + 0x33, epaddr);
addcpy(code1 + 0x39, GetProcAddress(lib, "GetCurrentProcess"));
addcpy(code1 + 0x41, GetProcAddress(lib, "WriteProcessMemory"));
addcpy(code1 + 0x48, epaddr);
FreeLibrary(lib);
WriteProcessMemory(process, loaderaddr, code1, sizeof(code1), &tmp);
if(tmp != sizeof(code1))
return -1;
/* Copy the second shell code where the old entry point was. */
addcpy(code2 + 0x01, loaderaddr + 12 + 7);
WriteProcessMemory(process, epaddr, code2, 7, &tmp);
if(tmp != 7)
return -1;
return 0;
}
/* Find the process's base address once it is loaded in memory (the header
* information is unreliable because of Vista's ASLR). */
static intptr_t get_base_address(DWORD pid)
{
MODULEENTRY32 entry;
intptr_t ret = 0;
void *list;
int 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);
return ret;
}
/* Find the process's entry point address offset. The information is in
* the file's PE header. */
static intptr_t get_entry_point_offset(char const *name)
{
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
intptr_t ret = 0;
void *file, *map, *base;
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 = (intptr_t)nt->OptionalHeader.AddressOfEntryPoint;
}
UnmapViewOfFile(base);
CloseHandle(map);
CloseHandle(file);
return ret;
}
#endif
+20
View File
@@ -0,0 +1,20 @@
/*
* zzuf - general purpose fuzzer
* Copyright (c) 2006-2009 Sam Hocevar <sam@hocevar.net>
* All Rights Reserved
*
* $Id$
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* myfork.h: process handling functions
*/
int myfork(struct child *child, struct opts *opts);
+6 -355
View File
@@ -18,8 +18,7 @@
#include "config.h"
/* Needed for STDERR_FILENO on HP-UX */
#define _INCLUDE_POSIX_SOURCE
#define _INCLUDE_POSIX_SOURCE /* for STDERR_FILENO on HP-UX */
#if defined HAVE_STDINT_H
# include <stdint.h>
@@ -34,24 +33,18 @@
#include <stdio.h>
#include <stdlib.h>
#if defined HAVE_UNISTD_H
# include <unistd.h>
# include <unistd.h> /* for read(), write(), close() */
#endif
#if defined HAVE_REGEX_H
# include <regex.h>
#endif
#if defined HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
#if defined HAVE_WINDOWS_H
# include <windows.h>
# include <imagehlp.h>
# include <tlhelp32.h>
# include <winsock2.h> /* for fd_set */
#endif
#if defined HAVE_IO_H
# include <io.h>
#endif
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#if defined HAVE_SYS_TIME_H
@@ -69,6 +62,7 @@
#include "random.h"
#include "fd.h"
#include "fuzz.h"
#include "myfork.h"
#include "md5.h"
#include "timer.h"
@@ -104,12 +98,7 @@
# undef ZZUF_RLIMIT_CPU
#endif
/* We use file descriptor 17 as the debug channel */
#define DEBUG_FILENO 17
#define DEBUG_FILENO_STR "17"
static void loop_stdin(struct opts *);
static int run_process(struct opts *, int[][2]);
static void spawn_children(struct opts *);
static void clean_children(struct opts *);
@@ -121,11 +110,6 @@ static void setenv(char const *, char const *, int);
#if defined HAVE_WAITPID
static char const *sig2name(int);
#endif
#if defined HAVE_WINDOWS_H
static int dll_inject(void *, void *);
static intptr_t get_base_address(DWORD);
static intptr_t get_entry_point_offset(char const *);
#endif
static void finfo(FILE *, struct opts *, uint32_t);
#if defined HAVE_REGEX_H
static char *merge_regex(char *, char *);
@@ -134,13 +118,6 @@ static char *merge_file(char *, char *);
static void version(void);
static void usage(void);
#if defined HAVE_WINDOWS_H
static inline void addcpy(void *buf, void *x)
{
memcpy(buf, &x, 4);
}
#endif
#define ZZUF_FD_SET(fd, p_fdset, maxfd) \
if(fd >= 0) \
{ \
@@ -658,10 +635,8 @@ static char *merge_regex(char *regex, char *string)
static void spawn_children(struct opts *opts)
{
int pipes[3][2];
int64_t now = _zz_time();
pid_t pid;
int i, j;
int i;
if(opts->nchild == opts->maxchild)
return; /* no slot */
@@ -680,25 +655,7 @@ static void spawn_children(struct opts *opts)
if(opts->child[i].status == STATUS_FREE)
break;
/* Prepare communication pipe */
for(j = 0; j < 3; j++)
{
int ret;
#if defined HAVE_PIPE
ret = pipe(pipes[j]);
#elif defined HAVE__PIPE
ret = _pipe(pipes[j], 512, _O_BINARY | O_NOINHERIT);
#endif
if(ret < 0)
{
perror("pipe");
opts->seed++;
return;
}
}
pid = run_process(opts, pipes);
if(pid < 0)
if (myfork(&opts->child[i], opts) < 0)
{
fprintf(stderr, "error launching `%s'\n", opts->newargv[0]);
opts->seed++;
@@ -707,12 +664,6 @@ static void spawn_children(struct opts *opts)
/* Were the parent, acknowledge spawn */
opts->child[i].date = now;
opts->child[i].pid = pid;
for(j = 0; j < 3; j++)
{
close(pipes[j][1]);
opts->child[i].fd[j] = pipes[j][0];
}
opts->child[i].bytes = 0;
opts->child[i].seed = opts->seed;
opts->child[i].ratio = _zz_getratio();
@@ -970,306 +921,6 @@ static char const *sig2name(int signum)
}
#endif
static int run_process(struct opts *opts, int pipes[][2])
{
char buf[64];
#if defined HAVE_FORK
static int const files[] = { DEBUG_FILENO, STDERR_FILENO, STDOUT_FILENO };
char *libpath, *tmp;
int pid, j, len = strlen(opts->oldargv[0]);
# if defined __APPLE__
# define EXTRAINFO ""
# define PRELOAD "DYLD_INSERT_LIBRARIES"
setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
# elif defined __osf__
# define EXTRAINFO ":DEFAULT"
# define PRELOAD "_RLD_LIST"
# else
# define EXTRAINFO ""
# define PRELOAD "LD_PRELOAD"
# endif
#elif HAVE_WINDOWS_H
PROCESS_INFORMATION pinfo;
STARTUPINFO sinfo;
HANDLE pid;
void *epaddr;
int ret;
#endif
#if defined HAVE_FORK
/* Fork and launch child */
pid = fork();
if(pid < -1)
perror("fork");
if(pid != 0)
return pid;
/* We loop in reverse order so that files[0] is done last,
* just in case one of the other dup2()ed fds had the value */
for(j = 3; j--; )
{
close(pipes[j][0]);
if(pipes[j][1] != files[j])
{
dup2(pipes[j][1], files[j]);
close(pipes[j][1]);
}
}
#endif
#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_MEM
if(opts->maxmem >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxmem * 1000000;
rlim.rlim_max = opts->maxmem * 1000000;
setrlimit(ZZUF_RLIMIT_MEM, &rlim);
}
#endif
#if defined HAVE_SETRLIMIT && defined ZZUF_RLIMIT_CPU
if(opts->maxcpu >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxcpu;
rlim.rlim_max = opts->maxcpu + 5;
setrlimit(ZZUF_RLIMIT_CPU, &rlim);
}
#endif
/* Set environment variables */
sprintf(buf, "%i", opts->seed);
setenv("ZZUF_SEED", buf, 1);
sprintf(buf, "%g", opts->minratio);
setenv("ZZUF_MINRATIO", buf, 1);
sprintf(buf, "%g", opts->maxratio);
setenv("ZZUF_MAXRATIO", buf, 1);
#if defined HAVE_FORK
/* Make sure there is space for everything we might do. */
libpath = malloc(len + strlen(LIBDIR "/" LT_OBJDIR SONAME EXTRAINFO) + 1);
strcpy(libpath, opts->oldargv[0]);
/* If the binary name contains a '/', we look for a libzzuf in the
* same directory. Otherwise, we only look into the system directory
* to avoid shared library attacks. Write the result in libpath. */
tmp = strrchr(libpath, '/');
if(tmp)
{
strcpy(tmp + 1, LT_OBJDIR SONAME);
if(access(libpath, R_OK) < 0)
strcpy(libpath, LIBDIR "/" SONAME);
}
else
strcpy(libpath, LIBDIR "/" SONAME);
/* OSF1 only */
strcat(libpath, EXTRAINFO);
/* Do not clobber previous LD_PRELOAD values */
tmp = getenv(PRELOAD);
if(tmp && *tmp)
{
char *bigbuf = malloc(strlen(tmp) + strlen(libpath) + 2);
sprintf(bigbuf, "%s:%s", tmp, libpath);
free(libpath);
libpath = bigbuf;
}
setenv(PRELOAD, libpath, 1);
free(libpath);
if(execvp(opts->newargv[0], opts->newargv))
{
perror(opts->newargv[0]);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
/* no return */
return 0;
#elif HAVE_WINDOWS_H
pid = GetCurrentProcess();
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[0][1]), pid,
/* FIXME */ &sinfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[1][1]), pid,
&sinfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(pid, (HANDLE)_get_osfhandle(pipes[2][1]), pid,
&sinfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
sinfo.dwFlags = STARTF_USESTDHANDLES;
ret = CreateProcess(NULL, opts->newargv[0], NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &sinfo, &pinfo);
if(!ret)
return -1;
/* Get the child process's entry point address */
epaddr = (void *)(get_base_address(pinfo.dwProcessId)
+ get_entry_point_offset(opts->newargv[0]));
if(!epaddr)
return -1;
/* Insert the replacement code */
ret = dll_inject(pinfo.hProcess, epaddr);
if(ret < 0)
{
TerminateProcess(pinfo.hProcess, -1);
return -1;
}
ret = ResumeThread(pinfo.hThread);
if(ret < 0)
{
TerminateProcess(pinfo.hProcess, -1);
return -1;
}
return (long int)pinfo.hProcess;
#endif
}
#if defined HAVE_WINDOWS_H
static int dll_inject(void *process, void *epaddr)
{
uint8_t code1[] = /* LIBZZUF: */
"libzzuf.dll\0"
/* OLDEP: */
"_______"
/* START: */
"\xb8____" /* mov eax,<libzzuf.dll> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<LoadLibraryA> */
"\xff\xd0" /* call eax */
"\xb8\0\0\0\0" /* mov eax,0 */
"\x50" /* push eax */
"\xb8\x07\0\0\0" /* mov eax,7 */
"\x50" /* push eax */
"\xb8____" /* mov eax,<OLDEP> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<NEWEP> */
"\x50" /* push eax */
"\xb8____" /* mov eax,<GetCurrentProcess> */
"\xff\xd0" /* call eax */
"\x50" /* push eax */
"\xb8____" /* mov eax,<WriteProcessMemory> */
"\xff\xd0" /* call eax */
"\xb8____" /* mov eax,<NEWEP> */
"\xff\xe0"; /* jmp eax */
uint8_t code2[] = /* NEWEP: */
"\xb8____" /* mov eax,<START> */
"\xff\xe0"; /* jmp eax */
void *lib;
uint8_t *loaderaddr;
DWORD tmp;
/* Backup the old entry-point code */
ReadProcessMemory(process, epaddr, code1 + 0x0c, 7, &tmp);
if(tmp != 7)
return -1;
/* Copy the first shell code to a freshly allocated memory area. */
loaderaddr = VirtualAllocEx(process, NULL, sizeof(code1), MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if(!loaderaddr)
return -1;
lib = LoadLibrary("kernel32.dll");
if(!lib)
return -1;
addcpy(code1 + 0x14, loaderaddr + 0x00); /* offset for dll string */
addcpy(code1 + 0x1a, GetProcAddress(lib, "LoadLibraryA"));
addcpy(code1 + 0x2d, loaderaddr + 0x0c);
addcpy(code1 + 0x33, epaddr);
addcpy(code1 + 0x39, GetProcAddress(lib, "GetCurrentProcess"));
addcpy(code1 + 0x41, GetProcAddress(lib, "WriteProcessMemory"));
addcpy(code1 + 0x48, epaddr);
FreeLibrary(lib);
WriteProcessMemory(process, loaderaddr, code1, sizeof(code1), &tmp);
if(tmp != sizeof(code1))
return -1;
/* Copy the second shell code where the old entry point was. */
addcpy(code2 + 0x01, loaderaddr + 12 + 7);
WriteProcessMemory(process, epaddr, code2, 7, &tmp);
if(tmp != 7)
return -1;
return 0;
}
/* Find the process's base address once it is loaded in memory (the header
* information is unreliable because of Vista's ASLR). */
static intptr_t get_base_address(DWORD pid)
{
MODULEENTRY32 entry;
intptr_t ret = 0;
void *list;
int 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);
return ret;
}
/* Find the process's entry point address offset. The information is in
* the file's PE header. */
static intptr_t get_entry_point_offset(char const *name)
{
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
intptr_t ret = 0;
void *file, *map, *base;
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 = (intptr_t)nt->OptionalHeader.AddressOfEntryPoint;
}
UnmapViewOfFile(base);
CloseHandle(map);
CloseHandle(file);
return ret;
}
#endif
static void version(void)
{
printf("zzuf %s\n", PACKAGE_VERSION);