# 第 5 章：IDA Pro

## Lab5-1

只用 IDA Pro 分析在文件 Lab05-01.dll 中发现的恶意代码。这个实验的目标是给你一个用 IDA Pro 动手的经验。如果你已经用 IDA Pro 工作过，你可以选择忽略这些问题，而将精力集中在逆向工程恶意代码上。

### **1、DllMain 的地址是什么？**

答案：.text:1000D02E。

### **2、使用 Imports 窗口并浏览到 gethostbyname，导入函数定位到什么地址？**

答案：.idata:100163CC。

### **3、有多少函数调用了 gethostbyname？**

答案：选择 Imports 视窗，找到 gethostbyname（注意：IDA Pro 中的函数名排序是区分大小写的，大写字母在前，小写字母在后，所以需要往后翻），双击跳转到定义位置。Ctrl + X 查看交叉引用。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqMGQ36_l8JrE0CQ0q%2F-MLqMscR8CrApUVJ0mhk%2F%7B3GFKSD8%257U7L0%60MO61\(M_O.png?alt=media\&token=2746c2f0-3fbf-4911-a9c4-bc4ded8e2858)

看上去有 18 行，实际上 IDA Pro 6.8 计算了两次交叉引用，一次是类型 p（被调用的引用），另一次是 r（被读取的引用）。所以是 9 次交叉引用。按照 Address 排序，仔细数一下，**一共被 5 个函数调用。**&#x540E;面 + 号和 : 号都是偏移地址，都属于同一个函数。

### **4、将精力集中在位于 0x10001757 处的对 gethostbyname 的调用，你能找出哪个 DNS 请求将被触发吗？**

答案：按 G 输入跳转的地址 0x10001757，或者直接在上面的交叉引用的表格里选中sub\_10001656+101 一项，点击 OK：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqNCmLi6f-DJDzQStY%2F-MLqPbHyN1G5XGdxdG78%2FI\)9%24ZYCL%7BX\)5K%7DM%5BVGEU3FN.png?alt=media\&token=1887670c-0c8a-43b1-8473-e405d3ee7ca4)

跳转到对应的地址：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqNCmLi6f-DJDzQStY%2F-MLqQILDIoeQseRYoRgZ%2FKM%60OSZS\)J759~DJ5586WDSH.png?alt=media\&token=9d444009-8bc9-4014-996d-4a2ed8db35f2)

查看输入参数需要往上找 3 行，在 off\_10019040 处。双击偏移地址，可以发现该地址开始储存了字符串 “**\[This is RDO]pics.practicalmalwareanalysis.com”。**&#x628A;光标悬浮在这里就可以看到存储的内容，或者在右边的注释中也有：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqNCmLi6f-DJDzQStY%2F-MLqPnrCbiIjDwIQi4Al%2F%40V\)FURC%5B88X\)CGEP3TYNQEF.png?alt=media\&token=c2e4cd97-1728-4203-8a92-b063e88798c6)

在上上图中，注意到 **mov eax,off\_10019040** 后面还有一句 **add eax,0Dh**，也即偏移 13 个字节，所以实际上请求的 DNS 为 **“pics.practicalmalwareanalysis.com”**：

```
[This is RDO]pics.practicalmalwareanalysis.com
             ↑
0123456789ABCD
```

字符串在内存中是这样存储的：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqTtz5zlcxK5UnA1vG%2F-MLqU3pDtMZ_mXqDFQ_n%2F0W%60B4O1C09E2ZH%5DKCJX%602SA.png?alt=media\&token=8808c746-d63a-44f8-8485-6ee704d13fa3)

### **5、IDA Pro 识别了在 0x10001656 处的子过程中的多少个局部变量？**

答案：按 G 跳转到 0x10001656。然后很有可能发现直接就是汇编（红框），这时需要往上翻（粉框），看到绿色的部分（紫框），也就是 IDA Pro 识别出来的局部变量。5 个一组，**细数一下是 23 个**（不包含最后一行的 lpThreadParameter，因为是传入的参数）。不同版本识别能力或许有差异，和这个数字可能会有些出入。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqXWnlYODoFMo0K9kW%2F-MLqZU7nDEnE1c1VPgJp%2FPR%40%60B%7B\)FUCC9Y05%5DEH%7B%7B5%24F.png?alt=media\&token=e6889581-172a-4226-a182-e4749ae063e5)

### **6、IDA Pro 识别了在 0x10001656 处的子过程中的多少个参数？**

答案：见上图橙色框出部分（两处），上面一处表明传入的参数为 **lpThreadParameter**，然后在下面一处也被识别出来了，也即 **dword ptr 4**。所以 IDA Pro 识别了子过程中的 **1 个参数**。

### **7、使用 Strings 窗口，来在反汇编中定位字符串 \cmd.exe /c。它位于哪？**

答案：通过 View > Open Subviews > Strings，或者 Shift + F12 打开 Strings 窗口。Ctrl + F 搜索 cmd。

在地址 **xdoors\_d:10095B34** 处可以找到 **\\\cmd.exe /c**。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLq_XIPzKjcbqTUpmjb%2F-MLq_wHt411hJMejEazk%2FTQ1HYEFYM~2%60X3M6%5D3_GHX6.png?alt=media\&token=ae67f86c-57a1-40a4-96f7-9096e1f19bc0)

双击查看汇编代码，按下 Ctrl + X 查看交叉引用，有且仅有 sub\_1000FF58+278 一处：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLq_XIPzKjcbqTUpmjb%2F-MLqcL_1gOarndtsBgYh%2FO404QA%7B%5B%244ID1C03BWKQ075.png?alt=media\&token=646f2d27-a497-4997-81fc-9588beb1f839)

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

答案：将上图中的重要信息框出：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqgI-zk6Z8Xe_PPbSu%2F-MLrC0p-REEVARoZZB2E%2FWKQY3BIO03IM2CAE%60WDCF%7BW.png?alt=media\&token=ecab65df-0568-4bb0-b5a5-e1b20f6c78be)

在上图中，点击 OK，跳到 cmd.exe 被交叉引用的地方，也即 .text:100101D0 处，该命令被压栈。在命令的后面还能看到用 memcmp 比较 recv、quit、exit、cd、uptime 等指令字符串。在青框中的注释里，也出现了字符串 “This Remote Shell Session”。**因此猜测这是一个远程 Shell 会话函数。**

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqgI-zk6Z8Xe_PPbSu%2F-MLr-a5SKjaXJuEUB6Rj%2FU%40B9L3%7BBYNL%40XWA77WD9SPF.png?alt=media\&token=f0d86984-66fc-4fc8-a658-273cab4ea12d)

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqgI-zk6Z8Xe_PPbSu%2F-MLr9vrMsopVSiTRuj9W%2FEFW%40%5D1KZ3%5DB%605%2535IG9KL~B.png?alt=media\&token=b7a79093-758c-41f7-b94d-3db67352142d)

右键选择 Graph View，可以看到图形化的表示。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLqgI-zk6Z8Xe_PPbSu%2F-MLr9V1dEJ0kdOFVLW_L%2FNK%5DQRA60QJ%5BP1TR3%247E47VR.png?alt=media\&token=872025fd-1b48-4df9-9058-8a1a3f806826)

### **9、在同样的区域，在 0x100101C8 处，看起来好像 dword\_1008E5C4 是一个全局变量，它帮助决定走哪条路径。那恶意代码是如何设置 dword\_1008E5C4 的呢？（提示：使用 dword\_1008E5C4 的交叉引用。）**

答案：跳到 100101c8，**cmp dword\_1008E5C4,ebx**，也即将 ebx 同该全局变量比较。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrCN8crnpVN5km_Fus%2F-MLrRJa_SHNMycF6yxqZ%2FE6\)\(\)JZ01S5R%250E9I%7BMIL%603.png?alt=media\&token=9b342647-efed-43c9-a18d-deeee15dc7e3)

双击跳到定义位置（.data:1008E5C4），Ctrl + X 查看交叉引用，只有 sub\_10001656+22 处的 **mov dword\_1008E5C4,eax** 语句修改了该值。选中，点击 OK 跳到对应位置。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrCN8crnpVN5km_Fus%2F-MLrRq9RK4l66SOdmYMY%2FDCOLCEUPLWZ%5BD%5B\(P%40P25M%400.png?alt=media\&token=d14fe1dd-37bd-4e1d-8ea5-297f3e35023a)

其中 eax （蓝框）是上一行调用的函数 sub\_10003695 （粉框）的返回值，双击进入该函数：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrCN8crnpVN5km_Fus%2F-MLrR01bjCY_4DEUjEEd%2F4E%25CH%24V8%401%40%25%5DSI\)\(TV6%5BWE.png?alt=media\&token=4e73d54a-911e-4b57-a906-4a8c4d7ea116)

可以看到该函数调用了 GetVersionEx，也即获取当前操作系统的信息，**xor eax,eax** 语句将 eax 置 0，并且，**cmp \[ebp+VersionInformation.dwPlatformId],2** 语句将平台类型同 2 相比。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrCN8crnpVN5km_Fus%2F-MLrT4ozv6lLHbMn5qTW%2FOFCG8~6%7B_%24%607L%403R%25F9~U%7B5.png?alt=media\&token=446095e4-736a-4f49-ab66-5e496a0d3e1d)

根据微软的文档，我们得知通常情况下 dwPlatformId 的值为 2：

`dwPlatformId`: The operating system platform. This member can be the following value.

| 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. |

* OSVERSIONINFOA (winnt.h) - Win32 apps | Microsoft Docs&#x20;
  * <https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa>

所以通常情况下，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。

### **10、在位于 0x1000FF58 处的子过程中的几百行指令中，一系列使用 memcmp 来比较字符串的比较。如果对 robotwork 的字符串比较是成功的（当 memcmp 返回 0），会发生什么？**

答案：跳转到 1000FF58 处的子过程，往上翻一点查看 subroutine 识别出来的变量与参数。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrc2umrL8oMIfCZcFg%2F-MLrdozm0-yOL3cT8SPI%2FTG9A%60R8%5D%60T44XK3%5DY7\(H5%7BQ.png?alt=media\&token=8cfc16d2-2bb6-424e-8773-b8faf8aa8de8)

往下翻很多，可以到不少 memcp 语句，好多在前面的问题分析中都出现过：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrc2umrL8oMIfCZcFg%2F-MLrePsmjkFPISmPnjtc%2FZ\(%402UQ9%5D1M\)4%5BBJ0A%7B%5B\(%7DK9.png?alt=media\&token=e6a2a89c-371d-4b6f-a44e-18d170cddaa7)

终于在 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 的内容“回收”或者“丢弃”了。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrc2umrL8oMIfCZcFg%2F-MLrhHrfOE0IM3qjNvD5%2FQ45QXVVZED%5D\(~%25H%25%5BMA3132.png?alt=media\&token=c59b1174-c4d0-463b-a9af-69bf6c870430)

双击查看 sub\_100052A2 的代码。其参数为 socket 类型。也就是上图中 1001045E 处 push 进去的 \[ebp+s]。其他可以忽略，往下一直翻到 100052E7 处的 aSoftWareMicros（红框），其值为 “SOFTWARE\Microsoft\Windows\CurrentVersion”。最后调用 RegOpenKeyEx 函数（蓝框），读取该注册表值。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrk6tkkO4E3sHEqLFz%2F-MLrl_5ptYi-NErJi5Nx%2FZNT7%7B%60X%5DOBD%5DH%7BNP2NU4%7B%5BQ.png?alt=media\&token=b0d0bb17-c8dc-4d8f-8136-91f32d5ab00d)

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrk6tkkO4E3sHEqLFz%2F-MLrkjAVSPskyrHA6rAQ%2FD157~Y4F%4055%4020M%7BSW5P%5D_M.png?alt=media\&token=d25f3a32-aa28-4363-9d0a-0cc44625c8e9)

在 CurrentVersion 的键值下，跳到 loc\_10005309（红框），取得 WorkTime 的键值（粉色+蓝色）。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrlrKVbvIo51Iy9IZp%2F-MLrpnSzMobbt6j_FeYv%2F0_M%40NZM%40H6GMKF41RC%5D8REG.png?alt=media\&token=e258c4c3-7520-4978-9056-7367b4d6772e)

再跳到 loc\_10005379（紫框），取得 WorkTimes 的键值（粉色+蓝色）。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrlrKVbvIo51Iy9IZp%2F-MLrqADa9nHnnM-7XL4q%2FBQ%5DUW%24UV2%404SR_V56\(Z_YR2.png?alt=media\&token=8a0351fb-7be7-4762-bcff-bc805a07346b)

按书中所述，这些信息最终传给了此前 push 进去的 \[ebp+s] 也即 socket s 处。

### **11、PSLIST 导出函数做了什么？**

答案：在 Exports 窗口找到 PSLIST，双击点开。首先调用 sub\_100036C（红色）。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLsMKKLfXGCbWRzEgSR%2F-MLsNsOnF0AKQ4zOHxi5%2FZNWVKM7GC%25BAWUTZADF%60AAJ.png?alt=media\&token=0de460ee-c8bd-47bc-b8af-c283e7fd1239)

双击点开如下图。若 dwPlatformId 不为 2（粉色），或 dwMajorVersion 小于 5（蓝色），则 eax 为 0（绿色），否则 eax 为 0（橙色）。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLrqfyFfVeNaPBYdxx9%2F-MLsKf5ctGrnZhU4jmiY%2FDJAQY%7D6%242PT%60FX2EFEKMFP1.png?alt=media\&token=8bddfca3-1cea-421e-aec4-eb0617125d39)

在第 9 问中已经讨论过，绝大多数系统的 dwPlatformId 都为 2。对于 dwMajorVersion，不同系统的值如下表所示。可见绝大多数系统的值也都是大于等于 5。

| 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                                                                                                                  |

* OSVERSIONINFOEXA (winnt.h) - Win32 apps | Microsoft Docs&#x20;
  * <https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa>

总之，对于绝大数系统，这两个判断得到的结果，都应当得到 eax 为 1。

为了参考方便，再次放上 PLIST 的图。上面讨论过，eax 通常应为 1，因此一般情况下不进行下图红色部分的跳转（跳转是直接结束），而是继续向下执行。先 push 一个字符串 Str，然后求出其长度（蓝色），存入 eax。若该字符串非空，那么 eax 非 0，也即 test eax,eax 得到 ZF=0，那么将会进行 **jnz short loc\_1000704E** （紫色）的跳转。空字符串的情况我们就略掉。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLuKB0ZzXtkZZYU18Kl%2F-MLv_2EW2FXwCWazspBo%2F5%246NBEX8LFJXTVNTWE2%5D~ZM.png?alt=media\&token=f6a16e57-1eff-4580-b943-3cd02a13a33b)

跳转后会执行 sub\_1000664C（橙色）。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLva4A5Czn1mtGJylpb%2F-MLvazI85HVbdRafe9ha%2F\)%5D%40FS%60I3IHWXK%243Q%5B_U8E75.png?alt=media\&token=6369ebb9-88a0-4fca-9ebd-08a4cadaa03a)

双击点开，并且往下翻，可以看到调用了 CreateToolHelp32Snapshot：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLva4A5Czn1mtGJylpb%2F-MLvd2dGVhp8ainJtQ2f%2FQU5%5D\(MH\(DXPR6C2L\)IX4%5BPC.png?alt=media\&token=b1ff20dd-c203-46fe-8eb6-de5584f1318f)

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLva4A5Czn1mtGJylpb%2F-MLvd3t815_zqUfKqnII%2F5%5BQ7%25ZZT%7D\)G1%5DQJCXCQ1_UW.png?alt=media\&token=a1f1a0ad-8a0e-4cc5-bf1d-95340bb6ee82)

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&#x20;
  * <https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot>

执行完 sub\_1000664C 之后，pop ecx，再 retn、endp，PSLIST 返回。

**综上，PSLIST 的作用应该是获得一个进程的列表。又依据书中所述，获得的进程列表将通过 socket  的 send 发送。**

### 12、使用图模式来绘制出对 sub\_10004E79 的交叉引用图。当进入这个函数时，哪个 API 函数可能被调用？仅仅基于这些 API 函数，你会如何重命名这个函数？

答案：View > Graphs > User xrefs chart ...，起始和终止地址均设置为 .text:10004E9C，得到交叉引用图（或者 G 到地址 10004E9C，然后右键 Xrefs graph **from**）。主要调用的 API 为 GetSystemDefaultLangID 和 send。因此推测可能是将系统的默认语言标识发送出去。可以重命名为 **send\_lang\_id**。直接在函数名处右键 Rename 即可。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvjgXkXWjTFa1KRp-o%2F-MLvoq16sLGy4NmgyrUW%2F2\(G~7T5%5B7\(E%24\(C8KIK4OU5Y.png?alt=media\&token=8deb0fa2-1e92-40e7-b505-a0c56ca375e3)

### 13、DllMain 直接调用了多少个 Windows API？多少个在深度为 2 时被调用？

答案：按 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。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvrOVklgFvvbjdFvFq%2F-MLvsWRNqW11vSFlhAwZ%2F5%5B9LGTC\(__35LKVFL%60%5DAXFT.png?alt=media\&token=4412e4f1-89a3-449a-99e4-df8cdb987768)

### 14、在 0x10001358 处，有一个对 Sleep（一个使用一个包含要睡眠的毫秒数的参数的 API 函数）的调用。顺着代码向后看，如果这段代码执行，这个程序会睡眠多久？

答案：调用的 sleep（红色）的参数为上一行 push 的 eax，eax 的值又来自乘法 **imul eax,3E8h** 的运算结果（蓝色）。3E8h 的十进制为 1000，也可以通过右键该数字查看。再往上，eax 是由 atoi 函数（粉色）对 Str 运算得到的，也即字符串转整数。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvsvwpYh3aQzdVzp_a%2F-MLvv2OcT6iqIKOZj3Bc%2F4\(A0NKPG8NA8V%25N80J%40QNGA.png?alt=media\&token=09909c43-428f-48d3-875f-40c3b63f6710)

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvvIzHZ-r5TUiOVVGq%2F-MLvvYuCneZQ0fzae0mW%2FORQNDXP%7DKSR%5B1DYA_\(HT\)BH.png?alt=media\&token=9547da9d-49af-4b8e-b5d4-007fa533336f)

再往上，该 Str 由 off\_10019020+0Dh 位置的字符串得到（橙色），也即 “30”，最终转换成数字 30。

```
[This is CTI]30
             ↑
0123456789ABCD
```

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvvIzHZ-r5TUiOVVGq%2F-MLvw4YyndhGL7HTTeN_%2FTL~VUD%7DC2QL2R9\)O%5DDC81%5D2.png?alt=media\&token=40882ec3-9d63-44e6-8954-5b8e06271bfd)

所以睡眠的时间应为 30\*1000 = 30000（毫秒），也即 30 秒。Sleep 函数的官方文档如下：

```cpp
// Parameters: dwMilliseconds
//   The time interval for which execution is to be suspended, in milliseconds.

void Sleep(
  DWORD dwMilliseconds
);
```

* Sleep function (synchapi.h) - Win32 apps | Microsoft Docs&#x20;
  * <https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep>

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

答案：IDA 中显示的三个参数名：af、type、protocol。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLvyiMavB5ToThxltGo%2F-MLwNu838GCiFpQyrgAd%2F%7BS0GV_%248%7B%7D%5DPSBCXGM~NQQF.png?alt=media\&token=2e047f8a-482f-4c05-ad3b-d17edc029695)

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

socket 的官方文档如下：

```cpp
// The socket function creates a socket 
//   that is bound to a specific transport service provider.

SOCKET WSAAPI socket(
  int af,
  int type,
  int protocol
);
```

* socket function (winsock2.h) - Win32 apps | Microsoft Docs&#x20;
  * <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket>

查看文档，af（2）、type（1）、protocol（6）中的数字分别对应：

| 参数名      | 输入数字 | 常量名          | 说明      |
| -------- | ---- | ------------ | ------- |
| af       | 2    | AF\_INET     | 使用 IPv4 |
| type     | 1    | SOCK\_STREAM | TCP 连接  |
| protocal | 6    | IPPROTO\_TCP | TCP 协议  |

**因此输入的参数含义为建立基于 IPv4 的 TCP 连接的 socket，通常在 HTTP 中使用。**

在数字上右键，Use standard symbolic constant，分别替换成实际的常量名，如图：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwPGMEXiGiUcaTmMbf%2F-MLwRTUf8cfeTq5imE3Y%2F11H94SW%24%7BNP6EAFW3OZKW%7D8.png?alt=media\&token=a881d78a-2bf9-4f2a-94d3-7b75be313a1b)

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

答案：Search > Text（Alt+T），输入 in；或者 Search Sequence of Bytes（Alt+B），输入 ED。然后选择 Find All Occurences。搜素结果中只有在地址 100061DB 处的一条 in eax,dx 的指令符合要求。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwTUaU1GzWsDbElaWz%2F-MLwToddi6nYNM1czz2x%2FW%7BDXKYK4S5%7B1TT\(O4O\)SD0A.png?alt=media\&token=7a92ffad-e00d-456d-be4e-4979c27a77b3)

双击跳转到对应位置，可以看到 eax 中储存了字符串 “VMXh”，也就确认了这段代码采用了反虚拟机技巧：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwTUaU1GzWsDbElaWz%2F-MLwUSr89iedinT7Y3ej%2F5QM4NTHV%60R%7D9\)V5K8J\(UM0R.png?alt=media\&token=6e6d03fc-3bc1-4403-a982-8c90986b3d97)

往上翻到所在函数的入口处，也即 sub\_10006196（粉色），按下 Ctrl+X 打开交叉引用，选择第一个，点击 OK。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwTUaU1GzWsDbElaWz%2F-MLwVSLI_OZ9rSFadZPs%2FNU\(PFZ3H%7DNF5JEU4%5DCB6%7BG0.png?alt=media\&token=02e99591-69e3-4839-827d-5d2e40972adf)

可以看到该函数的后文中也出现了字符串 “Found Virtual Machine,Install Cancel.” 的字眼，印证了我们的猜测。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwTUaU1GzWsDbElaWz%2F-MLwVcLCtMsMFpjOCz4m%2F_GVM3H_%24\(R40_1OJ\)FVFY1B.png?alt=media\&token=e15bfac0-de5d-4912-aca6-f6e8205d898e)

### 18、将你的光标跳转到 0x1001D988 处，你发现了什么？

答案：发现了一段看似随机的数据。据书中所述，需要运行一段 Python 脚本。

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwVrJ0sxHYPceevCxX%2F-MLwX3dc3QfrB1ZvoWd0%2FPLG6_G0J5%40WJ\)I763CW3I8S.png?alt=media\&token=9b84719f-b3a3-4688-aa94-80f29c55ae25)

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

该 Python 脚本内容如下：

{% tabs %}
{% tab title="Lab05-01.py" %}

```cpp
sea = ScreenEA()

for i in range(0x00,0x50):
        b = Byte(sea+i)
        decoded_byte = b ^ 0x55
        PatchByte(sea+i,decoded_byte)
```

{% endtab %}
{% endtabs %}

**一定确保光标恰好停在 0x1001D988 处（如果不是，就关闭文件再打开一次，否则转换始终是不对的）**，然后点击 File > Script file（Alt+F7），选择 Lab05-01.py。会自动运行，然后可以看到这部分的数据发生了变化。注释的 ASCII 字符由原来的乱码变成了有意义的内容。图太长，略。

### 20、将光标放在同一位置，你如何将这个数据转成一个单一的 ASCII 字符串？

答案：在地址 0x1001D988 处，右键选择转换成 ASCII 字符串（或者按下 A 键），得到字符串 'xdoor is this backdoor, string decoded for Practical Malware Analysis Lab :)1234'：

![](https://787279543-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MLT8iP0IvoyaLlQfCAi%2F-MLwXAfnsSHEQYJJw3Vp%2F-MLw_FB0WoObpBWs1RnN%2F\)66PN%5D%5BVZ90%7B3PW0923V9QR.png?alt=media\&token=2436d661-b8a5-4c12-bc84-e1eead35b017)

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

答案：再次粘贴 Lab05-01.py 的源代码如下。其作用就是从光标选中位置开始，共 0x50 个字节，将每个字节同 0x55 作异或运算（相当于解码），再写入 IDA 的数据库中（所以我们能够立刻看到修改结果）。

{% tabs %}
{% tab title="Lab05-01.py" %}

```cpp
sea = ScreenEA()

for i in range(0x00,0x50):
        b = Byte(sea+i)
        decoded_byte = b ^ 0x55
        PatchByte(sea+i,decoded_byte)
```

{% endtab %}
{% endtabs %}

## 参考链接

* 恶意代码分析实战 Lab 5-1 习题笔记\_isinstance的博客-CSDN博客&#x20;
  * <https://blog.csdn.net/isinstance/article/details/77867855>
* \[原创]《恶意代码分析实战》第五章IDA Pro（Lab5-1分析报告）-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pediy.com&#x20;
  * <https://bbs.pediy.com/thread-263319.htm>
* 恶意代码分析实战 — Lab 05-01 – Atom Kid&#x20;
  * [http://www.atomsec.org/安全/2638/](http://www.atomsec.org/%E5%AE%89%E5%85%A8/2638/)
