Windows平台C语言插0xCC断点调试偶发访问违规问题咨询
问题原因分析
1. 反汇编基址计算错误
你调用cs_disasm时第四个参数(反汇编结果的虚拟地址基址)计算逻辑错误:
count = cs_disasm(handle, data, size_to_modify, entry_point - text_section.VirtualAddress + text_section.PointerToRawData, 0, &instructions);
这个参数应该传入代码段运行时的起始虚拟地址(直接传text_section.VirtualAddress即可),你当前的计算方式把文件偏移和虚拟地址混淆了,导致反汇编得到的instructions[counter].address不是程序运行时的真实虚拟地址。后续你存储到表中的info.address也跟着出错,触发断点时部分地址查表失败,无法正确还原指令和修正EIP。
间隔5条指令插入断点时没有触发问题,只是刚好此时插入断点的位置地址计算偏差刚好和实际运行地址匹配,属于偶发现象;间隔10条时刚好命中地址不匹配的指令,就会触发崩溃。
2. 异常处理逻辑缺少校验
你当前的异常处理逻辑没有判断异常类型,只要收到异常就尝试还原指令、修改EIP。如果触发的不是断点异常(比如你查表失败导致0xCC没有被还原,后续CPU执行出错抛出的访问异常),你仍然强制把EIP减1,会进一步导致指令执行地址错位,触发栈访问错误。
3. 两种测试程序表现不同的原因
第一种测试用例char str[] = "hello"会在栈上分配空间并复制字符串,对应的汇编指令包含大量栈操作(sub esp、mov内存写入等),EIP错位后很容易访问到栈上的非法地址;第二种测试用例char* str = "hello"直接引用常量区地址,没有栈上的复制操作,指令序列对EIP错位的容错性更高,所以没有触发崩溃。
修复方案
- 修正
cs_disasm的基址参数,直接传入代码段运行时的起始虚拟地址text_section.VirtualAddress,反汇编得到的指令地址直接就是运行时的真实地址,不需要额外做偏移计算。 - 异常处理入口增加判断,只有异常代码为
STATUS_BREAKPOINT(0x80000003)时才走断点还原逻辑,其他异常直接分发给子进程处理。 - 查表逻辑增加校验,如果异常地址不在你的存储表中,不要执行还原和EIP修改操作,避免破坏程序执行上下文。
- 额外优化:插入断点时过滤掉
ret、int、间接跳转等特殊指令,避免触发不可预期的栈问题。
内容的提问来源于stack exchange,提问作者sh-ch
相关产品推荐
相关产品推荐

