浅析和介绍如何在delphi中定位要分析的函数
我喜欢废话,所以先废话下。
因为今天有重要的事情要做,所以就一直忙到现在了。不过因为一直在干活,头脑还是很兴奋,想了想,最近在delphi应用的分析上面有了一点点的经验,今天和大家分享下,希望可以帮到你。
但是呢,时间有点晚,而且文章也是从我自己逆向时候做的笔记里修改的,可能会有些难理解,甚至有错误的地方,这个万望指正,我肯定改的。
因为是笔记,所以里面也有摘的其他人的东西的,而且也引用了之前自己的一篇文章,希望见到了熟悉的段子,理解下。毕竟是介绍和笔记嘛,也要从低到高的 :)...
只要程序员还在用delphi,我们就还需要熟悉borland delphi的结构。
而且相当有价值的一个部分是,现在有大量的不人道的病毒程序员啊,人家写个病毒也不怕体积大,10KB的程序用delphi的控件来写,成了200KB。坏的是分析人员的事,想简单分析下流程都只能看字符串和导入表了。我们这就开始研究如何定位delphi的函数吧。
//----------
一开始看一个delphi程序,重要的第一要看的肯定是rsrc段,因为windows的API处理资源时候使用了硬编码的.rsrc字符串,所以delphi程序中不管怎么样做加壳,rsrc段肯定是存在的。
而delphi的程序的源代码是分为pascal源代码(.PAS, .DPR, .INC)和资源文件 (.RES, .RC, .DFM, .DCR)二种的,而资源文件在编译之后,就是几乎完全源代码形式的储存在rsrc段中的rcdata类型的资源中。
为什么这个rcdata重要,原因是在delphi里,form中在运行时(进程中)对用户代码的调用,都是通过保存在rcdata中的函数符号名称来进行的。这样,我们不仅仅可以通过rcdata定位特定事件的处理函数,也可以通过任意一个用户事件Handler,向上跟踪找到这个包含字符串的结构,来定位其他自己感兴趣的函数。
通常的delphi小程序,这样的分析就足够了,只是,这还不够浅析咧。
想要分析好目标,我们要从PE的入口点开始分析。
首先delphi的可执行文件无论是exe还是dll类型的,都有一个InitRouterTable,其中保存了在初始化时挨个调用到的routines。
struct tagInitTable
{
DWORD dwNum; //初始化函数的个数(是初始化,结束化不包括在里面,也就是说只是FunTable元素个素的一半)
PFUNTABLE pFunTable;
} * InitRoutineTable;
typedef struct tagFunTable
{
void (* Initialization1)(void);
void (* Finalization1)(void);
...
}FUNTABLE, *PFUNTABLE;
PFUNTABLE中的初始化函数和结束化函数是成对出现的,在调用这个表中的函数时候,delphi的循环每次是+0x8的偏移,于是Initialization时总会跳过Finalization的函数。
但是一个很沮丧的消息是,在这个初始化,还有完成初始化的列表的函数中,基本是找不到用户自定义的函数的,至少在我遇到的程序中没有。
下面是一个典型的带form的delphi exe入口:
push ebp
mov ebp, esp
add esp, 0FFFFFFF4h
mov eax, offset InitRoutineTable
call @@InitExe//
mov eax, ds:off_442C20
mov eax, [eax]
call unknown_libname_291
mov ecx, ds:off_442AB4
mov eax, ds:off_442C20
mov eax, [eax]
mov edx, off_441498
call @TApplication@CreateForm
mov eax, ds:off_442C20
mov eax, [eax]
call @TApplication@Run
call @@Halt0
InitExe,unknown_libname_291,TApplication::CreateForm,TApplication::Run 这些都是delphi的库函数,可以在VCL的system.pas中找到。
InitExe会调用一个叫做StartExe的库函数,来从InitRoutineTable读取出所有的FunTable,并且挨个执行Init的Routine。
TApplication::CreateForm则顾名思义,创建程序的主Form,这个就是delphi初始化的主要流程。传递给它的第一个参数是名称为TApplication的类的指针,而edx则是类似于c++的类成员函数的第一个参数,其指向的是
TCustomForm类的TMetaClass结构的指针,会被用来构造程序的CostumForm类型的主form。这个函数,其实也是delphi中一个普通的类为自己重载的ClassCreate构造函数,特别之处只是构造函数的是inline在TApplication的
成员函数中的,只是在入口点,所以被特别命名了。
TApplication::Run中,通常要先用AddExitProc把from的析构函数添加到退出时要执行的流程里,然后就是标准的进入TApplication::HandleMessage delphi的消息循环了。
Halt0则是delphi退出入口点的流程,当没有保存DLL方式进入口点的dwReason,即exe类型时的其值为0,在halt的最后就会调用ExitProcess结束进程的执行。
下面是一个标准的delphi dll入口:
push ebp
mov ebp,esp
add esp,-3C
mov eax, InitRouterTable
call InitLib //
call @@Halt0
InitLib是Delphi的一个库函数,从它的参数InitRouterTable 可以定位到DllMain中会被执行的流程的数组。和InitExe的功能是类似的
一般的,如果DLL中也有窗体,需要进行消息循环的话,也就是说,在DLL里也调用了TApplication::CreateForm来创建CostumForm主form的程序中,在入口点会先创建一个新线程,然后,再在新线程中执行
TApplation_CreateClass进行TApplation类的构造,以及执行TApplation::CreateForm和进入TApplication::Run消息循环。以避免DLL载入窗口的过程阻塞了原应用程序的执行。
在Halt0中,是DLL的时候,会判断一个全局结构里保存的进入DllMain的Reason,这个值不为0时,就意味着是DLL的入口点,会调用一个专为DLLMain返回准备的库函数System::_16618,它是以
leavel
retn 0Ch
结尾的。
//----------
上面的就是delphi的默认入口点。相信你也跟我一样不知其所谓,这是因为delphi的实现,全部都是用类来实现的!
而且delphi的入口点,功能其实只是调用类的构造函数,区别只是怎么样的调用类的构造函数。
而具体的程序如何初始化的,完全是由类的构造来决定的。这个类,就是CostumForm,没错,delphi中的form也完全就是一个类。
关于delphi的class逆向的一个实例性质循环渐进的说明,可以看下面的文章
http://www.pediy.com/bbshtml/BBS6/pediy6935.htm
或者同一篇文章在http://bbs.pediy.com/showthread.php?t=5476 #7 英文原版,以及我自己的杨白劳翻译。这篇文章中有一个笔误的地方是TmetaClass被写成ClassInit了。
在这儿,只简单叙述下delphi中的class的构造函数,以方便明白下面介绍的TMetaClass
在delphi中,一个类的构造函数都是单独存在的一个函数,不像c++中总是inline初始化过程到构造类对象的代码位置。同时,除非是自定义的构造函数,这个构造函数的功能一般都很简单。
在里面只有一个功能,以TMetaClass中保存的虚函数表作为参数,调用一个叫做System::ClassCreate的库函数。在这个ClassCreate里面会根据类的大小分配内存空间,以及调用类的初始化对象的函数,此函数的偏移是在虚函数表的 -0xc位置。
对于一个类而言,它在constructor中,首先要调用System::ClassCreate,它其中会使用函数表的 地址- 0xc位置的类特例的InitInstance函数,在其中调用System::TObject::InitInstance来做必备的初始化实例,此时通常会调用System::__linkproc__ GetMem(int)来申请到对象占用的内存。
如你所见,一个类的初始化函数完全没有我们想要的信息。它包含了什么东西,就像c++的初始化函数中不会有这些一样,delphi的也没有。那delphi的窗口、控件、函数是如何组织起来的,就完全要看TMetaClass了。
//---------------------------------------------
delphi里定义类的信息的TMetaClass结构,其结构格式是:
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
