本打算把 cabir 分析完的,后来发现,写了 8 篇,还只是个入门,算了,先把这部分仍出来,后面我自己都不知道还有没有了,因为一些我觉得有用的都扔出来了,后面即使有也不一定可以公开了,不管了,先把这个放出来给大家看看,由于是草稿,写得比较乱,希望大家见谅!
总算没有食言~哈
最近在玩疯狂卡丁车,网通区,有等级高的 m 我啊~,哈哈!
Tutorial: Understanding Symbian virus (II)
Part 1. Begin
上篇文章中,我们对 Symbian OS 的一些基本文件作了说明。通过对 SymbOS/Drever.A!tr 病毒的分析,让大家对 Symbian 程序的逆向工作有了一个比较基础的了解。这篇文章中,我们将对 SymbOS/Cabir.A!worm (病毒作者称之为 Carbie) 作尝试分析。
病毒样本是一个 SIS 文件,那么我们如何分析呢?这里我们需要两个工具:
l Unsis (Symbian 网站可以下载。呃,当然,你也可以使用其他的 SIS 解包工具,比如 Unmakesis)
l SISDump (这个是我编写一个 SIS dump 工具,通过这个工具,我们会得到许多其他工具忽略掉的信息,这些信息对我们会很有用处[1])
好了,使用你手边的 unsis 工具解包 carbie.sis 文件,我们会得到:
%EXTRACT_DIR%\system\apps\carbie\caribe.app
%EXTRACT_DIR%\system\apps\carbie\caribe.rsc
%EXTRACT_DIR%\system\apps\carbie\flo.mdl
根据上篇教程,我们可以猜测:
carbie.app - 病毒主体程序
caribe.rsc - 病毒资源文件
flo.mdl - 病毒的 Mime Recognizer Dll,也就是病毒的自启动模块
那么,病毒安装后,是如何运行的呢?通过 SISDump 工具,我们可以看到如下结果:
[!] ------------------------------------------------
[!] File record type: Simple File
[!] File type:
[!] File to be run during installation and/or removal
[!] Details:
[!] Run during installation only
Src name:
.\caribe.app
Dst name:
!:\system\apps\caribe\caribe.app
[!] ------------------------------------------------
请注意文中红色的一行,SIS 解包释放安装时,caribe.app 会被系统自动调用执行。
Part 2. Analyzing
l 分析 Flo.mdl 文件:
按照 SISDump 工具得出的结果,我们应该首先分析 app 文件。但实际上,我们可以非常容易的猜测到 mdl 会被病毒安装到 !:\System\recog\ 目录下,用以在 Symbian OS 启动的时候自动加载病毒主程序。Mdl 文件一般很小,所以,为了方便起见,建议首先分析该文件。
通过对 flo.mdl
的简单分析发现这个文件比上一篇中的
mdl 略复杂一些,不过,该病毒模块的最终目的仍是通过调用 RApaLsSession
::StartApp()
调用病毒的主体
app 程序。该 mdl
会注册为对 “text/vnd.newlc.zzzz”
MIME类型的识别模块,由于绝大部分的分析过程与上篇雷同,故这里不再重复。
l 分析 Carbie.app 文件:
这是一个包含了 GUI 的 app 程序,为了更好的分析该文件,我们首先来对 S60 GUI 的工作流程与框架结构作一个简单的介绍。对于这部分比较熟悉的人可以跳过。
1) 架构:
Symbian OS 是由C++ 编写的,因此,要想了解 app 程序,我们就应该知道它的继承关系,下面是 S60 应用程序框架的基本架构:
(图一)
了解 app 的加载顺序对于分析它有非常重要的意义,我们给出 Symbian OS 的app loader 加载执行 app 的序列图:
(图二)
2) 解析导出函数:
App 应用程序使用的是 DLL 架构,加载器要求 app 文件导出 NewApplication 函数,以便获取 Application 指针。为了节省内存(上篇文章中已有介绍),因此该函数仅仅导出序号(序号固定为 1)。
打开 IDA,我们可以查看导出函数情况:
(图三)
其中, start 对应程序的 E32Dll() 入口;caribe_1 (序号为 1),对应 NewApplication 函数。
分析 E32Dll() 函数,代码:
.text:10000000 EXPORT start
.text:10000000 start
.text:10000000
B loc_10000004
.text:10000004
.text:10000004 loc_10000004
.text:10000004 MOV R0,
#0
.text:10000008 BX LR
转换成 C++ 代码如下:
GLDEF_C TInt E32Dll(TDllReason
aReason)
{
return KErrNone; // KErrNone = 0
}
很明显,这部分代码很正常,没有任何问题。那么我们就剩下 NewApplication 函数了。
首先看一下这部分的逆向代码:
.text:
.text:
.text:
.text:10000010 MOV R0,
#0x
.text:10000014 BL CBase::__nw(uint)
.text:10000018 SUBS R4,
R0, #0
.text:
.text:10000020 MOV R0,
R4
.text:10000024 BL CEikApplication::CEikApplication(void)
.text:10000028 LDR R3,
=dword_10002458
.text:
.text:10000030
.text:10000030 loc_10000030
.text:10000030 MOV R0,
R4
.text:10000034 B loc_
.text:10000034 ; ===========================================================
.text:10000038 off_10000038 DCD dword_10002458
.text:
.text:
.text:
.text:
.text:10000040 BX LR
对应的 C++ 代码:
EXPORT_C CApaApplication*
NewApplication()
{
return new CCaribeApplication;
}
C++ 语言的编译器在背后为我们做了大量的工作,从这里我们就可以看出来。结合上述汇编代码,我将一步步说明 C++ 的构造动作:
a. 分配对象空间:
.text:
.text:
.text:
.text:10000010 MOV R0,
#0x
.text:10000014 BL CBase::__nw(uint)
.text:10000018 SUBS R4, R0,
#0
.text:
上述代码为类对象空间分配了
0x
b. 调用构造函数:
.text:10000020 MOV R0, R4
.text:10000024 BL CEikApplication::CEikApplication(void)
正如上篇介绍的那样, R0 传递 this 指针。
c. 初始化对象(C++ 编译器背后所作的工作):
.text:10000028 LDR R3,
=dword_10002458
.text:
这里两条红色语句是重点所在,其作用是初始化 vptr (对于一个类来说,vptr 可能不止一个)。Vptr 指向 vtable 表空间,在 Symbian OS 中,vtable 的结构如下:
struct vtable
{
DCD offset; // 该 vptr 位于 class object 对象中的偏移(补值)
DCD unknow; // 未知,基本上均为 0
DCD vfunc[]; // 虚拟函数表,数目不定(和类定义有关)
};
其中,编译器可以通过 vtable.offset 快速从当前的 vptr 计算出其所在的类对象的指针,计算方法如下:
类对象指针 = vptr + vtable.offset;
关于类对象的内存结构,下面显示了一个 C++ 类对象存在于内存中的可能结构情况:
Vptr 1 |
Variant 1 |
… |
Variant N |
Vptr N |
注意:由于 C++ 标准中没有对二进制的情况进行规定,因此不同的厂商及其编译器的二进制情况可能互不兼容。类对象基本上就是 vptr 和 variant 所组成的表结构。而这里 vptr 与 variant 的位置并没有任何的要求 (EPOC平台生成的 C++ 类对象并不像某些编译器 – 例如 VC – 那样,VC 编译器会将 vptr 放在variant 的前面)。
注:对于此部分下文 3) 中有比较详细地分析。
d. 返回类对象指针:
.text:10000030 MOV R0, R4
.text:10000034 B loc_
.text:
.text:10000040 BX LR
函数创建的 Application 对象的指针在创建后通过 R0 返回给调用者。
3) 分析 vtable:
类对象(class object)的结构是由 vptr 和类变量(class variant)组成的。Vptr 是指向 vtable 的重点,因此,我们在这里结合病毒文件分析一下 vtable 的内容。
在 2) 的 c 小节中,我们主要提到了 vptr,我们现在来看一下它所指向的内容:
.text:10002458 dword_10002458 DCD 0, 0
.text:10002460 DCD loc_10001BA8 ; CApplication::~CApplication()
.text:10002464 DCD CAknApplication::PreDocConstructL(void)
.text:10002468 DCD CEikApplication::CreateDocumentL(CApaProcess
*)
.text:
.text:10002470 DCD CAknApplication::OpenIniFileLC(RFs &)
.text:10002474 DCD CEikApplication::OpenAppInfoFileLC(void)
.text:10002478 DCD CApaApplication::AppFullName(void)
.text:
.text:10002480 DCD CEikApplication::Reserved_1(void)
.text:10002484 DCD CEikApplication::GetDefaultDocumentFileName(TBuf<256>
&)
.text:10002488 DCD CEikApplication::BitmapStoreName(void)
.text:
.text:10002490 DCD loc_10000044 ; CApplication::CreateDocumentL()
其中,上述红色的部分是我们需要重点检查的部分,检测后的函数名称就是注释的内容。 对应分析结果为:
CApplication::~CApplication()
{
}
TUid CApplication::AppDllUid()
{
return TUid(0x10005B91);
}
CDocument * CApplication::CreateDocumentL()
{
return CDocument::NewL();
}
提示:Symbian OS C++ 编程中使用的是二段构造法(这点和 ATL 很相似),具体原理很多地方都有讲解,我将不再重复。
通过 CApplication::CreateDocumentL() 函数的汇编代码,我们可以轻易得找到 CDocument 的类对象,从而取得其中的 vptr 及其指向的 vtable。以此类推,我们会通过:CApplication -> CDocument ->
CAppUi -> … 的顺序遍历其的结构,进而检查其中的代码内容。
对于 Caribe 病毒,我们会在 CAppUi::ConstructL() 中发现其传播动作。
l
其他
上述方法并不能完全的分析一个应用程序,因为类的非虚函数的地址不会放到 vtable 中,我们很难显性的找出它们,因此,分析病毒还需要结合其他的方法。
一些必要的辅助方法:
查看 app 或者 exe 地导入依赖文件及其导入函数 (可以使用我写的 EpocDep 工具);最好的方法还是通过手机测试执行,比较容易确认某些病毒动作。
[1] 例如在使用 SISDump 分析 Comwar.a 病毒样本的 SIS 文件时,可以看到如下信息:
[!] ------------------------------------------------
[!] File record type: Simple File
[!] File type:
[!] SIS Component file
Src name:
C:\DOCUME~1\mats\LOKALE~1\Temp\MKS0\CommWarrior.A.sis
[!] ------------------------------------------------
病毒的作者可能使用 mats 的名字,另外,该作者的母语可能不是英语语系。当然,这些信息仅作参考使用。