From 28163e430c706c892f97699af642890f81763720 Mon Sep 17 00:00:00 2001 From: Ruikai Liu Date: Thu, 1 Aug 2019 17:26:29 +0800 Subject: [PATCH] add code --- Makefile | 34 ++ README.md | 85 ++++ callback/demo-callback.c | 179 +++++++ demo-libcpreload.c | 31 ++ demo-libcpreload.so | Bin 0 -> 2424 bytes demo-vuln | Bin 0 -> 7016 bytes demo-vuln.c | 32 ++ libc-preload.c | 47 ++ uniFuzzer/elfLoader/COPYRIGHT | 49 ++ uniFuzzer/elfLoader/arm.c | 132 +++++ uniFuzzer/elfLoader/arm.h | 15 + uniFuzzer/elfLoader/common.h | 32 ++ uniFuzzer/elfLoader/dl-defs.h | 248 ++++++++++ uniFuzzer/elfLoader/dl-elf.h | 101 ++++ uniFuzzer/elfLoader/dl-hash.c | 204 ++++++++ uniFuzzer/elfLoader/dl-hash.h | 122 +++++ uniFuzzer/elfLoader/dl-string.h | 36 ++ uniFuzzer/elfLoader/elfLoader.c | 848 ++++++++++++++++++++++++++++++++ uniFuzzer/elfLoader/elfLoader.h | 12 + uniFuzzer/elfLoader/i386.c | 154 ++++++ uniFuzzer/elfLoader/i386.h | 11 + uniFuzzer/elfLoader/mips.c | 151 ++++++ uniFuzzer/elfLoader/mips.h | 13 + uniFuzzer/uniFuzzer.c | 49 ++ uniFuzzer/utils.c | 68 +++ uniFuzzer/utils.h | 10 + utils.c | 64 +++ utils.h | 10 + 28 files changed, 2737 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 callback/demo-callback.c create mode 100644 demo-libcpreload.c create mode 100755 demo-libcpreload.so create mode 100755 demo-vuln create mode 100644 demo-vuln.c create mode 100644 libc-preload.c create mode 100644 uniFuzzer/elfLoader/COPYRIGHT create mode 100644 uniFuzzer/elfLoader/arm.c create mode 100644 uniFuzzer/elfLoader/arm.h create mode 100644 uniFuzzer/elfLoader/common.h create mode 100644 uniFuzzer/elfLoader/dl-defs.h create mode 100644 uniFuzzer/elfLoader/dl-elf.h create mode 100644 uniFuzzer/elfLoader/dl-hash.c create mode 100644 uniFuzzer/elfLoader/dl-hash.h create mode 100644 uniFuzzer/elfLoader/dl-string.h create mode 100644 uniFuzzer/elfLoader/elfLoader.c create mode 100644 uniFuzzer/elfLoader/elfLoader.h create mode 100644 uniFuzzer/elfLoader/i386.c create mode 100644 uniFuzzer/elfLoader/i386.h create mode 100644 uniFuzzer/elfLoader/mips.c create mode 100644 uniFuzzer/elfLoader/mips.h create mode 100644 uniFuzzer/uniFuzzer.c create mode 100644 uniFuzzer/utils.c create mode 100644 uniFuzzer/utils.h create mode 100644 utils.c create mode 100644 utils.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..83cab4d --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +CC := clang +CFLAGS := -Wall -fPIC +#CFLAGS += -O2 +CFLAGS += -g -DUF_DEBUG +LDFLAGS := -fsanitize=fuzzer -lunicorn -pthread + +OUT := uf +.DEFAULT_GOAL := all + +SRC := $(wildcard callback/*.c) \ + $(wildcard uniFuzzer/*.c) \ + $(wildcard uniFuzzer/elfLoader/*.c) +OBJ := $(SRC:.c=.o) + +MAIN_SRC := uniFuzzer/uniFuzzer.c +MAIN_OBJ := uniFuzzer/uniFuzzer.o +$(MAIN_OBJ): CFLAGS += -fsanitize=fuzzer -IuniFuzzer/elfLoader + +OTHER_SRC := $(filter-out $(MAIN_SRC),$(SRC)) +OTHER_OBJ := $(OTHER_SRC:.c=.o) + +%.o:%.c + $(CC) -o $@ $(CFLAGS) -c $< + +all:$(OUT) + +$(OUT):$(OBJ) + $(CC) -o $@ $(LDFLAGS) $^ + +clean: + rm -f $(OUT) $(OBJ) + +.PHONY: all clean + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1401ab --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +uniFuzzer +--------- + +uniFuzzer is a fuzzing tool for closed-source binaries based on [Unicorn](https://github.com/unicorn-engine/unicorn) and [LibFuzzer](https://llvm.org/docs/LibFuzzer.html). Currently it supports fuzzing 32-bits LSB ELF files on ARM/MIPS, which are usually seen in IoT devices. + + +# Features + +- very little [hack](#-hack-on-unicorn) and easy to build +- can target any specified function or code snippet +- coverage-guided fuzzing with considerable speed +- dependence resolved and loaded automatically +- library function override by PRELOAD + + +# Build + +1. Reverse the target binary and find interesting functions for fuzzing. +2. Create a `.c` file in the directory `callback`, which should contain the following callbacks: + +* `void onLibLoad(const char *libName, void *baseAddr, void *ucBaseAddr)`: It's invoked each time an dependent library is loaded in Unicorn. +* `int uniFuzzerInit(uc_engine *uc)`: It's invoked just after all the binaries been loaded in Unicorn. Stack/heap/registers can be setup up here. +* `int uniFuzzerBeforeExec(uc_engine *uc, const uint8_t *data, size_t len)`: It's invoked before each round of fuzzing execution. +* `int uniFuzzerAfterExec(uc_engine *uc)`: It's invoked after each round of fuzzing execution. + +3. Run `make` and get the fuzzing tool named `uf`. + + +# Run + +uniFuzzer uses the following environment variables as parameters: + +- `UF_TARGET`: Path of the target ELF file +- `UF_PRELOAD`: Path of the preload library. Please make sure that the library has the same architecture as the target. +- `UF_LIBPATH`: Paths in which the dependent libraries reside. Use `:` to separate multiple paths. + +And the fuzzing can be started using the following command: + +```bash +UF_TARGET= [UF_PRELOAD=] UF_LIBPATH= ./uf +``` + + +# Demo + +There comes a demo for basic usage. The demo contains the following files: + +- demo-vuln.c: This is the target for fuzzing. It contains a simple function named `vuln()` which is vulnerable to stack/heap overflow. +- demo-libcpreload.c: This is for PRELOAD hooking. It defines an empty `printf()` and simplified `malloc()/free()`. +- callback/demo-callback.c: This defines the necessary callbacks for fuzzing the demo `vuln()` function. + +First, please install gcc for mipsel (package `gcc-mipsel-linux-gnu` on Debian) to build the demo: + +```bash +# the target binary +# '-Xlinker --hash-style=sysv' tells gcc to use 'DT_HASH' instead of 'DT_GNU_HASH' for symbol lookup +# since currently uniFuzzer does not support 'DT_GNU_HASH' +mipsel-linux-gnu-gcc demo-vuln.c -Xlinker --hash-style=sysv -no-pie -o demo-vuln + +# the preload library +mipsel-linux-gnu-gcc -shared -fPIC -nostdlib -Xlinker --hash-style=sysv demo-libcpreload.c -o demo-libcpreload.so +``` + +Or you can just use the file `demo-vuln` and `demo-libcpreload.so`, which are compiled using the commands above. + +Next, run `make` to build uniFuzzer. Please note that if you compiled the MIPS demo by yourself, then some addresses might be different from the prebuilt one and `demo-callback.c` should be updated accordingly. + +Finally, make sure that the libc library of MIPS is ready. On Debian it's in `/usr/mipsel-linux-gnu/lib/` after installing the package `libc6-mipsel-cross`, and that's what `UF_LIBPATH` should be: + +```bash +UF_TARGET= UF_PRELOAD= UF_LIBPATH= ./uf +``` + +# Hack on Unicorn + +Unicorn clears the JIT cache of QEMU due to this [issue](https://github.com/unicorn-engine/unicorn/issues/1043), which slows down the speed of fuzzing since the target binary would have to be JIT re-compiled during each round of execution. + +We can comment out `tb_flush(env);` as stated in that issue for performance. + +# TODO + +* support for syscall +* support for other architectures and binary formats +* support `GNU_HASH` +* integrate environment setup and provide APIs diff --git a/callback/demo-callback.c b/callback/demo-callback.c new file mode 100644 index 0000000..2bfaeb8 --- /dev/null +++ b/callback/demo-callback.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include + +#include + +static uc_context *context; + +// CHANGE ME! +// start addr of the emulation (entry point of function vuln) +#define START 0x4007f0 +// end addr of the emulation (return addr in main) +#define END 0x400970 +// return addr of the target function +#define RA 0x400970 + +// CHANGE ME! +// name of the preload library +#define PRELOAD_LIB "demo-libcpreload.so" + +// CHANGE ME! +// readelf -sW demo-libcpreload.so | grep heap_boundary +#define HEAP_BOUNDARY_GOT_OFFSET 0x10380 + +#define HEAP_SIZE 1024*1024*32 +#define STACK_SIZE 1024*1024*8 +#define DATA_SIZE 0x1000 + +static char *heapBase; +static char *stackTop; +static char *dataAddr; + +// heap_boundary@got for the simplified malloc() in demo-preload +static uint32_t *heapBoundaryGOT; + +#define HEAP_CANARY 0xdeadbeef + +// callback: invoked when ELFs(target binary and dependent libs) are loaded +void onLibLoad(const char *libName, void *baseAddr, void *ucBaseAddr) { + fprintf(stderr, "loading %s at %p, uc addr: %p\n", libName, baseAddr, ucBaseAddr); + + if(strlen(libName)+1 >= sizeof(PRELOAD_LIB)) { + // libname ends with "demo-libcpreload.so" + if(strcmp(libName+strlen(libName)-sizeof(PRELOAD_LIB)+1, PRELOAD_LIB) == 0) { + heapBoundaryGOT = (char *)baseAddr + HEAP_BOUNDARY_GOT_OFFSET; + fprintf(stderr, "demo-libcpreload.so is at %p, heap_boundary@got is at %p\n", baseAddr, heapBoundaryGOT); + } + } +} + +// callback: setup the env before emulation starts +int uniFuzzerInit(uc_engine *uc) { + + // setup heap area + heapBase = mmap(NULL, HEAP_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0); + if(heapBase == MAP_FAILED) { + perror("mapping heap"); + return 1; + } + if(uc_mem_map_ptr(uc, heapBase, HEAP_SIZE, UC_PROT_READ | UC_PROT_WRITE, heapBase) != UC_ERR_OK) { + fprintf(stderr, "uc mapping heap failed\n"); + return 1; + } + printf("heap is at %p\n", heapBase); + + + // setup stack area + stackTop = mmap(NULL, STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0); + if(stackTop == MAP_FAILED) { + perror("mapping stack"); + return 1; + } + if(uc_mem_map_ptr(uc, stackTop, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE, stackTop) != UC_ERR_OK) { + fprintf(stderr, "uc mapping stack failed\n"); + return 1; + } + printf("stack is at %p\n", stackTop+STACK_SIZE); + + + // setup data area + dataAddr = mmap(NULL, DATA_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0); + if(dataAddr == MAP_FAILED) { + perror("mapping data"); + return 1; + } + if(uc_mem_map_ptr(uc, dataAddr, DATA_SIZE, UC_PROT_READ | UC_PROT_WRITE, dataAddr) != UC_ERR_OK) { + fprintf(stderr, "uc mapping data failed\n"); + return 1; + } + printf("data is at %p\n", dataAddr); + + // for the registers + uint32_t reg; + + reg = stackTop+STACK_SIZE - 0x200; + uc_reg_write(uc, UC_MIPS_REG_SP, ®); + + reg = dataAddr; + uc_reg_write(uc, UC_MIPS_REG_A0, ®); + + reg = START; + uc_reg_write(uc, UC_MIPS_REG_T9, ®); + + reg = RA; + uc_reg_write(uc, UC_MIPS_REG_RA, ®); + + // alloc and save cpu context for restore + if(uc_context_alloc(uc, &context) != UC_ERR_OK) { + fprintf(stderr, "uc_context_alloc failed\n"); + return 1; + } + + uc_context_save(uc, context); + + return 0; +} + +// callback: invoked before each round of fuzzing +int uniFuzzerBeforeExec(uc_engine *uc, const uint8_t *data, size_t len) { + // filter on input size + if(len == 0 || len > 256) return 0; + + // reset heap base addr in preload library + *heapBoundaryGOT = heapBase; + + // restore cpu context + uc_context_restore(uc, context); + + // copy input to buffer + memcpy(dataAddr, data, len); + + // uncomment the following line to ignore heap overflow in the function vuln + // memset((char *)dataAddr+4, 0, 1); + + // uncomment the following line to ignore stack overflow in the function vuln + // memset(dataAddr, 0x20, 1); + + uc_err err; + + // start emulation of the target function + if((err = uc_emu_start(uc, START, END, 0, 0)) != UC_ERR_OK) { + fprintf(stderr, "uc_emu_start failed: %s\n", uc_strerror(err)); + return 1; + } + else { + return 0; + } +} + +// callback: invoked after each round of fuzzing +int uniFuzzerAfterExec(uc_engine *uc) { + // check all heap allocations to see if there's an overflow + + // current boundary for used heap area + uint32_t *boundary = *heapBoundaryGOT; + + // start addr for used heap are + uint32_t *start = heapBase; + + size_t chunk_len; + char *canary; + + // check canary for all chunks + while(start < boundary) { + chunk_len = *start; + canary = (char *)start + chunk_len + 4;// with header + + // overflow + if(*(uint32_t *)canary != HEAP_CANARY) { + fprintf(stderr, "heap overflow!\n"); + return 1; + } + + start = (char *)start + chunk_len + 8; + } + + return 0; +} diff --git a/demo-libcpreload.c b/demo-libcpreload.c new file mode 100644 index 0000000..4a5b006 --- /dev/null +++ b/demo-libcpreload.c @@ -0,0 +1,31 @@ +#include +#include + +#define HEAP_CANARY 0xdeadbeef + + +// very simple allocator that just cut and return memory from mmap-ed area +// | chunk size | chunk | canary | +// |--------------|------------------|---------| +// | 4 bytes | ... | 4 bytes | + +void *malloc(size_t size) { + static char *heap_boundary = 0x05000000; + size_t chunk_len = ((size+7)/8)*8; + + *((uint32_t *)heap_boundary) = chunk_len; // header + *((uint32_t *)(heap_boundary+4+chunk_len)) = HEAP_CANARY; + + void *chunk = heap_boundary + 4; + + heap_boundary += chunk_len + 8; // with header and canary + + return chunk; +} + +void free(void *ptr) { +} + +int printf() { + return 0; +} diff --git a/demo-libcpreload.so b/demo-libcpreload.so new file mode 100755 index 0000000000000000000000000000000000000000..8176fab3e0854003c0a1ede1ebceaf4d5b1c0591 GIT binary patch literal 2424 zcmb7F-)j_C6h4z#o7LJjNfj0J)eQquk%BJ@S*L#wplgRp+z+_{?xMzIIZo?qWR_uM<@ z?7cQ$SuhMkG?|hWTG5EeQOLD7L`KIXI4YAeDg~L4aWO@L96&<`E(gwlvtUqAL|ijt zI!+Aprzt{0@~+rvsQqJ~0ly&!;3uOLkRd2dT1cY#YuIGw*8CCTn)C3JbqwlDi5Nwb zBe)h-l6FC&jwdNIR->CnoO>TElr4+rE=lp=zdzUh{Ql~LzbfnNH^wJ^{N>h(cz+bn zq)kYkrvSMJl55`tkAa!v4$h4u1iUNY1D+Z90D|~{m~lwvoPc}>^4-LS`oD;|^tq{X zFHPKkCwdFc^8n`|CsIALme}lr0^)_lmbTq$`88SYx~>FWuM;jK!o3chly-)6MO#SmMR{pw?lRvxvyQ|iR$BrM9>gmhp=FXle zOSKV5b+NKknyXZo78WkdU#wo7D^=#Jdic`wDAvkqJG33hu&ZQKYiG}#zhK#px7@ND zD`IushSyp4#p?K>YoS3br{}fmGhSV+`fA5+do{6|_DVB0kygpDD^}=!8N#wdTdal; zwdS|mZU;(GN0_?&gTR(uBLbP>mSA+uLC=?-+^pw4|FV92opg2Y^;&%wkoC;L5u zqGNCk^{dbm+!*KX4shwI;u_ZYMS?3rlI{Y>w_Fo*kgp|D`+oxNiZ&pbi*yV8-(cX! z27Yn~r0ZiY(pO-u(=O-)G(b8=$*a&rTm&a`?gw)jb^gPkq#>>0Bl7Mw>3n#Tx8Zi- L!oSlXNR4|AhpGyV literal 0 HcmV?d00001 diff --git a/demo-vuln b/demo-vuln new file mode 100755 index 0000000000000000000000000000000000000000..f5f8296bcc332f7eed8e875daa781dbdf1ff1306 GIT binary patch literal 7016 zcmb7JeQaCR6+iY%+q5a*w51Ir8*Xbi88mKEGFGNYd(KC@h_nrDV1SrjocJZN=C9c= zsAZF8XvHc(b%dr3B#;6tTmN8lfb!2qN7NO@BsBG(u}bTtXhR6JNy{W)omAEP{qB1= zelcmqPI`Rr@1AqdJ@@0?ch2h%2Zr_r0s+w!ltv*MUTsP@%BjsFYeJImmawdocKqHZ ztI%? zRWnhTa=u9vuTqTxHHO<3M|)gm(f%fwe$#^>ey_m(71$;(0F!B3^Kr^pEDe%&>spEU{xu}$t2YmM?* zKwk4fRb6~4u54}sGQhO?z^hZcXD9xC!_Ygk|CEm}pZdj}|9FDqk=KJStTNRenN6nZ zdnstD!A>=pYTX>e#QuwX2*z?Ne{nSOi&)>Up?qa+KyF4miDSz8IBn-?A5P~v7p#At z`vp6Bo`+_X8&PgR`DK)-=ehq^tJT~b{Hda3|3#Ef0{_1R`?RS@`GlHxzSJ3@U@iDY zRzPdOJR|f?FEr0nrZ<=duz#j>i6Vrt)nAM(3DXccc8f z`e)$9HKr`0q;tJ8yHG$myVjIbD5<{}ig#OiYNDk}v$k(7*`q2@%vwk4BDr*q?C4IYGAGL^Nai*{0X94}5=scg#e;|VkXPiAsi z&#;BwBm1qSU9cxpMaM3T?C(qGvi3+~EN#286(x^Mr?aweXt1}>+8yh}oOyHA{sd=~ zPYr+FKh|Bjd%hr)P%4Gv8k9=}prEw&gr9i6ZR^5w#zOUMTS(rlw8~qR;nL&f1~GXo zWw`WQdF|z}dL#nUtd4On`Yk^7d|L#v57yk>c0KvR z`@M9$Eb=mZ_<7sqY9JE%=tbpUYw1VjaOp%jB&REzV0{gfPQUnS?Ztdgzm1JZ~3 z8kt?P)qfpZ7qG7F@_HpM8+&$QZ6oqpB`mLEo#!g~^<&Spin%E+&C1UUO1Z=}=`6tw?pYp4&K|KQVlAE-;c z|5QgeQSX&Nh}SmGLok9dUxFWH_*8~3W%yEtFKS;pu`j<4gc_+!;`xx{?)i8C^Ed_n zXXUq*=;ExwvvOL_gU?~FdS_bX9QNbwas+2*wy8goL>Yb86zx+;E|q(vAu_T;dn@|V z4tD!5tvnX?`dpg?R;zin zz^C*Ideotfc2D+V)qT#mW?UPv@)`b=;ZM0eQ1jW{DfgHD4?phu|1S1xC(b4JsZ-vl zL{HDlPB~MF&dwq-d%Y5UwuCt3HFXZVv9DLIHaGBGLciQungKsk-aa!NJT|id?>%!v z^aRJa zV6g87X^Hr8s1Dy$hi|OIH`L+vb$DGJUJFbg{KWm4D}DaHt-k|#uXg+H)%tr=+jOH- zjSxdm+2K?+KkbBzsYg*QhNH=KHL@@ zUjg3+reC0C@^%DAT27xuzFG43--8y$lkD%#2bDU~@;HOE$?UWQ82vS@s#8;tc?`+G zZA)TKKr(Qfl9tx!wxM!6us+Yt z!7cK2V0}-r|2|+oU)+D@ZubN0`G#QcJHTPzc#i`6bGzffyz@?>KXbb~;BRSZel7B2 z$ZPX$ky&7W?)NgVz7N>{mp&W+-yj`2dSSlpFK<%@Q@Bb~}lAL+ndyKB#`SgiK%b7FoTfdY&1g3}et$yC}AREy5^ z#6%3)n$xi z)3#$LV|R6T?iLEHRPqQ>H?qS-#?6$Xk+JLj+&6Tv zH$G$?+`ISiz=$;x?;RSzwoSmoby9hW6^~||#28Aa;FeRmhA$CzAuq9P&aq?h-oXwh zF)1+~idbSSHIYtC7A3|H1lft4r-f%EHa49~Cp%I}i6xI_6PeVw#HJF(DFrc@TRH`a zQTY+OP)y~r%YX%$ntn`8(j5^`&=`hOM=4gwsa1{HQqD_rg@N2aL;3fbQ0fA zFoDUOgZa6QT#gu?pNySFV?OEmk#L+sYHZrUBNxjg?Xl@e&hgIO-Uaam3ckT{rQuzM z_ax#Z2f&S5+|HDdwu2chQIGK$zt@IQ*Tnmk)CImBuVCuA-<#cU&6JTE!HhCYFrqP~ zHxGOBu;-6HXpeXhtjBe~|GM9P(X2?1%Wq_i?l`Xdof-Eq>TAIy>Tztw8>_(7V;so) z^jXv?BTM=fa3{mfD+Jmb~haYzsuRx^q7&o3m=MRB3QJ3_6FhcGe?J=Hw z5>D(uU60Fl@(D1%$Fj~ia}Ii8)cxZE%1^ +#include +#include +#include +#include +#include +#include +#include + +int vuln(unsigned char *input) { + size_t input_len = *input; + printf("the input size is %d\n", input_len); + char stack_buf[128]; + char *heap_buf = malloc(60); + + // heap overflow + strcpy(heap_buf, input+1); + // stack overflow + memcpy(stack_buf, input+1, input_len); + + free(heap_buf); + return input_len; +} + +int main(int argc, char *argv[]) { + char input[256]; + int fin = open(argv[1], O_RDONLY); + read(fin, input, sizeof(input)); + + int res = vuln(input); + return res; +} diff --git a/libc-preload.c b/libc-preload.c new file mode 100644 index 0000000..3d91da7 --- /dev/null +++ b/libc-preload.c @@ -0,0 +1,47 @@ +#include + +#define HEAP_CANARY 0xdeadbeef + +void perror(const char *s) { +} + +void *malloc(size_t size) { + static char *heap_base = 0x05000000; + size_t alignedSize = ((size+7)/8)*8; + *((uint32_t *)heap_base) = alignedSize; // header + *((uint32_t *)(heap_base+4+alignedSize)) = HEAP_CANARY; + void *res = heap_base + 4; + heap_base += alignedSize + 8; // with header and canary + return res; +} + +size_t send(int sockfd, const void *buf, size_t len, int flags) { + return len; +} + +int pthread_mutex_lock(void *lock) { + return 0; +} + +int pthread_mutex_unlock(void *lock) { + return 0; +} + +void free(void *ptr) { + uint32_t *base = ((uint32_t *)ptr) - 1; + char *canary = (*((char *)base)) + 4 + (*base); + // overflow + if(*(uint32_t *)canary != HEAP_CANARY) { + // trigger segfault + uint32_t *invalid_addr = 0xffffffff; + *invalid_addr = 0; + } +} + +int printf() { + return 0; +} + +int puts() { + return 0; +} diff --git a/uniFuzzer/elfLoader/COPYRIGHT b/uniFuzzer/elfLoader/COPYRIGHT new file mode 100644 index 0000000..fb34248 --- /dev/null +++ b/uniFuzzer/elfLoader/COPYRIGHT @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, David Engel, + * Hongjiu Lu and Mitch D'Souza + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Notice of general intent: + * + * The linux operating system generally contains large amounts of code + * that fall under the GNU General Public License, or GPL for short. + * This file contains source code that by it's very nature would always + * be linked with an application program, and because of this a GPL + * type of copyright on this file would place restrictions upon the + * distribution of binary-only commercial software. Since the goal of + * the Linux project as a whole is not to discourage the development and + * distribution of commercial software for Linux, this file has been + * placed under a more relaxed BSD-style of copyright. + * + * It is the general understanding of the above contributors that a + * program executable linked to a library containing code that falls + * under the GPL or GLPL style of license is not subject to the terms of + * the GPL or GLPL license if the program executable(s) that are supplied + * are linked to a shared library form of the GPL or GLPL library, and as + * long as the form of the shared library is such that it is possible for + * the end user to modify and rebuild the library and use it in + * conjunction with the program executable. + */ diff --git a/uniFuzzer/elfLoader/arm.c b/uniFuzzer/elfLoader/arm.c new file mode 100644 index 0000000..7139c4f --- /dev/null +++ b/uniFuzzer/elfLoader/arm.c @@ -0,0 +1,132 @@ +#include +#include + +#include "arm.h" + +#define elf_machine_type_class_arm(type) \ + ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \ + || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)) + + +int _dl_do_reloc_arm (struct elf_resolve *tpnt,struct r_scope_elem *scope, + ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; + Elf32(Addr) *reloc_addr; + Elf32(Addr) symbol_addr; + struct symbol_ref sym_ref; + struct elf_resolve *def_mod = 0; + int goof = 0; + + reloc_addr = (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); + symbol_addr = 0; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + symname = strtab + symtab[symtab_index].st_name; + if(strcmp(symname, "heap_base") == 0) sleep(1); + + + if (symtab_index) { + symbol_addr = _dl_find_hash(symname, scope, tpnt, + elf_machine_type_class_arm(reloc_type), &sym_ref); + + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) + && (ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) { + /* This may be non-fatal if called from dlopen. */ + fprintf(stderr, "can't resolve symbol %s\n", symname); + return 1; + + } + def_mod = sym_ref.tpnt; + } else { + /* + * Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. + */ + symbol_addr = symtab[symtab_index].st_value; + def_mod = tpnt; + } + + switch (reloc_type) { + case R_ARM_NONE: + break; + case R_ARM_ABS32: + *reloc_addr += symbol_addr; + break; + case R_ARM_PC24: + fprintf(stderr,"R_ARM_PC24: Compile shared libraries with -fPIC!\n"); + return -1; + case R_ARM_GLOB_DAT: + case R_ARM_JUMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_ARM_RELATIVE: + *reloc_addr += (unsigned long) tpnt->loadaddr; + break; + case R_ARM_COPY: + memcpy((void *) reloc_addr, + (void *) symbol_addr, symtab[symtab_index].st_size); + break; + default: + return -1; /*call _dl_exit(1) */ + } + + return goof; +} + + +int _dl_parse_relocation_information_arm(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab)) +{ + int i; + char *strtab; + int goof = 0; + Elf32(Sym) *symtab; + ELF_RELOC *rpnt; + int symtab_index; + //printf("rel for %s, rel addr %p, rel size %d\n", tpnt->libname, rel_addr, rel_size); + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *) rel_addr; + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (Elf32(Sym) *) tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *) tpnt->dynamic_info[DT_STRTAB]; + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF_R_SYM(rpnt->r_info); + + res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab); + + if (res==0) continue; + + if (unlikely(res <0)) + { + int reloc_type = ELF_R_TYPE(rpnt->r_info); + fprintf(stderr, "can't handle reloc type %x for lib %s\n", reloc_type, tpnt->libname); + continue; + } + if (unlikely(res >0)) + { + goof += res; + } + } + return goof; +} diff --git a/uniFuzzer/elfLoader/arm.h b/uniFuzzer/elfLoader/arm.h new file mode 100644 index 0000000..6d58131 --- /dev/null +++ b/uniFuzzer/elfLoader/arm.h @@ -0,0 +1,15 @@ +#ifndef DL_ARM_H +#define DL_ARM_H + +#include "dl-hash.h" + +int _dl_do_reloc_arm (struct elf_resolve *tpnt,struct r_scope_elem *scope, + ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab); + +int _dl_parse_relocation_information_arm(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab)); + + +#endif diff --git a/uniFuzzer/elfLoader/common.h b/uniFuzzer/elfLoader/common.h new file mode 100644 index 0000000..44cc6bf --- /dev/null +++ b/uniFuzzer/elfLoader/common.h @@ -0,0 +1,32 @@ +#ifndef DL_COMMON_H +#define DL_COMMON_H +#include + +#define Elf32(TYPE) Elf32_##TYPE + +#define unlikely(x) __builtin_expect((!!(x)),0) +#define attribute_unused __attribute__((unused)) +#define do_rem(result, n, base) ((result) = (n) % (base)) + +/* common align masks, if not specified by sysdep headers */ +#define _dl_pagesize 4096 +#ifndef ADDR_ALIGN +#define ADDR_ALIGN (_dl_pagesize - 1) +#endif + +#ifndef PAGE_ALIGN +#define PAGE_ALIGN (~ADDR_ALIGN) +#endif + +#ifndef OFFS_ALIGN +#define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1))) +#endif + +#ifdef UF_DEBUG +#define uf_debug(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) +#else +#define uf_debug(fmt, ...) +#endif + +#endif + diff --git a/uniFuzzer/elfLoader/dl-defs.h b/uniFuzzer/elfLoader/dl-defs.h new file mode 100644 index 0000000..a9e9a8a --- /dev/null +++ b/uniFuzzer/elfLoader/dl-defs.h @@ -0,0 +1,248 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2000-2006 by Erik Andersen + * + * GNU Lesser General Public License version 2.1 or later. + */ + +#ifndef _LD_DEFS_H +#define _LD_DEFS_H + +#include "common.h" + +#define FLAG_ANY -1 +#define FLAG_TYPE_MASK 0x00ff +#define FLAG_LIBC4 0x0000 +#define FLAG_ELF 0x0001 +#define FLAG_ELF_LIBC5 0x0002 +#define FLAG_ELF_LIBC6 0x0003 +#define FLAG_ELF_UCLIBC 0x0004 +#define FLAG_REQUIRED_MASK 0xff00 +#define FLAG_SPARC_LIB64 0x0100 +#define FLAG_IA64_LIB64 0x0200 +#define FLAG_X8664_LIB64 0x0300 +#define FLAG_S390_LIB64 0x0400 +#define FLAG_POWERPC_LIB64 0x0500 +#define FLAG_MIPS64_LIBN32 0x0600 +#define FLAG_MIPS64_LIBN64 0x0700 + +#define LIB_ANY -1 +#define LIB_DLL 0 +#define LIB_ELF 1 +#define LIB_ELF64 0x80 +#define LIB_ELF_LIBC5 2 +#define LIB_ELF_LIBC6 3 +#define LIB_ELF_LIBC0 4 + + +/* Provide a means for a port to pass additional arguments to the _dl_start + function. */ +#ifndef DL_START +# define DL_START(X) static void * __attribute_used__ _dl_start(X) +#endif + +/* Machines in which different sections may be relocated by different + * amounts should define this and LD_RELOC_ADDR. If you change this, + * make sure you change struct link_map in include/link.h accordingly + * such that it matches a prefix of struct elf_resolve. + */ +#ifndef DL_LOADADDR_TYPE +# define DL_LOADADDR_TYPE Elf32(Addr) +#endif + +/* When DL_LOADADDR_TYPE is not a scalar value, or some different + * computation is needed to relocate an address, define this. + */ +#ifndef DL_RELOC_ADDR +# define DL_RELOC_ADDR(LOADADDR, ADDR) \ + ((LOADADDR) + (ADDR)) +#endif + +/* Initialize the location of the dynamic addr. This is only called + * from DL_START, so additional arguments passed to it may be referenced. */ +#ifndef DL_BOOT_COMPUTE_DYN +#define DL_BOOT_COMPUTE_DYN(DPNT, GOT, LOAD_ADDR) \ + ((DPNT) = ((Elf32(Dyn) *) DL_RELOC_ADDR(LOAD_ADDR, GOT))) +#endif + +/* Initialize the location of the global offset table. This is only called + * from DL_START, so additional arguments passed to it may be referenced. */ +#ifndef DL_BOOT_COMPUTE_GOT +#define DL_BOOT_COMPUTE_GOT(GOT) \ + ((GOT) = elf_machine_dynamic()) +#endif + +/* Initialize a LOADADDR representing the loader itself. It's only + * called from DL_START, so additional arguments passed to it may be + * referenced. + */ +#ifndef DL_INIT_LOADADDR_BOOT +# define DL_INIT_LOADADDR_BOOT(LOADADDR, BASEADDR) \ + ((LOADADDR) = (BASEADDR)) +#endif + +/* Define if any declarations/definitions of local variables are + * needed in a function that calls DT_INIT_LOADADDR or + * DL_INIT_LOADADDR_HDR. Declarations must be properly terminated + * with a semicolon, and non-declaration statements are forbidden. + */ +#ifndef DL_INIT_LOADADDR_EXTRA_DECLS +# define DL_INIT_LOADADDR_EXTRA_DECLS /* int i; */ +#endif + +/* Prepare a DL_LOADADDR_TYPE data structure for incremental + * initialization with DL_INIT_LOADADDR_HDR, given pointers to a base + * load address and to program headers. + */ +#ifndef DL_INIT_LOADADDR +# define DL_INIT_LOADADDR(LOADADDR, BASEADDR, PHDR, PHDRCNT) \ + ((LOADADDR) = (BASEADDR)) +#endif + +/* Initialize a LOADADDR representing the program. It's called from + * DL_BOOT only. + */ +#ifndef DL_INIT_LOADADDR_PROG +# define DL_INIT_LOADADDR_PROG(LOADADDR, BASEADDR) \ + ((LOADADDR) = (DL_LOADADDR_TYPE)(BASEADDR)) +#endif + +/* Update LOADADDR with information about PHDR, just mapped to the + given ADDR. */ +#ifndef DL_INIT_LOADADDR_HDR +# define DL_INIT_LOADADDR_HDR(LOADADDR, ADDR, PHDR) /* Do nothing. */ +#endif + +/* Convert a DL_LOADADDR_TYPE to an identifying pointer. Used mostly + * for debugging. + */ +#ifndef DL_LOADADDR_BASE +# define DL_LOADADDR_BASE(LOADADDR) (LOADADDR) +#endif + +/* Test whether a given ADDR is more likely to be within the memory + * region mapped to TPNT (a struct elf_resolve *) than to TFROM. + * Everywhere that this is used, TFROM is initially NULL, and whenever + * a potential match is found, it's updated. One might want to walk + * the chain of elf_resolve to locate the best match and return false + * whenever TFROM is non-NULL, or use an exact-matching algorithm + * using additional information encoded in DL_LOADADDR_TYPE to test + * for exact containment. + */ +#ifndef DL_ADDR_IN_LOADADDR +# define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \ + ((void*)(TPNT)->mapaddr < (void*)(ADDR) \ + && (!(TFROM) || (TFROM)->mapaddr < (TPNT)->mapaddr)) +#endif + +/* This is called from dladdr() to give targets that use function descriptors + * a chance to map a function descriptor's address to the function's entry + * point before trying to find in which library it's defined. */ +#ifndef DL_LOOKUP_ADDRESS +#define DL_LOOKUP_ADDRESS(ADDRESS) (ADDRESS) +#endif + +/* On some architectures dladdr can't use st_size of all symbols this way. */ +#define DL_ADDR_SYM_MATCH(SYM_ADDR, SYM, MATCHSYM, ADDR) \ + ((ADDR) >= (SYM_ADDR) \ + && ((((SYM)->st_shndx == SHN_UNDEF || (SYM)->st_size == 0) \ + && (ADDR) == (SYM_ADDR)) \ + || (ADDR) < (SYM_ADDR) + (SYM)->st_size) \ + && (!(MATCHSYM) || MATCHSYM < (SYM_ADDR))) + +/* Use this macro to convert a pointer to a function's entry point to + * a pointer to function. The pointer is assumed to have already been + * relocated. LOADADDR is passed because it may contain additional + * information needed to compute the pointer to function. + */ +#ifndef DL_ADDR_TO_FUNC_PTR +# define DL_ADDR_TO_FUNC_PTR(ADDR, LOADADDR) ((void(*)(void))(ADDR)) +#endif + +/* On some platforms, computing a pointer to function is more + expensive than calling a function at a given address, so this + alternative is provided. The function signature must be given + within parentheses, as in a type cast. */ +#ifndef DL_CALL_FUNC_AT_ADDR +# define DL_CALL_FUNC_AT_ADDR(ADDR, LOADADDR, SIGNATURE, ...) \ + ((*SIGNATURE DL_ADDR_TO_FUNC_PTR ((ADDR), (LOADADDR)))(__VA_ARGS__)) +#endif + +/* An alignment value for a memory block returned by _dl_malloc. */ +#ifndef DL_MALLOC_ALIGN +# define DL_MALLOC_ALIGN (__WORDSIZE / 8) +#endif + +#ifdef __UCLIBC_UNDERSCORES__ +# define __C_SYMBOL_PREFIX__ "_" +#else +# define __C_SYMBOL_PREFIX__ "" +#endif + +/* Define this if you want to modify the VALUE returned by + _dl_find_hash for this reloc TYPE. TPNT is the module in which the + matching SYM was found. */ +#ifndef DL_FIND_HASH_VALUE +# define DL_FIND_HASH_VALUE(TPNT, TYPE, SYM) (DL_RELOC_ADDR ((((TPNT)->mapaddr == (TPNT)->loadaddr) ? (TPNT)->loadaddr : 0) \ + , (SYM)->st_value)) +#endif + +/* Unmap all previously-mapped segments accumulated in LOADADDR. + Generally used when an error occurs during loading. */ +#ifndef DL_LOADADDR_UNMAP +# define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ + _dl_munmap((char *) (LOADADDR), (LEN)) +#endif + +/* Similar to DL_LOADADDR_UNMAP, but used for libraries that have been + dlopen()ed successfully, when they're dlclose()d. */ +#ifndef DL_LIB_UNMAP +# define DL_LIB_UNMAP(LIB, LEN) (DL_LOADADDR_UNMAP ((LIB)->mapaddr, (LEN))) +#endif + +/* Define this to verify that a library named LIBNAME, whose ELF + headers are pointed to by EPNT, is suitable for dynamic linking. + If it is not, print an error message (optional) and return NULL. + If the library can have its segments relocated independently, + arrange for PICLIB to be set to 2. If all segments have to be + relocated by the same amount, set it to 1. If it has to be loaded + at physical addresses as specified in the program headers, set it + to 0. A reasonable (?) guess for PICLIB will already be in place, + so it is safe to do nothing here. */ +#ifndef DL_CHECK_LIB_TYPE +# define DL_CHECK_LIB_TYPE(EPNT, PICLIB, PROGNAME, LIBNAME) (void)0 +#endif + +/* Define this if you have special segment. */ +#ifndef DL_IS_SPECIAL_SEGMENT +# define DL_IS_SPECIAL_SEGMENT(EPNT, PPNT) 0 +#endif + +/* Define this if you want to use special method to map the segment. */ +#ifndef DL_MAP_SEGMENT +# define DL_MAP_SEGMENT(EPNT, PPNT, INFILE, FLAGS) 0 +#endif + +/* Define this to declare the library offset. */ +#ifndef DL_DEF_LIB_OFFSET +# define DL_DEF_LIB_OFFSET static unsigned long _dl_library_offset +#endif + +/* Define this to get the library offset. */ +#ifndef DL_GET_LIB_OFFSET +# define DL_GET_LIB_OFFSET() _dl_library_offset +#endif + +/* Define this to set the library offset as difference beetwen the mapped + library address and the smallest virtual address of the first PT_LOAD + segment. */ +#ifndef DL_SET_LIB_OFFSET +# define DL_SET_LIB_OFFSET(offset) (_dl_library_offset = (offset)) +#endif + +/* Define this to get the real object's runtime address. */ +#ifndef DL_GET_RUN_ADDR +# define DL_GET_RUN_ADDR(loadaddr, mapaddr) (mapaddr) +#endif + +#endif /* _LD_DEFS_H */ diff --git a/uniFuzzer/elfLoader/dl-elf.h b/uniFuzzer/elfLoader/dl-elf.h new file mode 100644 index 0000000..3b17704 --- /dev/null +++ b/uniFuzzer/elfLoader/dl-elf.h @@ -0,0 +1,101 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2000-2005 by Erik Andersen + * + * GNU Lesser General Public License version 2.1 or later. + */ + +#ifndef LINUXELF_H +#define LINUXELF_H + +#include +#include + +#include "common.h" + +/* + * Bitsize related settings for things Elf32() + * does not handle already + */ + +# define ELF_ST_BIND(val) ELF32_ST_BIND(val) +# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +# define ELF_R_SYM(i) ELF32_R_SYM(i) +# define ELF_R_TYPE(i) ELF32_R_TYPE(i) +# ifndef ELF_CLASS +# define ELF_CLASS ELFCLASS32 +# endif + +/* + * Datatype of a relocation on this platform + */ +#ifdef ELF_USES_RELOCA +# define ELF_RELOC Elf32(Rela) +# define DT_RELOC_TABLE_ADDR DT_RELA +# define DT_RELOC_TABLE_SIZE DT_RELASZ +# define DT_RELOCCOUNT DT_RELACOUNT +# define UNSUPPORTED_RELOC_TYPE DT_REL +# define UNSUPPORTED_RELOC_STR "REL" +#else +# define ELF_RELOC Elf32(Rel) +# define DT_RELOC_TABLE_ADDR DT_REL +# define DT_RELOC_TABLE_SIZE DT_RELSZ +# define DT_RELOCCOUNT DT_RELCOUNT +# define UNSUPPORTED_RELOC_TYPE DT_RELA +# define UNSUPPORTED_RELOC_STR "RELA" +#endif + +/* OS and/or GNU dynamic extensions */ + +#define OS_NUM_BASE 1 /* for DT_RELOCCOUNT */ + +# define OS_NUM_GNU_HASH 0 + +# define OS_NUM_PRELINK 0 + +#define OS_NUM (OS_NUM_BASE + OS_NUM_GNU_HASH + OS_NUM_PRELINK) + +#define ARCH_NUM 4 + +#define DYNAMIC_SIZE (DT_NUM + OS_NUM + ARCH_NUM) +/* Keep ARCH specific entries into dynamic section at the end of the array */ +#define DT_RELCONT_IDX (DYNAMIC_SIZE - OS_NUM - ARCH_NUM) + +#define DT_MIPS_GOTSYM_IDX (DT_NUM + OS_NUM) +#define DT_MIPS_LOCAL_GOTNO_IDX (DT_NUM + OS_NUM +1) +#define DT_MIPS_SYMTABNO_IDX (DT_NUM + OS_NUM +2) +#define DT_MIPS_PLTGOT_IDX (DT_NUM + OS_NUM +3) + +unsigned int _dl_parse_dynamic_info(Elf32(Dyn) *dpnt, unsigned long dynamic_info[], + Elf32(Addr) load_off); + + + +/* Reloc type classes as returned by elf_machine_type_class(). + ELF_RTYPE_CLASS_PLT means this reloc should not be satisfied by + some PLT symbol, ELF_RTYPE_CLASS_COPY means this reloc should not be + satisfied by any symbol in the executable. Some architectures do + not support copy relocations. In this case we define the macro to + zero so that the code for handling them gets automatically optimized + out. */ +#ifdef DL_NO_COPY_RELOCS +# define ELF_RTYPE_CLASS_COPY (0x0) +#else +# define ELF_RTYPE_CLASS_COPY (0x2) +#endif +#define ELF_RTYPE_CLASS_PLT (0x1) + +/* dlsym() calls _dl_find_hash with this value, that enables + DL_FIND_HASH_VALUE to return something different than the symbol + itself, e.g., a function descriptor. */ +#define ELF_RTYPE_CLASS_DLSYM 0x80000000 + + +/* Convert between the Linux flags for page protections and the + ones specified in the ELF standard. */ +#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \ + (((X) & PF_W) ? PROT_WRITE : 0) | \ + (((X) & PF_X) ? PROT_EXEC : 0)) + + +#endif /* LINUXELF_H */ diff --git a/uniFuzzer/elfLoader/dl-hash.c b/uniFuzzer/elfLoader/dl-hash.c new file mode 100644 index 0000000..975053b --- /dev/null +++ b/uniFuzzer/elfLoader/dl-hash.c @@ -0,0 +1,204 @@ +#include +#include +#include + +#include "dl-hash.h" +#include "dl-defs.h" + +extern struct elf_resolve *_dl_loaded_modules; + +static __attribute_noinline__ const Elf32(Sym) * +check_match (const Elf32(Sym) *sym, char *strtab, const char* undef_name, int type_class) +{ + + if (type_class & (sym->st_shndx == SHN_UNDEF)) + /* undefined symbol itself */ + return NULL; + + if (sym->st_value == 0) + /* No value */ + return NULL; + + if (ELF_ST_TYPE(sym->st_info) > STT_FUNC + && ELF_ST_TYPE(sym->st_info) != STT_COMMON) + /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC + * and STT_COMMON entries since these are no + * code/data definitions + */ + return NULL; +#ifdef ARCH_SKIP_RELOC + if (ARCH_SKIP_RELOC(type_class, sym)) + return NULL; +#endif + if (strcmp(strtab + sym->st_name, undef_name) != 0) + return NULL; + + /* This is the matching symbol */ + return sym; +} + + +static __inline__ Elf_Symndx _dl_elf_hash(const unsigned char *name) +{ + unsigned long hash=0; + unsigned long tmp; + + while (*name) { + hash = (hash << 4) + *name++; + tmp = hash & 0xf0000000; + /* The algorithm specified in the ELF ABI is as follows: + if (tmp != 0) + hash ^= tmp >> 24; + hash &= ~tmp; + But the following is equivalent and a lot + faster, especially on modern processors. */ + hash ^= tmp; + hash ^= tmp >> 24; + } + return hash; +} + +static __always_inline const Elf32(Sym) * +_dl_lookup_sysv_hash(struct elf_resolve *tpnt, Elf32(Sym) *symtab, unsigned long hash, const char* undef_name, int type_class) +{ + unsigned long hn; + char *strtab; + const Elf32(Sym) *sym; + Elf_Symndx symidx; + + /* Avoid calling .urem here. */ + do_rem(hn, hash, tpnt->nbucket); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]); + + assert(tpnt->elf_buckets != NULL); + + for (symidx = tpnt->elf_buckets[hn]; symidx != STN_UNDEF; symidx = tpnt->chains[symidx]) { + sym = check_match (&symtab[symidx], strtab, undef_name, type_class); + if (sym != NULL) + /* At this point the symbol is that we are looking for */ + return sym; + } + /* No symbol found into the current module*/ + return NULL; +} + +struct elf_resolve *_dl_add_elf_hash_table(const char *libname, + Elf32(Addr) loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr, + attribute_unused unsigned long dynamic_size) +{ + Elf_Symndx *hash_addr; + struct elf_resolve *tpnt; + int i; + + tpnt = malloc(sizeof(struct elf_resolve)); + memset(tpnt, 0, sizeof(struct elf_resolve)); + + if (!_dl_loaded_modules) + _dl_loaded_modules = tpnt; + else { + struct elf_resolve *t = _dl_loaded_modules; + while (t->next) + t = t->next; + t->next = tpnt; + t->next->prev = t; + tpnt = t->next; + } + + tpnt->next = NULL; + tpnt->init_flag = 0; + tpnt->libname = strdup(libname); + tpnt->dynamic_addr = (Elf32(Dyn) *)dynamic_addr; + tpnt->libtype = loaded_file; + + if (dynamic_info[DT_HASH] != 0) { + hash_addr = (Elf_Symndx*)(dynamic_info[DT_HASH]); + tpnt->nbucket = *hash_addr++; + tpnt->nchain = *hash_addr++; + tpnt->elf_buckets = hash_addr; + hash_addr += tpnt->nbucket; + tpnt->chains = hash_addr; + } + tpnt->loadaddr = loadaddr; + for (i = 0; i < DYNAMIC_SIZE; i++) + tpnt->dynamic_info[i] = dynamic_info[i]; + return tpnt; +} + +char *_dl_find_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt, + int type_class, struct symbol_ref *sym_ref) +{ + uf_debug("finding symbol %s\n", name); + struct elf_resolve *tpnt = NULL; + Elf32(Sym) *symtab; + int i = 0; + + unsigned long elf_hash_number = 0xffffffff; + const Elf32(Sym) *sym = NULL; + + char *weak_result = NULL; + struct r_scope_elem *loop_scope; + + if ((sym_ref) && (sym_ref->sym) && (ELF32_ST_VISIBILITY(sym_ref->sym->st_other) == STV_PROTECTED)) { + sym = sym_ref->sym; + if (mytpnt) + tpnt = mytpnt; + } else + for (loop_scope = scope; loop_scope && !sym; loop_scope = loop_scope->next) { + for (i = 0; i < loop_scope->r_nlist; i++) { + tpnt = loop_scope->r_list[i]; + + if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) { + if (mytpnt == tpnt) + ; + else { + struct init_fini_list *tmp; + + for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) { + if (tmp->tpnt == tpnt) + break; + } + if (!tmp) + continue; + } + } + /* Don't search the executable when resolving a copy reloc. */ + if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable) + continue; + + /* If the hash table is empty there is nothing to do here. */ + if (tpnt->nbucket == 0) + continue; + + symtab = (Elf32(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]); + + /* Use the old SysV-style hash table */ + + /* Calculate the old sysv hash number only once */ + if (elf_hash_number == 0xffffffff) + elf_hash_number = _dl_elf_hash((const unsigned char *)name); + + sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class); + if (sym != NULL) + /* If sym has been found, do not search further */ + break; + } /* End of inner for */ + } + uf_debug("sym is %p\n", sym); + + if (sym) { + if (sym_ref) { + sym_ref->sym = sym; + sym_ref->tpnt = tpnt; + } + /* At this point we have found the requested symbol, do binding */ + + switch (ELF_ST_BIND(sym->st_info)) { + case STB_WEAK: + case STB_GLOBAL: + return (char *)DL_FIND_HASH_VALUE(tpnt, type_class, sym); + default: /* Local symbols not handled here */ + break; + } + } + return weak_result; +} diff --git a/uniFuzzer/elfLoader/dl-hash.h b/uniFuzzer/elfLoader/dl-hash.h new file mode 100644 index 0000000..4933bee --- /dev/null +++ b/uniFuzzer/elfLoader/dl-hash.h @@ -0,0 +1,122 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2000-2006 by Erik Andersen + * + * GNU Lesser General Public License version 2.1 or later. + */ + +#ifndef _LD_HASH_H_ +#define _LD_HASH_H_ + +#include "common.h" +#include "dl-elf.h" + +#ifndef RTLD_NEXT +#define RTLD_NEXT ((void*)-1) +#endif + +struct init_fini_list { + struct init_fini_list *next; + struct elf_resolve *tpnt; +}; + +struct init_fini { + struct elf_resolve **init_fini; + unsigned long nlist; /* Number of entries in init_fini */ +}; + +struct dyn_elf { + struct elf_resolve * dyn; + struct dyn_elf * next_handle; /* Used by dlopen et al. */ + struct init_fini init_fini; + struct dyn_elf * next; + struct dyn_elf * prev; +}; + +struct symbol_ref { + const Elf32(Sym) *sym; + struct elf_resolve *tpnt; +}; + +/* Structure to describe a single list of scope elements. The lookup + functions get passed an array of pointers to such structures. */ +struct r_scope_elem { + struct elf_resolve **r_list; /* Array of maps for the scope. */ + unsigned int r_nlist; /* Number of entries in the scope. */ + struct r_scope_elem *next; +}; + +struct elf_resolve { + /* These entries must be in this order to be compatible with the interface used + by gdb to obtain the list of symbols. */ + Elf32(Addr) loadaddr; /* Base address shared object is loaded at. */ + char *libname; /* Absolute file name object was found in. */ + Elf32(Dyn) *dynamic_addr; /* Dynamic section of the shared object. */ + struct elf_resolve * next; + struct elf_resolve * prev; + /* Nothing after this address is used by gdb. */ + + Elf32(Addr) mapaddr; + + /* Store the entry point from the ELF header (e_entry) */ + Elf32(Addr) l_entry; + + enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype; + /* This is the local scope of the shared object */ + struct r_scope_elem symbol_scope; + unsigned short usage_count; + unsigned short int init_flag; + unsigned long rtld_flags; /* RTLD_GLOBAL, RTLD_NOW etc. */ + Elf_Symndx nbucket; + + Elf_Symndx *elf_buckets; + + struct init_fini_list *init_fini; + struct init_fini_list *rtld_local; /* keep tack of RTLD_LOCAL libs in same group */ + /* + * These are only used with ELF style shared libraries + */ + Elf_Symndx nchain; + + Elf_Symndx *chains; + unsigned long dynamic_info[DYNAMIC_SIZE]; + + unsigned long n_phent; + Elf32(Phdr) * ppnt; + + Elf32(Addr) relro_addr; + size_t relro_size; + + dev_t st_dev; /* device */ + ino_t st_ino; /* inode */ + +}; + +#define RELOCS_DONE 0x000001 +#define JMP_RELOCS_DONE 0x000002 +#define INIT_FUNCS_CALLED 0x000004 +#define FINI_FUNCS_CALLED 0x000008 +#define DL_OPENED 0x000010 +#define DL_RESERVED 0x000020 + +struct elf_resolve * _dl_add_elf_hash_table(const char * libname, + Elf32(Addr) loadaddr, unsigned long * dynamic_info, + unsigned long dynamic_addr, unsigned long dynamic_size); + +char *_dl_find_hash(const char *name, struct r_scope_elem *scope, + struct elf_resolve *mytpnt, int type_class, + struct symbol_ref *symbol); + +#define LD_ERROR_NOFILE 1 +#define LD_ERROR_NOZERO 2 +#define LD_ERROR_NOTELF 3 +#define LD_ERROR_NOTMAGIC 4 +#define LD_ERROR_NOTDYN 5 +#define LD_ERROR_MMAP_FAILED 6 +#define LD_ERROR_NODYNAMIC 7 +#define LD_ERROR_TLS_FAILED 8 +#define LD_WRONG_RELOCS 9 +#define LD_BAD_HANDLE 10 +#define LD_NO_SYMBOL 11 + +#endif /* _LD_HASH_H_ */ diff --git a/uniFuzzer/elfLoader/dl-string.h b/uniFuzzer/elfLoader/dl-string.h new file mode 100644 index 0000000..790f9da --- /dev/null +++ b/uniFuzzer/elfLoader/dl-string.h @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2000-2005 by Erik Andersen + * + * GNU Lesser General Public License version 2.1 or later. + */ + +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include +#include +#include + + +static char *_dl_get_last_path_component(char *path); + +static __always_inline char * _dl_get_last_path_component(char *path) +{ + register char *ptr = path-1; + + while (*++ptr) + ;/* empty */ + + /* strip trailing slashes */ + while (ptr != path && *--ptr == '/') { + *ptr = '\0'; + } + + /* find last component */ + while (ptr != path && *--ptr != '/') + ;/* empty */ + return ptr == path ? ptr : ptr+1; +} + +#endif diff --git a/uniFuzzer/elfLoader/elfLoader.c b/uniFuzzer/elfLoader/elfLoader.c new file mode 100644 index 0000000..dd43076 --- /dev/null +++ b/uniFuzzer/elfLoader/elfLoader.c @@ -0,0 +1,848 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define _dl_mmap_check_error(X) (((void *)X) == MAP_FAILED) + +#define UCFLAGS(X) ((((X) & PF_R) ? UC_PROT_READ : 0) | \ + (((X) & PF_W) ? UC_PROT_WRITE : 0) | \ + (((X) & PF_X) ? UC_PROT_EXEC : 0)) + +#include "dl-elf.h" +#include "dl-hash.h" +#include "dl-defs.h" +#include "dl-string.h" + +#include "mips.h" +#include "arm.h" + +static struct elf_resolve * _dl_load_elf_shared_library(struct dyn_elf **rpnt, + const char *libname); +static struct elf_resolve *_dl_load_shared_library(struct dyn_elf **rpnt, + struct elf_resolve *tpnt, char *full_libname, char *lib_path); +extern void onLibLoad(const char *libName, void *baseAddr, void *ucBaseAddr); + +DL_DEF_LIB_OFFSET; + +uc_engine *uc = NULL; + +struct elf_resolve *_dl_loaded_modules = NULL; +static struct dyn_elf *_dl_symbol_tables = NULL; +static struct elf_resolve **scope_elem_list = NULL; + +/* Used to return error codes back to dlopen et. al. */ +static unsigned long _dl_error_number; +static unsigned long _dl_internal_error_number; + +static int e_machine = EM_NONE; + + +static struct elf_resolve * +search_for_named_library(const char *name, const char *path_list, + struct dyn_elf **rpnt) +{ + char *path, *path_n, *mylibname; + struct elf_resolve *tpnt; + int done; + + if (path_list==NULL) + return NULL; + + /* We need a writable copy of this string, but we don't + * need this allocated permanently since we don't want + * to leak memory, so use alloca to put path on the stack */ + done = strlen(path_list); + path = alloca(done + 1); + + /* another bit of local storage */ + mylibname = alloca(2050); + + memcpy(path, path_list, done+1); + + /* Unlike ldd.c, don't bother to eliminate double //s */ + + /* Replace colons with zeros in path_list */ + /* : at the beginning or end of path maps to CWD */ + /* :: anywhere maps CWD */ + /* "" maps to CWD */ + done = 0; + path_n = path; + do { + if (*path == 0) { + *path = ':'; + done = 1; + } + if (*path == ':') { + *path = 0; + if (*path_n) + strcpy(mylibname, path_n); + else + strcpy(mylibname, "."); /* Assume current dir if empty path */ + strcat(mylibname, "/"); + strcat(mylibname, name); + if ((tpnt = _dl_load_elf_shared_library(rpnt, mylibname)) != NULL) + return tpnt; + path_n = path+1; + } + path++; + } while (!done); + return NULL; +} + + +static void * +map_writeable (int infile, Elf32(Phdr) *ppnt, int piclib, int flags, + unsigned long libaddr) +{ + int prot_flags = ppnt->p_flags | PF_W; + char *status, *retval; + char *tryaddr; + ssize_t size; + unsigned long map_size; + char *cpnt; + uc_err err; + + tryaddr = ((char *) (piclib ? libaddr : DL_GET_LIB_OFFSET()) + + (ppnt->p_vaddr & PAGE_ALIGN)); + + size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz; + + /* For !MMU, mmap to fixed address will fail. + So instead of desperately call mmap and fail, + we set status to MAP_FAILED to save a call + to mmap (). */ + status = (char *) mmap + (tryaddr, size, LXFLAGS(prot_flags), + flags, infile, ppnt->p_offset & OFFS_ALIGN); + + if((err = uc_mem_map_ptr(uc, + tryaddr - (piclib ? 0 : DL_GET_LIB_OFFSET()), + (size+ADDR_ALIGN) & PAGE_ALIGN, + UCFLAGS(prot_flags), + status)) + != UC_ERR_OK) { + fprintf(stderr, "uc_mem_map_ptr failed: %d\n", err); + return 0; + } + uf_debug("uc mem map %p size 0x%x at %p with prop %d\n", + tryaddr - (piclib ? 0 : DL_GET_LIB_OFFSET()), + (size+ADDR_ALIGN) & PAGE_ALIGN, status, prot_flags); + + if (_dl_mmap_check_error(status) || (tryaddr && tryaddr != status)) + return 0; + + retval = status; + + /* Now we want to allocate and zero-out any data from the end + of the region we mapped in from the file (filesz) to the + end of the loadable segment (memsz). We may need + additional pages for memsz, that we map in below, and we + can count on the kernel to zero them out, but we have to + zero out stuff in the last page that we mapped in from the + file. However, we can't assume to have actually obtained + full pages from the kernel, since we didn't ask for them, + and uClibc may not give us full pages for small + allocations. So only zero out up to memsz or the end of + the page, whichever comes first. */ + + /* CPNT is the beginning of the memsz portion not backed by + filesz. */ + cpnt = (char *) (status + size); + + /* MAP_SIZE is the address of the + beginning of the next page. */ + map_size = (ppnt->p_vaddr + ppnt->p_filesz + + ADDR_ALIGN) & PAGE_ALIGN; + + memset (cpnt, 0, + MIN (map_size + - (ppnt->p_vaddr + + ppnt->p_filesz), + ppnt->p_memsz + - ppnt->p_filesz)); + + if (map_size < ppnt->p_vaddr + ppnt->p_memsz) { + tryaddr = map_size + (char*)(piclib ? libaddr : DL_GET_LIB_OFFSET()); + size = ppnt->p_vaddr + ppnt->p_memsz - map_size; + status = (char *) mmap(tryaddr, size, + LXFLAGS(prot_flags), + flags | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(status) || tryaddr != status) + return NULL; + + if((err = uc_mem_map_ptr(uc, + map_size + (char*)(piclib ? libaddr : 0), + (size+ADDR_ALIGN) & PAGE_ALIGN, + UCFLAGS(prot_flags), + status)) + != UC_ERR_OK) { + fprintf(stderr, "uc_mem_map_ptr failed: %d\n", err); + return NULL; + } + uf_debug("uc mem map %p size 0x%x at %p with prop %d\n", + map_size + (char*)(piclib ? libaddr : 0), + (size+ADDR_ALIGN) & PAGE_ALIGN, status, prot_flags); +} + return retval; +} + +unsigned int _dl_parse_dynamic_info(Elf32(Dyn) *dpnt, unsigned long dynamic_info[], + DL_LOADADDR_TYPE load_off) +{ + unsigned int rtld_flags = 0; + + for (; dpnt->d_tag; dpnt++) { + if (dpnt->d_tag < DT_NUM) { + dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; + if (dpnt->d_tag == DT_TEXTREL) + dynamic_info[DT_TEXTREL] = 1; + } else if (dpnt->d_tag < DT_LOPROC) { + if (dpnt->d_tag == DT_RELOCCOUNT) + dynamic_info[DT_RELCONT_IDX] = dpnt->d_un.d_val; + } + else if(e_machine == EM_MIPS) { + switch(dpnt->d_tag) { + case DT_MIPS_GOTSYM: + dynamic_info[DT_MIPS_GOTSYM_IDX] = dpnt->d_un.d_val; + break; + case DT_MIPS_LOCAL_GOTNO: + dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX] = dpnt->d_un.d_val; + break; + case DT_MIPS_SYMTABNO: + dynamic_info[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; + break; + case DT_MIPS_PLTGOT: + dynamic_info[DT_MIPS_PLTGOT_IDX] = dpnt->d_un.d_val; + break; + default: + break; + } + } + } + +#define ADJUST_DYN_INFO(tag, load_off) \ + do { \ + if (dynamic_info[tag]) \ + dynamic_info[tag] = (unsigned long) DL_RELOC_ADDR(load_off, dynamic_info[tag]); \ + } while (0) + /* Don't adjust .dynamic unnecessarily. For FDPIC targets, + we'd have to walk all the loadsegs to find out if it was + actually unnecessary, so skip this optimization. */ + if (load_off != 0) + { + ADJUST_DYN_INFO(DT_HASH, load_off); + ADJUST_DYN_INFO(DT_PLTGOT, load_off); + ADJUST_DYN_INFO(DT_STRTAB, load_off); + ADJUST_DYN_INFO(DT_SYMTAB, load_off); + ADJUST_DYN_INFO(DT_RELOC_TABLE_ADDR, load_off); + ADJUST_DYN_INFO(DT_JMPREL, load_off); + } + + return rtld_flags; +} + + + +static struct elf_resolve *_dl_load_elf_shared_library(struct dyn_elf **rpnt, const char *libname) +{ + Elf32(Ehdr) *epnt; + unsigned long dynamic_addr = 0; + Elf32(Dyn) *dpnt; + struct elf_resolve *tpnt; + Elf32(Phdr) *ppnt; + char *status, *header; + unsigned long dynamic_info[DYNAMIC_SIZE]; + Elf32(Addr) *lpnt; + unsigned long libaddr; + unsigned long minvma = 0xffffffff, maxvma = 0; + unsigned int rtld_flags; + int i, flags, piclib, infile; + Elf32(Addr) relro_addr = 0; + size_t relro_size = 0; + struct stat st; + unsigned char *ident; + DL_LOADADDR_TYPE lib_loadaddr; + DL_INIT_LOADADDR_EXTRA_DECLS + + libaddr = 0; + infile = open(libname, O_RDONLY, 0); + if (infile < 0) { + _dl_internal_error_number = LD_ERROR_NOFILE; + return NULL; + } + + if (fstat(infile, &st) < 0) { + _dl_internal_error_number = LD_ERROR_NOFILE; + close(infile); + return NULL; + } + + /* Check if file is already loaded */ + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (tpnt->st_dev == st.st_dev && tpnt->st_ino == st.st_ino) { + /* Already loaded */ + tpnt->usage_count++; + close(infile); + return tpnt; + } + } + + header = mmap((void *) 0, _dl_pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(header)) { + fprintf(stderr, "can't map '%s'\n", libname); + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; + close(infile); + return NULL; + } + + read(infile, header, _dl_pagesize); + epnt = (Elf32(Ehdr) *) header; + ident = epnt->e_ident; + if (memcmp(ident, ELFMAG, 4)) { + fprintf(stderr, "'%s' is not an ELF file\n", libname); + _dl_internal_error_number = LD_ERROR_NOTELF; + close(infile); + munmap(header, _dl_pagesize); + return NULL; + } + + if(ident[EI_CLASS] != ELFCLASS32) { + fprintf(stderr, "unsupported elf class: %d\n", ident[EI_CLASS]); + return NULL; + } + + if(e_machine == EM_NONE) + e_machine = epnt->e_machine; + else if(e_machine != epnt->e_machine) { + fprintf(stderr, "inconsistent machines: %d and %d\n", e_machine, epnt->e_machine); + return NULL; + } + + uc_mode mode = (ident[EI_DATA] == ELFDATA2LSB) ? + UC_MODE_LITTLE_ENDIAN : + UC_MODE_BIG_ENDIAN; + + if(uc == NULL) { + switch(e_machine) { + case EM_MIPS: + uc_open(UC_ARCH_MIPS, mode | UC_MODE_MIPS32, &uc); + break; + case EM_ARM: + uc_open(UC_ARCH_ARM, mode | UC_MODE_ARM, &uc); + break; + case EM_386: + uc_open(UC_ARCH_X86, mode | UC_MODE_32, &uc); + break; + default: + fprintf(stderr, "unsupported machine: %d\n", e_machine); + return NULL; + } + } + + if (epnt->e_type != ET_DYN && epnt->e_type != ET_EXEC) { + fprintf(stderr, "unsupported type: %d\n", epnt->e_type); + close(infile); + munmap(header, _dl_pagesize); + return NULL; + } + + ppnt = (Elf32(Phdr) *) & header[epnt->e_phoff]; + + piclib = 1; + for (i = 0; i < epnt->e_phnum; i++) { + + if (ppnt->p_type == PT_DYNAMIC) { + if (dynamic_addr) + fprintf(stderr, "'%s' has more than one dynamic section\n", libname); + dynamic_addr = ppnt->p_vaddr; + } + + if (ppnt->p_type == PT_LOAD) { + /* See if this is a PIC library. */ + if (minvma == 0xffffffff && ppnt->p_vaddr > 0x1000000) { + piclib = 0; + minvma = ppnt->p_vaddr; + } + if (piclib && ppnt->p_vaddr < minvma) { + minvma = ppnt->p_vaddr; + } + if (((unsigned long) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { + maxvma = ppnt->p_vaddr + ppnt->p_memsz; + } + } + if (ppnt->p_type == PT_TLS) { + fprintf(stderr, "'%s' library contains unsupported TLS\n", libname); + } + ppnt++; + } + + if (epnt->e_type == ET_EXEC) + piclib = 0; + + maxvma = (maxvma + ADDR_ALIGN) & PAGE_ALIGN; + minvma = minvma & ~ADDR_ALIGN; + + flags = MAP_32BIT|MAP_PRIVATE /*| MAP_DENYWRITE */ ; + + status = (char *) mmap((char *) (piclib ? 0 : minvma), + maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(status)) { + cant_map: + fprintf(stderr, "can't map '%s'\n", libname); + _dl_internal_error_number = LD_ERROR_MMAP_FAILED; + close(infile); + munmap(header, _dl_pagesize); + return NULL; + } + libaddr = (unsigned long) status; + flags |= MAP_FIXED; + + /* Get the memory to store the library */ + ppnt = (Elf32(Phdr) *) & header[epnt->e_phoff]; + + DL_INIT_LOADADDR(lib_loadaddr, libaddr - minvma, ppnt, epnt->e_phnum); + + /* Set _dl_library_offset to lib_loadaddr or 0. */ + DL_SET_LIB_OFFSET(lib_loadaddr); + + for (i = 0; i < epnt->e_phnum; i++) { + if (ppnt->p_type == PT_GNU_RELRO) { + relro_addr = ppnt->p_vaddr; + relro_size = ppnt->p_memsz; + } + if (ppnt->p_type == PT_LOAD) { + char *tryaddr; + ssize_t size; + + if (ppnt->p_flags & PF_W) { + status = map_writeable (infile, ppnt, piclib, flags, libaddr); + if (status == NULL) + goto cant_map; + } else { + tryaddr = (char *) (ppnt->p_vaddr & PAGE_ALIGN) + + (piclib ? libaddr : DL_GET_LIB_OFFSET()); + size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz; + status = (char *) mmap + (tryaddr, size, LXFLAGS(ppnt->p_flags), + flags, infile, ppnt->p_offset & OFFS_ALIGN); + if (_dl_mmap_check_error(status) + || (tryaddr && tryaddr != status)) + goto cant_map; + uc_err err; + //printf("tryaddr: %p, piclib: %d, offset: %x, size: %x, real addr %p\n", tryaddr, piclib, DL_GET_LIB_OFFSET(), size, status); + if((err = uc_mem_map_ptr(uc, + tryaddr - (piclib ? 0 : DL_GET_LIB_OFFSET()), + (size+ADDR_ALIGN) & PAGE_ALIGN, + UCFLAGS(ppnt->p_flags), + status)) + != UC_ERR_OK) { + fprintf(stderr, "uc_mem_map_ptr failed: %d\n", err); + goto cant_map; + } + uf_debug("uc mem map %p size 0x%x at %p with prop %d\n", + tryaddr - (piclib ? 0 : DL_GET_LIB_OFFSET()), + (size+ADDR_ALIGN) & PAGE_ALIGN, status, ppnt->p_flags); + } + } + ppnt++; + } + + /* + * The dynamic_addr must be take into acount lib_loadaddr value, to note + * it is zero when the SO has been mapped to the elf's physical addr + */ + dynamic_addr = (unsigned long) DL_RELOC_ADDR(lib_loadaddr, dynamic_addr); + + /* + * OK, the ELF library is now loaded into VM in the correct locations + * The next step is to go through and do the dynamic linking (if needed). + */ + + /* Start by scanning the dynamic section to get all of the pointers */ + + if (!dynamic_addr) { + _dl_internal_error_number = LD_ERROR_NODYNAMIC; + fprintf(stderr, "'%s' is missing a dynamic section\n", libname); + munmap(header, _dl_pagesize); + close(infile); + return NULL; + } + + dpnt = (Elf32(Dyn) *) dynamic_addr; + memset(dynamic_info, 0, sizeof(dynamic_info)); + + rtld_flags = _dl_parse_dynamic_info(dpnt, dynamic_info, lib_loadaddr); + + /* If the TEXTREL is set, this means that we need to make the pages + writable before we perform relocations. Do this now. They get set + back again later. */ + + if (dynamic_info[DT_TEXTREL]) { + ppnt = (Elf32(Phdr) *)(intptr_t) & header[epnt->e_phoff]; + for (i = 0; i < epnt->e_phnum; i++, ppnt++) { + if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) { + mprotect((void *) ((piclib ? libaddr : DL_GET_LIB_OFFSET()) + + (ppnt->p_vaddr & PAGE_ALIGN)), + (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz, + PROT_READ | PROT_WRITE | PROT_EXEC); + } + } + } + + close(infile); + + tpnt = _dl_add_elf_hash_table(libname, lib_loadaddr, dynamic_info, + dynamic_addr, 0); + tpnt->mapaddr = libaddr; + tpnt->relro_addr = relro_addr; + tpnt->relro_size = relro_size; + tpnt->st_dev = st.st_dev; + tpnt->st_ino = st.st_ino; + tpnt->ppnt = (Elf32(Phdr) *) + DL_RELOC_ADDR(DL_GET_RUN_ADDR(tpnt->loadaddr, tpnt->mapaddr), + epnt->e_phoff); + tpnt->n_phent = epnt->e_phnum; + tpnt->rtld_flags |= rtld_flags; + tpnt->l_entry = epnt->e_entry; + + + /* + * Add this object into the symbol chain + */ + if (*rpnt + /* Do not create a new chain entry for the main executable */ + && (*rpnt)->dyn + ) { + (*rpnt)->next = malloc(sizeof(struct dyn_elf)); + memset((*rpnt)->next, 0, sizeof(struct dyn_elf)); + (*rpnt)->next->prev = (*rpnt); + *rpnt = (*rpnt)->next; + } + /* When statically linked, the first time we dlopen a DSO + * the *rpnt is NULL, so we need to allocate memory for it, + * and initialize the _dl_symbol_table. + */ + else if(*rpnt == NULL) { + *rpnt = _dl_symbol_tables = malloc(sizeof(struct dyn_elf)); + memset(*rpnt, 0, sizeof(struct dyn_elf)); + } + (*rpnt)->dyn = tpnt; + tpnt->usage_count++; + tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable; + + /* + * OK, the next thing we need to do is to insert the dynamic linker into + * the proper entry in the GOT so that the PLT symbols can be properly + * resolved. + */ + + lpnt = (Elf32(Addr) *) dynamic_info[DT_PLTGOT]; + + if (lpnt && piclib && e_machine == EM_MIPS) { + init_got_mips(lpnt, tpnt); + } + + onLibLoad(libname, tpnt->mapaddr, tpnt->mapaddr - (piclib ? 0 : lib_loadaddr)); + munmap(header, _dl_pagesize); + + return tpnt; +} + +static struct elf_resolve *_dl_load_shared_library(struct dyn_elf **rpnt, + struct elf_resolve *tpnt, char *full_libname, char *lib_path) +{ + char *pnt; + struct elf_resolve *tpnt1; + char *libname; + + _dl_internal_error_number = 0; + libname = full_libname; + + /* quick hack to ensure mylibname buffer doesn't overflow. don't + allow full_libname or any directory to be longer than 1024. */ + if (strlen(full_libname) > 1024) + goto goof; + + /* Skip over any initial initial './' and '/' stuff to + * get the short form libname with no path garbage */ + pnt = strrchr(libname, '/'); + if (pnt) { + libname = pnt + 1; + } + + /* If the filename has any '/', try it straight and leave it at that. + For IBCS2 compatibility under linux, we substitute the string + /usr/i486-sysv4/lib for /usr/lib in library names. */ + + if (libname != full_libname) { + tpnt1 = _dl_load_elf_shared_library(rpnt, full_libname); + if (tpnt1) { + return tpnt1; + } + } + + /* Lastly, search the standard list of paths for the library. + This list must exactly match the list in uClibc/ldso/util/ldd.c */ + tpnt1 = search_for_named_library(libname, lib_path, rpnt); + if (tpnt1 != NULL) + return tpnt1; + +goof: + /* Well, we shot our wad on that one. All we can do now is punt */ + if (_dl_internal_error_number) + _dl_error_number = _dl_internal_error_number; + else + _dl_error_number = LD_ERROR_NOFILE; + fprintf(stderr, "Bummer: could not find '%s'!\n", libname); + return NULL; +} + +static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list, + struct elf_resolve *map) +{ + struct elf_resolve **p = list; + struct init_fini_list *q; + + *p++ = map; + map->init_flag |= DL_RESERVED; + if (map->init_fini) + for (q = map->init_fini; q; q = q->next) + if (! (q->tpnt->init_flag & DL_RESERVED)) + p += _dl_build_local_scope (p, q->tpnt); + return p - list; +} + + +/* Relocate the global GOT entries for the object */ + +static int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) { + int res = 1; + switch(e_machine) { + case EM_MIPS: + res = _dl_parse_relocation_information_mips(rpnt, scope, rel_addr, rel_size); + break; + case EM_ARM: + res = _dl_parse_relocation_information_arm(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc_arm); + break; + case EM_386: + res = _dl_parse_relocation_information_i386(rpnt->dyn, scope, rel_addr, rel_size);//, _dl_do_reloc_i386); + break; + default: + fprintf(stderr, "unsupported arch for _dl_parse_relocation_information: %d\n", e_machine); + break; + } + return res; +} + +static int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, attribute_unused int now_flag) +{ + int goof = 0; + struct elf_resolve *tpnt; + Elf32(Word) reloc_size, relative_count; + Elf32(Addr) reloc_addr; + + if (rpnt->next) + goof = _dl_fixup(rpnt->next, scope, now_flag); + tpnt = rpnt->dyn; + + if (unlikely(tpnt->dynamic_info[UNSUPPORTED_RELOC_TYPE])) { + fprintf(stderr, "%s: can't handle %s relocation records\n", + tpnt->libname, UNSUPPORTED_RELOC_STR); + goof++; + } + + reloc_size = tpnt->dynamic_info[DT_RELOC_TABLE_SIZE]; +/* On some machines, notably SPARC & PPC, DT_REL* includes DT_JMPREL in its + range. Note that according to the ELF spec, this is completely legal! */ +#ifdef ELF_MACHINE_PLTREL_OVERLAP + reloc_size -= tpnt->dynamic_info [DT_PLTRELSZ]; +#endif + + if (tpnt->dynamic_info[DT_RELOC_TABLE_ADDR] && + !(tpnt->init_flag & RELOCS_DONE)) { + reloc_addr = tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]; + relative_count = tpnt->dynamic_info[DT_RELCONT_IDX]; + if (relative_count) { /* Optimize the XX_RELATIVE relocations if possible */ + reloc_size -= relative_count * sizeof(ELF_RELOC); + reloc_addr += relative_count * sizeof(ELF_RELOC); + } + goof += _dl_parse_relocation_information(rpnt, scope, + reloc_addr, + reloc_size); + tpnt->init_flag |= RELOCS_DONE; + } + + if (tpnt->dynamic_info[DT_JMPREL] && + (!(tpnt->init_flag & JMP_RELOCS_DONE))) { + goof += _dl_parse_relocation_information(rpnt, scope, + tpnt->dynamic_info[DT_JMPREL], + tpnt->dynamic_info[DT_PLTRELSZ]); + tpnt->init_flag |= JMP_RELOCS_DONE; + } + + return goof; +} + +uc_engine *loadELF(const char *target, char *preload, char *libPath) { + if(target == NULL || libPath == NULL) { + return NULL; + } + unsigned int nlist; + int unlazy = RTLD_NOW; + + struct dyn_elf *rpnt = NULL; + _dl_symbol_tables = rpnt = calloc(sizeof(struct dyn_elf), 1); + + struct elf_resolve *tcurr; + char *lpntstr; + struct elf_resolve *tpnt1; + unsigned int i, cnt, nscope_elem; + struct r_scope_elem *global_scope; + struct elf_resolve **local_scope; + + struct elf_resolve app_tpnt_tmp; + struct elf_resolve *app_tpnt = &app_tpnt_tmp; + memset(app_tpnt, 0, sizeof(*app_tpnt)); + + app_tpnt = _dl_load_elf_shared_library(&rpnt, target); + + if(app_tpnt == NULL) { + fprintf(stderr, "failed to load target ELF %s: %ld\n", target, _dl_internal_error_number); + return NULL; + } + + app_tpnt->rtld_flags = RTLD_NOW | RTLD_GLOBAL; + + if (preload) { + char c, *str, *str2; + + str = preload; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + + while (*str) { + str2 = str; + while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t') + str2++; + c = *str2; + *str2 = '\0'; + + tpnt1 = _dl_load_shared_library(&rpnt, NULL, str, "./"); + if (!tpnt1) { + fprintf(stderr, "can't preload library %s\n", str); + return NULL; + } else { + tpnt1->rtld_flags = RTLD_NOW | RTLD_GLOBAL; + } + + *str2 = c; + str = str2; + while (*str == ':' || *str == ' ' || *str == '\t') + str++; + } + } + + nlist = 0; + for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) { + Elf32(Dyn) *this_dpnt; + + nlist++; + for (this_dpnt = (Elf32(Dyn) *) tcurr->dynamic_addr; this_dpnt->d_tag; this_dpnt++) { + if (this_dpnt->d_tag == DT_NEEDED) { + char *name; + //struct init_fini_list *tmp; + + lpntstr = (char*) (tcurr->dynamic_info[DT_STRTAB] + this_dpnt->d_un.d_val); + name = _dl_get_last_path_component(lpntstr); + + if (strncmp(name, "ld", 2) == 0) { + continue; + } else { + tpnt1 = _dl_load_shared_library(&rpnt, tcurr, lpntstr, libPath); + } + + if (!tpnt1) { + fprintf(stderr, "can't load needed library '%s'\n", lpntstr); + continue; + } + +#if 0 + tmp = alloca(sizeof(struct init_fini_list)); /* Allocates on stack, no need to free this memory */ + tmp->tpnt = tpnt1; + tmp->next = tcurr->init_fini; + tcurr->init_fini = tmp; +#endif + + tpnt1->rtld_flags = RTLD_NOW | RTLD_GLOBAL; + + } + } + } + + nscope_elem = nlist; + + if (_dl_loaded_modules->libtype == elf_executable) { + --nlist; /* Exclude the application. */ + tcurr = _dl_loaded_modules->next; + } else + tcurr = _dl_loaded_modules; + + scope_elem_list = (struct elf_resolve **) malloc(nscope_elem * sizeof(struct elf_resolve *)); + + for (i = 0, tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) + scope_elem_list[i++] = tcurr; + + _dl_loaded_modules->symbol_scope.r_list = scope_elem_list; + _dl_loaded_modules->symbol_scope.r_nlist = nscope_elem; + + global_scope = &_dl_loaded_modules->symbol_scope; + + /* Build the local scope for each loaded modules. */ + local_scope = malloc(nscope_elem * sizeof(struct elf_resolve *)); + i = 1; + for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) { + unsigned int k; + cnt = _dl_build_local_scope(local_scope, scope_elem_list[i++]); + tcurr->symbol_scope.r_list = malloc(cnt * sizeof(struct elf_resolve *)); + tcurr->symbol_scope.r_nlist = cnt; + memcpy (tcurr->symbol_scope.r_list, local_scope, cnt * sizeof (struct elf_resolve *)); + /* Restoring the init_flag.*/ + for (k = 1; k < nscope_elem; k++) + scope_elem_list[k]->init_flag &= ~DL_RESERVED; + } + + free(local_scope); + + if(e_machine == EM_MIPS) { + _dl_perform_mips_global_got_relocations(_dl_loaded_modules); + } + + if (_dl_symbol_tables) { + if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy)) { + fprintf(stderr, "_dl_fixup error\n"); + } + } + + //TODO +#if 0 + for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { + if (tpnt->relro_size) + _dl_protect_relro (tpnt); + } +#endif + + return uc; +} + diff --git a/uniFuzzer/elfLoader/elfLoader.h b/uniFuzzer/elfLoader/elfLoader.h new file mode 100644 index 0000000..bead0e6 --- /dev/null +++ b/uniFuzzer/elfLoader/elfLoader.h @@ -0,0 +1,12 @@ +#ifndef ELFLOADER_H +#define ELFLOADER_H + +uc_engine *loadELF(const char *target, char *preload, char *libPath); + +/* +uc_engine *createUE(Elf *elf, int is32bits); +int checkBits(Elf *elf); +setupMem(Elf *elf, uc_engine *uc, int is32bits, uint64_t baseAddr, int fd); +*/ + +#endif diff --git a/uniFuzzer/elfLoader/i386.c b/uniFuzzer/elfLoader/i386.c new file mode 100644 index 0000000..22d2eef --- /dev/null +++ b/uniFuzzer/elfLoader/i386.c @@ -0,0 +1,154 @@ +#include + +#include "i386.h" + +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to + define the value. + ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one + of the main executable's symbols, as for a COPY reloc. */ +#define elf_machine_type_class(type) \ + ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \ + || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \ + || (type) == R_386_TLS_TPOFF) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY)) + + +static int +reloc_fnc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; + struct elf_resolve *tls_tpnt = NULL; + unsigned long *reloc_addr; + unsigned long symbol_addr; +#if defined (UF_DEBUG) + unsigned long old_val; +#endif + struct symbol_ref sym_ref; + + reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); + symbol_addr = 0; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + symname = strtab + symtab[symtab_index].st_name; + + if (symtab_index) { + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + /* + * We want to allow undefined references to weak symbols - this + * might have been intentional. We should not be linking local + * symbols here, so all bases should be covered. + */ + if (unlikely(!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) + && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) + return 1; +/* + if (_dl_trace_prelink) { + _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } +*/ + tls_tpnt = sym_ref.tpnt; + } else { + symbol_addr = symtab[symtab_index].st_value; + tls_tpnt = tpnt; + } + +#if defined (UF_DEBUG) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { + case R_386_NONE: + break; + case R_386_32: + *reloc_addr += symbol_addr; + break; + case R_386_PC32: + *reloc_addr += symbol_addr - (unsigned long)reloc_addr; + break; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_386_RELATIVE: + *reloc_addr += (unsigned long)tpnt->loadaddr; + break; + case R_386_COPY: + if (symbol_addr) { + uf_debug("\n%s move %d bytes from %x to %x", + symname, symtab[symtab_index].st_size, + symbol_addr, reloc_addr); + + memcpy((char *)reloc_addr, + (char *)symbol_addr, + symtab[symtab_index].st_size); + } + break; + default: + return -1; + } + + uf_debug("\n\tpatched: %x ==> %x @ %x\n", old_val, *reloc_addr, reloc_addr); + + return 0; +} + +int _dl_parse_relocation_information_i386(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size) + //int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, + // ELF_RELOC *rpnt, Elf32(Sym) *symtab, char *strtab)) +{ + unsigned int i; + char *strtab; + Elf32(Sym) *symtab; + ELF_RELOC *rpnt; + int symtab_index; + + /* Parse the relocation information. */ + rpnt = (ELF_RELOC *)(intptr_t)rel_addr; + rel_size /= sizeof(ELF_RELOC); + + symtab = (Elf32(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF_R_SYM(rpnt->r_info); + + //debug_sym(symtab, strtab, symtab_index); + //debug_reloc(symtab, strtab, rpnt); + + res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); + + if (res == 0) + continue; + + if (symtab_index) + fprintf(stderr, "symbol '%s': ", + strtab + symtab[symtab_index].st_name); + + if (unlikely(res < 0)) { + int reloc_type = ELF_R_TYPE(rpnt->r_info); + + fprintf(stderr, "can't handle reloc type %x in lib '%s'\n", + reloc_type, tpnt->libname); + //return res; + continue; + } else if (unlikely(res > 0)) { + fprintf(stderr, "can't resolve symbol in lib '%s'.\n", tpnt->libname); + //return res; + continue; + } + } + + return 0; +} diff --git a/uniFuzzer/elfLoader/i386.h b/uniFuzzer/elfLoader/i386.h new file mode 100644 index 0000000..de04712 --- /dev/null +++ b/uniFuzzer/elfLoader/i386.h @@ -0,0 +1,11 @@ +#ifndef DL_I386 +#define DL_I386 + +#include "dl-hash.h" + +int _dl_parse_relocation_information_i386(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size); + //int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, + //ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)); + +#endif diff --git a/uniFuzzer/elfLoader/mips.c b/uniFuzzer/elfLoader/mips.c new file mode 100644 index 0000000..139a2c7 --- /dev/null +++ b/uniFuzzer/elfLoader/mips.c @@ -0,0 +1,151 @@ +#include +#include + +#include "mips.h" + +extern struct elf_resolve *_dl_loaded_modules; + +#define elf_machine_type_class_mips(type) \ + ((((type) == R_MIPS_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY)) + +void init_got_mips(Elf32(Addr) *GOT_BASE, struct elf_resolve *MODULE){ + unsigned long idx; + Elf32(Addr) *pltgot; + + pltgot = (Elf32(Addr) *) MODULE->dynamic_info[DT_MIPS_PLTGOT_IDX]; + + /* Add load address displacement to all local GOT entries */ + idx = 2; + while (idx < MODULE->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX]) + GOT_BASE[idx++] += (unsigned long) MODULE->loadaddr; +} + +int _dl_parse_relocation_information_mips(struct dyn_elf *xpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) +{ + Elf32(Sym) *symtab; + ELF_RELOC *rpnt; + char *strtab; + unsigned long i; + Elf32(Addr) *got; + unsigned long *reloc_addr=NULL; + unsigned long symbol_addr; + int reloc_type, symtab_index; + struct elf_resolve *tpnt = xpnt->dyn; + char *symname = NULL; + + struct symbol_ref sym_ref; + /* Now parse the relocation information */ + rel_size = rel_size / sizeof(Elf32(Rel)); + rpnt = (ELF_RELOC *) rel_addr; + + symtab = (Elf32(Sym) *) (tpnt->dynamic_info[DT_SYMTAB]); + strtab = (char *) tpnt->dynamic_info[DT_STRTAB]; + got = (Elf32(Addr) *) (tpnt->dynamic_info[DT_PLTGOT]); + + for (i = 0; i < rel_size; i++, rpnt++) { + + reloc_addr = (unsigned long *) (tpnt->loadaddr + + (unsigned long) rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); + symbol_addr = 0; + symname = strtab + symtab[symtab_index].st_name; + + if (reloc_type == R_MIPS_JUMP_SLOT || reloc_type == R_MIPS_COPY) { + sym_ref.tpnt = NULL; + sym_ref.sym = &symtab[symtab_index]; + symbol_addr = (unsigned long)_dl_find_hash(symname, + scope, + tpnt, + elf_machine_type_class_mips(reloc_type), &sym_ref); + if (unlikely(!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) + return 1; + } + if (!symtab_index) { + /* Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. + */ + symbol_addr = symtab[symtab_index].st_value; + } + + switch (reloc_type) { + case R_MIPS_REL32: + if (symtab_index) { + if (symtab_index < tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX]) + *(Elf32(Word) *)reloc_addr += + symtab[symtab_index].st_value + + (unsigned long) tpnt->loadaddr; + else { + *(Elf32(Word) *)reloc_addr += got[symtab_index + tpnt->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX] - + tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX]]; + } + } + else { + *(Elf32(Word) *)reloc_addr += (unsigned long) tpnt->loadaddr; + } + break; + case R_MIPS_JUMP_SLOT: + *(Elf32(Word) *)reloc_addr = symbol_addr; + break; + case R_MIPS_COPY: + if (symbol_addr) { + + memcpy((char *)reloc_addr, + (char *)symbol_addr, + symtab[symtab_index].st_size); + } + break; + case R_MIPS_NONE: + break; + default: + { + fprintf(stderr, "can't handle reloc type %x in lib '%s'\n", reloc_type, tpnt->libname); + } + } + } + return 0; +} + + +void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt) +{ + Elf32(Sym) *sym; + char *strtab; + unsigned long i; + Elf32(Addr) *got_entry; + + for (; tpnt ; tpnt = tpnt->next) { + + /* Setup the loop variables */ + got_entry = (Elf32(Addr) *) (tpnt->dynamic_info[DT_PLTGOT]) + + tpnt->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX]; + sym = (Elf32(Sym) *) (tpnt->dynamic_info[DT_SYMTAB])+ tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX]; + strtab = (char *) tpnt->dynamic_info[DT_STRTAB]; + i = tpnt->dynamic_info[DT_MIPS_SYMTABNO_IDX] - tpnt->dynamic_info[DT_MIPS_GOTSYM_IDX]; + + /* Relocate the global GOT entries for the object */ + while (i--) { + if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON) { + *got_entry = _dl_find_hash(strtab + + sym->st_name, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + } + else if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { + if (sym->st_other == 0) + *got_entry += (unsigned long) tpnt->loadaddr; + } + else { + struct symbol_ref sym_ref; + sym_ref.sym = sym; + sym_ref.tpnt = NULL; + *got_entry = (unsigned long) _dl_find_hash(strtab + + sym->st_name, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, &sym_ref); + } + + got_entry++; + sym++; + } + } +} diff --git a/uniFuzzer/elfLoader/mips.h b/uniFuzzer/elfLoader/mips.h new file mode 100644 index 0000000..2f4ea16 --- /dev/null +++ b/uniFuzzer/elfLoader/mips.h @@ -0,0 +1,13 @@ +#ifndef DL_MIPS_H +#define DL_MIPS_H + +#include "dl-hash.h" + +int _dl_parse_relocation_information_mips(struct dyn_elf *xpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size); + +void init_got_mips(Elf32(Addr) *GOT_BASE, struct elf_resolve *MODULE); + +void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt); + +#endif diff --git a/uniFuzzer/uniFuzzer.c b/uniFuzzer/uniFuzzer.c new file mode 100644 index 0000000..3805846 --- /dev/null +++ b/uniFuzzer/uniFuzzer.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +#include "elfLoader.h" +#include "utils.h" + +extern int uniFuzzerInit(uc_engine *uc); +extern int uniFuzzerBeforeExec(uc_engine *uc, const uint8_t *data, size_t len); +extern int uniFuzzerAfterExec(uc_engine *uc); +extern uint16_t prevPR; + +uc_engine *uc; + +__attribute__((section("__libfuzzer_extra_counters"))) +uint8_t Counters[PCS_N]; + +int LLVMFuzzerInitialize(int *argc, char ***argv) { + char *target = getenv("UF_TARGET"); + char *preload = getenv("UF_PRELOAD"); + char *libPath = getenv("UF_LIBPATH"); + + uc = loadELF(target, preload, libPath); + if(uc == NULL || uniFuzzerInit(uc)) { + fprintf(stderr, "init failed for %s\n",target); + fprintf(stderr, "Usage: UF_TARGET= [UF_PRELOAD=] UF_LIBPATH= ./uf\n"); + exit(1); + } + + // hook basic block to get code coverage + uc_hook hookHandle; + uc_hook_add(uc, &hookHandle, UC_HOOK_BLOCK, hookBlock, NULL, 1, 0); + + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + prevPR = 0; + if(uniFuzzerBeforeExec(uc, data, size)) { + exit(1); + } + if(uniFuzzerAfterExec(uc)) { + exit(1); + } + + return 0; // Non-zero return values are reserved for future use. +} diff --git a/uniFuzzer/utils.c b/uniFuzzer/utils.c new file mode 100644 index 0000000..222bdba --- /dev/null +++ b/uniFuzzer/utils.c @@ -0,0 +1,68 @@ +#include +#include +#include "utils.h" + +extern uint8_t Counters[PCS_N]; + +uint16_t prevPR = 0; + +// ========== for CRC computation ========== + +static const uint16_t crc16tab[256]= { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +static uint16_t crc16(uint32_t value) { + int counter; + uint16_t crc = 0; + for (counter = 0; counter < 4; counter++) { + uint8_t v = value & 0xff; + crc = (crc<<8) ^ crc16tab[((crc>>8) ^ v)&0xff]; + value >>= 8; + } + return crc; +} + +// update code coverage counters by hooking basic block +void hookBlock(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + // use CRC16 to hash the basic block addr into some 16-bits number + uint16_t pr = crc16(address); + uint16_t idx = pr ^ prevPR; + Counters[idx]++; + // for debugging + // printf("counters idx is %x, pr is %x, address is %p, prev PC is %x\n", idx, pr, address, prevPR); + prevPR = (pr >> 1); +} + + diff --git a/uniFuzzer/utils.h b/uniFuzzer/utils.h new file mode 100644 index 0000000..2bb80db --- /dev/null +++ b/uniFuzzer/utils.h @@ -0,0 +1,10 @@ +#ifndef UTILS_H +#define UTILS_H + + +// code coverage counters +#define PCS_N (1 << 16) + +void hookBlock(uc_engine *uc, uint64_t address, uint32_t size, void *user_data); + +#endif diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..f246b67 --- /dev/null +++ b/utils.c @@ -0,0 +1,64 @@ +#include "utils.h" + +static uint16_t prevPR = 0; +extern uint8_t Counters[PCS_N]; +// ========== for CRC computation ========== + +static const uint16_t crc16tab[256]= { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +static uint16_t crc16(uint32_t value) { + int counter; + uint16_t crc = 0; + for (counter = 0; counter < 4; counter++) { + uint8_t v = value & 0xff; + crc = (crc<<8) ^ crc16tab[((crc>>8) ^ v)&0xff]; + value >>= 8; + } + return crc; +} + +// update code coverage counters by hooking basic block +void hookBlock(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + // use CRC16 to hash the basic block addr into some 16-bits number + uint16_t pr = crc16(address); + uint16_t idx = pr ^ prevPR; + Counters[idx]++; + // for debugging + // printf("counters idx is %x, pr is %x, address is %p, prev PC is %x\n", idx, pr, address, prevPR); + prevPR = (pr >> 1); +} + + diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..2bb80db --- /dev/null +++ b/utils.h @@ -0,0 +1,10 @@ +#ifndef UTILS_H +#define UTILS_H + + +// code coverage counters +#define PCS_N (1 << 16) + +void hookBlock(uc_engine *uc, uint64_t address, uint32_t size, void *user_data); + +#endif