diff options
-rwxr-xr-x | qbdi_mode/README.md | 197 | ||||
-rwxr-xr-x | qbdi_mode/build.sh | 37 | ||||
-rwxr-xr-x | qbdi_mode/demo-so.c | 39 | ||||
-rwxr-xr-x | qbdi_mode/template.cpp | 90 |
4 files changed, 288 insertions, 75 deletions
diff --git a/qbdi_mode/README.md b/qbdi_mode/README.md new file mode 100755 index 00000000..8891d99e --- /dev/null +++ b/qbdi_mode/README.md @@ -0,0 +1,197 @@ +# qbdi-based binary-only instrumentation for afl-fuzz + +## 1) Introduction + +The code in ./qbdi_mode allows you to build a standalone feature that +using the QBDI framework to fuzz android native library. + + +## 2) Build + +First download the Android NDK + +``` +https://developer.android.com/ndk/downloads +https://dl.google.com/android/repository/android-ndk-r20-linux-x86_64.zip +``` + +Then unzip it and build the standalone-toolchain +For x86_64 standalone-toolchain + +``` +unzip android-ndk-r20-linux-x86_64.zip +cd android-ndk-r20/ +./build/tools/make_standalone_toolchain.py --arch x86_64 --api 21 --install-dir ../android-standalone-toolchain-x86_64 +``` + +For x86 standalone-toolchain + +``` +./build/tools/make_standalone_toolchain.py --arch x86 --api 21 --install-dir ../android-standalone-toolchain-x86 +``` + +Then download the QBDI SDK from website + +``` +https://qbdi.quarkslab.com/ +``` + +For Android x86_64 +``` +https://github.com/QBDI/QBDI/releases/download/v0.7.0/QBDI-0.7.0-android-X86_64.tar.gz +``` + +Then decompress the sdk + +``` +mkdir android-qbdi-sdk-x86_64 +cp QBDI-0.7.0-android-X86_64.tar.gz android-qbdi-sdk-x86_64/ +cd android-qbdi-sdk-x86_64/ +tar xvf QBDI-0.7.0-android-X86_64.tar.gz +``` + +Now set the `STANDALONE_TOOLCHAIN_PATH` to the path of standalone-toolchain + +``` +export STANDALONE_TOOLCHAIN_PATH=/home/hac425/workspace/android-standalone-toolchain-x86_64 +``` + +set the `QBDI_SDK_PATH` to the path of QBDI SDK + +``` +export QBDI_SDK_PATH=/home/hac425/workspace/AFLplusplus/qbdi_mode/android-qbdi-sdk-x86_64/ +``` + +Then run the build.sh + +``` +./build.sh x86_64 +``` + +this could build the afl-fuzz and also the qbdi template for android x86_64 + + +### Example + +The demo-so.c is an vulnerable library, it has a function for test + +``` +int target_func(char *buf, int size) +{ + printf("buffer:%p, size:%p\n", buf, size); + switch (buf[0]) + { + case 1: + puts("222"); + if (buf[1] == '\x44') + { + puts("null ptr deference"); + *(char *)(0) = 1; + } + break; + case 0xff: + if (buf[2] == '\xff') + { + if (buf[1] == '\x44') + { + puts("crash...."); + *(char *)(0xdeadbeef) = 1; + } + } + break; + default: + puts("default action"); + break; + } + + return 1; +} +``` + +This could be build to `libdemo.so`. + +Then we should load the library in template.cpp and find the `target` function address. +``` + void *handle = dlopen(lib_path, RTLD_LAZY); + .......................................... + .......................................... + .......................................... + p_target_func = (target_func)dlsym(handle, "target_func"); +``` + +then we read the data from file and call the function in `fuzz_func` + +``` +QBDI_NOINLINE int fuzz_func() +{ + // afl forkserver stuff + if (afl_setup()) + { + afl_forkserver(); + } + + // read the data from file(argv[2]) + unsigned long len = 0; + char *data = read_file(FPATH, &len); + + + printf("In fuzz_func\n"); + + // call the target function with input data. + p_target_func(data, len); + return 1; +} +``` + +Just compile it +``` +./build.sh x86_64 +``` + +Then push the `afl-fuzz`, `loader`, `libdemo.so`, the `libQBDI.so` from the QBDI SDK and the `libc++_shared.so` from android-standalone-toolchain to android device + +``` +adb push afl-fuzz /data/local/tmp +adb push libdemo.so /data/local/tmp +adb push loader /data/local/tmp +adb push android-qbdi-sdk-x86_64/usr/local/lib/libQBDI.so /data/local/tmp +adb push ../../android-standalone-toolchain-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so +/data/local/tmp +``` + +In android adb shell, we could try to run the loader +``` +export LD_LIBRARY_PATH=/data/local/tmp +./loader /data/local/tmp/libdemo.so init +``` +the normal output like + +``` +# ./loader /data/local/tmp/libdemo.so init p_target_func:0x7b41ac26e600 +In fuzz_func + offset:0x600 + offset:0x580 +buffer:0x7b41abe2b050, size:0x4 + offset:0x628 + offset:0x646 + offset:0x64b + offset:0x65c + offset:0x6df + offset:0x590 +default action + offset:0x6eb +``` + +now run `afl-fuzz` to fuzz the library + +``` +mkdir in +echo xxxx > in/1 +./afl-fuzz -i in -o out -- ./loader /data/local/tmp/libdemo.so @@ +``` + +the snapshot + + + +good job. \ No newline at end of file diff --git a/qbdi_mode/build.sh b/qbdi_mode/build.sh index a45c76e6..7ac4c75d 100755 --- a/qbdi_mode/build.sh +++ b/qbdi_mode/build.sh @@ -1,12 +1,39 @@ -compiler_prefix="/home/hac425/workspace/android-standalone-toolchain-21-x86/bin/i686-linux-android-" -CFLAGS="-Iusr/local/include/ -Lusr/local/lib/" +if [ -z ${STANDALONE_TOOLCHAIN_PATH} ]; then + echo "please set the android-standalone-toolchain path in STANDALONE_TOOLCHAIN_PATH environmental variable" + echo "for example: " + echo " export STANDALONE_TOOLCHAIN_PATH=/home/android-standalone-toolchain-21/" + exit +fi -# for x86-64 android -# compiler_prefix="/home/hac425/workspace/android-standalone-toolchain-21/bin/x86_64-linux-android-" -# CFLAGS="-Iandroid-x64/usr/local/include/ -Landroid-x64/usr/local/lib/" +if [ -z ${QBDI_SDK_PATH} ]; then + echo "please set the qbdi sdk path in QBDI_SDK_PATH environmental variable" + echo "for example: " + echo " export QBDI_SDK_PATH=/home/QBDI-Android/" + exit +fi + + +if [ "$1" = "x86" ]; then + echo "build x86 qbdi" + compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/i686-linux-android-" +elif [ "$1" = "x86_64" ]; then + echo "build x86_64 qbdi" + compiler_prefix="${STANDALONE_TOOLCHAIN_PATH}/bin/x86_64-linux-android-" +else + echo "usage: ./build.sh arch[x86, x86_64]" + exit +fi + + +CFLAGS="-I${QBDI_SDK_PATH}/usr/local/include/ -L${QBDI_SDK_PATH}/usr/local/lib/" + +# build the qbdi template ${compiler_prefix}g++ -o loader template.cpp -lQBDI -ldl -w -g ${CFLAGS} + +# build the demo share library ${compiler_prefix}gcc -shared -o libdemo.so demo-so.c -w -g +# build afl-fuzz cd .. ${compiler_prefix}gcc -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-misc.c src/afl-fuzz-extras.c src/afl-fuzz-queue.c src/afl-fuzz-one.c src/afl-fuzz-python.c src/afl-fuzz-stats.c src/afl-fuzz-init.c src/afl-fuzz.c src/afl-fuzz-bitmap.c src/afl-fuzz-run.c src/afl-fuzz-globals.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o qbdi_mode/afl-fuzz -ldl -w diff --git a/qbdi_mode/demo-so.c b/qbdi_mode/demo-so.c index 3ba7c449..5e74f268 100755 --- a/qbdi_mode/demo-so.c +++ b/qbdi_mode/demo-so.c @@ -1,46 +1,33 @@ #include <stdio.h> - - // gcc -shared -o libdemo.so demo-so.c -w - - -int target_func(char* buf, int size){ - +int target_func(char *buf, int size) +{ printf("buffer:%p, size:%p\n", buf, size); - switch (buf[0]) { case 1: puts("222"); - if(buf[1]=='\x44'){ - puts("aaaaaaaaaaaaaaaaaaaaa"); - *(char*)(0) = 1; - } - break; - case '\xfe': - // assert(0); - if(buf[4]=='\xf0'){ - puts("xxxiiii"); + if (buf[1] == '\x44') + { + puts("null ptr deference"); + *(char *)(0) = 1; } break; case 0xff: - if(buf[2]=='\xff'){ - if(buf[1]=='\x44'){ - *(char*)(0xdeadbeef) = 1; - }else{ - puts("kkkkkk"); + if (buf[2] == '\xff') + { + if (buf[1] == '\x44') + { + puts("crash...."); + *(char *)(0xdeadbeef) = 1; } } - puts("xxxx"); break; default: - puts("xxxxxxx"); + puts("default action"); break; } return 1; } - - - diff --git a/qbdi_mode/template.cpp b/qbdi_mode/template.cpp index 85b46d2f..f0b0c601 100755 --- a/qbdi_mode/template.cpp +++ b/qbdi_mode/template.cpp @@ -18,9 +18,6 @@ #include <sys/shm.h> #include "../config.h" - - - #include <QBDI.h> using namespace QBDI; @@ -33,20 +30,21 @@ target_func p_target_func = NULL; rword module_base = 0; rword module_end = 0; static unsigned char - dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */ -unsigned char *afl_area_ptr = NULL; /* Exported for afl_gen_trace */ + dummy[MAP_SIZE]; /* costs MAP_SIZE but saves a few instructions */ +unsigned char *afl_area_ptr = NULL; /* Exported for afl_gen_trace */ unsigned long afl_prev_loc = 0; - /* Set up SHM region and initialize other stuff. */ -int afl_setup(void) { +int afl_setup(void) +{ char *id_str = getenv(SHM_ENV_VAR); int shm_id; - if (id_str) { + if (id_str) + { shm_id = atoi(id_str); - afl_area_ptr = (unsigned char*)shmat(shm_id, NULL, 0); + afl_area_ptr = (unsigned char *)shmat(shm_id, NULL, 0); if (afl_area_ptr == (void *)-1) return 0; memset(afl_area_ptr, 0, MAP_SIZE); @@ -54,7 +52,6 @@ int afl_setup(void) { return 1; } - /* Fork server logic, invoked once we hit _start. */ static void afl_forkserver() { @@ -74,7 +71,6 @@ static void afl_forkserver() if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2); - child_pid = fork(); if (child_pid < 0) exit(4); @@ -101,25 +97,28 @@ static void afl_forkserver() } } -void afl_maybe_log(unsigned long cur_loc) { - if(afl_area_ptr == NULL){ - return; - } - unsigned long afl_idx = cur_loc ^ afl_prev_loc; - afl_area_ptr[afl_idx % MAP_SIZE]++; - afl_prev_loc = cur_loc >> 1; +void afl_maybe_log(unsigned long cur_loc) +{ + if (afl_area_ptr == NULL) + { + return; + } + unsigned long afl_idx = cur_loc ^ afl_prev_loc; + afl_area_ptr[afl_idx % MAP_SIZE]++; + afl_prev_loc = cur_loc >> 1; } -char* read_file(char* path, unsigned long* length) { - FILE *pFile = fopen(path, "rb"); - char *pBuf; - fseek(pFile, 0, SEEK_END); - unsigned long len = ftell(pFile); - pBuf = (char*)malloc(len); - rewind(pFile); - fread(pBuf, 1, len, pFile); - fclose(pFile); - *length = len; - return pBuf; +char *read_file(char *path, unsigned long *length) +{ + FILE *pFile = fopen(path, "rb"); + char *pBuf; + fseek(pFile, 0, SEEK_END); + unsigned long len = ftell(pFile); + pBuf = (char *)malloc(len); + rewind(pFile); + fread(pBuf, 1, len, pFile); + fclose(pFile); + *length = len; + return pBuf; } char FPATH[200]; @@ -127,24 +126,21 @@ char FPATH[200]; QBDI_NOINLINE int fuzz_func() { - if(afl_setup()){ + if (afl_setup()) + { afl_forkserver(); } unsigned long len = 0; - char* data = read_file(FPATH, &len); + char *data = read_file(FPATH, &len); printf("In fuzz_func\n"); p_target_func(data, len); return 1; } - - - - - -static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm, const QBDI::VMState *state, QBDI::GPRState *gprState, QBDI::FPRState *fprState, void *data) { +static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm, const QBDI::VMState *state, QBDI::GPRState *gprState, QBDI::FPRState *fprState, void *data) +{ // errno = SAVED_ERRNO; #ifdef __x86_64__ @@ -154,9 +150,11 @@ static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm, const QBDI::VMState *st #elif defined(__arm__) unsigned long pc = gprState->pc; #endif - - if(pc >= module_base && pc <= module_end){ - unsigned long offset = pc - module_base; + + // just log the module path + if (pc >= module_base && pc <= module_end) + { + unsigned long offset = pc - module_base; printf("\toffset:%p\n", offset); afl_maybe_log(offset); } @@ -166,6 +164,12 @@ static QBDI::VMAction bbcallback(QBDI::VMInstanceRef vm, const QBDI::VMState *st int main(int argc, char **argv) { + if (argc < 3) + { + puts("usage: ./loader library_path input_file_path"); + exit(0); + } + const char *lib_path; lib_path = argv[1]; // FPATH = argv[2]; @@ -183,9 +187,9 @@ int main(int argc, char **argv) lib_name = strrchr(lib_name, '/') + 1; // printf("library name:%s\n", lib_name); - + // load library module address for log path for (MemoryMap &map : getCurrentProcessMaps()) - { + { // printf("module:%s\n", map.name.c_str()); if ((map.permission & PF_EXEC) && strstr(map.name.c_str(), lib_name) != NULL) { @@ -212,10 +216,8 @@ int main(int argc, char **argv) vm.addInstrumentedModuleFromAddr(module_base); vm.addInstrumentedModuleFromAddr((rword)&main); - vm.addVMEventCB(BASIC_BLOCK_ENTRY, bbcallback, nullptr); - // QBDI::simulateCall(state, FAKE_RET_ADDR); // vm.run((rword)&fuzz_func, (rword)FAKE_RET_ADDR); |