本打算把 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:1000000C                 EXPORT caribe_1

.text:1000000C caribe_1

.text:1000000C                 STMFD   SP!, {R4,LR}

.text:10000010                 MOV     R0, #0x22C

.text:10000014                 BL      CBase::__nw(uint)

.text:10000018                 SUBS    R4, R0, #0

.text:1000001C                 BEQ     loc_10000030

.text:10000020                 MOV     R0, R4

.text:10000024                 BL      CEikApplication::CEikApplication(void)

.text:10000028                 LDR     R3, =dword_10002458

.text:1000002C                 STR     R3, [R4]

.text:10000030

.text:10000030 loc_10000030

.text:10000030                 MOV     R0, R4

.text:10000034                 B       loc_1000003C

.text:10000034 ; ===========================================================

.text:10000038 off_10000038    DCD dword_10002458

.text:1000003C ; ===========================================================

.text:1000003C

.text:1000003C loc_1000003C

.text:1000003C                 LDMFD   SP!, {R4,LR}

.text:10000040                 BX      LR

 

对应的 C++ 代码:

 

EXPORT_C CApaApplication* NewApplication()

    {

    return new CCaribeApplication;

    }

 

C++ 语言的编译器在背后为我们做了大量的工作,从这里我们就可以看出来。结合上述汇编代码,我将一步步说明 C++ 的构造动作:

 

a.       分配对象空间:

 

.text:1000000C                 EXPORT caribe_1

.text:1000000C caribe_1

.text:1000000C                 STMFD   SP!, {R4,LR}

.text:10000010                 MOV     R0, #0x22C

.text:10000014                 BL      CBase::__nw(uint)

.text:10000018                 SUBS    R4, R0, #0

.text:1000001C                 BEQ     loc_10000030

 

              上述代码为类对象空间分配了 0x22C 字节的空间,用以存储类的变量以及 vtable 指针 (后面,我们将简称其为 vptr)

 

b.       调用构造函数:

 

.text:10000020                 MOV    R0, R4

.text:10000024                 BL     CEikApplication::CEikApplication(void)

 

正如上篇介绍的那样, R0 传递 this 指针。

 

c.       初始化对象(C++ 编译器背后所作的工作)

             

           .text:10000028                 LDR     R3, =dword_10002458

        .text:1000002C                 STR     R3, [R4]

 

              这里两条红色语句是重点所在,其作用是初始化 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_1000003C

        .text:1000003C                 LDMFD   SP!, {R4,LR}

        .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:1000246C  DCD loc_10000048        ; CApplication::AppDllUid()

.text:10002470  DCD CAknApplication::OpenIniFileLC(RFs &)

.text:10002474  DCD CEikApplication::OpenAppInfoFileLC(void)

.text:10002478  DCD CApaApplication::AppFullName(void)

.text:1000247C  DCD CEikApplication::Capability(TDes8 &)

.text:10002480  DCD CEikApplication::Reserved_1(void)

.text:10002484  DCD CEikApplication::GetDefaultDocumentFileName(TBuf<256> &)

.text:10002488  DCD CEikApplication::BitmapStoreName(void)

.text:1000248C  DCD CEikApplication::ResourceFileName(void)

.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 的名字,另外,该作者的母语可能不是英语语系。当然,这些信息仅作参考使用。