linux – 没有%gs寄存器的x86子集:使用%gs而不是捕获到仿真的二进制修补代码?

由于在这里解释得太复杂的原因,我需要在作为x86子集的平台上运行x86 GCC编译的Linux程序.该平台没有%gs寄存器,
这意味着它必须被模拟,因为GCC依赖于%gs寄存器的存在.

目前我有一个包装器,当程序试图访问%gs寄存器并模拟它时捕获异常.但这是狗慢.有没有办法可以使用等效指令提前修改ELF中的操作码,以避免陷阱和模拟?

解决方法:

(这是假设Adam Rosenfields解决方案不适用.它或类似的方法可能是解决它的更好方法.)

你还没有说明你是如何模仿%gs寄存器的,但是除非你对这个程序有一些特殊的了解,否则你可能很难修补每个用法,因为否则你只有2个字节(在最坏的情况下,常见情况)您可以使用补丁进行修改.当然,如果你使用像%es =%gs这样的东西,它应该是相对简单的.

假设这可以以某种方式在您的情况下工作,策略是扫描ELF文件的可执行部分并修补使用或修改GS寄存器的任何指令.这至少是以下说明:

>任何带有GS段的指令都会覆盖前缀(65表示分支指令,在这种情况下,前缀表示其他内容)
>推gs(0F A8)
> pop gs(0F A9)
> mov r / m16,gs(8C / r)
> mov gs,r / m16(8E / r)
> mov gs,r / m64(REX.W 8E / r)(如果支持64位模式)

还有其他任何允许段寄存器的指令(我认为不是那么多,但我不是100%肯定).

这一切都是从Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes 2A and 2B: Instruction Set Reference, A-Z开始的.请注意,指令有时会以其他前缀为前缀,有时不会,因此您应该使用library来执行指令解码,而不是盲目地搜索字节序列.

上面的一些说明应该相对简单地转换成调用my_patch或类似的,但你可能很难找到适合两个字节的东西并且一般都可以工作. int XX(CD XX)可能是一个很好的候选者,如果你可以设置一个中断向量,但我不确定它会比你目前使用的方法更快.您当然需要记录哪个指令被修补并让中断处理程序(或其他)根据返回地址(处理程序收到的)做出不同的反应.

如果你能在-128..127字节内找到空间并使用JMP rel8(EB cb)跳转到蹦床(通常是另一个JMP,但这次有更多的空间用于目标地址),你可能能够设置蹦床,然后处理指令仿真并跳转到修补后的%gs使用后的指令.

最后,我建议保持运行陷阱和模拟代码以捕获您可能没有想过的任何情况(例如,自我修改或注入代码).这样,您还可以记录任何未处理的案例并将其添加到您的解决方案中.

上一篇:ASM:输出Java字节码和操作码


下一篇:如何在多网卡环境下正确配置EHome协议?