Windows PE文件操作码

Windows PE文件操作码,windows,parsing,assembly,x86,portable-executable,Windows,Parsing,Assembly,X86,Portable Executable,我正在编写一个PE文件解析器,现在我想解析和解释PE文件中的实际代码,我假设它们存储为x86操作码 例如,DLL中的每个导出都指向函数将存储在内存中的RVA(相对虚拟偏移量),我编写了一个函数将这些RVA转换为物理文件偏移量 问题是,这些真的是操作码,还是其他什么 函数在文件中的存储方式取决于编译器/链接器,还是取决于单字节或双字节X86操作码 例如,Windows 7 DLL“BWContextHandler.DLL”包含四个加载到内存中的函数,使它们在系统中可用。第一个导出的函数是“DllC

我正在编写一个PE文件解析器,现在我想解析和解释PE文件中的实际代码,我假设它们存储为x86操作码

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

问题是,这些真的是操作码,还是其他什么

函数在文件中的存储方式取决于编译器/链接器,还是取决于单字节或双字节X86操作码

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

那么,这是一个或两个字节的操作码,还是完全其他的东西

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

谢谢

在进一步阅读并通过IDA的演示版本运行该文件之后,我认为我正确地说第一个字节0xA1是一个单字节操作码,意思是mov eax。我是从这里得到的:我现在假设它是正确的


然而,我对下面的字节如何构成指令的其余部分感到有点困惑。从我所知道的x86汇编程序来看,move指令需要两个参数,目标和源,因此该指令将(某物)移动到eax寄存器中,我假设某物在以下字节中。然而,我还不知道如何读取这些信息:)

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

单字节操作码,表示mov eax。我是从这里得到的:我现在假设它是正确的

让我们在桌子上看一看:

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

A1;W压敏电阻;eAX;Ov;消息;datamov;搬家

(提示:不要使用geek32表,切换到-is会有更少的字段和更多的解码,例如“A1 MOV eAX moffs16/32 Move”)

有用于操作数的列op1和op2。A1操作码的第一个总是
eAX
,第二个(op2)是Ov。根据下表:

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”是x86机器代码。

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

  • 指令长度可变,可以从任何偏移开始。有些体系结构需要指令对齐。不是x86。如果您从地址0开始读取,那么您将得到与从偏移量1开始读取不同的结果。您必须知道有效的“起始位置”(函数入口点)是什么

  • 并非可执行文件文本部分中的所有地址都是代码。有些是数据。VisualStudio将把“跳转表”(用于实现switch语句的数组)放在读取它们的过程下面的文本部分。将数据误解为代码将导致产生不正确的分解

  • 你不可能有一个完美的分解,它能与所有可能的程序一起工作。程序可以自我修改。在这些情况下,您必须运行程序来了解它的功能,这最终会导致“停止问题”。您所能期望的最好结果是在“大多数”程序上工作的分解

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

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

    机器学习可用于自动识别模式,但许多dis-a