第 5 章:IDA Pro
Last updated
Last updated
只用 IDA Pro 分析在文件 Lab05-01.dll 中发现的恶意代码。这个实验的目标是给你一个用 IDA Pro 动手的经验。如果你已经用 IDA Pro 工作过,你可以选择忽略这些问题,而将精力集中在逆向工程恶意代码上。
答案:.text:1000D02E。
答案:.idata:100163CC。
答案:选择 Imports 视窗,找到 gethostbyname(注意:IDA Pro 中的函数名排序是区分大小写的,大写字母在前,小写字母在后,所以需要往后翻),双击跳转到定义位置。Ctrl + X 查看交叉引用。
看上去有 18 行,实际上 IDA Pro 6.8 计算了两次交叉引用,一次是类型 p(被调用的引用),另一次是 r(被读取的引用)。所以是 9 次交叉引用。按照 Address 排序,仔细数一下,一共被 5 个函数调用。后面 + 号和 : 号都是偏移地址,都属于同一个函数。
答案:按 G 输入跳转的地址 0x10001757,或者直接在上面的交叉引用的表格里选中sub_10001656+101 一项,点击 OK:
跳转到对应的地址:
查看输入参数需要往上找 3 行,在 off_10019040 处。双击偏移地址,可以发现该地址开始储存了字符串 “[This is RDO]pics.practicalmalwareanalysis.com”。把光标悬浮在这里就可以看到存储的内容,或者在右边的注释中也有:
在上上图中,注意到 mov eax,off_10019040 后面还有一句 add eax,0Dh,也即偏移 13 个字节,所以实际上请求的 DNS 为 “pics.practicalmalwareanalysis.com”:
字符串在内存中是这样存储的:
答案:按 G 跳转到 0x10001656。然后很有可能发现直接就是汇编(红框),这时需要往上翻(粉框),看到绿色的部分(紫框),也就是 IDA Pro 识别出来的局部变量。5 个一组,细数一下是 23 个(不包含最后一行的 lpThreadParameter,因为是传入的参数)。不同版本识别能力或许有差异,和这个数字可能会有些出入。
答案:见上图橙色框出部分(两处),上面一处表明传入的参数为 lpThreadParameter,然后在下面一处也被识别出来了,也即 dword ptr 4。所以 IDA Pro 识别了子过程中的 1 个参数。
答案:通过 View > Open Subviews > Strings,或者 Shift + F12 打开 Strings 窗口。Ctrl + F 搜索 cmd。
在地址 xdoors_d:10095B34 处可以找到 \\cmd.exe /c。
双击查看汇编代码,按下 Ctrl + X 查看交叉引用,有且仅有 sub_1000FF58+278 一处:
答案:将上图中的重要信息框出:
在上图中,点击 OK,跳到 cmd.exe 被交叉引用的地方,也即 .text:100101D0 处,该命令被压栈。在命令的后面还能看到用 memcmp 比较 recv、quit、exit、cd、uptime 等指令字符串。在青框中的注释里,也出现了字符串 “This Remote Shell Session”。因此猜测这是一个远程 Shell 会话函数。
右键选择 Graph View,可以看到图形化的表示。
答案:跳到 100101c8,cmp dword_1008E5C4,ebx,也即将 ebx 同该全局变量比较。
双击跳到定义位置(.data:1008E5C4),Ctrl + X 查看交叉引用,只有 sub_10001656+22 处的 mov dword_1008E5C4,eax 语句修改了该值。选中,点击 OK 跳到对应位置。
其中 eax (蓝框)是上一行调用的函数 sub_10003695 (粉框)的返回值,双击进入该函数:
可以看到该函数调用了 GetVersionEx,也即获取当前操作系统的信息,xor eax,eax 语句将 eax 置 0,并且,cmp [ebp+VersionInformation.dwPlatformId],2 语句将平台类型同 2 相比。
根据微软的文档,我们得知通常情况下 dwPlatformId 的值为 2:
dwPlatformId
: The operating system platform. This member can be the following value.
OSVERSIONINFOA (winnt.h) - Win32 apps | Microsoft Docs
所以通常情况下,cmp 操作中,src==dst,则标志寄存器 ZF=1、CF=0,setz al 的含义是如果 ZF=1 则置 al 为 1。因此 al 的结果为 1。由于 al 是 eax 的最低 8 位,且 eax 此前已经通过异或操作置 0,故此时 eax 的值为 1。故 sub_10003695 执行完后,eax 为 1,紧接着执行 mov dword_1008E5C4,eax,故 dword_1008E5C4 的值为 1。
答案:跳转到 1000FF58 处的子过程,往上翻一点查看 subroutine 识别出来的变量与参数。
往下翻很多,可以到不少 memcp 语句,好多在前面的问题分析中都出现过:
终于在 1001044C 处找到了 robotworks(红框)。往下两行可以看到 call memcmp(粉框)。如果 eax 和 robotwork 相同,则 memcmp的结果为 0,也即 eax 为 0。
test 的作用 和 and 类似,只是不修改寄存器操作数,只修改标志寄存器,因此 test eax,eax (紫框)的含义是,若 eax 为 0,那么 test 的结果为 ZF=1。结合 jnz short loc_10010468 语句,若 ZF=1,则不会跳转,继续向下执行,直到 call sub_100052A2。
这里顺便解释一下 10010457 处的 add esp,0Ch 语句。0Ch=12d,由于上面三次 push(9、offset aRobotWork、eax)均为 2 个字,也即 4 字节,那么这三次总计 12 字节,将 esp 增加 12 字节,也就是把栈指针向“底部”移动 12 字节,等价于将此前那三次 push 的内容“回收”或者“丢弃”了。
双击查看 sub_100052A2 的代码。其参数为 socket 类型。也就是上图中 1001045E 处 push 进去的 [ebp+s]。其他可以忽略,往下一直翻到 100052E7 处的 aSoftWareMicros(红框),其值为 “SOFTWARE\Microsoft\Windows\CurrentVersion”。最后调用 RegOpenKeyEx 函数(蓝框),读取该注册表值。
在 CurrentVersion 的键值下,跳到 loc_10005309(红框),取得 WorkTime 的键值(粉色+蓝色)。
再跳到 loc_10005379(紫框),取得 WorkTimes 的键值(粉色+蓝色)。
按书中所述,这些信息最终传给了此前 push 进去的 [ebp+s] 也即 socket s 处。
答案:在 Exports 窗口找到 PSLIST,双击点开。首先调用 sub_100036C(红色)。
双击点开如下图。若 dwPlatformId 不为 2(粉色),或 dwMajorVersion 小于 5(蓝色),则 eax 为 0(绿色),否则 eax 为 0(橙色)。
在第 9 问中已经讨论过,绝大多数系统的 dwPlatformId 都为 2。对于 dwMajorVersion,不同系统的值如下表所示。可见绝大多数系统的值也都是大于等于 5。
OSVERSIONINFOEXA (winnt.h) - Win32 apps | Microsoft Docs
总之,对于绝大数系统,这两个判断得到的结果,都应当得到 eax 为 1。
为了参考方便,再次放上 PLIST 的图。上面讨论过,eax 通常应为 1,因此一般情况下不进行下图红色部分的跳转(跳转是直接结束),而是继续向下执行。先 push 一个字符串 Str,然后求出其长度(蓝色),存入 eax。若该字符串非空,那么 eax 非 0,也即 test eax,eax 得到 ZF=0,那么将会进行 jnz short loc_1000704E (紫色)的跳转。空字符串的情况我们就略掉。
跳转后会执行 sub_1000664C(橙色)。
双击点开,并且往下翻,可以看到调用了 CreateToolHelp32Snapshot:
CreateToolhelp32Snapshot 的作用是,为指定的进程,及其使用的堆、模块和线程,拍摄快照:
Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes.
CreateToolhelp32Snapshot function (tlhelp32.h) - Win32 apps | Microsoft Docs
执行完 sub_1000664C 之后,pop ecx,再 retn、endp,PSLIST 返回。
综上,PSLIST 的作用应该是获得一个进程的列表。又依据书中所述,获得的进程列表将通过 socket 的 send 发送。
答案:View > Graphs > User xrefs chart ...,起始和终止地址均设置为 .text:10004E9C,得到交叉引用图(或者 G 到地址 10004E9C,然后右键 Xrefs graph from)。主要调用的 API 为 GetSystemDefaultLangID 和 send。因此推测可能是将系统的默认语言标识发送出去。可以重命名为 send_lang_id。直接在函数名处右键 Rename 即可。
答案:按 G 跳到 Dllmain 的起始位置 1000D02E(或者 View > Open SubViews > Functions,然后找到 DllMain(x,x,x),然后双击),接着右键 Xrefs graph from ...,可以看到图中一团黑。
所以还是应当使用 View > Graphs > User xrefs chart ... 选项弹出对话框,曲线勾选 Cross references to,并且将 Recursion depth 从 -1 改为 1。可以看到调用的 Windows API (粉色)为 CreateThead、strncpy、strlen 以及 _strnicmp。
答案:调用的 sleep(红色)的参数为上一行 push 的 eax,eax 的值又来自乘法 imul eax,3E8h 的运算结果(蓝色)。3E8h 的十进制为 1000,也可以通过右键该数字查看。再往上,eax 是由 atoi 函数(粉色)对 Str 运算得到的,也即字符串转整数。
再往上,该 Str 由 off_10019020+0Dh 位置的字符串得到(橙色),也即 “30”,最终转换成数字 30。
所以睡眠的时间应为 30*1000 = 30000(毫秒),也即 30 秒。Sleep 函数的官方文档如下:
Sleep function (synchapi.h) - Win32 apps | Microsoft Docs
答案:IDA 中显示的三个参数名:af、type、protocol。
socket 的官方文档如下:
socket function (winsock2.h) - Win32 apps | Microsoft Docs
查看文档,af(2)、type(1)、protocol(6)中的数字分别对应:
因此输入的参数含义为建立基于 IPv4 的 TCP 连接的 socket,通常在 HTTP 中使用。
在数字上右键,Use standard symbolic constant,分别替换成实际的常量名,如图:
答案:Search > Text(Alt+T),输入 in;或者 Search Sequence of Bytes(Alt+B),输入 ED。然后选择 Find All Occurences。搜素结果中只有在地址 100061DB 处的一条 in eax,dx 的指令符合要求。
双击跳转到对应位置,可以看到 eax 中储存了字符串 “VMXh”,也就确认了这段代码采用了反虚拟机技巧:
往上翻到所在函数的入口处,也即 sub_10006196(粉色),按下 Ctrl+X 打开交叉引用,选择第一个,点击 OK。
可以看到该函数的后文中也出现了字符串 “Found Virtual Machine,Install Cancel.” 的字眼,印证了我们的猜测。
答案:发现了一段看似随机的数据。据书中所述,需要运行一段 Python 脚本。
该 Python 脚本内容如下:
一定确保光标恰好停在 0x1001D988 处(如果不是,就关闭文件再打开一次,否则转换始终是不对的),然后点击 File > Script file(Alt+F7),选择 Lab05-01.py。会自动运行,然后可以看到这部分的数据发生了变化。注释的 ASCII 字符由原来的乱码变成了有意义的内容。图太长,略。
答案:在地址 0x1001D988 处,右键选择转换成 ASCII 字符串(或者按下 A 键),得到字符串 'xdoor is this backdoor, string decoded for Practical Malware Analysis Lab :)1234':
答案:再次粘贴 Lab05-01.py 的源代码如下。其作用就是从光标选中位置开始,共 0x50 个字节,将每个字节同 0x55 作异或运算(相当于解码),再写入 IDA 的数据库中(所以我们能够立刻看到修改结果)。
恶意代码分析实战 Lab 5-1 习题笔记_isinstance的博客-CSDN博客
[原创]《恶意代码分析实战》第五章IDA Pro(Lab5-1分析报告)-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com
恶意代码分析实战 — Lab 05-01 – Atom Kid
Value
Meaning
VER_PLATFORM_WIN32_NT 2
The operating system is Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, Windows XP, or Windows 2000.
Operating system
Version number
dwMajorVersion
dwMinorVersion
Other
Windows 10
10.0*
10
0
OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2016
10.0*
10
0
OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 8.1
6.3*
6
3
OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2012 R2
6.3*
6
3
OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 8
6.2
6
2
OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2012
6.2
6
2
OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows 7
6.1
6
1
OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2008 R2
6.1
6
1
OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Server 2008
6.0
6
0
OSVERSIONINFOEX.wProductType != VER_NT_WORKSTATION
Windows Vista
6.0
6
0
OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION
Windows Server 2003 R2
5.2
5
2
GetSystemMetrics(SM_SERVERR2) != 0
Windows Home Server
5.2
5
2
OSVERSIONINFOEX.wSuiteMask & VER_SUITE_WH_SERVER
Windows Server 2003
5.2
5
2
GetSystemMetrics(SM_SERVERR2) == 0
Windows XP Professional x64 Edition
5.2
5
2
(OSVERSIONINFOEX.wProductType == VER_NT_WORKSTATION) && (SYSTEM_INFO.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
Windows XP
5.1
5
1
Not applicable
Windows 2000
5.0
5
0
Not applicable
参数名
输入数字
常量名
说明
af
2
AF_INET
使用 IPv4
type
1
SOCK_STREAM
TCP 连接
protocal
6
IPPROTO_TCP
TCP 协议