Improved FRIDA mode scripting support (#994)

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
WorksButNotTested
2021-06-25 22:14:27 +01:00
committed by GitHub
parent c88b98d1c9
commit 6a3877dcd3
47 changed files with 2626 additions and 1423 deletions

View File

@ -3,3 +3,5 @@ frida_test.dat
qemu_test.dat
frida_out/**
qemu_out/**
ts/dist/
ts/node_modules/

View File

@ -94,11 +94,15 @@ FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME)
AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c
AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o
.PHONY: all 32 clean format $(FRIDA_GUM) quickjs
HOOK_DIR:=$(PWD)hook/
AFLPP_DRIVER_HOOK_SRC=$(HOOK_DIR)hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)hook.so
.PHONY: all 32 clean format hook $(FRIDA_GUM)
############################## ALL #############################################
all: $(FRIDA_TRACE)
all: $(FRIDA_TRACE) $(AFLPP_DRIVER_HOOK_OBJ)
32:
CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all
@ -197,13 +201,20 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL
cp -v $(FRIDA_TRACE) $(ROOT)
############################# HOOK #############################################
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) $(LDFLAGS) -I $(FRIDA_BUILD_DIR) $< -o $@
hook: $(AFLPP_DRIVER_HOOK_OBJ)
############################# CLEAN ############################################
clean:
rm -rf $(BUILD_DIR)
############################# FORMAT ###########################################
format:
cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i
cd $(ROOT) && echo $(SOURCES) $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i
cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i
############################# RUN #############################################

View File

@ -11,3 +11,6 @@ clean:
format:
@gmake format
hook:
@gmake hook

View File

@ -99,34 +99,601 @@ const address = module.base.add(0xdeadface);
Afl.setPersistentAddress(address);
```
# API
# Persisent Hook
A persistent hook can be implemented using a conventional shared object, sample
source code for a hook suitable for the prototype of `LLVMFuzzerTestOneInput`
can be found [here](hook/hook.c). This can be configured using code similar to
the following.
```js
const path = Afl.module.path;
const dir = path.substring(0, path.lastIndexOf("/"));
const mod = Module.load(`${dir}/frida_mode/build/hook.so`);
const hook = mod.getExportByName('afl_persistent_hook');
Afl.setPersistentHook(hook);
```
Alternatively, the hook can be provided by using FRIDAs built in support for `CModule`, powered by TinyCC.
```js
const cm = new CModule(`
#include <string.h>
#include <gum/gumdefs.h>
void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf,
uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
`,
{
memcpy: Module.getExportByName(null, 'memcpy')
});
Afl.setPersistentHook(cm.afl_persistent_hook);
```
# Advanced Persistence
Consider the following target code...
```c
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void LLVMFuzzerTestOneInput(char *buf, int len) {
if (len < 1) return;
buf[len] = 0;
// we support three input cases
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else if (buf[0] == '1')
printf("Pretty sure that is a one!\n");
else
printf("Neither one or zero? How quaint!\n");
}
int run(char *file) {
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
do {
dprintf(STDERR_FILENO, "Running: %s\n", file);
fd = open(file, O_RDONLY);
if (fd < 0) {
perror("open");
break;
}
len = lseek(fd, 0, SEEK_END);
if (len < 0) {
perror("lseek (SEEK_END)");
break;
}
if (lseek(fd, 0, SEEK_SET) != 0) {
perror("lseek (SEEK_SET)");
break;
}
buf = malloc(len);
if (buf == NULL) {
perror("malloc");
break;
}
n_read = read(fd, buf, len);
if (n_read != len) {
perror("read");
break;
}
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
LLVMFuzzerTestOneInput(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
result = 0;
} while (false);
if (buf != NULL) { free(buf); }
if (fd != -1) { close(fd); }
return result;
}
void slow() {
usleep(100000);
}
int main(int argc, char **argv) {
if (argc != 2) { return 1; }
slow();
return run(argv[1]);
}
```
FRIDA mode supports the replacement of any function, with an implementation
generated by CModule. This allows for a bespoke harness to be written as
follows:
```
const slow = DebugSymbol.fromName('slow').address;
Afl.print(`slow: ${slow}`);
const LLVMFuzzerTestOneInput = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address;
Afl.print(`LLVMFuzzerTestOneInput: ${LLVMFuzzerTestOneInput}`);
const cm = new CModule(`
extern unsigned char * __afl_fuzz_ptr;
extern unsigned int * __afl_fuzz_len;
extern void LLVMFuzzerTestOneInput(char *buf, int len);
void slow(void) {
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
}
`,
{
LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput,
__afl_fuzz_ptr: Afl.getAflFuzzPtr(),
__afl_fuzz_len: Afl.getAflFuzzLen()
});
Afl.setEntryPoint(cm.slow);
Afl.setPersistentAddress(cm.slow);
Afl.setInMemoryFuzzing();
Interceptor.replace(slow, cm.slow);
Afl.print("done");
Afl.done();
```
Here, we replace the function `slow` with our own code. This code is then
selected as the entry point as well as the persistent loop address.
**WARNING** There are two key limitations in replacing a function in this way:
- The function which is to be replaced must not be `main` this is because this
is the point at which FRIDA mode is initialized and at the point the the JS has
been run, the start of the `main` function has already been instrumented and
cached.
- The replacement function must not call itself. e.g. in this example we
couldn't replace `LLVMFuzzerTestOneInput` and call itself.
# Patching
Consider the [following](test/js/test2.c) test code...
```c
/*
* Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages.
* If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue.
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
Afl.print(msg);
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
const uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
...
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t
crc32(const void *buf, size_t size)
{
const uint8_t *p = buf;
uint32_t crc;
crc = ~0U;
while (size--)
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
/*
* Don't you hate those contrived examples which CRC their data. We can use
* FRIDA to patch this function out and always return success. Otherwise, we
* could change it to actually correct the checksum.
*/
int crc32_check (char * buf, int len) {
if (len < sizeof(uint32_t)) { return 0; }
uint32_t expected = *(uint32_t *)&buf[len - sizeof(uint32_t)];
uint32_t calculated = crc32(buf, len - sizeof(uint32_t));
return expected == calculated;
}
/*
* So you've found a really boring bug in an earlier campaign which results in
* a NULL dereference or something like that. That bug can get in the way,
* causing the persistent loop to exit whenever it is triggered, and can also
* cloud your output unnecessarily. Again, we can use FRIDA to patch it out.
*/
void some_boring_bug(char c) {
switch (c) {
case 'A'...'Z':
case 'a'...'z':
__builtin_trap();
break;
}
}
void LLVMFuzzerTestOneInput(char *buf, int len) {
if (!crc32_check(buf, len)) return;
some_boring_bug(buf[0]);
if (buf[0] == '0') {
printf("Looks like a zero to me!\n");
}
else if (buf[0] == '1') {
printf("Pretty sure that is a one!\n");
}
else if (buf[0] == '2') {
if (buf[1] == '3') {
if (buf[2] == '4') {
printf("Oh we, weren't expecting that!");
__builtin_trap();
}
}
}
else
printf("Neither one or zero? How quaint!\n");
}
int main(int argc, char **argv) {
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
if (argc != 2) { return 1; }
printf("Running: %s\n", argv[1]);
fd = open(argv[1], O_RDONLY);
if (fd < 0) { return 1; }
len = lseek(fd, 0, SEEK_END);
if (len < 0) { return 1; }
if (lseek(fd, 0, SEEK_SET) != 0) { return 1; }
buf = malloc(len);
if (buf == NULL) { return 1; }
n_read = read(fd, buf, len);
if (n_read != len) { return 1; }
printf("Running: %s: (%zd bytes)\n", argv[1], n_read);
LLVMFuzzerTestOneInput(buf, len);
printf("Done: %s: (%zd bytes)\n", argv[1], n_read);
return 0;
}
```
There are a couple of obstacles with our target application. Unlike when fuzzing
source code, though, we can't simply edit it and recompile it. The following
script shows how we can use the normal functionality of FRIDA to modify any
troublesome behaviour.
```js
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
const main = DebugSymbol.fromName('main').address;
Afl.print(`main: ${main}`);
Afl.setEntryPoint(main);
Afl.setPersistentAddress(main);
Afl.setPersistentCount(10000000);
const crc32_check = DebugSymbol.fromName('crc32_check').address;
const crc32_replacement = new NativeCallback(
(buf, len) => {
Afl.print(`len: ${len}`);
if (len < 4) {
return 0;
}
return 1;
},
'int',
['pointer', 'int']);
Interceptor.replace(crc32_check, crc32_replacement);
const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address
const boring_replacement = new NativeCallback(
(c) => { },
'void',
['char']);
Interceptor.replace(some_boring_bug, boring_replacement);
Afl.done();
Afl.print("done");
```
# Advanced Patching
Consider the following code fragment...
```c
extern void some_boring_bug2(char c);
__asm__ (
".text \n"
"some_boring_bug2: \n"
".global some_boring_bug2 \n"
".type some_boring_bug2, @function \n"
"mov %edi, %eax \n"
"cmp $0xb4, %al \n"
"jne ok \n"
"ud2 \n"
"ok: \n"
"ret \n");
void LLVMFuzzerTestOneInput(char *buf, int len) {
...
some_boring_bug2(buf[0]);
...
}
```
Rather than using FRIDAs `Interceptor.replace` or `Interceptor.attach` APIs, it
is possible to apply much more fine grained modification to the target
application by means of using the Stalker APIs.
The following code locates the function of interest and patches out the UD2
instruction signifying a crash.
```js
/* Modify the instructions */
const some_boring_bug2 = DebugSymbol.fromName('some_boring_bug2').address
const pid = Memory.alloc(4);
pid.writeInt(Process.id);
const cm = new CModule(`
#include <stdio.h>
#include <gum/gumstalker.h>
typedef int pid_t;
#define STDERR_FILENO 2
#define BORING2_LEN 10
extern int dprintf(int fd, const char *format, ...);
extern void some_boring_bug2(char c);
extern pid_t getpid(void);
extern pid_t pid;
gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
gboolean excluded, GumStalkerOutput *output)
{
pid_t my_pid = getpid();
GumX86Writer *cw = output->writer.x86;
if (GUM_ADDRESS(insn->address) < GUM_ADDRESS(some_boring_bug2)) {
return TRUE;
}
if (GUM_ADDRESS(insn->address) >=
GUM_ADDRESS(some_boring_bug2) + BORING2_LEN) {
return TRUE;
}
if (my_pid == pid) {
if (begin) {
dprintf(STDERR_FILENO, "\n> 0x%016lX: %s %s\n", insn->address,
insn->mnemonic, insn->op_str);
} else {
dprintf(STDERR_FILENO, " 0x%016lX: %s %s\n", insn->address,
insn->mnemonic, insn->op_str);
}
}
if (insn->id == X86_INS_UD2) {
gum_x86_writer_put_nop(cw);
return FALSE;
} else {
return TRUE;
}
}
`,
{
dprintf: Module.getExportByName(null, 'dprintf'),
getpid: Module.getExportByName(null, 'getpid'),
some_boring_bug2: some_boring_bug2,
pid: pid
});
Afl.setStalkerCallback(cm.js_stalker_callback)
Afl.setStdErr("/tmp/stderr.txt");
```
Note that you will more likely want to find the
patch address by using:
```js
const module = Process.getModuleByName('target.exe');
/* Hardcoded offset within the target image */
const address = module.base.add(0xdeadface);
```
OR
```
const address = DebugSymbol.fromName("my_function").address.add(0xdeadface);
```
OR
```
const address = Module.getExportByName(null, "my_function").add(0xdeadface);
```
The function `js_stalker_callback` should return `TRUE` if the original
instruction should be emitted in the instrumented code, or `FALSE` otherwise.
In the example above, we can see it is replaced with a `NOP`.
Lastly, note that the same callback will be called when compiling instrumented
code both in the child of the forkserver (as it is executed) and also in the
parent of the forserver (when prefetching is enabled) so that it can be
inherited by the next forked child. It is **VERY** important that the same
instructions be generated in both the parent and the child, or if prefetching is
disabled that the same instructions are generated every time the block is
compiled. Failure to do so will likely lead to bugs which are incredibly
difficult to diagnose. The code above only prints the instructions when running
in the parent process (the one provided by `Process.id` when the JS script is
executed).
# API
```js
class Afl {
/**
* Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode
* implementation).
*/
public static module: Module = Process.getModuleByName("afl-frida-trace.so");
/**
* This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges.
*/
public static addExcludedRange(addressess: NativePointer, size: number): void {
Afl.jsApiAddExcludeRange(addressess, size);
}
/**
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges.
*/
public static addIncludedRange(addressess: NativePointer, size: number): void {
Afl.jsApiAddIncludeRange(addressess, size);
}
/**
* This must always be called at the end of your script. This lets
* FRIDA mode know that your configuration is finished and that
* execution has reached the end of your script. Failure to call
* this will result in a fatal error.
*/
Afl.done();
public static done(): void {
Afl.jsApiDone();
}
/*
/**
* This function can be called within your script to cause FRIDA
* mode to trigger a fatal error. This is useful if for example you
* discover a problem you weren't expecting and want everything to
* stop. The user will need to enable `AFL_DEBUG_CHILD=1` to view
* this error message.
*/
Afl.error();
public static error(msg: string): void {
const buf = Memory.allocUtf8String(msg);
Afl.jsApiError(buf);
}
/*
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the length of
* fuzzing data when using in-memory test case fuzzing.
*/
public static getAflFuzzLen(): NativePointer {
return Afl.jsApiGetSymbol("__afl_fuzz_len");
}
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the fuzzing
* data when using in-memory test case fuzzing.
*/
public static getAflFuzzPtr(): NativePointer {
return Afl.jsApiGetSymbol("__afl_fuzz_ptr");
}
/**
* Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages.
* If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue.
*/
public static print(msg: string): void {
const STDOUT_FILENO = 2;
const log = `${msg}\n`;
const buf = Memory.allocUtf8String(log);
Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
}
/**
* See `AFL_FRIDA_DEBUG_MAPS`.
*/
public static setDebugMaps(): void {
Afl.jsApiSetDebugMaps();
}
/**
* This has the same effect as setting `AFL_ENTRYPOINT`, but has the
* convenience of allowing you to use FRIDAs APIs to determine the
* address you would like to configure, rather than having to grep
@ -134,107 +701,150 @@ Afl.error();
* function should be called with a `NativePointer` as its
* argument.
*/
Afl.setEntryPoint(address);
public static setEntryPoint(address: NativePointer): void {
Afl.jsApiSetEntryPoint(address);
}
/*
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument.
/**
* Function used to enable in-memory test cases for fuzzing.
*/
Afl.setPersistentAddress(address);
public static setInMemoryFuzzing(): void {
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
}
/*
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument.
*/
Afl.setPersistentReturn(address);
/*
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument.
*/
Afl.setPersistentCount(count);
/*
* See `AFL_FRIDA_PERSISTENT_DEBUG`.
*/
Afl.setPersistentDebug();
/*
* See `AFL_FRIDA_DEBUG_MAPS`.
*/
Afl.setDebugMaps();
/*
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges.
*/
Afl.addIncludedRange(address, size);
/*
* This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges.
*/
Afl.addExcludedRange(address, size);
/*
* See `AFL_INST_LIBS`.
*/
Afl.setInstrumentLibraries();
/*
/**
* See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as
* an argument.
*/
Afl.setInstrumentDebugFile(file);
public static setInstrumentDebugFile(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetInstrumentDebugFile(buf);
}
/*
* See `AFL_FRIDA_INST_NO_PREFETCH`.
*/
Afl.setPrefetchDisable();
/*
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
Afl.setInstrumentNoOptimize();
/*
/**
* See `AFL_FRIDA_INST_TRACE`.
*/
Afl.setInstrumentEnableTracing();
public static setInstrumentEnableTracing(): void {
Afl.jsApiSetInstrumentTrace();
}
/*
/**
* See `AFL_INST_LIBS`.
*/
public static setInstrumentLibraries(): void {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
public static setInstrumentNoOptimize(): void {
Afl.jsApiSetInstrumentNoOptimize();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
Afl.setInstrumentTracingUnique()
public static setInstrumentTracingUnique(): void {
Afl.jsApiSetInstrumentTraceUnique();
}
/*
* See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as
* an argument.
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument.
*/
Afl.setStdOut(file);
public static setPersistentAddress(address: NativePointer): void {
Afl.jsApiSetPersistentAddress(address);
}
/*
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
* an argument.
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument.
*/
Afl.setStdErr(file);
public static setPersistentCount(count: number): void {
Afl.jsApiSetPersistentCount(count);
}
/**
* See `AFL_FRIDA_PERSISTENT_DEBUG`.
*/
public static setPersistentDebug(): void {
Afl.jsApiSetPersistentDebug();
}
/**
* See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an
* argument. See above for examples of use.
*/
public static setPersistentHook(address: NativePointer): void {
Afl.jsApiSetPersistentHook(address);
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument.
*/
public static setPersistentReturn(address: NativePointer): void {
Afl.jsApiSetPersistentReturn(address);
}
/**
* See `AFL_FRIDA_INST_NO_PREFETCH`.
*/
public static setPrefetchDisable(): void {
Afl.jsApiSetPrefetchDisable();
}
/*
* Set a function to be called for each instruction which is instrumented
* by AFL FRIDA mode.
*/
public static setStalkerCallback(callback: NativePointer): void {
Afl.jsApiSetStalkerCallback(callback);
}
/**
* See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
* an argument.
*/
Afl.setStatsFile(file);
public static setStatsFile(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStatsFile(buf);
}
/*
/**
* See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an
* argument
*/
Afl.setStatsInterval(interval);
public static setStatsInterval(interval: number): void {
Afl.jsApiSetStatsInterval(interval);
}
/*
/**
* See `AFL_FRIDA_STATS_TRANSITIONS`
*/
Afl.setStatsTransitions()
public static setStatsTransitions(): void {
Afl.jsApiSetStatsTransitions();
}
/**
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
* an argument.
*/
public static setStdErr(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdErr(buf);
}
/**
* See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as
* an argument.
*/
public static setStdOut(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdOut(buf);
}
}
```

50
frida_mode/hook/hook.c Normal file
View File

@ -0,0 +1,50 @@
#include <stdint.h>
#include <string.h>
#include "frida-gumjs.h"
#if defined(__x86_64__)
void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf,
uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf,
uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[0];
void **arg2 = &esp[1];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#elif defined(__aarch64__)
void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf,
uint32_t input_buf_len) {
memcpy((void *)regs->x[0], input_buf, input_buf_len);
regs->x[1] = input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

View File

@ -3,10 +3,15 @@
#include "frida-gumjs.h"
typedef gboolean (*js_api_stalker_callback_t)(const cs_insn *insn,
gboolean begin, gboolean excluded,
GumStalkerOutput *output);
extern unsigned char api_js[];
extern unsigned int api_js_len;
extern gboolean js_done;
extern js_api_stalker_callback_t js_user_callback;
/* Frida Mode */
@ -14,5 +19,8 @@ void js_config(void);
void js_start(void);
gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
gboolean excluded, GumStalkerOutput *output);
#endif

View File

@ -13,6 +13,7 @@ guint64 entry_point = 0;
static void entry_launch(void) {
OKF("Entry point reached");
__afl_manual_init();
/* Child here */

View File

@ -11,6 +11,7 @@
#include "entry.h"
#include "frida_cmplog.h"
#include "instrument.h"
#include "js.h"
#include "persistent.h"
#include "prefetch.h"
#include "ranges.h"
@ -165,8 +166,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
}
begin = FALSE;
}
instrument_debug_instruction(instr->address, instr->size);
@ -178,10 +177,16 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
}
if (js_stalker_callback(instr, begin, excluded, output)) {
gum_stalker_iterator_keep(iterator);
}
begin = FALSE;
}
instrument_flush(output);
instrument_debug_end(output);

View File

@ -1,201 +1,243 @@
const write = new NativeFunction(
Module.getExportByName(null, 'write'),
'int',
['int', 'pointer', 'int']
);
const afl_frida_trace = Process.findModuleByName('afl-frida-trace.so');
function get_api(name, ret, args) {
const addr = afl_frida_trace.findExportByName(name);
return new NativeFunction(addr, ret, args);
"use strict";
class Afl {
/**
* This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges.
*/
static addExcludedRange(addressess, size) {
Afl.jsApiAddExcludeRange(addressess, size);
}
const js_api_done = get_api(
'js_api_done',
'void',
[]);
const js_api_error = get_api(
'js_api_error',
'void',
['pointer']);
const js_api_set_entrypoint = get_api(
'js_api_set_entrypoint',
'void',
['pointer']);
const js_api_set_persistent_address = get_api(
'js_api_set_persistent_address',
'void',
['pointer']);
const js_api_set_persistent_return = get_api(
'js_api_set_persistent_return',
'void',
['pointer']);
const js_api_set_persistent_count = get_api(
'js_api_set_persistent_count',
'void',
['uint64']);
const js_api_set_persistent_debug = get_api(
'js_api_set_persistent_debug',
'void',
[]);
const js_api_set_debug_maps = get_api(
'js_api_set_debug_maps',
'void',
[]);
const js_api_add_include_range = get_api(
'js_api_add_include_range',
'void',
['pointer', 'size_t']);
const js_api_add_exclude_range = get_api(
'js_api_add_exclude_range',
'void',
['pointer', 'size_t']);
const js_api_set_instrument_libraries = get_api(
'js_api_set_instrument_libraries',
'void',
[]);
const js_api_set_instrument_debug_file = get_api(
'js_api_set_instrument_debug_file',
'void',
['pointer']);
const js_api_set_prefetch_disable = get_api(
'js_api_set_prefetch_disable',
'void',
[]);
const js_api_set_instrument_no_optimize = get_api(
'js_api_set_instrument_no_optimize',
'void',
[]);
const js_api_set_instrument_trace = get_api(
'js_api_set_instrument_trace',
'void',
[]);
const js_api_set_instrument_trace_unique = get_api(
'js_api_set_instrument_trace_unique',
'void',
[]);
const js_api_set_stdout = get_api(
'js_api_set_stdout',
'void',
['pointer']);
const js_api_set_stderr = get_api(
'js_api_set_stderr',
'void',
['pointer']);
const js_api_set_stats_file = get_api(
'js_api_set_stats_file',
'void',
['pointer']);
const js_api_set_stats_interval = get_api(
'js_api_set_stats_interval',
'void',
['uint64']);
const js_api_set_stats_transitions = get_api(
'js_api_set_stats_transitions',
'void',
[]);
const afl = {
print: function (msg) {
/**
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges.
*/
static addIncludedRange(addressess, size) {
Afl.jsApiAddIncludeRange(addressess, size);
}
/**
* This must always be called at the end of your script. This lets
* FRIDA mode know that your configuration is finished and that
* execution has reached the end of your script. Failure to call
* this will result in a fatal error.
*/
static done() {
Afl.jsApiDone();
}
/**
* This function can be called within your script to cause FRIDA
* mode to trigger a fatal error. This is useful if for example you
* discover a problem you weren't expecting and want everything to
* stop. The user will need to enable `AFL_DEBUG_CHILD=1` to view
* this error message.
*/
static error(msg) {
const buf = Memory.allocUtf8String(msg);
Afl.jsApiError(buf);
}
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the length of
* fuzzing data when using in-memory test case fuzzing.
*/
static getAflFuzzLen() {
return Afl.jsApiGetSymbol("__afl_fuzz_len");
}
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the fuzzing
* data when using in-memory test case fuzzing.
*/
static getAflFuzzPtr() {
return Afl.jsApiGetSymbol("__afl_fuzz_ptr");
}
/**
* Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages.
* If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue.
*/
static print(msg) {
const STDOUT_FILENO = 2;
const log = `${msg}\n`;
const buf = Memory.allocUtf8String(log);
write(STDOUT_FILENO, buf, log.length);
},
done: function() {
js_api_done();
},
error: function(msg) {
const buf = Memory.allocUtf8String(msg);
js_api_error(buf);
},
setEntryPoint: function(addr) {
js_api_set_entrypoint(addr);
},
setPersistentAddress: function(addr) {
js_api_set_persistent_address(addr);
},
setPersistentReturn: function(addr) {
js_api_set_persistent_return(addr);
},
setPersistentCount: function(addr) {
js_api_set_persistent_count(addr);
},
setPersistentDebug: function() {
js_api_set_persistent_debug();
},
setDebugMaps: function() {
js_api_set_debug_maps();
},
addIncludedRange: function(address, size) {
js_api_add_include_range(address, size);
},
addExcludedRange: function(address, size) {
js_api_add_exclude_range(address, size);
},
setInstrumentLibraries: function() {
js_api_set_instrument_libraries();
},
setInstrumentDebugFile: function(file) {
const buf = Memory.allocUtf8String(file);
js_api_set_instrument_debug_file(buf)
},
setPrefetchDisable: function() {
js_api_set_prefetch_disable();
},
setInstrumentNoOptimize: function() {
js_api_set_instrument_no_optimize();
},
setInstrumentEnableTracing: function() {
js_api_set_instrument_trace();
},
setInstrumentTracingUnique: function() {
js_api_set_instrument_trace_unique();
},
setStdOut: function(file) {
const buf = Memory.allocUtf8String(file);
js_api_set_stdout(buf)
},
setStdErr: function(file) {
const buf = Memory.allocUtf8String(file);
js_api_set_stderr(buf)
},
setStatsFile: function(file) {
const buf = Memory.allocUtf8String(file);
js_api_set_stats_file(buf)
},
setStatsInterval: function(interval) {
js_api_set_stats_interval(interval);
},
setStatsTransitions: function() {
js_api_set_stats_transitions();
Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
}
};
Object.defineProperty(global, 'Afl', {value: afl, writeable: false});
////////////////////////////////////////////////////////////////////////////////
// END OF API //
////////////////////////////////////////////////////////////////////////////////
/**
* See `AFL_FRIDA_DEBUG_MAPS`.
*/
static setDebugMaps() {
Afl.jsApiSetDebugMaps();
}
/**
* This has the same effect as setting `AFL_ENTRYPOINT`, but has the
* convenience of allowing you to use FRIDAs APIs to determine the
* address you would like to configure, rather than having to grep
* the output of `readelf` or something similarly ugly. This
* function should be called with a `NativePointer` as its
* argument.
*/
static setEntryPoint(address) {
Afl.jsApiSetEntryPoint(address);
}
/**
* Function used to enable in-memory test cases for fuzzing.
*/
static setInMemoryFuzzing() {
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
}
/**
* See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as
* an argument.
*/
static setInstrumentDebugFile(file) {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetInstrumentDebugFile(buf);
}
/**
* See `AFL_FRIDA_INST_TRACE`.
*/
static setInstrumentEnableTracing() {
Afl.jsApiSetInstrumentTrace();
}
/**
* See `AFL_INST_LIBS`.
*/
static setInstrumentLibraries() {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
static setInstrumentNoOptimize() {
Afl.jsApiSetInstrumentNoOptimize();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
static setInstrumentTracingUnique() {
Afl.jsApiSetInstrumentTraceUnique();
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument.
*/
static setPersistentAddress(address) {
Afl.jsApiSetPersistentAddress(address);
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument.
*/
static setPersistentCount(count) {
Afl.jsApiSetPersistentCount(count);
}
/**
* See `AFL_FRIDA_PERSISTENT_DEBUG`.
*/
static setPersistentDebug() {
Afl.jsApiSetPersistentDebug();
}
/**
* See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an
* argument. See above for examples of use.
*/
static setPersistentHook(address) {
Afl.jsApiSetPersistentHook(address);
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument.
*/
static setPersistentReturn(address) {
Afl.jsApiSetPersistentReturn(address);
}
/**
* See `AFL_FRIDA_INST_NO_PREFETCH`.
*/
static setPrefetchDisable() {
Afl.jsApiSetPrefetchDisable();
}
/*
* Set a function to be called for each instruction which is instrumented
* by AFL FRIDA mode.
*/
static setStalkerCallback(callback) {
Afl.jsApiSetStalkerCallback(callback);
}
/**
* See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
* an argument.
*/
static setStatsFile(file) {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStatsFile(buf);
}
/**
* See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an
* argument
*/
static setStatsInterval(interval) {
Afl.jsApiSetStatsInterval(interval);
}
/**
* See `AFL_FRIDA_STATS_TRANSITIONS`
*/
static setStatsTransitions() {
Afl.jsApiSetStatsTransitions();
}
/**
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
* an argument.
*/
static setStdErr(file) {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdErr(buf);
}
/**
* See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as
* an argument.
*/
static setStdOut(file) {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdOut(buf);
}
static jsApiGetFunction(name, retType, argTypes) {
const addr = Afl.module.getExportByName(name);
return new NativeFunction(addr, retType, argTypes);
}
static jsApiGetSymbol(name) {
return Afl.module.getExportByName(name);
}
}
/**
* Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode
* implementation).
*/
Afl.module = Process.getModuleByName("afl-frida-trace.so");
Afl.jsApiAddExcludeRange = Afl.jsApiGetFunction("js_api_add_exclude_range", "void", ["pointer", "size_t"]);
Afl.jsApiAddIncludeRange = Afl.jsApiGetFunction("js_api_add_include_range", "void", ["pointer", "size_t"]);
Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
Afl.jsApiSetPersistentAddress = Afl.jsApiGetFunction("js_api_set_persistent_address", "void", ["pointer"]);
Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count", "void", ["uint64"]);
Afl.jsApiSetPersistentDebug = Afl.jsApiGetFunction("js_api_set_persistent_debug", "void", []);
Afl.jsApiSetPersistentHook = Afl.jsApiGetFunction("js_api_set_persistent_hook", "void", ["pointer"]);
Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_return", "void", ["pointer"]);
Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []);
Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]);
Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]);
Afl.jsApiSetStatsInterval = Afl.jsApiGetFunction("js_api_set_stats_interval", "void", ["uint64"]);
Afl.jsApiSetStatsTransitions = Afl.jsApiGetFunction("js_api_set_stats_transitions", "void", []);
Afl.jsApiSetStdErr = Afl.jsApiGetFunction("js_api_set_stderr", "void", ["pointer"]);
Afl.jsApiSetStdOut = Afl.jsApiGetFunction("js_api_set_stdout", "void", ["pointer"]);
Afl.jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */
Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);

View File

@ -7,6 +7,7 @@
static char * js_script = NULL;
gboolean js_done = FALSE;
js_api_stalker_callback_t js_user_callback = NULL;
static gchar * filename = "afl.js";
static gchar * contents;
@ -111,3 +112,11 @@ void js_start(void) {
}
gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
gboolean excluded, GumStalkerOutput *output) {
if (js_user_callback == NULL) { return TRUE; }
return js_user_callback(insn, begin, excluded, output);
}

View File

@ -138,5 +138,15 @@ void js_api_set_stats_transitions() {
}
// "AFL_FRIDA_PERSISTENT_HOOK",
void js_api_set_persistent_hook(void *address) {
persistent_hook = address;
}
void js_api_set_stalker_callback(const js_api_stalker_callback_t callback) {
js_user_callback = callback;
}

View File

@ -47,19 +47,6 @@ void persistent_config(void) {
}
}
void persistent_init(void) {
OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_start == 0 ? ' ' : 'X', persistent_start);
OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)",
persistent_start == 0 ? ' ' : 'X', persistent_count);
OKF("Instrumentation - hook [%s]", hook_name);
OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_ret == 0 ? ' ' : 'X', persistent_ret);
if (hook_name == NULL) { return; }
void *hook_obj = dlopen(hook_name, RTLD_NOW);
@ -79,7 +66,20 @@ void persistent_init(void) {
if (persistent_hook == NULL)
FATAL("Failed to find afl_persistent_hook in %s", hook_name);
__afl_sharedmem_fuzzing = 1;
}
void persistent_init(void) {
OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_start == 0 ? ' ' : 'X', persistent_start);
OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)",
persistent_start == 0 ? ' ' : 'X', persistent_count);
OKF("Instrumentation - hook [%s]", hook_name);
OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_ret == 0 ? ' ' : 'X', persistent_ret);
if (persistent_hook != NULL) { __afl_sharedmem_fuzzing = 1; }
}

View File

@ -9,98 +9,14 @@
#include "util.h"
#if defined(__aarch64__)
typedef struct {
struct arm64_regs {
GumCpuContext ctx;
uint64_t rflags;
uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10;
} persistent_ctx_t;
union {
uint64_t x11;
uint32_t fp_32;
};
union {
uint64_t x12;
uint32_t ip_32;
};
union {
uint64_t x13;
uint32_t sp_32;
};
union {
uint64_t x14;
uint32_t lr_32;
};
union {
uint64_t x15;
uint32_t pc_32;
};
union {
uint64_t x16;
uint64_t ip0;
};
union {
uint64_t x17;
uint64_t ip1;
};
uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
union {
uint64_t x29;
uint64_t fp;
};
union {
uint64_t x30;
uint64_t lr;
};
union {
uint64_t x31;
uint64_t sp;
};
// the zero register is not saved here ofc
uint64_t pc;
uint32_t cpsr;
uint8_t vfp_zregs[32][16 * 16];
uint8_t vfp_pregs[17][32];
uint32_t vfp_xregs[16];
};
typedef struct arm64_regs arch_api_regs;
static arch_api_regs saved_regs = {0};
static persistent_ctx_t saved_regs = {0};
static gpointer saved_lr = NULL;
gboolean persistent_is_supported(void) {
@ -110,7 +26,7 @@ gboolean persistent_is_supported(void) {
}
static void instrument_persitent_save_regs(GumArm64Writer * cw,
struct arm64_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
const guint32 mrs_x1_nzcv = 0xd53b4201;
@ -129,83 +45,87 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw,
/* Skip x0 & x1 we'll do that later */
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3,
ARM64_REG_X0, (16 * 1),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5,
ARM64_REG_X0, (16 * 2),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7,
ARM64_REG_X0, (16 * 3),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9,
ARM64_REG_X0, (16 * 4),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11,
ARM64_REG_X0, (16 * 5),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13,
ARM64_REG_X0, (16 * 6),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15,
ARM64_REG_X0, (16 * 7),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17,
ARM64_REG_X0, (16 * 8),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19,
ARM64_REG_X0, (16 * 9),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21,
ARM64_REG_X0, (16 * 10),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23,
ARM64_REG_X0, (16 * 11),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25,
ARM64_REG_X0, (16 * 12),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27,
ARM64_REG_X0, (16 * 13),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29,
ARM64_REG_X0, (16 * 14),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0,
offsetof(GumCpuContext, x[2]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X4, ARM64_REG_X5, ARM64_REG_X0,
offsetof(GumCpuContext, x[4]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X6, ARM64_REG_X7, ARM64_REG_X0,
offsetof(GumCpuContext, x[6]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X8, ARM64_REG_X9, ARM64_REG_X0,
offsetof(GumCpuContext, x[8]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X10, ARM64_REG_X11, ARM64_REG_X0,
offsetof(GumCpuContext, x[10]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X12, ARM64_REG_X13, ARM64_REG_X0,
offsetof(GumCpuContext, x[12]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X14, ARM64_REG_X15, ARM64_REG_X0,
offsetof(GumCpuContext, x[14]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X16, ARM64_REG_X17, ARM64_REG_X0,
offsetof(GumCpuContext, x[16]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X18, ARM64_REG_X19, ARM64_REG_X0,
offsetof(GumCpuContext, x[18]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X20, ARM64_REG_X21, ARM64_REG_X0,
offsetof(GumCpuContext, x[20]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X22, ARM64_REG_X23, ARM64_REG_X0,
offsetof(GumCpuContext, x[22]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X24, ARM64_REG_X25, ARM64_REG_X0,
offsetof(GumCpuContext, x[24]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X26, ARM64_REG_X27, ARM64_REG_X0,
offsetof(GumCpuContext, x[26]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X28, ARM64_REG_X29, ARM64_REG_X0,
offsetof(GumCpuContext, x[28]), GUM_INDEX_SIGNED_OFFSET);
/* LR & Adjusted SP */
gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_SP,
(GUM_RED_ZONE_SIZE + 32));
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X2,
ARM64_REG_X0, (16 * 15),
GUM_INDEX_SIGNED_OFFSET);
/* LR (x30) */
gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0,
offsetof(GumCpuContext, x[30]));
/* PC & CPSR */
/* PC & Adjusted SP (31) */
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2,
GUM_ADDRESS(persistent_start));
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1,
ARM64_REG_X0, (16 * 16),
gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_X3, ARM64_REG_SP,
(GUM_RED_ZONE_SIZE + 32));
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0, offsetof(GumCpuContext, pc),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1,
ARM64_REG_X0, (16 * 17),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3,
ARM64_REG_X0, (16 * 18),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5,
ARM64_REG_X0, (16 * 19),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7,
ARM64_REG_X0, (16 * 20),
GUM_INDEX_SIGNED_OFFSET);
/* CPSR */
gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0,
offsetof(persistent_ctx_t, rflags));
/* Q */
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0,
offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0,
offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0,
offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0,
offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET);
/* x0 & x1 */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3,
ARM64_REG_SP, 16,
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3,
ARM64_REG_X0, (16 * 0),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_stp_reg_reg_reg_offset(
cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0,
offsetof(GumCpuContext, x[0]), GUM_INDEX_SIGNED_OFFSET);
/* Pop the saved values */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
@ -218,7 +138,7 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw,
}
static void instrument_persitent_restore_regs(GumArm64Writer * cw,
struct arm64_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
const guint32 msr_nzcv_x1 = 0xd51b4201;
@ -228,82 +148,81 @@ static void instrument_persitent_restore_regs(GumArm64Writer * cw,
/* Skip x0 - x3 we'll do that last */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5,
ARM64_REG_X0, (16 * 2),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7,
ARM64_REG_X0, (16 * 3),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9,
ARM64_REG_X0, (16 * 4),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11,
ARM64_REG_X0, (16 * 5),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13,
ARM64_REG_X0, (16 * 6),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15,
ARM64_REG_X0, (16 * 7),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17,
ARM64_REG_X0, (16 * 8),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19,
ARM64_REG_X0, (16 * 9),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21,
ARM64_REG_X0, (16 * 10),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23,
ARM64_REG_X0, (16 * 11),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25,
ARM64_REG_X0, (16 * 12),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27,
ARM64_REG_X0, (16 * 13),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29,
ARM64_REG_X0, (16 * 14),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X4, ARM64_REG_X5, ARM64_REG_X0,
offsetof(GumCpuContext, x[4]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X6, ARM64_REG_X7, ARM64_REG_X0,
offsetof(GumCpuContext, x[6]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X8, ARM64_REG_X9, ARM64_REG_X0,
offsetof(GumCpuContext, x[8]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X10, ARM64_REG_X11, ARM64_REG_X0,
offsetof(GumCpuContext, x[10]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X12, ARM64_REG_X13, ARM64_REG_X0,
offsetof(GumCpuContext, x[12]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X14, ARM64_REG_X15, ARM64_REG_X0,
offsetof(GumCpuContext, x[14]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X16, ARM64_REG_X17, ARM64_REG_X0,
offsetof(GumCpuContext, x[16]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X18, ARM64_REG_X19, ARM64_REG_X0,
offsetof(GumCpuContext, x[18]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X20, ARM64_REG_X21, ARM64_REG_X0,
offsetof(GumCpuContext, x[20]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X22, ARM64_REG_X23, ARM64_REG_X0,
offsetof(GumCpuContext, x[22]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X24, ARM64_REG_X25, ARM64_REG_X0,
offsetof(GumCpuContext, x[24]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X26, ARM64_REG_X27, ARM64_REG_X0,
offsetof(GumCpuContext, x[26]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X28, ARM64_REG_X29, ARM64_REG_X0,
offsetof(GumCpuContext, x[28]), GUM_INDEX_SIGNED_OFFSET);
/* LR & Adjusted SP (use x1 as clobber) */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X1,
ARM64_REG_X0, (16 * 15),
GUM_INDEX_SIGNED_OFFSET);
/* LR (x30) */
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0,
offsetof(GumCpuContext, x[30]));
/* Adjusted SP (31) (use x1 as clobber)*/
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0,
offsetof(GumCpuContext, sp));
gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_SP, ARM64_REG_X1);
/* Don't restore RIP use x1-x3 as clobber */
/* PC (x2) & CPSR (x1) */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1,
ARM64_REG_X0, (16 * 16),
GUM_INDEX_SIGNED_OFFSET);
/* CPSR */
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0,
offsetof(persistent_ctx_t, rflags));
gum_arm64_writer_put_instruction(cw, msr_nzcv_x1);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1,
ARM64_REG_X0, (16 * 17),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3,
ARM64_REG_X0, (16 * 18),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5,
ARM64_REG_X0, (16 * 19),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7,
ARM64_REG_X0, (16 * 20),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0,
offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0,
offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0,
offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0,
offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET);
/* x2 & x3 */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3,
ARM64_REG_X0, (16 * 1),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0,
offsetof(GumCpuContext, x[2]), GUM_INDEX_SIGNED_OFFSET);
/* x0 & x1 */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X1,
ARM64_REG_X0, (16 * 0),
GUM_INDEX_SIGNED_OFFSET);
gum_arm64_writer_put_ldp_reg_reg_reg_offset(
cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_X0,
offsetof(GumCpuContext, x[0]), GUM_INDEX_SIGNED_OFFSET);
}
@ -335,28 +254,28 @@ static void instrument_afl_persistent_loop(GumArm64Writer *cw) {
}
static void persistent_prologue_hook(GumArm64Writer * cw,
struct arm64_regs *regs) {
persistent_ctx_t *regs) {
if (persistent_hook == NULL) return;
gum_arm64_writer_put_sub_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP,
GUM_RED_ZONE_SIZE);
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X3,
GUM_ADDRESS(&__afl_fuzz_len));
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0);
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0);
gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X3, ARM64_REG_X3,
G_MAXULONG);
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2,
GUM_ADDRESS(&__afl_fuzz_ptr));
GUM_ADDRESS(&__afl_fuzz_len));
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0);
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0);
gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_X2,
G_MAXULONG);
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X1,
GUM_ADDRESS(&__afl_fuzz_ptr));
gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X1, 0);
gum_arm64_writer_put_call_address_with_arguments(
cw, GUM_ADDRESS(persistent_hook), 4, GUM_ARG_ADDRESS, GUM_ADDRESS(regs),
GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, ARM64_REG_X2,
GUM_ARG_REGISTER, ARM64_REG_X3);
cw, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
GUM_ADDRESS(&regs->ctx), GUM_ARG_REGISTER, ARM64_REG_X1, GUM_ARG_REGISTER,
ARM64_REG_X2);
gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP,
GUM_RED_ZONE_SIZE);
@ -406,6 +325,8 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
OKF("Persistent loop reached");
instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */

View File

@ -10,39 +10,14 @@
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
typedef struct {
GumCpuContext ctx;
uint64_t rflags;
uint64_t flags;
};
} persistent_ctx_t;
uint8_t zmm_regs[32][64];
};
typedef struct x86_64_regs arch_api_regs;
static arch_api_regs saved_regs = {0};
static persistent_ctx_t saved_regs = {0};
static gpointer saved_ret = NULL;
gboolean persistent_is_supported(void) {
@ -52,7 +27,7 @@ gboolean persistent_is_supported(void) {
}
static void instrument_persitent_save_regs(GumX86Writer * cw,
struct x86_64_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
@ -64,41 +39,41 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1),
GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2),
GUM_REG_RCX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3),
GUM_REG_RDX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4),
GUM_REG_RDI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5),
GUM_REG_RSI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6),
GUM_REG_RBP);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7),
GUM_REG_R8);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8),
GUM_REG_R9);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9),
GUM_REG_R10);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10),
GUM_REG_R11);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11),
GUM_REG_R12);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12),
GUM_REG_R13);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13),
GUM_REG_R14);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14),
GUM_REG_R15);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rbx), GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rcx), GUM_REG_RCX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rdx), GUM_REG_RDX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rdi), GUM_REG_RDI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rsi), GUM_REG_RSI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rbp), GUM_REG_RBP);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r8), GUM_REG_R8);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r9), GUM_REG_R9);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r10), GUM_REG_R10);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r11), GUM_REG_R11);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r12), GUM_REG_R12);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r13), GUM_REG_R13);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r14), GUM_REG_R14);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, r15), GUM_REG_R15);
/* Store RIP */
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX,
GUM_ADDRESS(persistent_start));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15),
GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rip), GUM_REG_RBX);
/* Store adjusted RSP */
gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP);
@ -106,18 +81,18 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
/* RED_ZONE + Saved flags, RAX, alignment */
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX,
GUM_RED_ZONE_SIZE + (0x8 * 2));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16),
GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rsp), GUM_REG_RBX);
/* Save the flags */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17),
GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(persistent_ctx_t, rflags), GUM_REG_RBX);
/* Save the RAX */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0),
GUM_REG_RBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_RAX, offsetof(GumCpuContext, rax), GUM_REG_RBX);
/* Pop the saved values */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10);
@ -128,55 +103,55 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
}
static void instrument_persitent_restore_regs(GumX86Writer * cw,
struct x86_64_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX,
(0x8 * 2));
offsetof(GumCpuContext, rcx));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX,
(0x8 * 3));
offsetof(GumCpuContext, rdx));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX,
(0x8 * 4));
offsetof(GumCpuContext, rdi));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX,
(0x8 * 5));
offsetof(GumCpuContext, rsi));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX,
(0x8 * 6));
offsetof(GumCpuContext, rbp));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX,
(0x8 * 7));
offsetof(GumCpuContext, r8));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX,
(0x8 * 8));
offsetof(GumCpuContext, r9));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX,
(0x8 * 9));
offsetof(GumCpuContext, r10));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX,
(0x8 * 10));
offsetof(GumCpuContext, r11));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX,
(0x8 * 11));
offsetof(GumCpuContext, r12));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX,
(0x8 * 12));
offsetof(GumCpuContext, r13));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX,
(0x8 * 13));
offsetof(GumCpuContext, r14));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX,
(0x8 * 14));
offsetof(GumCpuContext, r15));
/* Don't restore RIP */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSP, GUM_REG_RAX,
(0x8 * 16));
offsetof(GumCpuContext, rsp));
/* Restore RBX, RAX & Flags */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
-(GUM_RED_ZONE_SIZE));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
(0x8 * 1));
offsetof(GumCpuContext, rbx));
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
(0x8 * 0));
offsetof(GumCpuContext, rax));
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX,
(0x8 * 17));
offsetof(persistent_ctx_t, rflags));
gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
gum_x86_writer_put_popfx(cw);
@ -217,28 +192,27 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
}
static void persistent_prologue_hook(GumX86Writer * cw,
struct x86_64_regs *regs) {
static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) {
if (persistent_hook == NULL) return;
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
-(GUM_RED_ZONE_SIZE));
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX,
GUM_ADDRESS(&__afl_fuzz_len));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0);
gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff);
gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX,
GUM_ADDRESS(&__afl_fuzz_ptr));
GUM_ADDRESS(&__afl_fuzz_len));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0);
gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff);
gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RDX, GUM_REG_RDI);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RSI,
GUM_ADDRESS(&__afl_fuzz_ptr));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RSI, 0);
gum_x86_writer_put_call_address_with_arguments(
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 4, GUM_ARG_ADDRESS,
GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER,
GUM_REG_RDX, GUM_ARG_REGISTER, GUM_REG_RCX);
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
GUM_ADDRESS(&regs->ctx), GUM_ARG_REGISTER, GUM_REG_RSI, GUM_ARG_REGISTER,
GUM_REG_RDX);
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
(GUM_RED_ZONE_SIZE));
@ -296,6 +270,8 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
OKF("Persistent loop reached");
/* Pop the return value */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 8);

View File

@ -1,44 +1,22 @@
#include "frida-gumjs.h"
#include "config.h"
#include "debug.h"
#include "instrument.h"
#include "persistent.h"
#if defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
typedef struct {
GumCpuContext ctx;
uint32_t eflags;
uint32_t flags;
};
} persistent_ctx_t;
uint8_t xmm_regs[8][16];
static persistent_ctx_t saved_regs = {0};
};
typedef struct x86_regs arch_api_regs;
static arch_api_regs saved_regs = {0};
static gpointer saved_ret = NULL;
gboolean persistent_is_supported(void) {
@ -48,7 +26,7 @@ gboolean persistent_is_supported(void) {
}
static void instrument_persitent_save_regs(GumX86Writer * cw,
struct x86_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
@ -58,43 +36,43 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1),
GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2),
GUM_REG_ECX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3),
GUM_REG_EDX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4),
GUM_REG_EDI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5),
GUM_REG_ESI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6),
GUM_REG_EBP);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, ebx), GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, ecx), GUM_REG_ECX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, edx), GUM_REG_EDX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, edi), GUM_REG_EDI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, esi), GUM_REG_ESI);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, ebp), GUM_REG_EBP);
/* Store RIP */
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX,
GUM_ADDRESS(persistent_start));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7),
GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, eip), GUM_REG_EBX);
/* Store adjusted RSP */
gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP);
/* RED_ZONE + Saved flags, RAX */
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8),
GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, esp), GUM_REG_EBX);
/* Save the flags */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9),
GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(persistent_ctx_t, eflags), GUM_REG_EBX);
/* Save the RAX */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0);
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0),
GUM_REG_EBX);
gum_x86_writer_put_mov_reg_offset_ptr_reg(
cw, GUM_REG_EAX, offsetof(GumCpuContext, eax), GUM_REG_EBX);
/* Pop the saved values */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8);
@ -102,36 +80,36 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
}
static void instrument_persitent_restore_regs(GumX86Writer * cw,
struct x86_regs *regs) {
persistent_ctx_t *regs) {
GumAddress regs_address = GUM_ADDRESS(regs);
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX,
(0x4 * 2));
offsetof(GumCpuContext, ecx));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX,
(0x4 * 3));
offsetof(GumCpuContext, edx));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX,
(0x4 * 4));
offsetof(GumCpuContext, edi));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX,
(0x4 * 5));
offsetof(GumCpuContext, esi));
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
(0x4 * 6));
offsetof(GumCpuContext, ebp));
/* Don't restore RIP */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX,
(0x4 * 8));
offsetof(GumCpuContext, esp));
/* Restore RBX, RAX & Flags */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
(0x4 * 1));
offsetof(GumCpuContext, ebx));
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
(0x4 * 0));
offsetof(GumCpuContext, eax));
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
(0x4 * 9));
offsetof(persistent_ctx_t, eflags));
gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
gum_x86_writer_put_popfx(cw);
@ -165,7 +143,7 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) {
}
static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) {
static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) {
if (persistent_hook == NULL) return;
@ -180,9 +158,8 @@ static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) {
/* Base address is 64-bits (hence two zero arguments) */
gum_x86_writer_put_call_address_with_arguments(
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 5, GUM_ARG_ADDRESS,
GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS,
GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS,
GUM_ADDRESS(&regs->ctx), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER,
GUM_REG_ECX);
}
@ -233,6 +210,8 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
OKF("Persistent loop reached");
/* Pop the return value */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4);

View File

@ -2,8 +2,7 @@ PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
BUILD_DIR:=$(PWD)build/
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so
LIBJPEG_BUILD_DIR:=$(BUILD_DIR)libjpeg/
HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
@ -118,11 +117,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(JPEGTEST_OBJ) $(LIBJPEG_LIB)
$(LDFLAGS) \
$(TEST_BIN_LDFLAGS) \
########## HOOK ########
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
########## DUMMY #######
$(TEST_DATA_DIR): | $(BUILD_DIR)
@ -133,8 +127,6 @@ $(TEST_DATA_FILE): | $(TEST_DATA_DIR)
###### TEST DATA #######
hook: $(AFLPP_DRIVER_HOOK_OBJ)
clean:
rm -rf $(BUILD_DIR)

View File

@ -14,6 +14,3 @@ frida:
debug:
@gmake debug
hook:
@gmake hook

View File

@ -1,97 +0,0 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
uint64_t rflags;
uint64_t flags;
};
uint8_t zmm_regs[32][64];
};
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
uint32_t eflags;
uint32_t flags;
};
uint8_t xmm_regs[8][16];
};
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[1];
void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

View File

@ -1,18 +1,21 @@
PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
BUILD_DIR:=$(PWD)build/
TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
TEST_DATA_DIR:=$(BUILD_DIR)in/
TEST_DATA_FILE:=$(TEST_DATA_DIR)in
TESTINSTBIN:=$(BUILD_DIR)testinstr
TESTINSTSRC:=$(PWD)testinstr.c
TESTINSTBIN:=$(BUILD_DIR)test
TESTINSTSRC:=$(PWD)test.c
TESTINSTBIN2:=$(BUILD_DIR)test2
TESTINSTSRC2:=$(PWD)test2.c
QEMU_OUT:=$(BUILD_DIR)qemu-out
FRIDA_OUT:=$(BUILD_DIR)frida-out
.PHONY: all 32 clean qemu frida
all: $(TESTINSTBIN)
all: $(TESTINSTBIN) $(TESTINSTBIN2)
make -C $(ROOT)frida_mode/
32:
@ -21,24 +24,57 @@ all: $(TESTINSTBIN)
$(BUILD_DIR):
mkdir -p $@
$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
$(TEST_DATA_DIR): | $(BUILD_DIR)
mkdir -p $@
$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
$(TEST_DATA_FILE): | $(TEST_DATA_DIR)
echo -n "000" > $@
$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
$(TESTINSTBIN2): $(TESTINSTSRC2) | $(BUILD_DIR)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
rm -rf $(BUILD_DIR)
frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
AFL_FRIDA_JS_SCRIPT=test.js \
frida_js_entry: $(TESTINSTBIN) $(TEST_DATA_FILE)
AFL_FRIDA_JS_SCRIPT=entry.js \
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TESTINSTR_DATA_DIR) \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@
frida_js_replace: $(TESTINSTBIN) $(TEST_DATA_FILE)
AFL_FRIDA_JS_SCRIPT=replace.js \
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@
frida_js_patch: $(TESTINSTBIN2) $(TEST_DATA_FILE)
AFL_FRIDA_JS_SCRIPT=patch.js \
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN2) @@
frida_js_stalker: $(TESTINSTBIN2) $(TEST_DATA_FILE)
AFL_FRIDA_JS_SCRIPT=stalker.js \
$(ROOT)afl-fuzz \
-D \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN2) @@

View File

@ -9,8 +9,17 @@ all:
clean:
@gmake clean
frida:
@gmake frida
frida_js_entry:
@gmake frida_js_entry
frida_js_replace:
@gmake frida_js_replace
frida_js_patch:
@gmake frida_js_patch
frida_js_stalker:
@gmake frida_js_stalker
debug:
@gmake debug

View File

@ -0,0 +1,34 @@
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
const main = DebugSymbol.fromName('main').address;
Afl.print(`main: ${main}`);
Afl.setEntryPoint(main);
Afl.setPersistentAddress(main);
Afl.setPersistentCount(10000000);
const crc32_check = DebugSymbol.fromName('crc32_check').address;
const crc32_replacement = new NativeCallback(
(buf, len) => {
Afl.print(`len: ${len}`);
if (len < 4) {
return 0;
}
return 1;
},
'int',
['pointer', 'int']);
Interceptor.replace(crc32_check, crc32_replacement);
const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address
const boring_replacement = new NativeCallback(
(c) => { },
'void',
['char']);
Interceptor.replace(some_boring_bug, boring_replacement);
Afl.done();
Afl.print("done");

View File

@ -0,0 +1,43 @@
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
Afl.print(`PID: ${Process.id}`);
const name = Process.enumerateModules()[0].name;
Afl.print(`Name: ${name}`);
new ModuleMap().values().forEach(m => {
Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`);
});
const slow = DebugSymbol.fromName('slow').address;
Afl.print(`slow: ${slow}`);
const LLVMFuzzerTestOneInput = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address;
Afl.print(`LLVMFuzzerTestOneInput: ${LLVMFuzzerTestOneInput}`);
const cm = new CModule(`
extern unsigned char * __afl_fuzz_ptr;
extern unsigned int * __afl_fuzz_len;
extern void LLVMFuzzerTestOneInput(char *buf, int len);
void slow(void) {
LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len);
}
`,
{
LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput,
__afl_fuzz_ptr: Afl.getAflFuzzPtr(),
__afl_fuzz_len: Afl.getAflFuzzLen()
});
Afl.setEntryPoint(cm.slow);
Afl.setPersistentAddress(cm.slow);
Afl.setInMemoryFuzzing();
Interceptor.replace(slow, cm.slow);
Afl.print("done");
Afl.done();

View File

@ -0,0 +1,109 @@
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
const main = DebugSymbol.fromName('main').address;
Afl.print(`main: ${main}`);
Afl.setEntryPoint(main);
Afl.setPersistentAddress(main);
Afl.setPersistentCount(10000000);
/* Replace CRC-32 check */
const crc32_check = DebugSymbol.fromName('crc32_check').address;
const crc32_replacement = new NativeCallback(
(buf, len) => {
if (len < 4) {
return 0;
}
return 1;
},
'int',
['pointer', 'int']);
Interceptor.replace(crc32_check, crc32_replacement);
/* Patch out the first boring bug */
const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address
const boring_replacement = new NativeCallback(
(c) => { },
'void',
['char']);
Interceptor.replace(some_boring_bug, boring_replacement);
/* Modify the instructions */
const some_boring_bug2 = DebugSymbol.fromName('some_boring_bug2').address
const pid = Memory.alloc(4);
pid.writeInt(Process.id);
const cm = new CModule(`
#include <stdio.h>
#include <gum/gumstalker.h>
typedef int pid_t;
#define STDERR_FILENO 2
#define BORING2_LEN 10
extern int dprintf(int fd, const char *format, ...);
extern void some_boring_bug2(char c);
extern pid_t getpid(void);
extern pid_t pid;
gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
gboolean excluded, GumStalkerOutput *output)
{
pid_t my_pid = getpid();
GumX86Writer *cw = output->writer.x86;
if (GUM_ADDRESS(insn->address) < GUM_ADDRESS(some_boring_bug2)) {
return TRUE;
}
if (GUM_ADDRESS(insn->address) >=
GUM_ADDRESS(some_boring_bug2) + BORING2_LEN) {
return TRUE;
}
if (my_pid == pid) {
if (begin) {
dprintf(STDERR_FILENO, "\n> 0x%016lX: %s %s\n", insn->address,
insn->mnemonic, insn->op_str);
} else {
dprintf(STDERR_FILENO, " 0x%016lX: %s %s\n", insn->address,
insn->mnemonic, insn->op_str);
}
}
if (insn->id == X86_INS_UD2) {
gum_x86_writer_put_nop(cw);
return FALSE;
} else {
return TRUE;
}
}
`,
{
dprintf: Module.getExportByName(null, 'dprintf'),
getpid: Module.getExportByName(null, 'getpid'),
some_boring_bug2: some_boring_bug2,
pid: pid
});
Afl.setStalkerCallback(cm.js_stalker_callback)
Afl.setStdErr("/tmp/stderr.txt");
Afl.done();
Afl.print("done");

View File

@ -16,13 +16,7 @@
#include <stdlib.h>
#include <unistd.h>
#ifdef __APPLE__
#define TESTINSTR_SECTION
#else
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
#endif
void testinstr(char *buf, int len) {
void LLVMFuzzerTestOneInput(char *buf, int len) {
if (len < 1) return;
buf[len] = 0;
@ -90,7 +84,7 @@ int run(char *file) {
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
testinstr(buf, len);
LLVMFuzzerTestOneInput(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
result = 0;

177
frida_mode/test/js/test2.c Normal file
View File

@ -0,0 +1,177 @@
/*
american fuzzy lop++ - a trivial program to test the build
--------------------------------------------------------
Originally written by Michal Zalewski
Copyright 2014 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define IGNORED_RETURN(x) (void)!(x)
const uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t
crc32(const void *buf, size_t size)
{
const uint8_t *p = buf;
uint32_t crc;
crc = ~0U;
while (size--)
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
/*
* Don't you hate those contrived examples which CRC their data. We can use
* FRIDA to patch this function out and always return success. Otherwise, we
* could change it to actually correct the checksum.
*/
int crc32_check (char * buf, int len) {
if (len < sizeof(uint32_t)) { return 0; }
uint32_t expected = *(uint32_t *)&buf[len - sizeof(uint32_t)];
uint32_t calculated = crc32(buf, len - sizeof(uint32_t));
return expected == calculated;
}
/*
* So you've found a really boring bug in an earlier campaign which results in
* a NULL dereference or something like that. That bug can get in the way,
* causing the persistent loop to exit whenever it is triggered, and can also
* cloud your output unnecessarily. Again, we can use FRIDA to patch it out.
*/
void some_boring_bug(char c) {
switch (c) {
case 'A'...'Z':
case 'a'...'z':
__builtin_trap();
break;
}
}
extern void some_boring_bug2(char c);
__asm__ (
".text \n"
"some_boring_bug2: \n"
".global some_boring_bug2 \n"
".type some_boring_bug2, @function \n"
"mov %edi, %eax \n"
"cmp $0xb4, %al \n"
"jne ok \n"
"ud2 \n"
"ok: \n"
"ret \n");
void LLVMFuzzerTestOneInput(char *buf, int len) {
if (!crc32_check(buf, len)) return;
some_boring_bug(buf[0]);
some_boring_bug2(buf[0]);
if (buf[0] == '0') {
printf("Looks like a zero to me!\n");
}
else if (buf[0] == '1') {
printf("Pretty sure that is a one!\n");
}
else if (buf[0] == '2') {
printf("Oh we, weren't expecting that!");
__builtin_trap();
}
else
printf("Neither one or zero? How quaint!\n");
}
int main(int argc, char **argv) {
int fd = -1;
off_t len;
char * buf = NULL;
size_t n_read;
int result = -1;
if (argc != 2) { return 1; }
printf("Running: %s\n", argv[1]);
fd = open(argv[1], O_RDONLY);
if (fd < 0) { return 1; }
len = lseek(fd, 0, SEEK_END);
if (len < 0) { return 1; }
if (lseek(fd, 0, SEEK_SET) != 0) { return 1; }
buf = malloc(len);
if (buf == NULL) { return 1; }
n_read = read(fd, buf, len);
if (n_read != len) { return 1; }
printf("Running: %s: (%zd bytes)\n", argv[1], n_read);
LLVMFuzzerTestOneInput(buf, len);
printf("Done: %s: (%zd bytes)\n", argv[1], n_read);
return 0;
}

View File

@ -2,8 +2,7 @@ PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
BUILD_DIR:=$(PWD)build/
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so
LIBPCAP_BUILD_DIR:=$(BUILD_DIR)libpcap/
HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
@ -137,11 +136,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB)
$(LDFLAGS) \
$(TEST_BIN_LDFLAGS) \
########## HOOK ########
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
########## DUMMY #######
$(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR)
@ -149,8 +143,6 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR)
###### TEST DATA #######
hook: $(AFLPP_DRIVER_HOOK_OBJ)
clean:
rm -rf $(BUILD_DIR)

View File

@ -1,97 +0,0 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
uint64_t rflags;
uint64_t flags;
};
uint8_t zmm_regs[32][64];
};
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
uint32_t eflags;
uint32_t flags;
};
uint8_t xmm_regs[8][16];
};
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[1];
void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

View File

@ -90,7 +90,7 @@ frida_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
-i $(TESTINSTR_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TESTINSTBIN) @@
$(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
gdb \
@ -102,6 +102,15 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
--ex 'set disassembly-flavor intel' \
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
debug_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
gdb \
--ex 'set environment AFL_FRIDA_JS_SCRIPT=test.js' \
--ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \
--ex 'set environment AFL_DEBUG_CHILD=1' \
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
--ex 'set disassembly-flavor intel' \
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
run: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \

View File

@ -5,34 +5,44 @@ Afl.print('');
Afl.print(`PID: ${Process.id}`);
const name = Process.enumerateModules()[0].name;
Afl.print(`Name: ${name}`);
new ModuleMap().values().forEach(m => {
Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`);
});
const persistent_addr = DebugSymbol.fromName('main');
Afl.print(`persistent_addr: ${persistent_addr.address}`);
const persistent_ret = DebugSymbol.fromName('slow');
Afl.print(`persistent_ret: ${persistent_ret.address}`);
Afl.setPersistentAddress(persistent_addr.address);
Afl.setPersistentReturn(persistent_ret.address);
Afl.setPersistentCount(1000000);
Afl.setDebugMaps();
const mod = Process.findModuleByName("libc-2.31.so")
Afl.addExcludedRange(mod.base, mod.size);
Afl.setInstrumentLibraries();
Afl.setInstrumentDebugFile("/tmp/instr.log");
Afl.setPrefetchDisable();
if (name === 'testinstr') {
const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address;
Afl.print(`persistent_addr: ${persistent_addr}`);
Afl.setEntryPoint(persistent_addr);
Afl.setPersistentAddress(persistent_addr);
Afl.setInstrumentDebugFile("/dev/stdout");
Afl.setPersistentDebug();
Afl.setInstrumentNoOptimize();
Afl.setInstrumentEnableTracing();
Afl.setInstrumentTracingUnique();
Afl.setStdOut("/tmp/stdout.txt");
Afl.setStdErr("/tmp/stderr.txt");
Afl.setStatsFile("/tmp/stats.txt");
Afl.setStatsInterval(1);
Afl.setStatsTransitions();
Afl.done();
const LLVMFuzzerTestOneInput = new NativeFunction(
persistent_addr,
'void',
['pointer', 'uint64'],
{traps: "all"});
const persistentHook = new NativeCallback(
(data, size) => {
const input = Afl.aflFuzzPtr.readPointer();
const len = Afl.aflFuzzLen.readPointer().readU32();
const hd = hexdump(input, {length: len, header: false, ansi: true});
Afl.print(`input: ${hd}`);
LLVMFuzzerTestOneInput(input, len);
},
'void',
['pointer', 'uint64']);
Afl.aflSharedMemFuzzing.writeInt(1);
Interceptor.replace(persistent_addr, persistentHook);
Interceptor.flush();
}
Afl.print("done");
Afl.done();

View File

@ -17,13 +17,14 @@
#include <unistd.h>
#ifdef __APPLE__
#define TESTINSTR_SECTION
#define MAIN_SECTION
#else
#define TESTINSTR_SECTION __attribute__((section(".testinstr")))
#define MAIN_SECTION __attribute__((section(".main")))
#endif
void testinstr(char *buf, int len) {
void LLVMFuzzerTestOneInput(char *buf, int len) {
printf (">>> LLVMFuzzerTestOneInput >>>\n");
if (len < 1) return;
buf[len] = 0;
@ -43,7 +44,7 @@ void slow() {
}
TESTINSTR_SECTION int main(int argc, char **argv) {
MAIN_SECTION int main(int argc, char **argv) {
char * file;
int fd = -1;
@ -101,7 +102,7 @@ TESTINSTR_SECTION int main(int argc, char **argv) {
dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read);
testinstr(buf, len);
LLVMFuzzerTestOneInput(buf, len);
dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read);
slow();

View File

@ -2,8 +2,7 @@ PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../../../..)/
BUILD_DIR:=$(PWD)build/
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so
CFLAGS+=-O3 \
-funroll-loops \
@ -48,7 +47,7 @@ endif
.PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug
all: $(AFLPP_DRIVER_HOOK_OBJ)
all:
make -C $(ROOT)frida_mode/test/png/persistent/
32:
@ -68,9 +67,6 @@ $(TEST_DATA_DIR): | $(BUILD_DIR)
$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
truncate -s 1M $@
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \
AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \
@ -124,6 +120,28 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
-- \
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
AFL_FRIDA_JS_SCRIPT=load.js \
$(ROOT)afl-fuzz \
-D \
-V 30 \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
frida_js_cmodule: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR)
AFL_FRIDA_JS_SCRIPT=cmodule.js \
$(ROOT)afl-fuzz \
-D \
-V 30 \
-O \
-i $(TEST_DATA_DIR) \
-o $(FRIDA_OUT) \
-- \
$(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT)
debug: $(AFLPP_DRIVER_DUMMY_INPUT)
echo $(AFL_FRIDA_PERSISTENT_ADDR)
gdb \

View File

@ -24,5 +24,8 @@ frida:
frida_entry:
@gmake frida_entry
frida_js:
@gmake frida_js
debug:
@gmake debug

View File

@ -1,193 +0,0 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
uint64_t rflags;
uint64_t flags;
};
uint8_t zmm_regs[32][64];
};
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
uint32_t eflags;
uint32_t flags;
};
uint8_t xmm_regs[8][16];
};
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[1];
void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#elif defined(__aarch64__)
struct arm64_regs {
uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10;
union {
uint64_t x11;
uint32_t fp_32;
};
union {
uint64_t x12;
uint32_t ip_32;
};
union {
uint64_t x13;
uint32_t sp_32;
};
union {
uint64_t x14;
uint32_t lr_32;
};
union {
uint64_t x15;
uint32_t pc_32;
};
union {
uint64_t x16;
uint64_t ip0;
};
union {
uint64_t x17;
uint64_t ip1;
};
uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
union {
uint64_t x29;
uint64_t fp;
};
union {
uint64_t x30;
uint64_t lr;
};
union {
uint64_t x31;
uint64_t sp;
};
// the zero register is not saved here ofc
uint64_t pc;
uint32_t cpsr;
uint8_t vfp_zregs[32][16 * 16];
uint8_t vfp_pregs[17][32];
uint32_t vfp_xregs[16];
};
void afl_persistent_hook(struct arm64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->x0, input_buf, input_buf_len);
regs->x1 = input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

View File

@ -0,0 +1,39 @@
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
Afl.print(`PID: ${Process.id}`);
const name = Process.enumerateModules()[0].name;
Afl.print(`Name: ${name}`);
new ModuleMap().values().forEach(m => {
Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`);
});
const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address;
Afl.print(`persistent_addr: ${persistent_addr}`);
Afl.setEntryPoint(persistent_addr);
Afl.setPersistentAddress(persistent_addr);
const cm = new CModule(`
#include <string.h>
#include <gum/gumdefs.h>
void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf,
uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
`,
{
memcpy: Module.getExportByName(null, 'memcpy')
});
Afl.setPersistentHook(cm.afl_persistent_hook);
Afl.print("done");
Afl.done();

View File

@ -0,0 +1,27 @@
Afl.print('******************');
Afl.print('* AFL FRIDA MODE *');
Afl.print('******************');
Afl.print('');
Afl.print(`PID: ${Process.id}`);
const name = Process.enumerateModules()[0].name;
Afl.print(`Name: ${name}`);
new ModuleMap().values().forEach(m => {
Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`);
});
const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address;
Afl.print(`persistent_addr: ${persistent_addr}`);
Afl.setEntryPoint(persistent_addr);
Afl.setPersistentAddress(persistent_addr);
const path = Afl.module.path;
const dir = path.substring(0, path.lastIndexOf("/"));
const mod = Module.load(`${dir}/frida_mode/build/hook.so`);
const hook = mod.getExportByName('afl_persistent_hook');
Afl.setPersistentHook(hook);
Afl.print("done");
Afl.done();

View File

@ -2,8 +2,7 @@ PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
BUILD_DIR:=$(PWD)build/
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so
LIBPROJ4_BUILD_DIR:=$(BUILD_DIR)libproj4/
HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
@ -118,11 +117,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PROJ4TEST_OBJ) $(LIBPROJ4_LIB)
$(LDFLAGS) \
$(TEST_BIN_LDFLAGS) \
########## HOOK ########
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
########## DUMMY #######
$(TEST_DATA_DIR): | $(BUILD_DIR)
@ -133,8 +127,6 @@ $(TEST_DATA_FILE): | $(TEST_DATA_DIR)
###### TEST DATA #######
hook: $(AFLPP_DRIVER_HOOK_OBJ)
clean:
rm -rf $(BUILD_DIR)

View File

@ -15,5 +15,3 @@ frida:
debug:
@gmake debug
hook:
@gmake hook

View File

@ -1,97 +0,0 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
uint64_t rflags;
uint64_t flags;
};
uint8_t zmm_regs[32][64];
};
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
uint32_t eflags;
uint32_t flags;
};
uint8_t xmm_regs[8][16];
};
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[1];
void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

View File

@ -2,8 +2,7 @@ PWD:=$(shell pwd)/
ROOT:=$(shell realpath $(PWD)../../..)/
BUILD_DIR:=$(PWD)build/
AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c
AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so
AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so
LIBRE2_BUILD_DIR:=$(BUILD_DIR)libre2/
HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/
@ -116,11 +115,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB)
$(LDFLAGS) \
$(TEST_BIN_LDFLAGS) \
########## HOOK ########
$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR)
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
########## DUMMY #######
$(TEST_DATA_DIR): | $(BUILD_DIR)
@ -131,8 +125,6 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR)
###### TEST DATA #######
hook: $(AFLPP_DRIVER_HOOK_OBJ)
clean:
rm -rf $(BUILD_DIR)

View File

@ -18,5 +18,3 @@ frida:
debug:
@gmake debug
hook:
@gmake hook

View File

@ -1,97 +0,0 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
struct x86_64_regs {
uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14,
r15;
union {
uint64_t rip;
uint64_t pc;
};
union {
uint64_t rsp;
uint64_t sp;
};
union {
uint64_t rflags;
uint64_t flags;
};
uint8_t zmm_regs[32][64];
};
void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
memcpy((void *)regs->rdi, input_buf, input_buf_len);
regs->rsi = input_buf_len;
}
#elif defined(__i386__)
struct x86_regs {
uint32_t eax, ebx, ecx, edx, edi, esi, ebp;
union {
uint32_t eip;
uint32_t pc;
};
union {
uint32_t esp;
uint32_t sp;
};
union {
uint32_t eflags;
uint32_t flags;
};
uint8_t xmm_regs[8][16];
};
void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base,
uint8_t *input_buf, uint32_t input_buf_len) {
void **esp = (void **)regs->esp;
void * arg1 = esp[1];
void **arg2 = &esp[2];
memcpy(arg1, input_buf, input_buf_len);
*arg2 = (void *)input_buf_len;
}
#else
#pragma error "Unsupported architecture"
#endif
int afl_persistent_hook_init(void) {
// 1 for shared memory input (faster), 0 for normal input (you have to use
// read(), input_buf will be NULL)
return 1;
}

373
frida_mode/ts/lib/afl.ts Normal file
View File

@ -0,0 +1,373 @@
class Afl {
/**
* Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode
* implementation).
*/
public static module: Module = Process.getModuleByName("afl-frida-trace.so");
/**
* This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to exclude several ranges.
*/
public static addExcludedRange(addressess: NativePointer, size: number): void {
Afl.jsApiAddExcludeRange(addressess, size);
}
/**
* This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
* it takes as arguments a `NativePointer` and a `number`. It can be
* called multiple times to include several ranges.
*/
public static addIncludedRange(addressess: NativePointer, size: number): void {
Afl.jsApiAddIncludeRange(addressess, size);
}
/**
* This must always be called at the end of your script. This lets
* FRIDA mode know that your configuration is finished and that
* execution has reached the end of your script. Failure to call
* this will result in a fatal error.
*/
public static done(): void {
Afl.jsApiDone();
}
/**
* This function can be called within your script to cause FRIDA
* mode to trigger a fatal error. This is useful if for example you
* discover a problem you weren't expecting and want everything to
* stop. The user will need to enable `AFL_DEBUG_CHILD=1` to view
* this error message.
*/
public static error(msg: string): void {
const buf = Memory.allocUtf8String(msg);
Afl.jsApiError(buf);
}
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the length of
* fuzzing data when using in-memory test case fuzzing.
*/
public static getAflFuzzLen(): NativePointer {
return Afl.jsApiGetSymbol("__afl_fuzz_len");
}
/**
* Function used to provide access to `__afl_fuzz_ptr`, which contains the fuzzing
* data when using in-memory test case fuzzing.
*/
public static getAflFuzzPtr(): NativePointer {
return Afl.jsApiGetSymbol("__afl_fuzz_ptr");
}
/**
* Print a message to the STDOUT. This should be preferred to
* FRIDA's `console.log` since FRIDA will queue it's log messages.
* If `console.log` is used in a callback in particular, then there
* may no longer be a thread running to service this queue.
*/
public static print(msg: string): void {
const STDOUT_FILENO = 2;
const log = `${msg}\n`;
const buf = Memory.allocUtf8String(log);
Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
}
/**
* See `AFL_FRIDA_DEBUG_MAPS`.
*/
public static setDebugMaps(): void {
Afl.jsApiSetDebugMaps();
}
/**
* This has the same effect as setting `AFL_ENTRYPOINT`, but has the
* convenience of allowing you to use FRIDAs APIs to determine the
* address you would like to configure, rather than having to grep
* the output of `readelf` or something similarly ugly. This
* function should be called with a `NativePointer` as its
* argument.
*/
public static setEntryPoint(address: NativePointer): void {
Afl.jsApiSetEntryPoint(address);
}
/**
* Function used to enable in-memory test cases for fuzzing.
*/
public static setInMemoryFuzzing(): void {
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
}
/**
* See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as
* an argument.
*/
public static setInstrumentDebugFile(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetInstrumentDebugFile(buf);
}
/**
* See `AFL_FRIDA_INST_TRACE`.
*/
public static setInstrumentEnableTracing(): void {
Afl.jsApiSetInstrumentTrace();
}
/**
* See `AFL_INST_LIBS`.
*/
public static setInstrumentLibraries(): void {
Afl.jsApiSetInstrumentLibraries();
}
/**
* See `AFL_FRIDA_INST_NO_OPTIMIZE`
*/
public static setInstrumentNoOptimize(): void {
Afl.jsApiSetInstrumentNoOptimize();
}
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
public static setInstrumentTracingUnique(): void {
Afl.jsApiSetInstrumentTraceUnique();
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
* `NativePointer` should be provided as it's argument.
*/
public static setPersistentAddress(address: NativePointer): void {
Afl.jsApiSetPersistentAddress(address);
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
* `number` should be provided as it's argument.
*/
public static setPersistentCount(count: number): void {
Afl.jsApiSetPersistentCount(count);
}
/**
* See `AFL_FRIDA_PERSISTENT_DEBUG`.
*/
public static setPersistentDebug(): void {
Afl.jsApiSetPersistentDebug();
}
/**
* See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an
* argument. See above for examples of use.
*/
public static setPersistentHook(address: NativePointer): void {
Afl.jsApiSetPersistentHook(address);
}
/**
* This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
* `NativePointer` should be provided as it's argument.
*/
public static setPersistentReturn(address: NativePointer): void {
Afl.jsApiSetPersistentReturn(address);
}
/**
* See `AFL_FRIDA_INST_NO_PREFETCH`.
*/
public static setPrefetchDisable(): void {
Afl.jsApiSetPrefetchDisable();
}
/*
* Set a function to be called for each instruction which is instrumented
* by AFL FRIDA mode.
*/
public static setStalkerCallback(callback: NativePointer): void {
Afl.jsApiSetStalkerCallback(callback);
}
/**
* See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
* an argument.
*/
public static setStatsFile(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStatsFile(buf);
}
/**
* See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an
* argument
*/
public static setStatsInterval(interval: number): void {
Afl.jsApiSetStatsInterval(interval);
}
/**
* See `AFL_FRIDA_STATS_TRANSITIONS`
*/
public static setStatsTransitions(): void {
Afl.jsApiSetStatsTransitions();
}
/**
* See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
* an argument.
*/
public static setStdErr(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdErr(buf);
}
/**
* See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as
* an argument.
*/
public static setStdOut(file: string): void {
const buf = Memory.allocUtf8String(file);
Afl.jsApiSetStdOut(buf);
}
private static readonly jsApiAddExcludeRange = Afl.jsApiGetFunction(
"js_api_add_exclude_range",
"void",
["pointer", "size_t"]);
private static readonly jsApiAddIncludeRange = Afl.jsApiGetFunction(
"js_api_add_include_range",
"void",
["pointer", "size_t"]);
private static readonly jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
private static readonly jsApiDone = Afl.jsApiGetFunction(
"js_api_done",
"void",
[]);
private static readonly jsApiError = Afl.jsApiGetFunction(
"js_api_error",
"void",
["pointer"]);
private static readonly jsApiSetDebugMaps = Afl.jsApiGetFunction(
"js_api_set_debug_maps",
"void",
[]);
private static readonly jsApiSetEntryPoint = Afl.jsApiGetFunction(
"js_api_set_entrypoint",
"void",
["pointer"]);
private static readonly jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction(
"js_api_set_instrument_debug_file",
"void",
["pointer"]);
private static readonly jsApiSetInstrumentLibraries = Afl.jsApiGetFunction(
"js_api_set_instrument_libraries",
"void",
[]);
private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction(
"js_api_set_instrument_no_optimize",
"void",
[]);
private static readonly jsApiSetInstrumentTrace = Afl.jsApiGetFunction(
"js_api_set_instrument_trace",
"void",
[]);
private static readonly jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction(
"js_api_set_instrument_trace_unique",
"void",
[]);
private static readonly jsApiSetPersistentAddress = Afl.jsApiGetFunction(
"js_api_set_persistent_address",
"void",
["pointer"]);
private static readonly jsApiSetPersistentCount = Afl.jsApiGetFunction(
"js_api_set_persistent_count",
"void",
["uint64"]);
private static readonly jsApiSetPersistentDebug = Afl.jsApiGetFunction(
"js_api_set_persistent_debug",
"void",
[]);
private static readonly jsApiSetPersistentHook = Afl.jsApiGetFunction(
"js_api_set_persistent_hook",
"void",
["pointer"]);
private static readonly jsApiSetPersistentReturn = Afl.jsApiGetFunction(
"js_api_set_persistent_return",
"void",
["pointer"]);
private static readonly jsApiSetPrefetchDisable = Afl.jsApiGetFunction(
"js_api_set_prefetch_disable",
"void",
[]);
private static readonly jsApiSetStalkerCallback = Afl.jsApiGetFunction(
"js_api_set_stalker_callback",
"void",
["pointer"]);
private static readonly jsApiSetStatsFile = Afl.jsApiGetFunction(
"js_api_set_stats_file",
"void",
["pointer"]);
private static readonly jsApiSetStatsInterval = Afl.jsApiGetFunction(
"js_api_set_stats_interval",
"void",
["uint64"]);
private static readonly jsApiSetStatsTransitions = Afl.jsApiGetFunction(
"js_api_set_stats_transitions",
"void",
[]);
private static readonly jsApiSetStdErr = Afl.jsApiGetFunction(
"js_api_set_stderr",
"void",
["pointer"]);
private static readonly jsApiSetStdOut = Afl.jsApiGetFunction(
"js_api_set_stdout",
"void",
["pointer"]);
private static readonly jsApiWrite = new NativeFunction(
/* tslint:disable-next-line:no-null-keyword */
Module.getExportByName(null, "write"),
"int",
["int", "pointer", "int"]);
private static jsApiGetFunction(name: string, retType: NativeType, argTypes: NativeType[]): NativeFunction {
const addr: NativePointer = Afl.module.getExportByName(name);
return new NativeFunction(addr, retType, argTypes);
}
private static jsApiGetSymbol(name: string): NativePointer {
return Afl.module.getExportByName(name);
}
}

12
frida_mode/ts/package-lock.json generated Normal file
View File

@ -0,0 +1,12 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"tsc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.3.tgz",
"integrity": "sha512-SN+9zBUtrpUcOpaUO7GjkEHgWtf22c7FKbKCA4e858eEM7Qz86rRDpgOU2lBIDf0fLCsEg65ms899UMUIB2+Ow==",
"dev": true
}
}
}

View File

@ -0,0 +1,32 @@
{
"name": "@worksbutnottested/aflplusplus-frida",
"version": "1.0.0",
"description": "AFLplusplus Frida Mode",
"main": "./dist/frida.js",
"types": "./dist/frida.d.ts",
"files": [
"/dist/"
],
"repository": {
"type": "git",
"url": "git@github.com:worksbutnottested/AFLplusplus.git"
},
"publishConfig": {
"cache": "~/.npm",
"registry": "https://npm.pkg.github.com/@worksbutnottested"
},
"scripts": {
"prepare": "npm run build",
"build": "tsc",
"lint": "tslint -p tslint.json"
},
"devDependencies": {
"@types/node": "^14.14.2",
"typescript": "^4.0.3",
"typescript-tslint-plugin": "^0.5.5",
"tslint": "^6.1.3"
},
"dependencies": {
"@types/frida-gum": "^16.2.0"
}
}

View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es2020",
"lib": ["es2020"],
"strict": true,
"module": "commonjs",
"esModuleInterop": true,
"declaration": true,
"outDir": "./dist"
},
"include": [
"lib/**/*"
]
}

256
frida_mode/ts/tslint.json Normal file
View File

@ -0,0 +1,256 @@
{
"rules": {
"adjacent-overload-signatures": true,
"ban-types": {
"options": [
["Object", "Avoid using the `Object` type. Did you mean `object`?"],
[
"Function",
"Avoid using the `Function` type. Prefer a specific function type, like `() => void`."
],
["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"],
["Number", "Avoid using the `Number` type. Did you mean `number`?"],
["String", "Avoid using the `String` type. Did you mean `string`?"],
["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"]
]
},
"ban-ts-ignore": true,
"member-access": {
"options": ["check-accessor", "check-constructor", "check-parameter-property"]
},
"member-ordering": {
"options": {
"order": "statics-first",
"alphabetize": true
}
},
"no-any": true,
"no-empty-interface": true,
"no-for-in": true,
"no-import-side-effect": true,
"no-inferrable-types": { "options": ["ignore-params"] },
"no-internal-module": true,
"no-magic-numbers": true,
"no-namespace": true,
"no-non-null-assertion": true,
"no-reference": true,
"no-restricted-globals": true,
"no-this-assignment": true,
"no-var-requires": true,
"only-arrow-functions": true,
"prefer-for-of": true,
"prefer-readonly": true,
"promise-function-async": true,
"typedef": {
"options": [
"call-signature",
"parameter",
"property-declaration"
]
},
"typedef-whitespace": {
"options": [
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
},
"unified-signatures": true,
"await-promise": true,
"ban-comma-operator": true,
"curly": true,
"forin": true,
"function-constructor": true,
"label-position": true,
"no-arg": true,
"no-async-without-await": true,
"no-bitwise": true,
"no-conditional-assignment": true,
"no-console": true,
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-duplicate-switch-case": true,
"no-duplicate-variable": { "options": ["check-parameters"] },
"no-dynamic-delete": true,
"no-empty": true,
"no-eval": true,
"no-floating-promises": true,
"no-for-in-array": true,
"no-implicit-dependencies": true,
"no-inferred-empty-object-type": true,
"no-invalid-template-strings": true,
"no-misused-new": true,
"no-null-keyword": true,
"no-null-undefined-union": true,
"no-object-literal-type-assertion": true,
"no-promise-as-boolean": true,
"no-return-await": true,
"no-shadowed-variable": true,
"no-string-literal": true,
"no-string-throw": true,
"no-sparse-arrays": true,
"no-submodule-imports": true,
"no-tautology-expression": true,
"no-unbound-method": true,
"no-unnecessary-class": { "options": ["allow-empty-class", "allow-static-only"] },
"no-unsafe-any": false,
"no-unsafe-finally": true,
"no-unused-expression": true,
"no-var-keyword": true,
"no-void-expression": true,
"prefer-conditional-expression": true,
"radix": true,
"restrict-plus-operands": true,
"static-this": true,
"strict-boolean-expressions": true,
"strict-string-expressions": true,
"strict-comparisons": true,
"strict-type-predicates": true,
"switch-default": true,
"triple-equals": true,
"unnecessary-constructor": true,
"use-default-type-parameter": true,
"use-isnan": true,
"cyclomatic-complexity": true,
"eofline": true,
"indent": { "options": ["spaces"] },
"invalid-void": true,
"linebreak-style": { "options": "LF" },
"max-classes-per-file": { "options": 1 },
"max-file-line-count": { "options": 1000 },
"max-line-length": {
"options": { "limit": 120 }
},
"no-default-export": true,
"no-default-import": true,
"no-duplicate-imports": true,
"no-irregular-whitespace": true,
"no-mergeable-namespace": true,
"no-parameter-reassignment": true,
"no-require-imports": true,
"no-trailing-whitespace": true,
"object-literal-sort-keys": true,
"prefer-const": true,
"trailing-comma": {
"options": {
"esSpecCompliant": true,
"multiline": "always",
"singleline": "never"
}
},
"align": {
"options": ["parameters", "arguments", "statements", "elements", "members"]
},
"array-type": { "options": "array-simple" },
"arrow-parens": true,
"arrow-return-shorthand": { "options": "multiline" },
"binary-expression-operand-order": true,
"callable-types": true,
"class-name": true,
"comment-format": { "options": ["check-space", "check-uppercase"] },
"comment-type": { "options": ["singleline", "multiline", "doc", "directive"] },
"completed-docs": [
true,
{
"enums": true,
"methods": {"locations": "all", "privacies": ["public", "protected"]},
"properties": {"locations": "all", "privacies": ["public", "protected"]}
}
],
"deprecation": true,
"encoding": true,
"file-name-casing": { "options": "camel-case" },
"import-spacing": true,
"increment-decrement": true,
"interface-name": true,
"interface-over-type-literal": true,
"jsdoc-format": { "options": "check-multiline-start" },
"match-default-export-name": true,
"new-parens": true,
"newline-before-return": true,
"newline-per-chained-call": true,
"no-angle-bracket-type-assertion": true,
"no-boolean-literal-compare": true,
"no-consecutive-blank-lines": true,
"no-parameter-properties": true,
"no-redundant-jsdoc": true,
"no-reference-import": true,
"no-unnecessary-callback-wrapper": true,
"no-unnecessary-initializer": true,
"no-unnecessary-qualifier": true,
"no-unnecessary-type-assertion": true,
"number-literal-format": true,
"object-literal-key-quotes": { "options": "consistent-as-needed" },
"object-literal-shorthand": true,
"one-line": {
"options": [
"check-catch",
"check-else",
"check-finally",
"check-open-brace",
"check-whitespace"
]
},
"one-variable-per-declaration": true,
"ordered-imports": {
"options": {
"grouped-imports": true,
"import-sources-order": "case-insensitive",
"named-imports-order": "case-insensitive",
"module-source-path": "full"
}
},
"prefer-function-over-method": true,
"prefer-method-signature": true,
"prefer-object-spread": true,
"prefer-switch": true,
"prefer-template": true,
"prefer-while": true,
"quotemark": {
"options": ["double", "avoid-escape", "avoid-template"]
},
"return-undefined": true,
"semicolon": { "options": ["always"] },
"space-before-function-paren": {
"options": {
"anonymous": "never",
"asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
},
"space-within-parens": { "options": 0 },
"switch-final-break": true,
"type-literal-delimiter": true,
"unnecessary-bind": true,
"unnecessary-else": true,
"variable-name": { "options": ["ban-keywords", "check-format", "require-const-for-all-caps"] },
"whitespace": {
"options": [
"check-branch",
"check-decl",
"check-operator",
"check-module",
"check-separator",
"check-type",
"check-typecast",
"check-preblock",
"check-type-operator",
"check-rest-spread"
]
}
}
}