前几天,写了个判定Overlay的东东,都在瞎闭门造车,今天分析了下PEid的ExtOverlay插件的判定算法,这玩意其实很简单。

分析了下别人的东东,对自己写的东东也更自信了几分:)


bp CreateFileA,F9,Alt + F9返回后,到0x0121391F处

0121391A    E8 6DFEFFFF     call    0121378C                         ; jmp 到 kernel32.CreateFileA
0121391F    A3 7C562101     mov     dword ptr [121567C], eax  //保存文件句柄
01213924    833D 7C562101 F>cmp     dword ptr [121567C], -1
0121392B    0F84 30020000   je      01213B61
01213931    6A 00           push    0
01213933    A1 7C562101     mov     eax, dword ptr [121567C]
01213938    50              push    eax
01213939    E8 5EFEFFFF     call    0121379C                         ; jmp 到 kernel32.GetFileSize
0121393E    A3 84562101     mov     dword ptr [1215684], eax  //保存文件大小
01213943    A1 84562101     mov     eax, dword ptr [1215684]
01213948    E8 FBEAFFFF     call    01212448
0121394D    A3 80562101     mov     dword ptr [1215680], eax  //保存文件缓冲指针
01213952    33C0            xor     eax, eax
01213954    55              push    ebp
01213955    68 5A3B2101     push    01213B5A
0121395A    64:FF30         push    dword ptr fs:[eax]
0121395D    64:8920         mov     dword ptr fs:[eax], esp
01213960    6A 00           push    0
01213962    8D45 F8         lea     eax, dword ptr [ebp-8]
01213965    50              push    eax
01213966    A1 84562101     mov     eax, dword ptr [1215684]
0121396B    50              push    eax
0121396C    A1 80562101     mov     eax, dword ptr [1215680]
01213971    50              push    eax
01213972    A1 7C562101     mov     eax, dword ptr [121567C]
01213977    50              push    eax
01213978    E8 27FEFFFF     call    012137A4                         ; jmp 到 kernel32.ReadFile
0121397D    E8 CEFEFFFF     call    01213850


01213850    53              push    ebx
01213851    56              push    esi
01213852    57              push    edi
01213853    33C0            xor     eax, eax
01213855    A3 70562101     mov     dword ptr [1215670], eax  //[1215670]用来保存Overlay起始地址
0121385A    33C0            xor     eax, eax
0121385C    A3 74562101     mov     dword ptr [1215674], eax  //[1215674]用来保存Overlay长度
01213861    33F6            xor     esi, esi
01213863    A1 80562101     mov     eax, dword ptr [1215680]  //ReadFile读出内容放在
01213868    8B40 3C         mov     eax, dword ptr [eax+3C]
0121386B    0305 80562101   add     eax, dword ptr [1215680]
01213871    8D58 18         lea     ebx, dword ptr [eax+18]
01213874    0FB750 14       movzx   edx, word ptr [eax+14]  //SizeOfOptionHeader
01213878    03DA            add     ebx, edx      //ebx指向节表位置
0121387A    0FB778 06       movzx   edi, word ptr [eax+6]  //NumberOfSections
0121387E    4F              dec     edi
0121387F    85FF            test    edi, edi
01213881    7C 1F           jl      short 012138A2
01213883    47              inc     edi
01213884    BA 00020000     mov     edx, 200
01213889    8B43 10         mov     eax, dword ptr [ebx+10]  //SizeOfRawData
0121388C    E8 ABFFFFFF     call    0121383C      //这个函数作用:SizeOfRawData按0x200向上取整
01213891    8B53 14         mov     edx, dword ptr [ebx+14]  //PointerToRawData
01213894    03D0            add     edx, eax
01213896    3BF2            cmp     esi, edx
01213898    73 02           jnb     short 0121389C
0121389A    8BF2            mov     esi, edx      //上面三行代码:把SizeOfRawData + PointerToRawData最大值放esi,其中SizeOfRawData为0x200向上取整值,PointerToRawData未按0x200向下作对齐处理
0121389C    83C3 28         add     ebx, 28      //指向下个节
0121389F    4F              dec     edi        //节计数减1
012138A0  ^ 75 E2           jnz     short 01213884
012138A2    85F6            test    esi, esi
012138A4    76 20           jbe     short 012138C6
012138A6    3B35 84562101   cmp     esi, dword ptr [1215684]  //esi与文件大小比较(esi为PE文件有效大小,不含Overlay大小)
012138AC    73 18           jnb     short 012138C6
012138AE    A1 80562101     mov     eax, dword ptr [1215680]  //esi小于文件大小情况(有Overlay)
012138B3    03C6            add     eax, esi
012138B5    A3 70562101     mov     dword ptr [1215670], eax  //保存Overlay起始地址到[1215670]
012138BA    A1 84562101     mov     eax, dword ptr [1215684]
012138BF    2BC6            sub     eax, esi
012138C1    A3 74562101     mov     dword ptr [1215674], eax  //保存Overlay长度到[1215674]
012138C6    5F              pop     edi
012138C7    5E              pop     esi
012138C8    5B              pop     ebx
012138C9    C3              retn  //返回到下面语句


01213982    833D 70562101 0>cmp     dword ptr [1215670], 0
01213989    0F84 7E010000   je      01213B0D      //没有发现Overlay则跳
0121398F    8D45 FC         lea     eax, dword ptr [ebp-4]  //底下代码大致是再作善后处理了,保存Overlay到文件...  
01213992    8B15 B0402101   mov     edx, dword ptr [12140B0]
01213998    E8 B7F6FFFF     call    01213054
0121399D    EB 13           jmp     short 012139B2
0121399F    8B45 FC         mov     eax, dword ptr [ebp-4]
012139A2    E8 7DF7FFFF     call    01213124
012139A7    8BD0            mov     edx, eax
012139A9    4A              dec     edx
012139AA    8D45 FC         lea     eax, dword ptr [ebp-4]
012139AD    E8 DEF8FFFF     call    01213290
012139B2    8B45 FC         mov     eax, dword ptr [ebp-4]
012139B5    E8 6AF7FFFF     call    01213124
012139BA    8B55 FC         mov     edx, dword ptr [ebp-4]
012139BD    807C02 FF 2E    cmp     byte ptr [edx+eax-1], 2E
012139C2  ^ 75 DB           jnz     short 0121399F
012139C4    8D45 FC         lea     eax, dword ptr [ebp-4]
012139C7    BA 903B2101     mov     edx, 01213B90                    ; ovr
012139CC    E8 5BF7FFFF     call    0121312C
012139D1    8B45 FC         mov     eax, dword ptr [ebp-4]
012139D4    E8 23F8FFFF     call    012131FC
012139D9    8BD8            mov     ebx, eax


下面给出ExtOverlay的Overlay判定C代码(不容错处理):

int has_overlay(char * pBuf, int nBufLen)
{
  IMAGE_DOS_HEADER * pIDH = (IMAGE_DOS_HEADER *)pBuf;
  IMAGE_NT_HEADERS * pINH = (IMAGE_NT_HEADERS *)(pBuf + pIDH->e_lfanew);
  
  int nSectionNum = pINH->FileHeader.NumberOfSections;
  
  IMAGE_SECTION_HEADER * pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + 0x18 + pINH->FileHeader.SizeOfOptionalHeader);
  
  int nPESize = 0;
  
  for(int nIndex = 0; nIndex < nSectionNum; nIndex++, pISH++)
  {
    int nTemp = ((pISH->SizeOfRawData + 0x200 - 1) / 0x200) * 0x200;
    nTemp += pISH->PointerToRawData;
    
    if(nTemp > nPESize)
    {
      nPESize = nTemp;
    }
  }
  
  if(nBufLen > nPESize)
  {
    //pBuf + nPESize是Overlay开始地址
    //nBufLen - nPESize是Overlay长度
    return 1; //有Overlay
  }
  else
  {
    return 0;
  }
}