《恶意代码分析实战》这本书简要的讲了一下IDA咋用,虽然以前做CTF也用过,但是只是一些简单的题,所以只会Ctrl+F,搜索“main”,然后F5,看伪代码。经过一段时间的简单学习,好像会一点点了,但是真的只会一点点。即便如此,我还是记录一下这次的学习吧。
在这学习之前,我还是要瞎扯几句。作为初学者,我按照书上的注意事项,选择了binary方式反编译,然而,啥也没有,连导出和导入函数都没有。果然初学者还没有理解透的情况下还是默认反编译吧。文中多多少少会有一些错误的地方,请各位看官多指正。
分析目标:lab5-1.dll
1. DLLMain的地址是什么?
选中函数列表,Ctrl+F,搜索DLLMain,双击该函数,IDA自动定位到该函数的内存地址处。地址是1000D02E
2. 使用Imports窗口并浏览到gethostbyname,导入函数定位到什么位置?
点击Imports,进入导如函数窗口,Ctrl+F,搜索gethostbyname,获得地址100163CC。
3. 有多少函数调用了gethostbyname?
在第二步,双击gethostbyname,链接到该函数处,按“X”键,获得交叉引用次数。除去重复的,由此可知有5个函数调用了它
4. 注意0x10001757处对gethostbyname的调用,请问哪一个DNS请求将被触发?(原问题意思,太长了)
在汇编界面,按“G”,弹出地址跳转窗口,输入该地址,点击ok
似乎已经告诉了是哪个DNS了,直接双击off_10019040就可以了,但是还是分析一下吧。
直接看调用,使用了call函数调用,百度了一下,call在操作栈,把栈顶的数据作为参数传给函数,往上看发现一个push命令,将eax值压入栈中,在找eax值,网上是个add指令,加法指令,加上0D,十进制为13,为什么要加十三呢?在往上看,发现一个mov指令,将off_10019040赋值给eax,直接双击该参数,就跳转到了这个位置。
发现一个aThisIsRdoPicsP的东西。再双击该该变量,直接获取字符串。
然而那个add指令就很迷,一直不是很明白,主要是无法辨别给的是地址还是数值。但是这样想就对了。字符串和10进制数相加是没有意义的,只有一种可能就是offset传递的是aThisIsRdoPicsP的地址,eax首先获取的也是地址,而此时eax所获得的地址是第一个字符的,也就是“[”,加13之后,eax的地址指向的是“p”,也就是类似于c语言的指针。
因此DNS的内容就是pics.praticalmalwareanalysis.com。
5. IDA Pro识别了在0x10001656处的子过程中的多少个局部变量?
直接跳转到此处,跳转方法此处略过,直接看IDA给你是被出来的东西,根据书上所说,IDA会把局部变量标记为var前缀,存在负偏移,因此数一数有多少个var前缀的就行和有负偏移的个数,所以有23个。
6. IDA Pro识别了在0x10001656处的子过程中的多少个参数
借用5题图,结合书本所说,参数一般使用arg前缀,存在正偏移,所以只有1个参数(lpThreadParameter)。
7. 使用String窗口,来在反汇编中定位字符串\cmd.exe /c。它位于哪?
view -> opensubview -> strings,打开strings窗口,然后Ctrl+F,搜索\cmd.exe /c。其地址为10095B34。
8. 在引用\cmd.exe /c的代码所在区域发生了什么。
双击该选项,跳转到代码块。
但是这只是个变量,没有任何代码,它是被其他地方引用了,再双击后面的自动注释,跳转到这个字符串被引用的地方。当然可能好多地方都引用了,所以选中变量名,按“X”,发现只有一个地方被引用了,就直接跳转吧。
然后就发现这个字符被压入了栈中,我认为我可以好好的看看汇编,然后我就懵啦~,然后我就不会啦~。我去看了书后的答案。首先打开函数图形化,也就是对当前函数制作流程图。view -> graphs -> flowchart,就能获得一个流程图,图太大了,就不放了。然后看流程图会发现有很多分支,把每一个小矩形都看一遍会发现一些东西,比如closesocket,由此判断既然可以关闭socket,那就要打开它,但是我并没有看到有打开的函数,可能不在这个地方,由此判断开启这个函数应该需要开启会话。
开启会话后,该函数还做了一些操作,可能需要创建一些东西。
之后还会看见一些“inject”的字样,还能创建进程,似乎还要运行一个exe。
整体看下来还有一些获取当前文件的操作,我估计是个远控程序的样子,但是这样给出答案是有些粗糙了,证据太少了。最后看了一下书后的答案,书中表示还看到了cd,exit,install,甚至还看到了this remote shell session(0x1001009D)。
答案直接写我脸上了。然而我没看到几个,事实证明只能函数流程图只能辅助。
9. 在同样的区域里,在0x100101C8处,看起来好像dword_1008E5C4是一个全局变量,它帮助决定走那一条路径?恶意代码是如何设置dword_1008E5C4的?(提示:使用dword_1008E5C4的交叉引用)
先跳转到 这个位置上,然后选中这个变量,然后按“X”查看交叉引用,发现有3处交叉引用。
根据direction,双击第一个,进入第一次被引用的地方(从书本后面的答案来看,跳到这里的目的也是因为只有在这里被修改过)。然后向上看代码,第一次被引用的地方向上不多就到了函数的起始部分。
从其指令来看,是把eax的值给了dword_1008E5C4,所以是把sub_10003695这个函数返回值赋给了dword_1008E5C4,先不看它如何被赋值,先看这个值帮助决定走哪条路。直接看代码还是挺累的,在查看其余两处引用后,第三个dword_1008E5C4决定是否走command.exe这条;
第二个根据所在函数的注释,也不知道干啥,该不会是要打开远程桌面吧。
接下来看它如何被赋值的。直接双击sub_10003695,跳转到该函数,函数内容如下,实在不行还能再看看函数流程图(没有分支,所以没啥用)。
看这个函数主要是要看它返回了什么东西。函数中eax首先赋值的是VersionInformation局部变量然后将94h这个内存空间(我个人理解)给了VersionInformation.dwOSVersionInfoSize,然后将eax压入栈中(这里只是将VersionInformation放入了栈中),然后调用GetVersionExA函数,这个函数是未来获取系统版本的,然后将eax置空,然后比较VersionInfomation.dwPlatformId是不是2。根据微软的文档,dwPlatformId是系统版本的标志位。而前面的dwOSVersionInfoSize有什么用呢,文档中说在调用GetVsersionExA前,必须要设置这个结构体成员,用来声明哪一种数据结构将被传递给函数。
函数判断为2的话,则zf将被置1,之后执行setz指令,setz指令是指当ZF被置位(置1),将al寄存器置1,否则为0。然后函数返回,该函数返回的就是al的值,所以就是将该全局变量直接置1。dwPlatformId为2,平台为VER_PLATFORM_WIN32_NT,具体系统有那些如下所示。
10. 在位于0x1000FFF58处的子过程中的几百行指令中,一系列使用memcmp来比较字符串的比较。如果对robotwork的字符串比较是成功的(当memcmp返回0),会发生什么?
先条状到0x1000FFF58,然后向下找到robotwork所在位置
如果memcmp比较返回0,那么ZF则被置位,所以不执行jnz指令,则调用sub_100052A2函数,然后跳转到loc_100103F6。直接双击该函数进行跳转,然后大致看了一下发现有一个注释(字符串),SOFTWARE//,双击该注释
从条状结果看,它操作了注册表选项SOFTWARE\\Microsoft\\Windows\\Currentversion,
然后调用了RegOpenKeyExA函数,打开指定注册表项,然后调用RegQueryValueExA进行查询。根据书后答案说操作了SOFTWARE\\Microsoft\\Windows\\Currentversion\\WorkTime确实在之后的操作里面出现了WorkTime,但是由于没太看懂代码,所以还是比较懵的,所以书上说返回给了socket,也是一脸懵逼的。
11. PSLIST导出函数做了什么?
进入exports窗口,然后双击该函数,跳转到目的地,函数如下。
函数内容不多,直接看函数流程图吧。
从流程图看有两个分支,然后有几处调用。该函数先把dword_1008E5BC变量置1,然后调用了sub_100036C3,双击后,发现该函数获取了系统平台信息的详细版本信息,准确的说是对比了一下是否是某一个操作系统。
之后出现了分支,true是直接退出,所以看false分支,再次出现两个分支,分别调用了sub_1000664C和sub_10006518。分别查看这两个函数。查看sub_1000664C时,出现了“CreateToolhelp32Snapshuot”的字样,还有最多的字样是“thread”。该函数开启了一个进程(openProcess)。
随后又发现如下字样:
看起来像一个进程列表,猜测该函数获取了系统的进程列表。sub_10006518的内容和这个差不多,所以该函数应该是获取一个进程列表信息。
12. 使用图模式来绘制出对sub_10004E79的交叉引用图。当进入这个函数时,哪个API将会被调用?仅仅基于这些API函数,你会如何重命名这个函数?
在函数视图中(function name),Ctrl+F,搜索该函数,然后双击该函数。然后view->Graphs->Xrefs from,然后就可以绘制出该函数所引用的API,并且从左往右按顺序排列。所以第一调用的API时GetSystemDefaultLangID。
根据其引用函数,可以看出其获取了系统的语言,然后使用send发送。这个函数功能应该就是获取系统语言,因此函数名称可以命名未GetSystemLanguage(书中是send_languageID)。
13. DllMain直接调用了多少个Windows API?多少个在深度2时使用?
同样的方法找到DllMain,然后像上图一样。但是图太大了。所以要改一下,view->Graphs->Xrefs chart,起始地址和结束地址都写DllMain的起始地址,然后选取深度(Recursion deptch)为1,然后绘图。
得知总共调用了4个Windows API。同样的方法,我们可以将深度设为2,就可以知道第2层的东西。图太大就不放了。有三个在第二层使用。
14. 在0x10001358处,有一个对Sleep(一个使用一个包含睡眠毫秒的参数的API函数)的调用,顺着代码向后看,如果这段代码执行,这个程序会睡眠多久?
调用该函数需要传入参数,参数存储在eax中被压入栈中,往上查看eax的操作过程,在0x10001632处,eax被赋值,提示“[This is CTI]30”,是一个字符串,,然后eax加0D,换算过来是13,此时eax指向了“3”,然后将eax压入栈中,然后调用atoi将字符串“30”转化成整型30。然后eax乘以3E8,换算过来是1000,也就是30*1000,最后等于30000,也就是说要睡眠30秒。
15. 在0x10001701处有一个对socket的调用。它的三个参数是什么。
跳转到该地方。
总共向栈中压入了3个数值,分别是6,1,2,后面的注释里写了protocol,type和af,之前写过一些python的socket编程,对此,我们直接搜这个函数看看需要传进去的参数就可以了。经过百度,得知type是传输方式\套接字类型,protocol是传输所用的协议,af是地址族,也就是IP类型(是IPv4还是IPv6)。那传入的参数每一个数字代表什么呢。通过百度查看windows的手册,得知,protocol的6代表IPPROTO_TCP,也就是设置传输协议为TCP。
type的1代表使用internet地址系列,指要使用IP进行通信。
af的2代表使用IPv4进行通信。
16. 使用MSDN页面的socket和IDA Pro中的命名符号常量,你能使参数更加有意义吗?在你应用了修改以后,参数是什么?
结合15题,把6,1,2重命名一下。就是把搜到的东西写上去罢了。右键->rename。
17. 搜索in指令(opencode 0xED)的使用。这个指令和一个魔术字符串VMXh用来进行VMware检测。这在这个恶意代码中被使用了吗?使用对执行in指令函数的交叉引用,能发现进一步检测VMware的证据吗?
search->text…->find all occurrences,然后就可以把所有包含in的内容全搜出来了。然后一个一个找一下。既然是指令,那就直接找指令就行,内容比较多,用书上的另一种方法,search->Sequence of bytes…->find all occurrences,hex。这样搜出来的内容会少一些,然后一个一个找一下就行,也可以再搜索。
之后发现有一个cmp指令,对比0x564D586,转化一下,选中该字符串,按“R”键,于是就看见了VMXh。
那说明这里确实使用in和VMXh进行了虚拟机检测。接下来看一看这函数的交叉引用。
查看每一个交叉引用,都会发现有一段“Found Virtual Machine,Install Cancel”。
说明确实存虚拟机检测。
18. 将你的光标跳转到0x1001D988处,你发现了什么?
有一堆字符串,太长了就不全放了。
19. 如果你安装了IDA python插件(包括IDA pro商业版本的插件),运行Lab05-01.py,一个本书中随恶意代码提供的脚本,(确定光标实在0x1001D988处。)在你运行了这个脚本后发生了什么?
我没有IDA python插件,看书表示运行后这堆字符串改变了。也懒得把字符串全拉出来单独跑一下。书中内容如下。
20. 将光标放在同一个位置,你如何将这个数据转成一个单一的ASCII字符串?
选中,然后按“R”键(文中也说按“A”)。或者打开自动注释。Options->General->Comments
21. 使用文本编辑器打开 这个脚本。它是如何工作的?
获取光标所在位置,然后在0x00到0x50间循环,逐字相加,在与0x55异或,然后输出。