在X86上,您可以为调用者的上下文设置Trap标志,以便在一条指令之后获得SIGTRAP(此标志通常用于单步执行).也就是说,遇到SIGSEGV时,在调用者的EFLAGS中设置TF(请参阅参考资料ucontext.h
),启用读取mprotect
并返回.如果使用相同的IP立即重复SIGSEGV,则启用写入(如果要区分读取 - 修改 - 写入和"只写"访问,则可以选择禁用读取).如果从同一IP获取SIGSEGV以进行只读和只写保护,则启用读写.
无论何时获得SIGTRAP,您都可以分析写入的值(如果是写访问权限),还可以重新保护页面以捕获将来的访问.
更正:如果读取和写入都有副作用,请先尝试只写保护,然后应用读取副作用并尝试只读保护,然后在最终的SIGTRAP处理程序中启用写入和处理写入的副作用.
更新:我推荐假设的只写保护,这在大多数架构中都不存在,这是致命的错误.幸运的是,有一种更简单的方法可以知道失败的操作是否尝试读取内存,至少在x86上是这样:
页面错误异常将错误代码推送到堆栈,该堆栈在Linux SIGSEGV处理程序中可用作结构的err
成员sigcontext
.写入错误的错误代码的第1 位为1,否则为0.对于读 - 修改 - 写操作,它最初将为0(在这里你可以模拟读数,确切地知道它会发生).
在X86上,您可以为调用者的上下文设置Trap标志,以便在一条指令之后获得SIGTRAP(此标志通常用于单步执行).也就是说,遇到SIGSEGV时,在调用者的EFLAGS中设置TF(请参阅参考资料ucontext.h
),启用读取mprotect
并返回.如果使用相同的IP立即重复SIGSEGV,则启用写入(如果要区分读取 - 修改 - 写入和"只写"访问,则可以选择禁用读取).如果从同一IP获取SIGSEGV以进行只读和只写保护,则启用读写.
无论何时获得SIGTRAP,您都可以分析写入的值(如果是写访问权限),还可以重新保护页面以捕获将来的访问.
更正:如果读取和写入都有副作用,请先尝试只写保护,然后应用读取副作用并尝试只读保护,然后在最终的SIGTRAP处理程序中启用写入和处理写入的副作用.
更新:我推荐假设的只写保护,这在大多数架构中都不存在,这是致命的错误.幸运的是,有一种更简单的方法可以知道失败的操作是否尝试读取内存,至少在x86上是这样:
页面错误异常将错误代码推送到堆栈,该堆栈在Linux SIGSEGV处理程序中可用作结构的err
成员sigcontext
.写入错误的错误代码的第1 位为1,否则为0.对于读 - 修改 - 写操作,它最初将为0(在这里你可以模拟读数,确切地知道它会发生).