恶意代码分析实战 Lab 5-1 习题笔记

Lab 5-1

问题

1.DllMain的地址是什么?

解答: 这个我们用IDA Pro打开来查找,因为最新的IDA Pro不支持我们运行病毒那个虚拟机的版本(xp pro 32),所以下面的分析都是在win7上的

打开IDA Pro之后就会提示你是否打开一个叫proximity browser的东西,然后打开这个东西就可以看到DllMain的位置

Main

如果没有跳出来,这里可以点开这个窗口

Proximity browser

然后右键选择Text view就可以看到地址了

右键

注意标黄的地方

地址

标黄的地方都是一样的地址,不是IDA的bug,上面那些都是一些IDA生成的一些注释,真正在这个地址上的只有

mov eas, [esp+fdwReson]

这一行

所以DllMain的地址就是在.text节的0x100D02E


2.使用Imports窗口并浏览到gethostbyname,导入函数定位到什么地址?

解答: 我们打开Imports窗口

然后搜索这个

搜索

然后双击这个找到的函数也行,其实Imports这里已经标明了地址了

地址

于是这个问题的答案就是0x100163CC,但是我们可以用双击去原文中查找的方式

地址

这里可以看出这是在.idata节的0x100163CC

最后的答案就是gethostbyname.idata节的0x100163CC


3.有多少函数调用了gethostbyname?

解答: 这个按照说中说的做就行了,但是注意一点,不是在Imports窗口按Ctrl x

是在IDA View窗口里面,也就双击Imports窗口里面gethostbyname函数跳出来的那个窗口

点击

这是右击gethostbyname之后的显示,然后点击Jump to xref to oprand...这个选项,会跳出这个

跳出

类型r是被”读取”的引用,CPU必须先读取这个导入项,再调用它,类型p是被调用的引用

这里显示了18行,但是并不是18个函数调用了这个gethostbyname,注意看,好多函数都是一样的(+后面的是偏移地址)

标注

然后我们自己数一下就会发现,其实只有五个函数引用了gethostbyname

然后注意看就是每个r的类型,总有一个p的类型,所以被引用的次数就是18/2=9次

所以答案就是五个函数引用了九次


4.将精力集中在位于0x10001757处的对gethostname的调用,你能找到哪个DNS请求将被出发吗?

解答: 我们先跳过去看看

按一下g就跳出这个窗口了

然后输入0x10001757这个地址,就会跳了

跳

跳到

然后我们查看这个代码

代码

call函数默认将栈顶的一个值作为函数的参数传递给函数,然后栈顶现在是eax push进去的

所以我们找eax的值,然后找到了mov off_10019040这个,然后查看off_10019040

参数

然后我们可以跳到off_1001940定义的地方,看到了这个字符串(蓝色的是IDA标识的)

[This is RDO]pics.praticalmalwareanalys

然后这里大家也看到了,ida显示不全,我们继续追查

双击后面的aThisIsRdoPics

无

就可以看到完整的字符串了

[This is RDO]pics.praticalmalwareanalysis.com

然后我们回过头来看当时的那段代码

代码

off_10019040中的值给了eax之后(off_10019040是字符串指针)

学过C语言的同学都应该知道指针

现在这个off_10019040指针指向的是字符串的第一个字符,也就是符号[

0Dh转换成十进制是13

字符串是这个[This is RDO]pics.praticalmalwareanalysis.com

+在指针里面的意思你可以理解成是指针向后移动,这个C语言里面有讲,然后我们讲指针往后移动13

最后指针指向的是p这个字符

所以最后push进栈的值是pics.praticalmalwareanalysis.com

于是我们可以得出这个问题的答案就是会对

pics.praticalmalwareanalysis.com

进行DNS解析


5.IDA pro识别了在0x10001656处的子过程中的多少个局部变量?

解答: 老规矩,跳先

然后会发现这些被IDA识别的变量

变量

然后简单的一数,是24个,和书中的计算结果有点差异,然后我数了一下书里的截图,是24个,这里就不纠结这个了,方法知道了就行


6.IDA pro识别了在0x10001656处的子过程中的多少个参数?

解答: 参数是调用这个函数的函数传递给被调用函数的值,搞清楚这个就好办了

参数

我们可以看见这里IDA识别的结果是传入了一个LPVOID类型的lpThreadParameter

所以答案就是识别了一个参数


7.使用string窗口,来在反汇编中定位字符串\cmd.exe /c。它位于哪?

解答: 这个我们按SHIFT F12就调出String窗口了

然后查看这个字符串,双击就行了

查找

然后

双击

所以答案就是在xdoors_d:10095B34


8.在引用\cmd.exe /c的代码所在的区域发生了什么?

解答: 我们右键查找aCmd_exeC引用

引用

然后跳到这个引用的地方

跳

然后我们可以发现在这里,字符串被压入了栈中

然后分析这个函数会发现开头这个字符串

字符串

'Hi,Master [%d/%d/%d %d:%d:%d]

然后可以在这个大概位置上

大概位置

发现一些比较函数,然后点开之后会发现

有关

这些有关于系统信息和系统操作的字符串

按书中的观点这是一个远程shell会话函数


9.在同样的区域,在0x100101c8处,看起来好像dword_1008E5C4是一个全局变量,它帮助决定走哪条路径。那恶意代码是如何设置dword_1008E5C4的呢?(提示:使用dword_1008E5C4的交叉引用。)

解答: 先跳到这个地方,然后邮件查看交叉引用

交叉引用

其他两处都是cmp函数

只有第一处是mov改变了它的值

我们跳到这个地方查看

mov

可以看到这个dword_1008E5C4的上面,有一次sub_10003695函数的调用,而汇编中,函数调用的返回值存储在eax

然后我们查看sub_10003695这个函数到底返回了什么

我们双击这个函数就可以跳到这个函数的定义了

函数

然后这里注意一下,就是双击会跳到.text:100036C2这个位置的sub_10003694,但是其实这个位置是函数的结束,上面.text:10003695处还有一个sub_10003695(发现没有,其实IDA命名函数是用他的位置加上sub来的)

sub_10003695    proc near               ; CODE XREF: 
VersionInformation= _OSVERSIONINFOA ptr -94h
                push    ebp
                mov     ebp, esp
                sub     esp, 94h        ; 将esp增加94h也就是148d,37个字节
                lea     eax, [ebp+VersionInformation] ; 将ebp+VersionInformation的地址赋值给eax
                mov     [ebp+VersionInformation.dwOSVersionInfoSize], 94h ; 将这个地址的值赋值成94h
                push    eax             ; lpVersionInformation
                call    ds:GetVersionExA ; 在一个OSVERSIONINFO结构中载入与平台和操作系统有关的版本信息
                                         ; 上面有定义这个OSVERSIONINFO结构
                xor     eax, eax        ; 将eax置0(因为GetVersionExA的返回值在eax中)
                cmp     [ebp+VersionInformation.dwPlatformId], 2 ; 这里将dwPlatformId和2进行比较
                                                                 ; 为什么和2比较我们下面解释
                setz    al              ; Set Byte if Zero (ZF=1) ; 
                leave                   ; High Level Procedure Exit
                retn                    ; Return Near from Procedure
sub_10003695    endp

我们可以来查看一个OSVERSIONINFOA的结构

OSVERSIONINFOA

查看dwPlatformId中的可能的值

dwPlatformId

因为在windows系统中,VER_PLATFORM_WIN32_NT代表的值是2

无

对windows内核不是很了解,但是从文档来看,VER_PLATFORM_WIN32_NT等于2的话,就是代表系统是

Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, Windows XP, or Windows 2000

setz意思是当ZF标志被设定时,AL寄存器设1

因为刚刚我们cmp了两个数,所以如果两个数相同,ZF=1,然后setzAL被设置为1,反之不相同的话,AL被设置为0(ALEAX的低8位,对应的AHEAX的高8位)

一般来说,会运行这个机器的都是上面那几种windows机器,所以这里比较一般都是会相同的,所以,AL被设置成了1,然后就是用retn返回了eax中的值

但是为什么书上说的是返回的是1,因为我们前面执行过

xor eax, eax

eax现在是被异或都成了0eax有16位)

我们现在分析一下,01234567代表的是高8位(ah),剩下的代表的是低八位(al)

先是

xor eax, eax

这个运行完之后的eax

01234567 89ABCDEF
-------- --------
00000000 00000000

然后我们接着运行

cmp [ebp+VersionInformation.dwPlatformId], 2
setz al

之后的eax89ABCDEF代表的al被置为了1,其余的ah保存不变

01234567 89ABCDEF
-------- --------
00000000 00000001

然后这个值其实就是十进制的1

所以sub_10003694的返回值是1

于是

mov dword_1008E5C4, eax

最后的dword_1008E5C4的值就被赋成了1

所以这个全局变量在程序运行的时候一直保持的是1


10.在位于0x1000FF58处的子过程中的几百行指令中,一系列使用memcmp来比较字符串的比较。如果对robotword的字符串比较是成功的(当memcmp返回0),会发生什么?

解答: 这个函数我们刚刚看过,但是没细入分析过

整个从0x1000FF58开始的函数,第一个使用memecp是这里(标黄的那里

这里

一开始是比较了quiteax的值,因为这两个值被压入了栈中

然后我们找到robotwork,慢慢往右下角拖就是了

robotwork

它首先压入了一个robotwork字符串指针,然后压入了eax,然后call memcmp,如果两个数相同,返回0,然后

add eap, 0Ch

0Ch12d,也是4(字节)*3(个),因为push后面跟的是立即数,所以一个数占4字节,然后offset也是4个字节,所以,一开始的push 9,和后面的两次push,加起来一共是3次,所以这里回收了这3个一共12字节的空间

test eax, eax

如果eax0,则ZF置为1JZ跳转,eax0说明前面的memcmp比较的结果是相同,也就是

如果前面两个数相同,则JZ跳转,JNZ不跳转

然后问题当字符串比较成功,memcmp返回0会发生什么

会发生的是,JNZ不跳转,程序继续按从上到下的顺序执行,下面要执行的就是

无

push [ebp+s] ; 将ebp(esp是栈顶指针,ebp是栈基址)地址增加s
             ; (栈中,esp地址减小,栈空间增大,ebp增加,ebp将向栈底偏移)
             ; 将ebp向下s的指针地址压栈
call sub_100052A2
jmp short loc_100103F6

然后就是调用了sub_100052A2这个函数

这个函数是这样的

程序

其他的都可以不管,看最下的地方

这个函数查询了

值

SOFTWARE\Microsoft\Windows\CurrentVersion

这个注册表的地方,用的是RegOpenKeyExA

其实这里也只查询了这个,没有查询书中说的那个WorKTime,在这个注册表目录下,甚至就没有这个项

无

然后跳转到这里

跳转

书中说

将这一信息返回给push [ebp+s]处传给该函数的网络socket

s是这里定义的

s

但是不知道是怎么把这信息返回给上面的的参数的

返回


11.PSLIST导出函数做了什么?

解答: 我们打开导出函数表

导出函数

这个函数有两条执行大路径

路径

然后执行的选择取决于这个sub_100036C3

取决

这个函数返回的是1

返回

call    ds:GetVersionExA ; 调用函数查看系统版本
cmp     [ebp+VersionInformation.dwPlatformId], 2 ; 这个我们上面说过,如果等于2,是那些windows版本
                                                 ; 包括`Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, Windows XP, or Windows 2000`
jnz     short loc_100036FA ; 如果不想等,则跳转结束
cmp     [ebp+VersionInformation.dwMajorVersion], 5 ; 5代表特殊版本的windows
jb      short loc_100036FA ; 无符号比较,如果[ebp+VersionInformation.dwMajorVersion]小于5跳转
push    1
pop     eax
leave                   ; High Level Procedure Exit
retn
cmp     [ebp+VersionInformation.dwMajorVersion], 5

这里的5代表什么意思

5

代表的就是这么几个版本的windows

所以这个函数的作用就是具体判断目标主机的系统版本,如果是过低的版本,就直接跳转结束

如果是符合要求的版本,则返回1

无

然后就是比较跳转,如果eax0test之后,ZF1,然后JZ跳转
如果eax不为0ZF不为0,然后JZ不跳转
也就是如果版本符合要求,就不跳转(跳转之后是直接结束)

不

不跳转之后,push了一个字符串进去,然后调用strlen返回字符串的长度在eax中,然后test eax, eax

如果eax(字符串长度)0ZF置为1JNZ不跳转
反之如果不为0JNZ跳转

假设eax0JNZ不跳转,我们走一下这条线

不跳转

那么下一个执行完push之后,就是执行call sub_10006518

无

从汇编中可以看出,这个sub_10006518执行了这个函数CreateToolHelp32Snapshot,这个函数是

CreateToolhelp32Snapshot函数为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]。

然后我们看跳转那条线

跳转

跳转这条线上(蓝色),它将字符串压入栈之后,又压入了一个0,然后调用了sub_1000664C这个函数

无

这个函数依旧还是调用了CreateToolHelp32Snapshot这个函数,然后还有GetLastErrorsprintf这些个函数

sprintf函数的输出是

无

所以我们不难想,GetLastError是用于判断CreateToolHelp32Snapshot这个函数有没有执行成功的

无

如果失败,就执行endp(也就是图中标注的exit_0)

如果成功,则执行retn(也就是图中的return_0)

按照书中的说法

这两条代码路径都通过send将进程列表通过socket发送

但是我是没找到这个sendsocket这两个函数

无

唯一能扯上一点关系的就是这里有个

push [ebp+s]

但是这个s是如何看出就是代表socket或者send呢,不得而解


12.使用图模式来绘制出对sub_10004E79的交叉引用图。当进入这个函数时,哪个API函数可能被调用?仅仅基于这些API函数,你会如何重命名这个函数?

解答:: 按照书上的做法

这里

我们跳到指定位置之后,按照这个菜单,点击

然后出来这个

出来

直接默认点确定就行了

然后就出现这个了

出现

我们关心的主要是下面这三层

可以看出这个函数sub_10004E79主要调用的有

GetSystemDefaultLangIDsprintfsub_100038EEstrlen

sub_100038EE主要调用了sendmallocfree__imp_strlen

然后GetSystemDefaultLangID是获取系统的默认语言的函数,sendsocket发送的函数

由此我们可以按照书上的做法,将这个函数重命名为send_languageID


13.DllMain直接调用了多少个Windows API?多少个在深度为2的时候被调用?

解答: 搜索DllMain找到这个函数的位置

DLL

然后用上面的方法打开视图

视图

会发现视图极其庞大。。。(因为默认Recursion depth为-1)

我们重新打开,将这里改为1

深度

然后就可以看到调用深度为1的所有函数了

深度为1

所以DllMain在深度为1直接调用的API也就是strncpy_strnicmpCreateThreadstrlen这么几个

要知道全部的 API,那就得一个一个数了。。。

深度为2

同样的方法查看深度为2时候的调用(很大的调用表)


14.在0x10001358处,有一个对Sleep(一个使用一个包含要睡眠的毫秒数的参数的API函数)的调用。顺着代码往后看,如果这段代码执行,这个程序会睡眠多久?

解答: 我们跳到那个地方看看

函数

Sleep函数的参数是压入栈的eax,而这个eax从哪里来,是call ds:atoi的返回值,再乘以3E8h,最后就被压入了栈中,供Sleep做入参

atoi的参数是从前面的push eax中来的,eax的根源是从off_10019020传进来的

off_10019020的值放在这里

无

[This is CTI]30

然后执行了这个(这个前面说过,指针的+多少相当于指针往后偏移多少

 add eax, 0Dh

0Dh相当于十进制的13d

往后偏移13个字节,最后指针指向3(从0开始数)

然后将指向3的指针压入栈,其实现在指针就相当于这样

char origin_str[] = "[This is CTI]30";
char *p_str = origin_str;
p_str = p_str + 13;

最后输出的p_str就是30,然后调用这个atoi,它是把字符串(char)转换成整型(int)的函数

call ds:atoi

然后这个函数的输出就是(int)30

imul eax, 3E8h

3E8h就是1000dimul是乘,然后301000就是30000(3w)

然后我们从MSDN确定一下单位

单位

这里显示是以milliseconds为单位,就是毫秒,30000ms = 30s

所以这个函数会休眠30s


15.在0x10001701处是一个对socket的调用。它的3个参数是什么?

解答: 我们还是先跳到这个函数的位置

socket

这里是将612压入了栈中,然后我们不知道具体的配置信息,按照书中的做法

无

然后就会跳出一大堆的东西

无

然后我们查找一下关于socket有关的函数,这时候如果你对socket的相关函数的参数不是很清楚的话,建议还是查查MSDN

我们都知道栈是先进后出的类型,先压入的数据,其实是最后才调用的

MSDN

最后压入的是2这个数(汇编不像其他高级语言,参数的顺序可以颠倒),然后2应该对应的就是af这个参数

我们就点开2的对话框,然后去MSDN查对应的值,一般输入都有的头就可以了

MSDN

这里是AF,一般这种对应表里面,一个函数用的到的,肯定只会出现一次,果不其然,我们搜AF之后,就会发现,这里之后两个AF开头的

AF

除了第一个的AF_INET之外,还有一个AF_OP_COMM,其实这个并不是socket函数的参数

太长

太长了截不完,不信的同学可以自己上MSDN去查(手动滑稽)

然后我们就可以将这个参数重命名一下

重命名

大概看起来就像这样,然后我们按这种方法来找(其实双击你找到的那个对话框里面的参数名就可以重命名了)

然后第二个压入栈中的1,在socket中对应的是type

这里都有的

这里都有的都是带sock

sock

然后注意就是不要和socket混淆了,这里是sock,然后就是为什么会出现两个一摸一样的SOCK_STREAM,其实一个东西

一样

一个是MS SDK另一个是Virtual C++ 6.0,其实都是一样的,然后我们重命名一下

最后一个6,它是第一个压入栈中的值,但是却是最后调用的

他对应的是protocol

protocol

这里只有搜IPPROTO就可以了

一样的方法

一样的

然后最后把这些符号常量重命名之后,汇编代码成了这样的

这样

我们的函数入参就一目了然了,稍微解释了一下这三个参数的意思

AF_INET 用于连接连接对象是IPv4时(对应的IPv6用的是 AF_INET6)

SOCK_STREAM 用于连接方式使用TCP时候(对应的UDP对应的是SOCK_DGRAM)

IPPROTO_TCP 用于继续指明传输的方式是TCP(对应的UDP是IPPROTO_UDP)


16.使用MSDN页面的socket和IDA pro中的命名符号常量,你能使参数更加有意义吗?在你应用修改之后,参数是什么?

解答: 就是上面刚刚分析的那些参数。。。感觉分析多了


17.搜索in指令(opcode 0xED)的使用。这个指令和一个魔术字符串VMXh用来进行VMware的检测。 在这个恶意代码中被使用了吗?使用对执行in指令函数的交叉引用,能发现进一步检测VMware的证据吗?

解答: 按照书上的做法我们试试

无

这里搜索要学会使用技巧,不然出一大堆没用的东西

无

然后我们可以发现,出了一些不是运算的注释和名称之外,只剩下标黄这个东西可以值得点开看看,如果是在不确定,可以一个一个点开看看

无

我这一版本的IDA并没有标注这个二进制的意思,书上是标注出来的

右键

我们右键,会显示出各种不同的编码结果

可以发现有个VMXh,但是书中说经过一个比较之后,后面会发现一个Found Virtual Machine字符串,但是目前暂时没发现这个字符串


18.将你的光标跳转到0x1001D988处,你发现了什么?

解答: 这个我们跳了看看就知道了

无

发现一些不知道什么鬼的东西,然后按照书中说的,我们运行这个python代码看看

运行这个脚本的前提是装了python


19.如果你安装了IDA Python插件(包裹IDA Pro的商业版本的插件),运行Lab05-01.py,一个本书中随恶意代码提供的IDA Pro Python脚本,(确定光标是在0x1001D988处。)在你运行这个脚本后发生了什么?

解答: 运行这个python脚本之后,其实没啥变化,如果你不仔细看的话

其实字符已经变了

租房也

然后现在这串字符串已经变可读了,反正就是在那一瞬间,哈哈哈


20.将光标放在同一位置,你如何将这个数据转成一个单一的ASCII字符串?

解答: 这个其实前面的就是ASCII码,也就是db后面的

可以在设置里面开自动注释来显示

注释


21.使用一个文本编辑器打开这个脚本。它是如何工作的?

解答: 如下

脚本解释

本文完

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值