PEiD原理分析

环境:Win10;Ollydbg v1.10 dyk158修改版;PEID v0.94;IDA
6.8.150423(32-bit)

首先熟悉PEID的界面及其功能,PEID载入之前用VC++6.0编写的程序

PEID界面<span
data-label="fig:PEID1_PNG"></span>{width=”80.00000%”}

这里我们从字符串“Microsoft Visual C++
6.0”入手。为什么要从这入手呢?因为PEID是一个查壳软件,我们得到的这个“Microsoft
Visual C++
6.0”字符串信息是PEID根据软件的特征侦察出来的。因此找到这个字符串的地址信息,以此来为入口分析PEID的工作原理是一个很好的切入点。^1

OD载入程序,使用字符串参考插件,这里查找ASCII模式的字符串。Ctrl+F查找“Microsoft
Visual C++ 6.0”,可能会找到多条信息,z或p查找下一个,b或n查找上一个。

找到字符串地址<span
data-label="fig:PEID2_PNG"></span>{width=”80.00000%”}

找到后,Enter进入,F2下断点。这个地址是0x00438fff,上一行的地址是0x00438ffd,现在我们需要找到调用这个此处的代码在哪(也就是找到需要什么条件才能使PEID判断程序为Microsoft
Visual C++
6.0),顺藤摸瓜,其实我们可以找到很多处跳转到0x00438ffd的代码,我们以最前面的地址0x00438d13来向上分析,

调用0x00428ffd的代码IDA和OD分析<span
data-label="fig:PEID3_PNG"></span>{width=”80.00000%”}

其有效代码如图[fig:PEID3_PNG]所示,可以看到0x00438c20前面的代码为int3的指令,而且IDA和OD此处的代码并无异同。

PE节数目位置<span
data-label="fig:PEID4_PNG"></span>{width=”80.00000%”}

节表项<span
data-label="fig:PEID5_PNG"></span>{width=”80.00000%”}

0x00438C2C 0x00438D60分析<span
data-label="fig:PEID6_PNG"></span>{width=”80.00000%”}

如图[fig:PEID6_PNG]可以看出,开始就定义了一个很大的数组,并对数组进行了初始化。可以推断出这个数组中存放的数据应该为相关特征码。这段代码主要的做的就是检查OEP是否在“.text”中,若条件成立,则跳转到显示编译器版本的代码处。如果条件不成立,程序会先根据入口特征码比较OEP入口处的8字节机器码,分析目标是否为其他编译器所生成。如果不符合特征,将会调整OEP,加入文件偏移与虚拟地址偏移的转换过程,再次用特征码对比OEP处的机器码。如符合特征,则程序流程进入字符串文本输出部分。

OK,其实这只是判定过程的结尾,我们继续向上查找调用0x438d13(因为在此地址处是经过分类处理后执行的代码)的程序。

怎么找调用它的函数呢?根据函数调用机制,函数被调用后会在栈的最顶端压入函数的返回地址,执行到0x438d13查看堆栈窗口,我们可以得到0x00452f46这个地址。

返回地址分析<span
data-label="fig:PEID7_PNG"></span>{width=”80.00000%”}

那么我们就可以推断出0x452f3f这个地址就是调用0x438d13的函数,跟踪进去,跳到0x401E8C处。

0x401e8c处的部分数组数据<span
data-label="fig:PEID8_PNG"></span>{width=”80.00000%”}

0x401e8c这个处保存了大量的数据。

我们接着向上分析[fig:PEID9_PNG]

0x00452e90 0x00452f58编译器检查分类函数<span
data-label="fig:PEID9_PNG"></span>{width=”80.00000%”}

图[fig:PEID9_PNG]完成了对OEP处特征码的比较并根据比较结果,从函数指针数组中找到符合此特征的处理流程,记录下标值,记录下标值,然后将它们保存在另一个存放下标值的数组中。这时第一次过滤已经完成,进入第二次过滤检查分析程序中是否存在第二个节。

OK,我们可以继续分析0x0045A3E0查看PEID会将OEP处的哪些机器码作为特征码进行对比。

特征码校验分析<span
data-label="fig:PEID10_PNG"></span>{width=”80.00000%”}

找到重要的比较函数0x0045A1D0,这个函数完成分析程序的机器码与事先准备好的特征码的比较,最终提取出了具有相同特性的编译器的版本。

VC++6.0特征码<span
data-label="fig:PEID11_PNG"></span>{width=”80.00000%”}

至此我们可以推断出PEID的工作流程:

  1. 读取分析文件到内存中,并分析出相关的PE文件的信息,然后保存

  2.  检查OEP,计算地址偏移,并修正OEP

  3.  再次检查OEP地址的合法性

  4.  将OEP处的机器码与特征码进行比较

  5.  检查分析文件中是否存在“.rdata”节

  6. 根据分析结构获取对应处理函数所在数组中的下标并保存

  7. 循环调用处理函数

  8. 在处理函数中再次检查

  9. 显示编译器版本