From a536af6e16fe2da284cbde7a63237f60eab738ba Mon Sep 17 00:00:00 2001 From: em0 <1834530227@qq.com> Date: Wed, 8 Jan 2025 22:33:39 +0800 Subject: [PATCH] dislocator --- src/libdislocator/libdislocator.so.c | 210 ++++++++++++++------------- 1 file changed, 109 insertions(+), 101 deletions(-) diff --git a/src/libdislocator/libdislocator.so.c b/src/libdislocator/libdislocator.so.c index 8f415d5..0d41c29 100644 --- a/src/libdislocator/libdislocator.so.c +++ b/src/libdislocator/libdislocator.so.c @@ -36,19 +36,19 @@ #include "../types.h" #ifndef PAGE_SIZE -# define PAGE_SIZE 4096 +# define PAGE_SIZE 4096 // 定义页面大小为4096字节 #endif /* !PAGE_SIZE */ #ifndef MAP_ANONYMOUS -# define MAP_ANONYMOUS MAP_ANON +# define MAP_ANONYMOUS MAP_ANON // 定义MAP_ANONYMOUS为MAP_ANON,用于匿名映射 #endif /* !MAP_ANONYMOUS */ -/* Error / message handling: */ +/* 错误/消息处理: */ #define DEBUGF(_x...) do { \ if (alloc_verbose) { \ if (++call_depth == 1) { \ - fprintf(stderr, "[AFL] " _x); \ + fprintf(stderr, "[AFL] " _x); // 输出调试信息 fprintf(stderr, "\n"); \ } \ call_depth--; \ @@ -57,101 +57,97 @@ #define FATAL(_x...) do { \ if (++call_depth == 1) { \ - fprintf(stderr, "*** [AFL] " _x); \ + fprintf(stderr, "*** [AFL] " _x); // 输出致命错误信息 fprintf(stderr, " ***\n"); \ - abort(); \ + abort(); // 终止程序 } \ call_depth--; \ } while (0) -/* Macro to count the number of pages needed to store a buffer: */ +/* 宏来计算存储缓冲区所需的页面数量: */ -#define PG_COUNT(_l) (((_l) + (PAGE_SIZE - 1)) / PAGE_SIZE) +#define PG_COUNT(_l) (((_l) + (PAGE_SIZE - 1)) / PAGE_SIZE) // 计算所需页面数,向上取整 /* Canary & clobber bytes: */ -#define ALLOC_CANARY 0xAACCAACC -#define ALLOC_CLOBBER 0xCC +#define ALLOC_CANARY 0xAACCAACC // 定义canary值 +#define ALLOC_CLOBBER 0xCC // 定义clobber值 -#define PTR_C(_p) (((u32*)(_p))[-1]) -#define PTR_L(_p) (((u32*)(_p))[-2]) +#define PTR_C(_p) (((u32*)(_p))[-1]) // 获取canary值的指针 +#define PTR_L(_p) (((u32*)(_p))[-2]) // 获取分配长度值的指针 -/* Configurable stuff (use AFL_LD_* to set): */ +/* 可配置项(使用AFL_LD_*来设置): */ -static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */ -static u8 alloc_verbose, /* Additional debug messages */ - hard_fail, /* abort() when max_mem exceeded? */ - no_calloc_over; /* abort() on calloc() overflows? */ +static u32 max_mem = MAX_ALLOC; /* 允许的最大堆使用量 */ +static u8 alloc_verbose, /* 是否显示额外的调试消息 */ + hard_fail, /* 当超过max_mem时是否使用abort() */ + no_calloc_over; /* 对calloc()溢出是否使用abort() */ -static __thread size_t total_mem; /* Currently allocated mem */ +static __thread size_t total_mem; /* 当前已分配的内存 */ -static __thread u32 call_depth; /* To avoid recursion via fprintf() */ +static __thread u32 call_depth; /* 避免通过fprintf()引起的递归 */ - -/* This is the main alloc function. It allocates one page more than necessary, - sets that tailing page to PROT_NONE, and then increments the return address - so that it is right-aligned to that boundary. Since it always uses mmap(), - the returned memory will be zeroed. */ +/* 这是主要的分配函数。它分配比必要多一个页面的内存, + 将最后一个页面设置为PROT_NONE,并然后增加返回地址 + 使其对齐到该边界。由于它总是使用mmap(), + 返回的内存将是零化的。 */ static void* __dislocator_alloc(size_t len) { void* ret; - if (total_mem + len > max_mem || total_mem + len < total_mem) { if (hard_fail) - FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024); + FATAL("total allocs exceed %u MB", max_mem / 1024 / 1024); // 如果超过最大内存且hard_fail为真,输出错误并终止程序 DEBUGF("total allocs exceed %u MB, returning NULL", - max_mem / 1024 / 1024); + max_mem / 1024 / 1024); // 如果超过最大内存且hard_fail为假,输出调试信息并返回NULL return NULL; } - /* We will also store buffer length and a canary below the actual buffer, so - let's add 8 bytes for that. */ + /* 我们还会在实际缓冲区下面存储缓冲区长度和canary, + 因此让我们加上8个字节以存储这些信息。 */ ret = mmap(NULL, (1 + PG_COUNT(len + 8)) * PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // 使用mmap分配内存 if (ret == (void*)-1) { - if (hard_fail) FATAL("mmap() failed on alloc (OOM?)"); + if (hard_fail) FATAL("mmap() failed on alloc (OOM?)"); // 如果mmap失败且hard_fail为真,输出错误并终止程序 - DEBUGF("mmap() failed on alloc (OOM?)"); + DEBUGF("mmap() failed on alloc (OOM?)"); // 如果mmap失败且hard_fail为假,输出调试信息并返回NULL return NULL; } - /* Set PROT_NONE on the last page. */ + /* 在最后一个页面设置PROT_NONE。 */ if (mprotect(ret + PG_COUNT(len + 8) * PAGE_SIZE, PAGE_SIZE, PROT_NONE)) - FATAL("mprotect() failed when allocating memory"); + FATAL("mprotect() failed when allocating memory"); // 如果mprotect失败,输出错误并终止程序 - /* Offset the return pointer so that it's right-aligned to the page - boundary. */ + /* 增加返回指针,使其对齐到页面边界。 */ ret += PAGE_SIZE * PG_COUNT(len + 8) - len - 8; - /* Store allocation metadata. */ + /* 存储分配元数据。 */ ret += 8; - PTR_L(ret) = len; - PTR_C(ret) = ALLOC_CANARY; + PTR_L(ret) = len; // 存储分配长度 + PTR_C(ret) = ALLOC_CANARY; // 存储canary值 - total_mem += len; + total_mem += len; // 增加已分配内存计数 return ret; } - -/* The "user-facing" wrapper for calloc(). This just checks for overflows and - displays debug messages if requested. */ +/* 面向用户的calloc()包装器。这只是一个溢出检查和 + 在请求时显示调试消息。 */ void* calloc(size_t elem_len, size_t elem_cnt) { @@ -159,42 +155,40 @@ void* calloc(size_t elem_len, size_t elem_cnt) { size_t len = elem_len * elem_cnt; - /* Perform some sanity checks to detect obvious issues... */ + /* 进行一些简单的检查,以检测明显的错误... */ if (elem_cnt && len / elem_cnt != elem_len) { if (no_calloc_over) { - DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len, elem_cnt); + DEBUGF("calloc(%zu, %zu) would overflow, returning NULL", elem_len, elem_cnt); // 如果no_calloc_over为真,输出调试信息并返回NULL return NULL; } - FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt); + FATAL("calloc(%zu, %zu) would overflow", elem_len, elem_cnt); // 如果no_calloc_over为假,输出错误并终止程序 } - ret = __dislocator_alloc(len); + ret = __dislocator_alloc(len); // 调用内部分配函数 DEBUGF("calloc(%zu, %zu) = %p [%zu total]", elem_len, elem_cnt, ret, - total_mem); + total_mem); // 输出调试信息 return ret; } - -/* The wrapper for malloc(). Roughly the same, also clobbers the returned - memory (unlike calloc(), malloc() is not guaranteed to return zeroed - memory). */ +/* malloc()的包装器。大致相同, + 也会污染返回的内存(与calloc()不同,malloc()不保证返回零化的内存)。 */ void* malloc(size_t len) { void* ret; - ret = __dislocator_alloc(len); + ret = __dislocator_alloc(len); // 调用内部分配函数 - DEBUGF("malloc(%zu) = %p [%zu total]", len, ret, total_mem); + DEBUGF("malloc(%zu) = %p [%zu total]", len, ret, total_mem); // 输出调试信息 - if (ret && len) memset(ret, ALLOC_CLOBBER, len); + if (ret && len) memset(ret, ALLOC_CLOBBER, len); // 使用clobber值填充内存 return ret; @@ -206,70 +200,84 @@ void* malloc(size_t len) { read the canary. Not very graceful, but works, right? */ void free(void* ptr) { + // 定义一个变量len用于存储要释放的内存块的长度 + u32 len; - u32 len; - - DEBUGF("free(%p)", ptr); - - if (!ptr) return; - - if (PTR_C(ptr) != ALLOC_CANARY) FATAL("bad allocator canary on free()"); + // 调试信息,打印正在释放的内存指针地址 + DEBUGF("free(%p)", ptr); - len = PTR_L(ptr); + // 如果指针为NULL,直接返回,不进行任何操作 + if (!ptr) return; - total_mem -= len; + // 检查指针的canary值是否正确,如果不正确,程序将致命错误并退出 + if (PTR_C(ptr) != ALLOC_CANARY) FATAL("bad allocator canary on free()"); - /* Protect everything. Note that the extra page at the end is already - set as PROT_NONE, so we don't need to touch that. */ + // 获取指针所指向的内存块的实际长度 + len = PTR_L(ptr); - ptr -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8; + // 减少全局变量total_mem的值,表示当前分配的内存总大小减少 + total_mem -= len; - if (mprotect(ptr - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE)) - FATAL("mprotect() failed when freeing memory"); + // 计算出内存块的实际起始地址,以便后续对整个内存块进行操作 + // 减去len+8是因为在分配内存时,内存块的前面8个字节用于存储canary和长度信息 + ptr -= PAGE_SIZE * PG_COUNT(len + 8) - len - 8; - /* Keep the mapping; this is wasteful, but prevents ptr reuse. */ + // 使用mprotect系统调用来将内存块的权限设置为PROT_NONE,即无法读写执行 + // 这样可以防止内存块被再次使用,增加了程序的安全性 + if (mprotect(ptr - 8, PG_COUNT(len + 8) * PAGE_SIZE, PROT_NONE)) + FATAL("mprotect() failed when freeing memory"); + // 保持内存映射的存在,虽然这样做会浪费一些内存,但是防止内存地址被重复使用 + // 这是一种保护机制,防止使用已经释放的内存 } - -/* Realloc is pretty straightforward, too. We forcibly reallocate the buffer, - move data, and then free (aka mprotect()) the original one. */ - +/* realloc函数用于重新分配内存,其逻辑是: + 1. 为新的长度分配内存 + 2. 将原始内存中的数据复制到新分配的内存中 + 3. 释放原始内存(通过调用free函数来实现,free函数中会调用mprotect来保护原始内存) +*/ void* realloc(void* ptr, size_t len) { + // 定义一个指针ret用于存储新分配的内存地址 + void* ret; - void* ret; - - ret = malloc(len); - - if (ret && ptr) { + // 为新的长度分配内存,分配失败时ret为NULL + ret = malloc(len); - if (PTR_C(ptr) != ALLOC_CANARY) FATAL("bad allocator canary on realloc()"); + // 如果新内存分配成功且原始指针不为NULL,则进行数据复制和原始内存释放 + if (ret && ptr) { + // 检查原始指针的canary值是否正确,如果不正确,程序将致命错误并退出 + if (PTR_C(ptr) != ALLOC_CANARY) FATAL("bad allocator canary on realloc()"); - memcpy(ret, ptr, MIN(len, PTR_L(ptr))); - free(ptr); - - } + // 将原始内存中的数据复制到新分配的内存中,复制的数据长度为原始内存和新内存长度的最小值 + memcpy(ret, ptr, MIN(len, PTR_L(ptr))); + // 释放原始内存,free函数中同样会调用mprotect来保护原始内存 + free(ptr); + } - DEBUGF("realloc(%p, %zu) = %p [%zu total]", ptr, len, ret, total_mem); - - return ret; + // 调试信息,打印原始指针地址、新长度、新内存地址以及当前分配的总内存大小 + DEBUGF("realloc(%p, %zu) = %p [%zu total]", ptr, len, ret, total_mem); + // 返回新分配的内存地址 + return ret; } - +// __dislocator_init函数在程序加载时通过构造函数属性自动执行 __attribute__((constructor)) void __dislocator_init(void) { + // 定义一个临时变量tmp用于存储环境变量AFL_LD_LIMIT_MB的值 + u8* tmp = getenv("AFL_LD_LIMIT_MB"); + + // 如果环境变量AFL_LD_LIMIT_MB存在,则将其转换为max_mem的值(以字节为单位) + if (tmp) { + // atoi将字符串转换为整数,乘以1024*1024表示将MB转换为字节 + max_mem = atoi(tmp) * 1024 * 1024; + // 如果转换后的max_mem为0,表示环境变量设置不正确,程序将致命错误并退出 + if (!max_mem) FATAL("Bad value for AFL_LD_LIMIT_MB"); + } - u8* tmp = getenv("AFL_LD_LIMIT_MB"); - - if (tmp) { - - max_mem = atoi(tmp) * 1024 * 1024; - if (!max_mem) FATAL("Bad value for AFL_LD_LIMIT_MB"); - - } - - alloc_verbose = !!getenv("AFL_LD_VERBOSE"); - hard_fail = !!getenv("AFL_LD_HARD_FAIL"); - no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER"); - + // 检查环境变量AFL_LD_VERBOSE是否存在,存在则将alloc_verbose设置为1,否则为0 + alloc_verbose = !!getenv("AFL_LD_VERBOSE"); + // 检查环境变量AFL_LD_HARD_FAIL是否存在,存在则将hard_fail设置为1,否则为0 + hard_fail = !!getenv("AFL_LD_HARD_FAIL"); + // 检查环境变量AFL_LD_NO_CALLOC_OVER是否存在,存在则将no_calloc_over设置为1,否则为0 + no_calloc_over = !!getenv("AFL_LD_NO_CALLOC_OVER"); }