恶意代码分析实战(三)

1:DllMain的地址是什么?

image-20191213173917324.png

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

image-20191213174017362.png

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

image-20191213174044141.png

4: 将精力集中在位于0x10001757处的对gethostbyname的调用,你能找出那个DNS请求将被触发吗?

image-20191213180757726.png

在这儿,找DNS,前面PUSH了这样一个字符串,跟进去

image-20191213180828528.png

image-20191213180859421.png

image-20191213180904886.png

这个就是要DNS查询的地址,上面在压栈的时候有add eax,0dh的操作,因此指向的就是pics.praticalmalwareanalysis.com

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

image-20191213212713210.png

局部变量有23个

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

参数就是IpThreadParameter=dword ptr 4这一个

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

image-20191213213025628.png

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

image-20191213213438591.png

上面的部分看上去像是一个命令行操作

image-20191213213936548.png

上面一部分就是开启一个系统进程,然后GetSystemDirectoryA获取系统目录,然后在系统目录下面执行命令行cmd.exe或者是command.exe

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

image-20191213223357790.png

这一处我已经改名字

前面的这个判断是一个GetVersionExA的API

image-20191213223110763.png

查询这个API是干什么的,发现就是判断是不是windows 2000的,因为在windows 2000之前的命令行是command.exe,这也是为什么要有上面的判断的原因

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

首先分析前面

image-20191213223836408.png

image-20191213223847953.png

屏幕上显示这么一串字符串,前面是显示时间的一串操作,然后最后一句话有点意思,说是加密的魔数,然后就是这个dword_1009E5D0,待会儿逆向一下,我们先按照要求看下面的memcmp函数

image-20191213224323988.png

这个函数的s就是来自socket 的远程指令

image-20191213224352251.png

这一堆memcmp长得像是CTF里面经常出现的虚拟机,其实就是判断远程发送过来的指令,并通过不同的函数来执行远程发出的指令

我们找到RobotWork的指令部分

image-20191213224534691.png

然后对这个函数跟进去逆向(已改名)

image-20191214141604980.png

获取注册表的HKEY_LOCAL_MACHIME\SOFTWARE\Microsoft\Windows\CurrentVersion里面的Worktime的值,然后传入这个sub_100038EE函数里面

又跟进去之后发现

image-20191214145022619.png

就是把worktime时间加上一个偏移,然后发送到远程套接字里面

image-20191214145217009.png

查询前面这个dword_1008E5D0就是和魔数的加密有关,留待后面破解

11、问题:PSLIST导出函数做了什么?

在导出函数窗口找到这个函数

image-20191214145325997.png

跟进去看

image-20191214145536247.png

之前的遇上的函数,result就是这个是否是32位windows,以及是否是windows server 2003之后的版本

然后就是分支,由于这个函数的调用还不明确,所以这个result就是在如果这个是符合条件的结果之后的分支,我们就跟进去,首先是符合条件的这个sub_1000664C()这个函数

image-20191214150758268.png

经过一通逆向之后算是弄明白了这个,就是获取当前进程列表并远程发送给套接字,写入进去一个叫做Xinstall.dll的文件里面,成功就返回0,失败就返回1,这个函数改名为getProcessList

接下来进入分支的第二个函数sub_10006518()

image-20191214151035079.png

和上面的函数功能大致一样,获取进程列表,但是这个只是写了Xinstall.dll,并没有发送到套接字,函数改名为getProcessListNoSend()

至此这个PSLIST被我们分析完毕

image-20191214151445007.png

首先是获取操作系统版本,如果版本过低或过新,return false,如果版本符合windows 2000-windows 8.1 x32,那就遍历进程列表,根据传入的str的进程名字来决定发送哪一个进程。

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

image-20191214152132352.png

图模式打不开,看这个也是一样的

image-20191214152152206.png

进去之后一通改名,发现这个函数就是获取系统语言,然后发送给套接字的,这个函数我们改名为sendLanguageInfo()

13、问题:DllMain直接调用了多少个Windwos API? 多少深度为2时被调用?

image-20191214152906311.png

由于无法看图,就在题解中找了个图

img

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

image-20191214153227893.png

我们进入伪代码界面

image-20191214153248408.png

sleep1000*v14 ms,现在就是要找v14,是由一个字符通过atoi转化的

image-20191214153355596.png

查到这个[的ascii是91,加上13,也就是sleep一共104秒

15、问题:在0x10001701处是一个对socket的调用,它的3个参数是什么?

image-20191214154045868.png

三个参数倒序入栈,搜索参数含义,找到了函数原型

官方文档

https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket

1
2
3
4
5
6
7
8
9
#include <cket.c>
int __socket (domain, type, protocol)
int domain;
int type;
int protocol;
{
__set_errno (ENOSYS);
return -1;
}

af = 2 = AF_INET

type = 1 = SOCK_STREAM

protocol = 6 = IPPROTO_TCP

综上可知,是建立一个TCP流式通信的连接

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

image-20191214155026920.png

通过IDA的Symbolic Constant改名就好看多了

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

使用alt+t来搜索in指令,发现了如下的vmxh魔数

image-20191214155409861.png

image-20191214155604603.png

使用xref查看引用,发现了三个地方在调用检测vmware的函数

image-20191214155733402.png

如果发现了VMware,就在日志里面输出

image-20191214155814569.png

实锤了检测VMware的操作

18、问题:将光标跳转到0x1001D988处,你发现了什么?

image-20191214160029679.png

看上去是一堆乱码

写个脚本进行xor操作看看是什么

1
2
3
4
5
6
7
8
9
10
11
12
13
a = [0x2D,0x31,0x3A,0x3A,0x27,0x75,0x3C,0x26,0x75,0x21,
0x3D,0x3C,0x26,0x75,0x37,0x34,0x36,0x3E,0x31,0x3A,
0x3A,0x27,0x79,0x75,0x26,0x21,0x27,0x3C,0x3B,0x32,
0x75,0x31,0x30,0x36,0x3A,0x31,0x30,0x31,0x75,0x33,
0x3A,0x27,0x75,0x05,0x27,0x34,0x36,0x21,0x3C,0x36,
0x34,0x39,0x75,0x18,0x34,0x39,0x22,0x34,0x27,0x30,
0x75,0x14,0x3B,0x34,0x39,0x2C,0x26,0x3C,0x26,0x75,
0x19,0x34,0x37,0x75,0x6F,0x7C,0x64,0x67,0x66,0x61]
res = ''
for i in a:
chs = i^0x55
res+=chr(chs)
print(res)

结果如下

image-20191214160558499.png

额外

现在我们还差一个对之前magicNumberWaitiongForCrack进行逆向破解的过程了

image-20191214161136943.png

因为在sendtoSocket()函数会被调用很多次,这个变量就是在这个函数里面

打开交叉引用查看引用

image-20191214161218525.png

找到对赋值的最后一个函数,进去看看

image-20191214161326717.png

这是个随机数,获取CPU始终周期,然后取低5位,+1,然后作为一个偏移

image-20191214161458729.png

再结合之前的这个函数,就明白了,远程发送Enmagic被接收到了之后就显示这个随机数,因此这个变量就得改名为randomMagicNumber

在进行发送的时候都会加上这样一个数字来进行加密