我想了解更多有关x86_64二进制文件中ptrace功能的信息,以反汇编指令。 目的是检查字节是否为指令前缀之一。
我在Intel® 64 and IA-32 Architectures Software Developer’s Manual(第2卷,第2章)中找到了一些信息。
2.1.1 INSTRUCTION PREFIXES
部分显示以下前缀:
0x26
] ES段覆盖0x36
] SS段覆盖前缀0x2E
] CS段覆盖前缀或未采用分支0x3E
] DS段覆盖前缀或已采取分支0x64
] FS段覆盖前缀0x65
] GS段覆盖前缀0x66
]操作数大小的覆盖前缀0x67
]地址大小覆盖前缀0xF0
] LOCK前缀0xF2
] REPNE / REPNZ前缀或 BND前缀0xF3
] REP或REPE / REPZ前缀视觉上,this chart以黄色显示前缀。
如果我想知道字节是否为前缀,我将尝试提高效率,并检查是否可以执行二进制操作。
如果我将0x26
,0x36
,0x2E
和0x3E
分组。以2为底的这些数字(00100110
,00110110
,00101110
和00111110
)显示了一个公共部分:001XX110
。
如果我的字节在该组中,则会发现11100111
(0xE7
)的二进制运算。
太好了。现在,如果我第二个组包含0x64
,0x65
,0x66
和0x67
(01100100
,01100101
,{{1} },01100110
),我发现了另一个常见部分:01100111
。
然后,如果该字节在第二组中,则可以找到011001XX
(11111100
)的和二进制运算。
剩余的指令前缀(0xFC
,0xF0
和0xF2
)出现问题:没有共同的部分。 0xF3
(11111100
)的与运算将使字节0xFC
。
一种解决方案是检查字节是否不是0xF1
。
因此,在C中可能的实现方式是:
0xF1
我来自英特尔,除了最后一组只能签入一个操作。
然后,最后一个问题是:我可以检查一个字节是0xF0、0xF2还是0xF3吗?
答案 0 :(得分:2)
然后,最后一个问题是:我可以检查一个字节是0xF0、0xF2还是0xF3吗?
与一条指令最接近的是:
;ecx = the byte
bt [table],ecx ;Is the byte F0, F2 or F3?
jc .isF0F2orF3 ; yes
但是,有时前缀不被视为前缀(例如pause
指令,其编码类似于rep nop
,以兼容旧CPU)。
还要注意,对于高速反汇编程序,最快的方法可能是“跳转表驱动”,其中一个寄存器指向与解码器状态相对应的表,而另一个寄存器包含指令的下一个字节,例如:
;ebx = address of table corresponding to the decoder's current state
movzx eax,byte [esi] ;eax = next byte of the instruction
inc esi ;esi = address of byte after the next byte of this instruction
jmp [ebx+eax*4] ;Go to the code that figures out what to do
在这种情况下,跳转到的某些代码段将设置一些标志而不更改当前表(例如,初始表中0xF3的条目将导致跳转到设置“看到前缀前缀”标志的代码) ),而跳转到的某些代码段将切换到另一个表(例如,初始表中0x0F的条目将导致跳转到更改EBX
的代码,以指向用于所有用户的完全不同的表以0x0F, ...
开头的指令);然后跳转到其中的一些代码将显示一条指令(并重置解码器的状态)。
例如;对于pause
,代码可能是:
table0entryF3:
or dword [prefixes],REP
movzx eax,byte [esi] ;eax = next byte of the instruction
inc esi ;esi = address of byte after the next byte
jmp [ebx+eax*4]
table0entry90:
mov edx,instructionNameString_NOP
test dword [prefixes],REP ;Was it a PAUSE or NOP?
je doneInstruction_noOperands ; NOP, current name is right
and dword [prefixes],~REP ; PAUSE, pretend the REP prefix wasn't there
mov edx,instructionNameString_PAUSE ; and use the right name
jmp doneInstruction_noOperands
doneInstruction_noOperands:
call displayPrefixes
call displayInstructionName
mov dword [prefixes],0 ;Reset prefixes
mov ebx,table0 ;Switch current table back to the initial table
movzx eax,byte [esi] ;eax = first byte of next instruction
inc esi ;esi = address of byte after the next byte
jmp [ebx+eax*4]