繁体   English   中英

PE文件操作码

[英]PE file opcodes

我正处于编写PE文件解析器的过程中,我已经达到了解析和解释PE文件中的实际代码的程度,我假设它存储为x86操作码。

例如,DLL中的每个导出都指向函数将存储在内存中的RVAs(相对虚拟偏移),并且我编写了一个函数来将这些RVA转换为物理文件偏移。

问题是,这些是真正的操作码,还是其他的?

是否依赖于编译器/链接器关于函数如何存储在文件中,或者它们是一个还是两个字节的X86操作码。

例如,Windows 7 DLL“BWContextHandler.dll”包含四个加载到内存中的函数,使它们在系统中可用。 第一个导出的函数是'DllCanUnloadNow',它位于文件中的偏移0x245D处。 该数据的前四个字节是: 0xA1 0x5C 0xF1 0xF2

这些一个或两个字节的操作码是这样的,还是完全不同的?

如果任何人都可以提供有关如何检查这些信息的任何信息,我们将不胜感激。

谢谢!

经过一些进一步的阅读,并通过IDA的演示版本运行文件,我认为我说第一个字节0xA1是一个单字节操作码,这意味着mov eax。 我从这里得到了它: http//ref.x86asm.net/geek32.html#xA1 ,我认为它暂时是正确的。

但是,我对下面的字节如何构成指令的其余部分感到困惑。 从我所知道的x86汇编程序来看,移动指令需要两个参数,即目标和源,因此指令是将(某些)移动到eax寄存器中,并且我假设某些内容来自以下字节。 但是我不知道如何阅读这些信息:)

x86编码是复杂的多字节编码,您不能简单地在指令表中找到单行来解码它,就像在RISC(MIPS / SPARC / DLX)中一样。 一条指令甚至可以有16字节编码:1-3字节操作码+几个前缀(包括多字节VEX )+几个字段用于编码立即或存储器地址,偏移,缩放(imm,ModR / M和SIB; moff)。 单个助记符有时会有几十个操作码。 而且,对于几种情况,有两种编码可能是相同的asm行(“inc eax”= 0x40和= 0xff 0xc0)。

一个字节的操作码,意思是mov eax。 我从这里得到了它: http//ref.x86asm.net/geek32.html#xA1 ,我认为它暂时是正确的。

我们来看看桌子:

po; flds; 助记符 op1; op2; grp1; grp2; 描述

A1; W; MOV; eAX; Ov; gen; 数据; 移动;

(提示:不要使用geek32表,切换到http://ref.x86asm.net/coder32.html#xA1 - 具有更少解码的字段,例如“A1 MOV eAX moffs16 / 32 Move”)

有op1和op2列, http ://ref.x86asm.net/#column_op用于操作数。 A1操作码的第一个始终是eAX ,第二个(op2)是Ov。 根据表http://ref.x86asm.net/#Instruction-Operand-Codes

O / moffs原始指令没有ModR / M字节; 操作数的偏移量在指令中被编码为字,双字或四字(取决于地址大小属性)。 不能应用基址寄存器,索引寄存器或缩放因子(仅MOV(A0,A1,A2,A3))。

因此,在A1操作码之后,存储器偏移被编码。 我认为,x86(32位模式)有32位偏移量。

PS:如果您的任务是解析PE而不是发明反汇编程序,请使用一些x86反汇编库,如libdisasm或libudis86或其他任何东西。

PPS:原始问题:

问题是,这些是真正的操作码,还是其他的?

是,“A1 5C F1 F2 05 B9 5C F1 F2 05 FF 50 0C F7 D8 1B C0 F7 D8 C3 CC CC CC CC CC”是x86机器代码。

反汇编很困难,特别是对于Visual Studio编译器生成的代码,特别是对于x86程序。 有几个问题:

  1. 指令是可变长度的,可以从任何偏移量开始。 一些架构需要指令对齐。 不是x86。 如果您从地址0开始阅读,那么如果您开始在偏移1处读取,则会得到不同的结果。您必须知道有效的“起始位置”(功能入口点)是什么。

  2. 并非可执行文件部分的所有地址都是代码。 有些是数据。 Visual Studio将在读取它们的过程下的文本部分中放置“跳转表”(用于实现switch语句的数组)。 将数据误解为代码会导致产生错误的拆卸。

  3. 你不可能拥有适用于所有可能程序的完美dis-assemby。 程序可以自行修改。 在这些情况下,你必须运行程序才能知道它的作用,最终导致“暂停问题”。 您可以期待的最好的解决方案是“大多数”程序。

通常用于尝试解决这些问题的算法称为“递归下降”拆卸。 它类似于递归下降解析器,因为它以已知的“入口点”(exe的“main”方法或dll的所有导出)开始,然后开始反汇编。 在拆卸过程中发现了其他入口点。 例如,给定“调用”指令,目标将被假定为入口点。 反汇编程序将迭代地反汇编已发现的入口点,直到找不到更多入口点。

然而,这种技术存在一些问题。 它不会找到仅通过间接执行的代码。 在Windows上,一个很好的例子是SEH异常的处理程序。 分派给它们的代码实际上是在操作系统内部,因此递归下降分解将无法找到它们,也不会对它们进行反汇编。 然而,它们通常可以通过增加模式识别(启发式匹配)的递归下降来检测。

机器学习可用于自动识别模式,但许多反汇编程序(如IDA pro)使用手写模式并取得了很大成功。

在任何情况下,如果要反汇编x86代码,则需要阅读“ 英特尔手册” 有很多场景需要支持。 根据修饰符,前缀,处理器的隐式状态等,可以以各种不同的方式解释指令中的相同位模式。这些都在手册中有所涉及。 首先阅读第一卷的前几节。这将介绍基本的执行环境。 你需要的大部分其他东西都在第二卷。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM