Intel Pin无法检测memcmp与strcmp函数的技术求助
解决Pintool无法捕获memcmp/strcmp的问题
这问题我之前排查过,大概率是编译器优化或PLT调用机制导致的,给你拆解下原因和解决方案:
核心原因分析
1. 编译器内联优化
现代GCC/Clang这类编译器会对memcmp/strcmp这类高频小函数做内联优化——直接把函数逻辑展开到调用代码里,不会生成单独的函数调用指令。比如你写的简单字符串比较代码,编译器完全可以把memcmp替换成逐字节比较的指令,根本不会去调用标准库的memcmp函数,你的Pintool自然追踪不到。
2. PLT条目未被枚举
如果确实调用了标准库版本的memcmp/strcmp,它们通常是通过PLT(Procedure Linkage Table) 间接调用的。你的枚举代码遍历的是镜像的普通段(SEC)里的例程(RTN),但PLT的特殊条目不会被当成常规RTN处理,所以遍历过程会漏掉它们。
解决方案
方案一:强制编译器关闭内联优化
编译测试程序时,添加编译选项禁用内联,让编译器强制调用标准库的memcmp/strcmp:
gcc test.c -o test -fno-builtin-memcmp -fno-builtin-strcmp
这样Pintool就能捕获到标准库函数的调用了。
方案二:直接查找目标函数(推荐)
不要遍历所有段和例程,改用RTN_FindByName直接定位目标函数,不管它在主程序还是动态库中:
#include "pin.H" #include <stdio.h> VOID MemcmpBefore(ADDRINT str1, ADDRINT str2, ADDRINT len) { printf("memcmp called, length: %d\n", len); } VOID StrcmpBefore(ADDRINT str1, ADDRINT str2) { printf("strcmp called\n"); } VOID Image(IMG img, VOID* v) { // 查找并插装memcmp RTN memcmpRtn = RTN_FindByName(img, "memcmp"); if (RTN_Valid(memcmpRtn)) { RTN_Open(memcmpRtn); RTN_InsertCall(memcmpRtn, IPOINT_BEFORE, (AFUNPTR)MemcmpBefore, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_FUNCARG_ENTRYPOINT_VALUE, 2, IARG_END); RTN_Close(memcmpRtn); } // 查找并插装strcmp RTN strcmpRtn = RTN_FindByName(img, "strcmp"); if (RTN_Valid(strcmpRtn)) { RTN_Open(strcmpRtn); RTN_InsertCall(strcmpRtn, IPOINT_BEFORE, (AFUNPTR)StrcmpBefore, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END); RTN_Close(strcmpRtn); } } int main(int argc, char* argv[]) { if (PIN_Init(argc, argv)) { puts("PIN初始化失败"); return 1; } IMG_AddInstrumentFunction(Image, NULL); PIN_StartProgram(); return 0; }
方案三:全局函数入口挂钩
使用PIN_AddFunctionEntryHook全局挂钩函数,无需关心函数所在镜像:
#include "pin.H" #include <stdio.h> VOID MemcmpEntry(CHAR* name, ADDRINT retAddr, ADDRINT str1, ADDRINT str2, ADDRINT len) { printf("memcmp called, length: %d\n", len); } VOID StrcmpEntry(CHAR* name, ADDRINT retAddr, ADDRINT str1, ADDRINT str2) { printf("strcmp called\n"); } int main(int argc, char* argv[]) { if (PIN_Init(argc, argv)) { puts("PIN初始化失败"); return 1; } PIN_AddFunctionEntryHook((AFUNPTR)MemcmpEntry, "memcmp"); PIN_AddFunctionEntryHook((AFUNPTR)StrcmpEntry, "strcmp"); PIN_StartProgram(); return 0; }
额外注意:变体函数名
有些编译器会把memcmp/strcmp替换成带指令集后缀的优化版本,比如__memcmp_sse4_1、__strcmp_avx2。如果上面的方法还是找不到,可以在枚举时检查函数名是否包含memcmp或strcmp关键字:
if (strstr(rtn_name, "memcmp") != NULL || strstr(rtn_name, "strcmp") != NULL) { printf("%s -- %s -- %s\n", img_name, sec_name, rtn_name); }
内容的提问来源于stack exchange,提问作者Lught
相关产品推荐
相关产品推荐

