* Added DLL injection to the Win32 port attempt.

This commit is contained in:
Sam Hocevar
2007-01-24 15:06:17 +00:00
committed by sam
parent 760befa464
commit 0d2e0f587f
6 changed files with 316 additions and 78 deletions
+3 -2
View File
@@ -18,14 +18,15 @@ mkdir "${BUILDDIR}"
cd "${BUILDDIR}"
# Build for win32
"${SRCDIR}/configure" --host=i586-mingw32msvc --program-suffix=.exe --prefix=/ --bindir=/bin --libdir=/lib
"${SRCDIR}/configure" --host=i586-mingw32msvc --prefix=/ --bindir=/bin --libdir=/lib
make pkglibdir=/lib pkgdatadir=/data bindir=/bin
make install DESTDIR="${INSTALLDIR}" pkglibdir=/lib/ pkgdatadir=/ bindir=/bin/
(cd "${SRCDIR}" && rm -Rf "${BUILDDIR}")
rm -Rf "${BUILDDIR}"
# Pack the directory
cd "${SRCDIR}"
zip "${DIRNAME}.zip" `find "${DIRNAME}"`
rm -Rf "${INSTALLDIR}"
+6 -3
View File
@@ -16,17 +16,20 @@ AC_PROG_LIBTOOL
case "${host_os}" in
*mingw32*)
WIN32DLL_LDFLAGS="-Wl,-l,imagehlp"
DLL_LDFLAGS="-Wl,-l,imagehlp" # Trick libtool here
WINSOCK2_LIBS="-lws2_32"
ac_cv_func_recv=yes
ac_cv_func_recvfrom=yes
ac_cv_func_socket=yes
ac_cv_func_accept=yes
;;
esac
AC_SUBST(WIN32DLL_LDFLAGS)
AC_SUBST(WINSOCK2_LIBS)
AC_SUBST(DLL_LDFLAGS)
AC_CHECK_HEADERS(windows.h winsock2.h inttypes.h stdint.h getopt.h libc.h malloc.h dlfcn.h regex.h sys/socket.h sys/uio.h aio.h sys/mman.h sys/wait.h sys/resource.h)
AC_CHECK_HEADERS(windows.h winsock2.h io.h inttypes.h stdint.h getopt.h libc.h malloc.h dlfcn.h regex.h sys/socket.h sys/uio.h aio.h sys/mman.h sys/wait.h sys/resource.h)
AC_CHECK_FUNCS(setenv waitpid setrlimit gettimeofday fork kill pipe _pipe)
AC_CHECK_FUNCS(open64 lseek64 mmap64 fopen64 fseeko _IO_getc getline getdelim __getdelim fgetln __srefill map_fd memalign posix_memalign aio_read accept socket readv pread recv recvfrom recvmsg mmap valloc sigaction)
AC_CHECK_TYPES(sighandler_t, [], [],
+2 -2
View File
@@ -5,11 +5,11 @@ COMMON = random.c random.h fd.c fd.h fuzz.c fuzz.h
bin_PROGRAMS = zzuf
zzuf_SOURCES = zzuf.c $(COMMON) opts.c opts.h md5.c md5.h timer.c timer.h
zzuf_CFLAGS = -DLIBDIR=\"$(libdir)/zzuf\"
zzuf_LDFLAGS = $(MATH_LIBS)
zzuf_LDFLAGS = $(MATH_LIBS) $(WINSOCK2_LIBS)
pkglib_LTLIBRARIES = libzzuf.la
libzzuf_la_SOURCES = libzzuf.c libzzuf.h $(COMMON) debug.c debug.h sys.c sys.h \
lib-fd.c lib-mem.c lib-signal.c lib-stream.c lib-load.h
libzzuf_la_LDFLAGS = -avoid-version -no-undefined $(WIN32DLL_LDFLAGS)
libzzuf_la_LDFLAGS = -avoid-version -no-undefined $(DLL_LDFLAGS)
libzzuf_la_LIBADD = $(GETOPT_LIBS) $(DL_LIBS) $(MATH_LIBS)
+1 -1
View File
@@ -18,7 +18,7 @@
struct opts
{
char **newargv;
char const **newargv;
char *protect, *refuse;
uint32_t seed;
uint32_t endseed;
+26
View File
@@ -23,6 +23,9 @@
#elif defined HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#if defined HAVE_WINDOWS_H
# include <windows.h>
#endif
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
@@ -31,8 +34,31 @@
int64_t _zz_time(void)
{
#if defined HAVE_GETTIMEOFDAY
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
#else
static CRITICAL_SECTION cs;
static unsigned long int prev;
static int64_t tv_base = 0;
unsigned long int tv_msec;
if(tv_base == 0)
{
tv_base = 1;
prev = 0;
InitializeCriticalSection(&cs);
}
EnterCriticalSection(&cs);
tv_msec = GetTickCount();
if(tv_msec < prev)
tv_base += 0x100000000LL; /* We wrapped */
prev = tv_msec;
LeaveCriticalSection(&cs);
return (tv_base + tv_msec) * 1000;
#endif
}
+278 -70
View File
@@ -37,9 +37,12 @@
#endif
#if defined HAVE_WINSOCK2_H
# include <winsock2.h>
#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_WAIT_H
@@ -62,27 +65,43 @@
# define SIGKILL 9
#endif
static void loop_stdin(struct opts *opts);
static void loop_stdin(struct opts *);
static int run_process(char const *[]);
static void spawn_children(struct opts *opts);
static void clean_children(struct opts *opts);
static void read_children(struct opts *opts);
static void spawn_children(struct opts *);
static void clean_children(struct opts *);
static void read_children(struct opts *);
#if !defined HAVE_GETENV
static void setenv(char const *, char const *, int);
#endif
#if defined HAVE_WAITPID
static char const *sig2str(int);
#endif
#if defined HAVE_WINDOWS_H
static int dll_inject(void *, void *);
static void *get_entry(char const *);
#endif
#if defined HAVE_REGEX_H
static char *merge_regex(char *, char *);
static char *merge_file(char *, char *);
#endif
static void set_environment(char const *);
static void version(void);
#if defined HAVE_GETOPT_H
static void usage(void);
#endif
#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) \
{ \
FD_SET(fd, p_fdset); \
FD_SET((unsigned int)fd, p_fdset); \
if(fd > maxfd) \
maxfd = fd; \
}
@@ -211,10 +230,12 @@ int main(int argc, char *argv[])
case 'm': /* --md5 */
opts->md5 = 1;
break;
#if defined HAVE_SETRLIMIT
case 'M': /* --max-memory */
setenv("ZZUF_MEMORY", "1", 1);
opts->maxmem = atoi(optarg);
break;
#endif
case 'n': /* --network */
setenv("ZZUF_NETWORK", "1", 1);
break;
@@ -324,9 +345,6 @@ int main(int argc, char *argv[])
opts->child[i].status = STATUS_FREE;
opts->nchild = 0;
/* Preload libzzuf.so */
set_environment(argv[0]);
/* Create new argv */
opts->newargv = malloc((argc - optind + 1) * sizeof(char *));
memcpy(opts->newargv, argv + optind, (argc - optind) * sizeof(char *));
@@ -488,56 +506,74 @@ static void spawn_children(struct opts *opts)
/* Prepare communication pipe */
for(j = 0; j < 3; j++)
if(pipe(fd[j]) == -1)
{
int ret;
#if defined HAVE_PIPE
ret = pipe(fd[j]);
#elif defined HAVE__PIPE
ret = _pipe(fd[j], 256, _O_BINARY);
#endif
if(ret < 0)
{
perror("pipe");
return;
}
}
#if defined HAVE_FORK
/* Fork and launch child */
pid = fork();
switch(pid)
if(pid < -1)
{
case -1:
perror("fork");
return;
case 0:
/* Were the child */
if(opts->maxmem >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxmem * 1000000;
rlim.rlim_max = opts->maxmem * 1000000;
setrlimit(RLIMIT_AS, &rlim);
}
/* 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(fd[j][0]);
if(fd[j][1] != files[j])
{
dup2(fd[j][1], files[j]);
close(fd[j][1]);
}
}
/* 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);
/* Run our process */
if(execvp(opts->newargv[0], opts->newargv))
{
perror(opts->newargv[0]);
exit(EXIT_FAILURE);
}
perror("fork");
return;
}
#else
pid = 0;
#endif
if(pid == 0)
{
#if defined HAVE_SETRLIMIT
if(opts->maxmem >= 0)
{
struct rlimit rlim;
rlim.rlim_cur = opts->maxmem * 1000000;
rlim.rlim_max = opts->maxmem * 1000000;
setrlimit(RLIMIT_AS, &rlim);
}
#endif
#if defined HAVE_FORK
/* 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(fd[j][0]);
if(fd[j][1] != files[j])
{
dup2(fd[j][1], files[j]);
close(fd[j][1]);
}
}
#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
if(run_process(opts->newargv) < 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
#else
if(run_process(opts->newargv) < 0)
return;
#endif
}
/* Were the parent, acknowledge spawn */
@@ -569,9 +605,12 @@ static void spawn_children(struct opts *opts)
static void clean_children(struct opts *opts)
{
#if defined HAVE_KILL
int64_t now = _zz_time();
#endif
int i, j;
#if defined HAVE_KILL
/* Terminate children if necessary */
for(i = 0; i < opts->maxchild; i++)
{
@@ -616,19 +655,23 @@ static void clean_children(struct opts *opts)
opts->child[i].status = STATUS_SIGKILL;
}
}
#endif
/* Collect dead children */
for(i = 0; i < opts->maxchild; i++)
{
uint8_t md5sum[16];
#if defined HAVE_WAITPID
int status;
pid_t pid;
#endif
if(opts->child[i].status != STATUS_SIGKILL
&& opts->child[i].status != STATUS_SIGTERM
&& opts->child[i].status != STATUS_EOF)
continue;
#if defined HAVE_WAITPID
pid = waitpid(opts->child[i].pid, &status, WNOHANG);
if(pid <= 0)
continue;
@@ -651,6 +694,7 @@ static void clean_children(struct opts *opts)
" (memory exceeded?)" : "");
opts->crashes++;
}
#endif
for(j = 0; j < 3; j++)
if(opts->child[i].fd[j] >= 0)
@@ -693,7 +737,7 @@ static void read_children(struct opts *opts)
tv.tv_usec = 1000;
ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
if(ret < 0)
if(ret < 0 && errno)
perror("select");
if(ret <= 0)
return;
@@ -735,6 +779,21 @@ static void read_children(struct opts *opts)
}
}
#if !defined HAVE_GETENV
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
#if defined HAVE_WAITPID
static char const *sig2str(int signum)
{
switch(signum)
@@ -742,9 +801,13 @@ static char const *sig2str(int signum)
case SIGABRT: return " (SIGABRT)";
case SIGFPE: return " (SIGFPE)";
case SIGILL: return " (SIGILL)";
#ifdef SIGQUIT
case SIGQUIT: return " (SIGQUIT)";
#endif
case SIGSEGV: return " (SIGSEGV)";
#ifdef SIGTRAP
case SIGTRAP: return " (SIGTRAP)";
#endif
#ifdef SIGSYS
case SIGSYS: return " (SIGSYS)";
#endif
@@ -764,28 +827,30 @@ static char const *sig2str(int signum)
return "";
}
static void set_environment(char const *progpath)
{
char *libpath, *tmp;
int ret, len = strlen(progpath);
#if defined __APPLE__
# define FILENAME "libzzuf.dylib"
# define EXTRAINFO ""
# define PRELOAD "DYLD_INSERT_LIBRARIES"
setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
#elif defined __osf__
# define FILENAME "libzzuf.so"
# define EXTRAINFO ":DEFAULT"
# define PRELOAD "_RLD_LIST"
#else
# define FILENAME "libzzuf.so"
# define EXTRAINFO ""
# define PRELOAD "LD_PRELOAD"
#endif
static int run_process(char const *argv[])
{
#if defined HAVE_FORK
char *libpath, *tmp;
int ret, len = strlen(argv[0]);
# if defined __APPLE__
# define FILENAME "libzzuf.dylib"
# define EXTRAINFO ""
# define PRELOAD "DYLD_INSERT_LIBRARIES"
setenv("DYLD_FORCE_FLAT_NAMESPACE", "1", 1);
# elif defined __osf__
# define FILENAME "libzzuf.so"
# define EXTRAINFO ":DEFAULT"
# define PRELOAD "_RLD_LIST"
# else
# define FILENAME "libzzuf.so"
# define EXTRAINFO ""
# define PRELOAD "LD_PRELOAD"
# endif
libpath = malloc(len + strlen("/.libs/" FILENAME EXTRAINFO) + 1);
strcpy(libpath, progpath);
strcpy(libpath, argv[0]);
tmp = strrchr(libpath, '/');
strcpy(tmp ? tmp + 1 : libpath, ".libs/" FILENAME);
@@ -797,8 +862,147 @@ static void set_environment(char const *progpath)
else
setenv(PRELOAD, LIBDIR "/" FILENAME EXTRAINFO, 1);
free(libpath);
if(execvp(argv[0], argv))
{
perror(argv[0]);
return -1;
}
return 0;
#elif HAVE_WINDOWS_H
PROCESS_INFORMATION pinfo;
STARTUPINFO sinfo;
void *epaddr;
int ret;
/* Get entry point */
epaddr = get_entry(argv[0]);
if(!epaddr)
return -1;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
ret = CreateProcess(NULL, argv[0], NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &sinfo, &pinfo);
if(!ret)
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 0;
#else
return -1;
#endif
}
#if defined HAVE_WINDOWS_H
static int dll_inject(void *process, void *epaddr)
{
uint8_t old_ep[7];
uint8_t new_ep[] = "\xb8<01>\xff\xe0";
uint8_t loader[] = "libzzuf.dll\0<0000c>\xb8<14>\x50\xb8<1a>\xff\xd0"
"\xb8\0\0\0\0\x50\xb8\x07\x00\x00\x00\x50\xb8<2d>"
"\x50\xb8<33>\x50\xb8<39>\xff\xd0\x50\xb8<41>\xff"
"\xd0\xb8<48>\xff\xe0";
void *lib;
uint8_t *loaderaddr;
DWORD tmp;
/* Save the old entry-point code */
ReadProcessMemory(process, epaddr, old_ep, 7, &tmp);
if(tmp != 7)
return -1;
loaderaddr = VirtualAllocEx(process, NULL, 78, MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if(!loaderaddr)
return -1;
addcpy(new_ep + 0x01, loaderaddr + 0x0c + 7);
WriteProcessMemory(process, epaddr, new_ep, 7, &tmp);
if(tmp != 7)
return -1;
lib = LoadLibrary("kernel32.dll");
if(!lib)
return -1;
memcpy(loader + 0x0c, old_ep, 7);
addcpy(loader + 0x14, loaderaddr + 0x00); /* offset for dll string */
addcpy(loader + 0x1a, GetProcAddress(lib, "LoadLibraryA"));
addcpy(loader + 0x2d, loaderaddr + 0x0c);
addcpy(loader + 0x33, epaddr);
addcpy(loader + 0x39, GetProcAddress(lib, "GetCurrentProcess"));
addcpy(loader + 0x41, GetProcAddress(lib, "WriteProcessMemory"));
addcpy(loader + 0x48, epaddr);
FreeLibrary(lib);
WriteProcessMemory(process, loaderaddr, loader, 78, &tmp);
if(tmp != 78)
return -1;
return 0;
}
static void *get_entry(char const *name)
{
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
void *file, *map, *base;
file = CreateFile(name, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if(file == INVALID_HANDLE_VALUE)
return NULL;
map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
if(!map)
{
CloseHandle(file);
return NULL;
}
base = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
if(!base)
{
CloseHandle(map);
CloseHandle(file);
return NULL;
}
/* Sanity checks */
dos = (PIMAGE_DOS_HEADER)base;
nt = (PIMAGE_NT_HEADERS)((char *)base + dos->e_lfanew);
if(dos->e_magic != IMAGE_DOS_SIGNATURE
|| nt->Signature != IMAGE_NT_SIGNATURE
|| nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
|| nt->OptionalHeader.Magic != 0x10b /* IMAGE_NT_OPTIONAL_HDR32_MAGIC */)
{
UnmapViewOfFile(base);
CloseHandle(map);
CloseHandle(file);
return NULL;
}
return (char *)nt->OptionalHeader.ImageBase +
nt->OptionalHeader.AddressOfEntryPoint;
}
#endif
static void version(void)
{
printf("zzuf %s\n", VERSION);
@@ -853,7 +1057,9 @@ static void usage(void)
printf(" -I, --include <regex> only fuzz files matching <regex>\n");
#endif
printf(" -m, --md5 compute the output's MD5 hash\n");
#if defined HAVE_SETRLIMIT
printf(" -M, --max-memory <n> maximum child virtual memory size in MB\n");
#endif
printf(" -n, --network fuzz network input\n");
printf(" -P, --protect <list> protect bytes and characters in <list>\n");
printf(" -q, --quiet do not print children's messages\n");
@@ -886,7 +1092,9 @@ static void usage(void)
printf(" -I <regex> only fuzz files matching <regex>\n");
#endif
printf(" -m compute the output's MD5 hash\n");
#if defined HAVE_SETRLIMIT
printf(" -M maximum child virtual memory size in MB\n");
#endif
printf(" -n fuzz network input\n");
printf(" -P <list> protect bytes and characters in <list>\n");
printf(" -q do not print the fuzzed application's messages\n");