标 题: 如何快速定位Delphi DLL中用户写的代码
作 者: Kangaroo
时 间: 2008-08-05
链 接:http://bbs.pediy.com/showthread.php?t=70057

目前大多数病毒都用Delphi写,并且是动态库的形式,由于Delphi库旁大,分析人员在进行病毒分析时候,无从下手,唯一的一个DLLEntry仅仅看到如下代码(都是Delphi库函数,汗颜):


那病毒的入口函数在哪里呢(我说的是病毒作者自己写的代码)?如何被调用呢?带着一层层疑惑我们把问题解开。

先给出Delphi函数调用层次
InitLib->StartLib->InitUnits

先看样就如下结构(给我感觉有点像COM):

typedef struct tagFunTable
{
    void (* Initialization1)(void);
    void (* Finalization1)(void);
    void (* Initialization2)(void);
    void (* Finalization2)(void);
    ...
    void (* InitializationN)(void);
    void (* FinalizationN)(void);
}FUNTABLE, *PFUNTABLE;  //初始化函数和结束化函数成对出现

typedef struct tagInitTable
{
    DWORD dwNum;  //初始化函数的个数(是初始化,结束化不包括在里面,也就是说只是FunTable元素个素的一半)
    PFUNTABLE pFunTable;
}INITTABLE, *PINITTABLE;

//DELPHI DLL的典型入口代码
push ebp
mov ebp,esp
add esp,-3C
mov eax,address  //address就是InitTable的首地址,等下供InitUnits函数调用FunTable中的每一个初始化函数
call InitLib  //InitLib是Delphi的一个库函数


下面给出了,InitUnits代码,注释里面说的很清楚了,你就知道InitUnits如果遍历FunTable表中的每一个函数,并调用。
CODE:004018A4                   InitUnits       proc near               ; CODE XREF: System::__linkproc__ StartLib(void)+BFp
CODE:004018A4 55                                push    ebp
CODE:004018A5 8B EC                             mov     ebp, esp
CODE:004018A7 53                                push    ebx
CODE:004018A8 56                                push    esi
CODE:004018A9 57                                push    edi
CODE:004018AA A1 FC 65 40 00                    mov     eax, ds:dword_4065FC ; 这个就是InitTable数地址了
CODE:004018AF 85 C0                             test    eax, eax
CODE:004018B1 74 4B                             jz      short loc_4018FE
CODE:004018B3 8B 30                             mov     esi, [eax]      ; 初始化函数个数
CODE:004018B5 33 DB                             xor     ebx, ebx        ; ebx是计数器
CODE:004018B7 8B 78 04                          mov     edi, [eax+4]    ; 指向FunTable
CODE:004018BA 33 D2                             xor     edx, edx
CODE:004018BC 55                                push    ebp             ; 结构化异常处理
CODE:004018BD 68 EA 18 40 00                    push    offset loc_4018EA
CODE:004018C2 64 FF 32                          push    dword ptr fs:[edx]
CODE:004018C5 64 89 22                          mov     fs:[edx], esp
CODE:004018C8 3B F3                             cmp     esi, ebx
CODE:004018CA 7E 14                             jle     short loc_4018E0
CODE:004018CC
CODE:004018CC                   loc_4018CC:                             ; CODE XREF: InitUnits+3Aj
CODE:004018CC 8B 04 DF                          mov     eax, [edi+ebx*8] ; 为什么是加八了,上面结构不是说了,初始化和结束化是成对出现的
CODE:004018CF 43                                inc     ebx             ; 加8就会指向下一个初始化函数
CODE:004018D0 89 1D 00 66 40 00                 mov     ds:dword_406600, ebx
CODE:004018D6 85 C0                             test    eax, eax
CODE:004018D8 74 02                             jz      short loc_4018DC ; 计数器和函数个数进行了比较,如果小远就继续循环
CODE:004018DA FF D0                             call    eax
CODE:004018DC
CODE:004018DC                   loc_4018DC:                             ; CODE XREF: InitUnits+34j
CODE:004018DC 3B F3                             cmp     esi, ebx        ; 计数器和函数个数进行了比较,如果小远就继续循环
CODE:004018DE 7F EC                             jg      short loc_4018CC ; 这个循环就是不断调用,FunTable中的每一个初始化函数
CODE:004018E0
CODE:004018E0                   loc_4018E0:                             ; CODE XREF: InitUnits+26j
CODE:004018E0 33 C0                             xor     eax, eax
CODE:004018E2 5A                                pop     edx
CODE:004018E3 59                                pop     ecx
CODE:004018E4 59                                pop     ecx
CODE:004018E5 64 89 10                          mov     fs:[eax], edx
CODE:004018E8 EB 14                             jmp     short loc_4018FE
CODE:004018EA                   ; ---------------------------------------------------------------------------
CODE:004018EA
CODE:004018EA                   loc_4018EA:                             ; DATA XREF: InitUnits+19o
CODE:004018EA E9 E5 FB FF FF                    jmp     @System@@HandleAnyException$qqrv ; System::__linkproc__ HandleAnyException(void)
CODE:004018EF                   ; ---------------------------------------------------------------------------
CODE:004018EF E8 50 FF FF FF                    call    FinalizeUnits_0
CODE:004018F4 E8 3F FD FF FF                    call    @System@@RaiseAgain$qqrv ; System::__linkproc__ RaiseAgain(void)
CODE:004018F9 E8 8E FD FF FF                    call    @System@@DoneExcept$qqrv ; System::__linkproc__ DoneExcept(void)
CODE:004018FE
CODE:004018FE                   loc_4018FE:                             ; CODE XREF: InitUnits+Dj
CODE:004018FE                                                           ; InitUnits+44j
CODE:004018FE 5F                                pop     edi
CODE:004018FF 5E                                pop     esi
CODE:00401900 5B                                pop     ebx
CODE:00401901 5D                                pop     ebp
CODE:00401902 C3                                retn
CODE:00401902                   InitUnits       endp
  
结束语:分析到这里,我们就知道,我们应该直接找FunTable中的函数,从而找到病毒作者写的代码处,进行快速分析。(FunTable地址在InitaTable中,InitTable地址,就是在调用InitLib函数时入口处的一条mov eax,address指令)