逆向与反汇编实战(一)--PEiD分析复现

1.准备

简介:

PEiD(PE Identifier)是一款著名的查壳工具,其功能强大,几乎可以侦测出所有的壳,其数量已超过470 种PE 文档 的加壳类型和签名。

 

整个过程需要测试文件成品:https://www.lanzous.com/b07r7qu0d

 

首先使用PEiD检测之前做的一个异常捕捉测试程序。源码在下面,编译器为VC++ 6.0,编译方法为 Win32 Release

复制代码
#include <stdio.h>

class CExcepctionBase {
public:
    virtual const char* GetExcepctionInfo() = 0;
};

class CDiv0Excepction :public CExcepctionBase {
public:
    CDiv0Excepction() {
        printf("CExcepctionDiv0()\r\n");
    }
    virtual ~CDiv0Excepction() {
        printf("~CDiv0Excepction()\r\n");
    }
    virtual const char* GetExcepctionInfo() {
        return "div zero excepction";
    }
};

class CAccessExcepction :public CExcepctionBase {
public:
    CAccessExcepction() {
        printf("CAccessExcepction()\r\n");
    }
    virtual ~CAccessExcepction() {
        printf("~CAccessExcepction()\r\n");
    }
    virtual const char* GetExcepctionInfo() {
        return "access excepction";
    }
};

void TestExcepction(int n) {
    try {
        if (1 == n) {
            throw 3;
        }
        if (2 == n) {
            throw 3.0f;
        }
        if (3 == n) {
            throw '3';
        }
        if (4 == n) {
            throw 3.0;
        }
        if (5 == n) {
            throw CDiv0Excepction();
        }
        if (6 == n) {
            throw CAccessExcepction();
        }
        if (7 == n) {
            CAccessExcepction excAccess;
            throw& excAccess;
        }
    }
    catch (int n) {
        printf("catch int %d\r\n", n);
    }
    catch (float f) {
        printf("catch float %f\r\n", f);
    }
    catch (char c) {
        printf("catch char %c\r\n", c);
    }
    catch (double d) {
        printf("catch double %f\r\n", d);
    }
    catch (CExcepctionBase &exc) {
        printf("catch error %s\r\n", exc.GetExcepctionInfo());
    }
    catch (CAccessExcepction *pExc) {
        printf("catch error %s\r\n", pExc->GetExcepctionInfo());
    }
    catch (...) {
        printf("catch ... ...");
    }
    printf("Test End!\r\n");
}

int main()
{
    for (int i = 1; i <= 8; ++i) {
        TestExcepction(i);
    }

    return 0;
}
复制代码

使用PEiD检测情况

 

2.文件判定分析

2.1 函数定位

从PEiD的分析情况,可以看到“Microsoft Visual C++ 6.0”的字符串,使用OD打开PEiD,找到字符串位置后下断点

00438FF6  |> \8BAC24 9C0400>mov ebp,dword ptr ss:[esp+0x49C]
00438FFD  |>  6A 18         push 0x18
00438FFF  |.  68 285A4000   push upPEiD.00405A28                     ;  ASCII "Microsoft Visual C++ 6.0"
00439004  |>  8D4D 04       lea ecx,dword ptr ss:[ebp+0x4]
00439007  |.  E8 04D4FFFF   call upPEiD.00436410

 

实际上,运行到此处时,已经结束了文件判断分析阶段,得到了结果,在上一条指令(红线指引),我们可以返回到跳转之前的函数,即是文件判定函数。

 

2.2 文件判定函数分析

接着向上查找,找到函数的入口处,设置断点,开始文件判定函数的分析

复制代码
00438C20  /$  81EC 88040000 sub esp,0x488
00438C26  |.  53            push ebx
00438C27  |.  55            push ebp
00438C28  |.  56            push esi
00438C29  |.  57            push edi
00438C2A  |.  B0 72         mov al,0x72                              ;  定义特征码
00438C2C  |.  884424 2F     mov byte ptr ss:[esp+0x2F],al
00438C30  |.  884424 31     mov byte ptr ss:[esp+0x31],al
00438C34  |.  884424 34     mov byte ptr ss:[esp+0x34],al
00438C38  |.  884424 39     mov byte ptr ss:[esp+0x39],al
00438C3C  |.  884424 3D     mov byte ptr ss:[esp+0x3D],al
00438C40  |.  B0 63         mov al,0x63                              ;  定义特征码
00438C42  |.  884424 40     mov byte ptr ss:[esp+0x40],al
00438C46  |.  884424 41     mov byte ptr ss:[esp+0x41],al
00438C4A  |.  B0 73         mov al,0x73                              ;  定义特征码
00438C4C  |.  884424 43     mov byte ptr ss:[esp+0x43],al
00438C50  |.  884424 44     mov byte ptr ss:[esp+0x44],al
00438C54  |.  B0 6C         mov al,0x6C                              ;  定义特征码
00438C56  |.  884424 47     mov byte ptr ss:[esp+0x47],al
00438C5A  |.  884424 48     mov byte ptr ss:[esp+0x48],al
00438C5E  |.  8BB424 A00400>mov esi,dword ptr ss:[esp+0x4A0]
00438C65  |.  8B46 0C       mov eax,dword ptr ds:[esi+0xC]           ;  PE首地址,即IMAGE_NT_HEADERS
00438C68  |.  8B56 18       mov edx,dword ptr ds:[esi+0x18]          ;  ".text"节首地址
00438C6B  |.  B1 6D         mov cl,0x6D                              ;  定义特征码
00438C6D  |.  884C24 36     mov byte ptr ss:[esp+0x36],cl
00438C71  |.  884C24 3E     mov byte ptr ss:[esp+0x3E],cl
00438C75  |.  B3 41         mov bl,0x41                              ;  定义特征码
00438C77  |.  C64424 2C 7B  mov byte ptr ss:[esp+0x2C],0x7B
00438C7C  |.  C64424 2D 4F  mov byte ptr ss:[esp+0x2D],0x4F
00438C81  |.  C64424 2E 75  mov byte ptr ss:[esp+0x2E],0x75
00438C86  |.  C64424 30 50  mov byte ptr ss:[esp+0x30],0x50
00438C8B  |.  C64424 32 6F  mov byte ptr ss:[esp+0x32],0x6F
00438C90  |.  C64424 33 67  mov byte ptr ss:[esp+0x33],0x67
00438C95  |.  C64424 35 61  mov byte ptr ss:[esp+0x35],0x61
00438C9A  |.  C64424 37 44  mov byte ptr ss:[esp+0x37],0x44
00438C9F  |.  C64424 38 69  mov byte ptr ss:[esp+0x38],0x69
00438CA4  |.  C64424 3A 7D  mov byte ptr ss:[esp+0x3A],0x7D
00438CA9  |.  C64424 3B 5C  mov byte ptr ss:[esp+0x3B],0x5C
00438CAE  |.  885C24 3C     mov byte ptr ss:[esp+0x3C],bl
00438CB2  |.  885C24 3F     mov byte ptr ss:[esp+0x3F],bl
00438CB6  |.  C64424 42 65  mov byte ptr ss:[esp+0x42],0x65
00438CBB  |.  C64424 45 2E  mov byte ptr ss:[esp+0x45],0x2E
00438CC0  |.  C64424 46 64  mov byte ptr ss:[esp+0x46],0x64
00438CC5  |.  C64424 18 4D  mov byte ptr ss:[esp+0x18],0x4D
00438CCA  |.  C64424 19 53  mov byte ptr ss:[esp+0x19],0x53
00438CCF  |.  C64424 1A 43  mov byte ptr ss:[esp+0x1A],0x43
00438CD4  |.  C64424 1B 46  mov byte ptr ss:[esp+0x1B],0x46
00438CD9  |.  0FB740 06     movzx eax,word ptr ds:[eax+0x6]          ;  eax中为IMAGE_NT_HEADERS首地址,[eax+0x6]为Section Number(节数目) = 3
00438CDD  |.  8D0C80        lea ecx,dword ptr ds:[eax+eax*4]         ;  节数目乘5
00438CE0  |.  8B6CCA E8     mov ebp,dword ptr ds:[edx+ecx*8-0x18]    ;  得到".data"所占大小
00438CE4  |.  8D44CA D8     lea eax,dword ptr ds:[edx+ecx*8-0x28]    ;  保存".data"节的首地址
00438CE8  |.  8B78 14       mov edi,dword ptr ds:[eax+0x14]          ;  ".data"在磁盘中的偏移
00438CEB  |.  8B46 04       mov eax,dword ptr ds:[esi+0x4]           ;  第二个参数指向结构中的第二项数据
00438CEE  |.  03FD          add edi,ebp                              ;  ".data"偏移地址+".data"节所占大小=".data"节末尾
00438CF0  |.  8BAC24 9C0400>mov ebp,dword ptr ss:[esp+0x49C]         ;  获取第一个参数
00438CF7  |.  8D8F 00390000 lea ecx,dword ptr ds:[edi+0x3900]        ;  .data节在内存中的位置
00438CFD  |.  3BC1          cmp eax,ecx                              ;  判断第二个参数是否不小于.data节(.data之后就是OEP),如果成功,跳过OEP检查
00438CFF  |.  73 1A         jnb XupPEiD.00438D1B                     ;  跳过OEP检查
00438D01  |.  8B55 20       mov edx,dword ptr ss:[ebp+0x20]          ;  获取到程序入口地址
00438D04  |.  85D2          test edx,edx                             ;  检查OEP
00438D06  |.  74 13         je XupPEiD.00438D1B
00438D08  |.  8B4E 18       mov ecx,dword ptr ds:[esi+0x18]          ;  .text节首地址
00438D0B  |.  8B79 14       mov edi,dword ptr ds:[ecx+0x14]          ;  .text节文件偏移
00438D0E  |.  0379 10       add edi,dword ptr ds:[ecx+0x10]          ;  .text节文件偏移+.text节大小=.text节末尾
00438D11  |.  3BD7          cmp edx,edi                              ;  判断OEP是否在.text节中
00438D13  |.  0F82 E4020000 jb upPEiD.00438FFD                       ;  如果在,跳转,检查结束
复制代码

通过,分析实际上这个函数就做了两件事,一是判定第二个参数是否在.data节中,二是判断OEP是否在.text节中。对于节区以及对应位置功能的判断,可以使用PEView,010 Editor以及结合OD寄存器区判断,这里不给出判定过程了。但是,在这里却没有用到特征码,我们将最后一步的跳转命令nop。分析OEP检查错误情况的代码。

 

2.3 OEP检查错误和编译器判断

复制代码
00438D13      90              nop                                      ;  如果在,跳转,检查结束
00438D14      90              nop
00438D15      90              nop
00438D16      90              nop
00438D17      90              nop
00438D18      90              nop                                      ;  ************下面的代码是OEP检查失败的情况************
00438D19  |.  8BFA            mov edi,edx                              ;  OEP偏移地址存入EDI,0x1634
00438D1B  |>  2BC7            sub eax,edi                              ;  保存.data节的末尾地址
00438D1D  |.  83F8 09         cmp eax,0x9                              ;  判断OEP是否在.data节中
00438D20  |.  0F82 D7020000   jb upPEiD.00438FFD                       ;  不在就跳转
00438D26  |.  8B16            mov edx,dword ptr ds:[esi]               ;  edx保存IMAGE_DOS_HEADER首地址
00438D28  |.  8D0C3A          lea ecx,dword ptr ds:[edx+edi]           ;  得到OEP的地址
00438D2B  |.  8B11            mov edx,dword ptr ds:[ecx]               ;  将OEP前四个直接存入edx中,edx=0x6AEC8B55
00438D2D  |.  81FA 496E7374   cmp edx,0x74736E49                       ;  OEP与特征码比较
00438D33  |.  75 15           jnz XupPEiD.00438D4A                     ;  条件成立,跳转,不成立则继续比较OEP后双字的数据
00438D35  |.  8179 04 616C6C5>cmp dword ptr ds:[ecx+0x4],0x536C6C61    ;  OEP与特征码比较
00438D3C  |.  75 0C           jnz XupPEiD.00438D4A                     ;  成立则跳转
00438D3E  |.  6A 17           push 0x17                                ;  压入字符串长度
00438D40  |.  68 B45A4000     push upPEiD.00405AB4                     ;  ASCII "InstallShield 2003 Stub"
00438D45  |.  E9 BA020000     jmp upPEiD.00439004                      ;  跳转到显示字符串函数处
00438D4A  |>  81FA 64617461   cmp edx,0x61746164                       ;  OEP与特征码比较
00438D50  |.  75 27           jnz XupPEiD.00438D79
00438D52  |.  8179 04 312E636>cmp dword ptr ds:[ecx+0x4],0x61632E31    ;  下面实际上就是一些其他版本的特征码比较了
00438D59  |.  75 1E           jnz XupPEiD.00438D79
00438D5B  |.  68 B45A4000     push upPEiD.00405AB4                     ;  ASCII "InstallShield 2003 Stub"
00438D60  |.  8D4D 04         lea ecx,dword ptr ss:[ebp+0x4]
00438D63  |.  E8 38E9FFFF     call upPEiD.004376A0
00438D68  |.  5F              pop edi
00438D69  |.  5E              pop esi
00438D6A  |.  C645 00 01      mov byte ptr ss:[ebp],0x1
00438D6E  |.  5D              pop ebp
00438D6F  |.  B0 01           mov al,0x1
00438D71  |.  5B              pop ebx
00438D72  |.  81C4 88040000   add esp,0x488
00438D78  |.  C3              retn
00438D79  |>  3D 00020000     cmp eax,0x200
00438D7E  |.  BD 00020000     mov ebp,0x200
00438D83  |.  77 02           ja XupPEiD.00438D87
00438D85  |.  8BE8            mov ebp,eax
00438D87  |>  6A 1D           push 0x1D
00438D89  |.  8D4424 30       lea eax,dword ptr ss:[esp+0x30]
00438D8D  |.  50              push eax
00438D8E  |.  8D8C24 98000000 lea ecx,dword ptr ss:[esp+0x98]
00438D95  |.  E8 26E5FFFF     call upPEiD.004372C0
00438D9A  |.  8B16            mov edx,dword ptr ds:[esi]
00438D9C  |.  8D4C24 10       lea ecx,dword ptr ss:[esp+0x10]
00438DA0  |.  51              push ecx
00438DA1  |.  55              push ebp
00438DA2  |.  03D7            add edx,edi
00438DA4  |.  52              push edx
00438DA5  |.  8D8C24 9C000000 lea ecx,dword ptr ss:[esp+0x9C]
00438DAC  |.  E8 4FE6FFFF     call upPEiD.00437400
00438DB1  |.  84C0            test al,al
00438DB3  |.  74 26           je XupPEiD.00438DDB
00438DB5  |.  8BB424 9C040000 mov esi,dword ptr ss:[esp+0x49C]
00438DBC  |.  6A 1B           push 0x1B
00438DBE  |.  68 985A4000     push upPEiD.00405A98                     ;  ASCII "Silicon Realms Install Stub"
00438DC3  |.  8D4E 04         lea ecx,dword ptr ds:[esi+0x4]
00438DC6  |.  E8 45D6FFFF     call upPEiD.00436410
00438DCB  |.  5F              pop edi
00438DCC  |.  C606 01         mov byte ptr ds:[esi],0x1
00438DCF  |.  5E              pop esi
00438DD0  |.  5D              pop ebp
00438DD1  |.  B0 01           mov al,0x1
00438DD3  |.  5B              pop ebx
00438DD4  |.  81C4 88040000   add esp,0x488
00438DDA  |.  C3              retn
00438DDB  |>  8B46 04         mov eax,dword ptr ds:[esi+0x4]
00438DDE  |.  2BC7            sub eax,edi
00438DE0  |.  3D 00400000     cmp eax,0x4000
00438DE5  |.  BD 00400000     mov ebp,0x4000
00438DEA  |.  77 02           ja XupPEiD.00438DEE
00438DEC  |.  8BE8            mov ebp,eax
00438DEE  |>  6A 04           push 0x4
00438DF0  |.  8D4424 1C       lea eax,dword ptr ss:[esp+0x1C]
00438DF4  |.  50              push eax
00438DF5  |.  8D8C24 98000000 lea ecx,dword ptr ss:[esp+0x98]
00438DFC  |.  E8 BFE4FFFF     call upPEiD.004372C0
00438E01  |.  8B16            mov edx,dword ptr ds:[esi]
00438E03  |.  8D4C24 10       lea ecx,dword ptr ss:[esp+0x10]
00438E07  |.  51              push ecx
00438E08  |.  55              push ebp
00438E09  |.  03D7            add edx,edi
00438E0B  |.  52              push edx
00438E0C  |.  8D8C24 9C000000 lea ecx,dword ptr ss:[esp+0x9C]
00438E13  |.  E8 E8E5FFFF     call upPEiD.00437400
00438E18  |.  84C0            test al,al
00438E1A  |.  74 24           je XupPEiD.00438E40
00438E1C  |.  8BB424 9C040000 mov esi,dword ptr ss:[esp+0x49C]
00438E23  |.  68 845A4000     push upPEiD.00405A84                     ;  ASCII "InstallShield AFW"
00438E28  |.  8D4E 04         lea ecx,dword ptr ds:[esi+0x4]
00438E2B  |.  E8 70E8FFFF     call upPEiD.004376A0
00438E30  |.  5F              pop edi
00438E31  |.  C606 01         mov byte ptr ds:[esi],0x1
00438E34  |.  5E              pop esi
00438E35  |.  5D              pop ebp
00438E36  |.  B0 01           mov al,0x1
00438E38  |.  5B              pop ebx
00438E39  |.  81C4 88040000   add esp,0x488
00438E3F  |.  C3              retn
00438E40  |>  8B46 0C         mov eax,dword ptr ds:[esi+0xC]           ;  eax为IMAGE_NT_HEADERS地址=0x64800D8
00438E43  |.  8B40 28         mov eax,dword ptr ds:[eax+0x28]          ;  eax为代码段的地址
00438E46  |.  50              push eax
00438E47  |.  8BCE            mov ecx,esi
00438E49  |.  E8 32A40100     call upPEiD.00453280                     ;  计算偏移位置,得到正确的OEP
00438E4E  |.  8BF8            mov edi,eax
00438E50  |.  8B46 18         mov eax,dword ptr ds:[esi+0x18]          ;  获取.text节首地址,0x064801D0
00438E53  |.  8B48 14         mov ecx,dword ptr ds:[eax+0x14]          ;  .text节文件偏移地址
00438E56  |.  0348 10         add ecx,dword ptr ds:[eax+0x10]          ;  .text节文件偏移地址+.text节大小=.text节末尾偏移地址
00438E59  |.  3BF9            cmp edi,ecx                              ;  比较OEP是否在.text节中
00438E5B  |.  0F82 95010000   jb upPEiD.00438FF6                       ;  跳转到显示编译器版本处,此处即显示"Microsoft Visual C++ 6.0”
复制代码

 因为在第一部分对OEP的检测中,已经完成的跳转,实际上是不会执行这一段代码的,因此对于真正的文件判定代码,是会调用上面这段函数的。

要找到函数的调用处,因为函数在最后ret时,都会出栈函数调用处的调用地址,所以直接在函数结尾设置断点,执行观察栈区。

转到0x452F46

存放数据处

 

2.4 "真"文件分析函数

对上面分析函数进行分析

复制代码
00452E90  /$  64:A1 00000000  mov eax,dword ptr fs:[0]                 ;  入口地址
00452E96  |.  6A FF           push -0x1
00452E98  |.  68 C8CD4600     push upPEiD.0046CDC8                     ;  异常处理
00452E9D  |.  50              push eax
00452E9E  |.  64:8925 0000000>mov dword ptr fs:[0],esp
00452EA5  |.  83EC 10         sub esp,0x10                             ;  局部变量空间
00452EA8  |.  56              push esi
00452EA9  |.  8B7424 24       mov esi,dword ptr ss:[esp+0x24]          ;  第一个参数
00452EAD  |.  8B46 14         mov eax,dword ptr ds:[esi+0x14]
00452EB0  |.  8B40 10         mov eax,dword ptr ds:[eax+0x10]          ;  获取起始相对虚拟偏移地址
00452EB3  |.  57              push edi                                 ;  压入参数一
00452EB4  |.  8BF9            mov edi,ecx                              ;  获取this指针
00452EB6  |.  50              push eax                                 ;  压入代码起始RVA
00452EB7  |.  8BCE            mov ecx,esi
00452EB9  |.  E8 C2030000     call upPEiD.00453280                     ;  检查PE文件格式,将OEP的RWA与RVA进行转换
00452EBE  |.  3B46 04         cmp eax,dword ptr ds:[esi+0x4]           ;  函数返回调整之后的OEP
00452EC1  |.  72 15           jb XupPEiD.00452ED8                      ;  条件成立,跳转到分析阶段
00452EC3  |.  5F              pop edi                                  ;  =============分析失败代码===========
00452EC4  |.  32C0            xor al,al
00452EC6  |.  5E              pop esi
00452EC7  |.  8B4C24 10       mov ecx,dword ptr ss:[esp+0x10]
00452ECB  |.  64:890D 0000000>mov dword ptr fs:[0],ecx
00452ED2  |.  83C4 1C         add esp,0x1C
00452ED5  |.  C2 0800         retn 0x8                                 ;  =======================================
00452ED8  |>  53              push ebx
00452ED9  |.  8B5C24 30       mov ebx,dword ptr ss:[esp+0x30]
00452EDD  |.  8943 20         mov dword ptr ds:[ebx+0x20],eax          ;  保存调整之后的OEP
00452EE0  |.  8B4E 04         mov ecx,dword ptr ds:[esi+0x4]
00452EE3  |.  8B16            mov edx,dword ptr ds:[esi]
00452EE5  |.  2BC8            sub ecx,eax
00452EE7  |.  51              push ecx
00452EE8  |.  03D0            add edx,eax
00452EEA  |.  52              push edx                                 ;  载入内存后的程序入口地址
00452EEB  |.  8D4C24 14       lea ecx,dword ptr ss:[esp+0x14]
00452EEF  |.  51              push ecx
00452EF0  |.  8BCF            mov ecx,edi
00452EF2  |.  E8 E9740000     call upPEiD.0045A3E0                     ;  将OEP代码与特征码进行对比--PEiD可以检查出分析程序是否在可识别的编译器范围内
00452EF7  |.  8B4424 14       mov eax,dword ptr ss:[esp+0x14]
00452EFB  |.  8B4C24 10       mov ecx,dword ptr ss:[esp+0x10]
00452EFF  |.  8BD0            mov edx,eax
00452F01  |.  2BD1            sub edx,ecx
00452F03  |.  C1FA 02         sar edx,0x2
00452F06  |.  52              push edx
00452F07  |.  50              push eax
00452F08  |.  51              push ecx
00452F09  |.  C74424 30 00000>mov dword ptr ss:[esp+0x30],0x0
00452F11  |.  E8 9AF5FFFF     call upPEiD.004524B0                     ;  根据函数0x45A3E0对OEP处特征码的对比结果,将特征匹配的处理流程的函数指针,在数组中的下标值都存放在地址ESP+1C的数组中
00452F16  |.  8B7C24 1C       mov edi,dword ptr ss:[esp+0x1C]
00452F1A  |.  8B4424 20       mov eax,dword ptr ss:[esp+0x20]
00452F1E  |.  83C4 0C         add esp,0xC
00452F21  |.  3BF8            cmp edi,eax
00452F23  |.  74 37           je XupPEiD.00452F5C                      ;  没有匹配的特征函数,结束分析
00452F25  |>  8B07            /mov eax,dword ptr ds:[edi]
00452F27  |.  50              |push eax
00452F28  |.  56              |push esi
00452F29  |.  53              |push ebx
00452F2A  |.  FF15 8C1E4000   |call dword ptr ds:[0x401E8C]            ;  检查.rdata节是否存在
00452F30  |.  83C4 0C         |add esp,0xC
00452F33  |.  84C0            |test al,al
00452F35  |.  75 48           |jnz XupPEiD.00452F7F                    ;  如果不存在,结束查询分析
00452F37  |.  8B07            |mov eax,dword ptr ds:[edi]
00452F39  |.  50              |push eax
00452F3A  |.  56              |push esi
00452F3B  |.  8D0C40          |lea ecx,dword ptr ds:[eax+eax*2]
00452F3E  |.  53              |push ebx
00452F3F  |.  FF148D 8C1E4000 |call dword ptr ds:[ecx*4+0x401E8C]      ;  调用分析函数,存放数据的首地址在0x401E8C
00452F46  |.  83C4 0C         |add esp,0xC
00452F49  |.  84C0            |test al,al
00452F4B  |.  75 32           |jnz XupPEiD.00452F7F
00452F4D  |.  8B4424 14       |mov eax,dword ptr ss:[esp+0x14]
00452F51  |.  83C7 04         |add edi,0x4
00452F54  |.  3BF8            |cmp edi,eax
00452F56  |.^ 75 CD           \jnz XupPEiD.00452F25                    ;  循环跳转。一直循环到匹配到对应的处理函数
复制代码

上面的函数,整个过程:

  1. 对OEP的特征码比较
  2. 通过比较结果匹配储存函数指针的数组中的过程,将下标存储到数组
  3. 检测程序中是否存在.rdata节
  4. 从存储下标的数组中取出下标,调用对应的函数。

在第一步中,会产生一个使用OEP的哪些机器码作为特征码进行比较的问题(特征码的定义)。因此,我们进一步分析函数0x45A3E0

00452EF2  |.  E8 E9740000     call upPEiD.0045A3E0                     ;  将OEP代码与特征码进行对比--PEiD可以检查出分析程序是否在可识别的编译器范围内

 

3.特征码分析

复制代码
0045A3E0  /$  6A FF           push -0x1
0045A3E2  |.  68 38D24600     push upPEiD.0046D238                     ;  SE 处理程序安装
0045A3E7  |.  64:A1 00000000  mov eax,dword ptr fs:[0]
0045A3ED  |.  50              push eax
0045A3EE  |.  64:8925 0000000>mov dword ptr fs:[0],esp
0045A3F5  |.  83EC 14         sub esp,0x14
0045A3F8  |.  53              push ebx
0045A3F9  |.  55              push ebp
0045A3FA  |.  33DB            xor ebx,ebx
0045A3FC  |.  56              push esi
0045A3FD  |.  57              push edi
0045A3FE  |.  8BF1            mov esi,ecx                              ;  获取this指针
0045A400  |.  895C24 10       mov dword ptr ss:[esp+0x10],ebx          ;  将数组清零
0045A404  |.  895C24 18       mov dword ptr ss:[esp+0x18],ebx
0045A408  |.  895C24 1C       mov dword ptr ss:[esp+0x1C],ebx
0045A40C  |.  895C24 20       mov dword ptr ss:[esp+0x20],ebx
0045A410  |.  8B7C24 38       mov edi,dword ptr ss:[esp+0x38]          ;  获取OEP,保存到EDI
0045A414  |.  0FB607          movzx eax,byte ptr ds:[edi]              ;  获取OEP地址处的数据
0045A417  |.  8B4486 14       mov eax,dword ptr ds:[esi+eax*4+0x14]    ;  对this指针偏移计算
0045A41B  |.  83F8 FF         cmp eax,-0x1
0045A41E  |.  8B6C24 3C       mov ebp,dword ptr ss:[esp+0x3C]          ;  OEP差值
0045A422  |.  895C24 2C       mov dword ptr ss:[esp+0x2C],ebx          ;  EBX=0,将局部变量清0
0045A426  |.  74 0F           je XupPEiD.0045A437
0045A428  |.  55              push ebp
0045A429  |.  57              push edi
0045A42A  |.  50              push eax
0045A42B  |.  8D4C24 20       lea ecx,dword ptr ss:[esp+0x20]          ;  获取数组首地址
0045A42F  |.  51              push ecx
0045A430  |.  8BCE            mov ecx,esi                              ;  将ECX赋值为this指针
0045A432  |.  E8 99FDFFFF     call upPEiD.0045A1D0                     ;  检查OEP处代码是否与特征码相同(将OEP处的字节码与特征码对比,从而比较OEP处的机器码)
0045A437  |>  8B86 14040000   mov eax,dword ptr ds:[esi+0x414]
0045A43D  |.  83F8 FF         cmp eax,-0x1
0045A440  |.  74 0F           je XupPEiD.0045A451
0045A442  |.  55              push ebp
0045A443  |.  57              push edi
0045A444  |.  50              push eax
0045A445  |.  8D5424 20       lea edx,dword ptr ss:[esp+0x20]
0045A449  |.  52              push edx
0045A44A  |.  8BCE            mov ecx,esi
0045A44C  |.  E8 7FFDFFFF     call upPEiD.0045A1D0                     ;  检查OEP处代码是否与特征码相同(将OEP处的字节码与特征码对比,从而比较OEP处的机器码)
复制代码

机器码和特征码的介绍与关系:https://www.cnblogs.com/qiumingcheng/p/5400265.html

在上面的函数中通过0x45A1D0比较OEP的机器码与特征码,提取出具有相同特性的编译器版本。

例如

这是OEP的部分数据

05551634  55 8B EC 6A FF 68 F0 80 40 00 68 40 41 40 00 64  U嬱jh饊@.h@A@.d
05551644  A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 10  ?...Pd?....冹
05551654  53 56 57 89 65 E8 FF 15 0C 80 40 00 33 D2 8A D4  SVW塭?.€@.3見?
05551664  89 15 6C BA 40 00 8B C8 81 E1 FF 00 00 00 89 0D  ?l篅.嬋佱...?
05551674  68 BA 40 00 C1 E1 08 03 CA 89 0D 64 BA 40 00 C1  h篅.玲蕢.d篅.?

使用数据拼接成机器码指令

0x55 0x8b 0xec 0x6a 0xff

0045A3E0      55              push ebp
0045A3E1      8BEC            mov ebp,esp
0045A3E3      6A FF           push -0x1

 

4.PEiD解析流程

  1. PEiD解析编译器的流程总结:
  2. 读取文件,分析出PE结构,保存。
  3. 检查OEP,修正OE,再次检查OEP
  4. 使用OEP处的机器码与特征码比较
  5. 通过比较结果匹配储存函数指针的数组中的过程,将下标存储到数组
  6. 检查文件是否存在rdata节
  7. 循环,从存储下标的数组中取出下标,调用对应的函数。
  8. 在处理函数中再次检查OEP的机器码与特征码
  9. 获取并显示编译器版本

5.开发环境伪造

在第一次文件判定中,我们知道会检测OEP是否在.text节中,因此,我们只需要将伪造OEP写入.text节后,使用HEX Editor改变原来OEP即可

55 8B EC 6A FF 68 F0 80 40 00 68 40 41 40 00 64
A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 10
53 56 57 89 65 E8 5F 5E 5B 83 C4 10 58 64 A3 00
00 00 00 58 58 58 58 E8 76 FA FF FF 00 00 00 00

 

使用一个简单的Hello World程序进行伪造OEP

 

1.初始的OEP地址在0xF012C2处,写入伪造OEP数据

 

2.保存修改后的文件后,OD打开,起始偏移地址为1810

 

3.HEX Editor定位到偏移地址0x110处

将原OEP偏移地址0x12C2改为0x1810即可

posted @ 2020-01-16 17:47  Luminous~  阅读(2753)  评论(0编辑  收藏  举报