上篇对测试程序进行了分析,挖坑到现在一直都没有填。这次尝试对 wannacry 使用 S2E 进行分析。
准备工作 软件版本 S2E 镜像:windows-7sp1pro-i386,使用 en_windows_7_professional_with_sp1_x86_dvd_u_677056.iso 制作。(SHA-1:d89937df3a9bc2ec1a1486195fd308cd3dade928)
Visual Studio 2017 Community:记得安装 “对 C++ 的 Windows XP 支持”。
wannacry:我没找到原版的 DB349B97C37D22F5EA1D1841E3C89EB4,只能使用其他版本的 41B5BA4BF74E65845FA8C9861CA34508 (~~~~下载链接 ~~~~)原版下载链接https://malshare.com/sample.php?action=detail&hash=db349b97c37d22f5ea1d1841e3c89eb4 。这个网站免费注册。后面再有找病毒的需求可以去 https://cyberlab.pacific.edu/resources/malware-samples-for-students ,整理了很多网站的链接。
S2E.sln 我们需要通过 API hook 的方式向 wannacry 中注入符号变量。之前一样,找到 $S2EDIR/source/s2e/guest/windows/s2e.sln 工程,并使用 VS 打开。
这里先把之前 malware-inject 项目重写出来,顺便检查环境是否有问题。
如果编译时报错和“静态分析”、“代码分析”有关,那么可以去 项目→属性→代码分析→常规,取消选中“生成时启用代码分析”。
同时,把平台工具集改成 Windows XP (v141_xp):
Wannacry 简单分析 参考链接:
这里不会详细分析 wannacry 的动作,具体完整的分析报告见参考链接。
所以这里需要 hook InternetOpenUrlA 函数,让它返回符号变量,进而可以探索这两个不同的分支。
使用 S2E 分析 wannacry 编写 Hook 注入符号变量 在 VS2017 中新建 Wannacry-hook 项目,创建 malware-hook.c ,直接使用作者写好的代码 即可。
在这个 malware-hook.c 中主要看 InternetOpenUrlAHook:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 static HINTERNET WINAPI InternetOpenUrlAHook ( HINTERNET hInternet, LPCSTR lpszUrl, LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext ) { Message("Intercepted InternetOpenUrlA(%p, %s, %s, 0x%x, 0x%x, %p)\n" , hInternet,lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext); UINT8 returnResource = S2ESymbolicChar("hInternet" , 1 ); if (returnResource) { HINTERNET resourceHandle = (HINTERNET) malloc (sizeof (HINTERNET)); dummyHandles.insert(resourceHandle); return resourceHandle; } else { return NULL ; } }
调用 S2ESymbolicChar 创建了 1 字节的符号化变量(returnResource)。随后立刻进入 if 语句,判断 returnResource 的真假。显然对于符号化变量遇到分支会 fork。此时强行要求程序分出两个状态来分别探索。这里由于 wannacry 对返回的 HINTERNET 结构体不感兴趣(没有使用),所以只是返回了一个 malloc 分配的空间,本质上它不是一个合法的 HINTERNET 结构体。假如有恶意程序使用了某个结构体,我们也可以向其写入符号变量返回给它。
说白了就是在这里插入符号变量,迫使 state fork 进而执行两种不同的路径。
此外,可以看出来符号变量并没有传递给 wannacry,所以其内部也不会有别的 fork。
接下来编译这个 dll。仍然需要用 nuget 安装 EasyHookNativePackage,并引入 s2e/s2e.h 文件。
编译时报错:
项目→ 属性 → C/C++ → 语言 → 符合模式 设置为 “否” 即可。
完成编译后,目录下会有两个 PE 文件:
为了能够正常运行,需要把 EasyHook32.dll 找出来,一起放到 S2E 里去。
运行 S2E 创建 S2E 工程:
1 s2e new_project -i windows-7 sp1pro-i386 /home/ubuntu/workspace/wannacry/wcry.exe
然后修改 bootstrap.sh ,主要是用 malware-inject 来启动 wcry.exe 并把这几个文件拷贝到 VM 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # This function executes the target program. # You can customize it if your program needs special invocation, # custom symbolic arguments, etc. function execute_target { local TARGET TARGET="$1" run_cmd "malware-inject.exe --dll wannacry-hook.dll --app ${TARGET}" > /dev/null 2> /dev/null } ... ... # Download the target file to analyze $ {S2EGET} "wcry.exe" $ {S2EGET} "easyhook32.dll" $ {S2EGET} "wannacry-hook.dll" $ {S2EGET} "malware-inject.exe"
然后在 s2e-config.lua 最后添加 add_plugin("LibraryCallMonitor")
。
这里有一个坑:EasyHook32.dll 拷贝到 S2E 环境下的时候,一定一定一定要重命名为 easyhook32.dll,然后在 bootstrap.sh 里也是用小写,否则不能正常运行!!!
在启动 S2E 时,可以用 GUI=1 ./launch-s2e.sh
,这样会弹出 QEMU 窗口,可以实时看到效果
Hook 运行相关的部分日志如下,可以看出 API Hook 正常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ cat s2e-last/info.txt | grep -E "malware-inject\]|malware-hook\]" 133 [State 0] BaseInstructions: Message from guest (0x12f254): [malware-inject] Successfully injected c:\s2e\wannacry-hook.dll into c:\s2e\wcry.exe (PID=0x494) # 成功将 wannacry-hook.dll 注入到 wcry.exe 中 133 [State 0] BaseInstructions: Message from guest (0x197faf4): [0x494|malware-hook] Successfully hooked wininet.InternetOpenUrlA 133 [State 0] BaseInstructions: Message from guest (0x197faf4): [0x494|malware-hook] Successfully hooked wininet.InternetCloseHandle 133 [State 0] BaseInstructions: Message from guest (0x197faf4): [0x494|malware-hook] Successfully hooked kernel32.CreateProcessA # 对 wininet.InternetOpenUrlA, wininet.InternetCloseHandle, kernel32.CreateProcessA 进行 hook 142 [State 0] BaseInstructions: Message from guest (0x12fa28): [0x494|malware-hook] Intercepted InternetOpenUrlA(00CC0004, http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com, (null), 0x0, 0x84000000, 00000000) 142 [State 0] BaseInstructions: Message from guest (0x12fa48): [0x494|malware-hook] Intercepted InternetCloseHandle(00CC0004) 142 [State 0] BaseInstructions: Message from guest (0x12fa48): [0x494|malware-hook] Intercepted InternetCloseHandle(00B9F2C0) 146 [State 1] BaseInstructions: Message from guest (0x12fa48): [0x494|malware-hook] Intercepted InternetCloseHandle(00CC0004) 147 [State 1] BaseInstructions: Message from guest (0x12fa48): [0x494|malware-hook] Intercepted InternetCloseHandle(00000000) 208 [State 1] BaseInstructions: Message from guest (0x12f548): [0x494|malware-hook] Intercepted CreateProcessA((null), C:\WINDOWS\tasksche.exe /i, 00000000, 00000000, 0, 134217728, 00000000, (null), 0012FC30, 0012FC20) # 拦截到新进程的创建 220 [State 1] BaseInstructions: Message from guest (0x12f56c): [0x494|malware-hook] Failed to create suspended process: 0x36B1
由于使用了 LibraryCallMonitor 插件,info.txt 中的无用信息很多。我们只关心 wcry.exe 本体调用的外部函数。先看 State 0 调用的函数(State 0 就是 InternetOpenUrlA 返回了非空,wcry.exe 没有正常启动的状态 ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ cat s2e-last/info.txt | grep "LibraryCallMonitor: wcry.exe:" | grep "State 0" 133 [State 0] LibraryCallMonitor: wcry.exe:0x409a43 (0x409a43) called msvcrt.dll!__set_app_type:0x6ff62804 (0x76762804) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409a58 (0x409a58) called msvcrt.dll!__p__fmode:0x6ff627ce (0x767627ce) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409a66 (0x409a66) called msvcrt.dll!__p__commode:0x6ff627c3 (0x767627c3) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409acb (0x409acb) called msvcrt.dll!__getmainargs:0x6ff62bc0 (0x76762bc0) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x408238 (0x408238) called msvcp60.dll!??0_Lockit@std@@QAE@XZ:0x6e6b16c0 (0x6ed416c0) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x40826a (0x40826a) called msvcp60.dll!??1_Lockit@std@@QAE@XZ:0x6e6ddf70 (0x6ed6df70) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409823 (0x409823) called msvcrt.dll!_onexit:0x6ff6112d (0x7676112d) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409b1a (0x409b1a) called kernel32.dll!GetStartupInfoA:0x77de1e10 (0x769d1e10) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x409b3e (0x409b3e) called kernel32.dll!GetModuleHandleA:0x77e2dac3 (0x76a1dac3) (pid=0x494) 133 [State 0] LibraryCallMonitor: wcry.exe:0x40817b (0x40817b) called wininet.dll!InternetOpenA:0x6302abf0 (0x76d9abf0) (pid=0x494) 142 [State 0] LibraryCallMonitor: wcry.exe:0x408194 (0x408194) called wininet.dll!InternetOpenUrlA:0x630f6610 (0x76e66610) (pid=0x494) # 从这里开始发生 fork 142 [State 0] LibraryCallMonitor: wcry.exe:0x4081bc (0x4081bc) called wininet.dll!InternetCloseHandle:0x630120c0 (0x76d820c0) (pid=0x494) 142 [State 0] LibraryCallMonitor: wcry.exe:0x4081bf (0x4081bf) called wininet.dll!InternetCloseHandle:0x630120c0 (0x76d820c0) (pid=0x494) 142 [State 0] LibraryCallMonitor: wcry.exe:0x409b4e (0x409b4e) called msvcrt.dll!exit:0x6ff636aa (0x767636aa) (pid=0x494) 142 [State 0] LibraryCallMonitor: wcry.exe:0x4010fe (0x4010fe) called msvcp60.dll!??0_Lockit@std@@QAE@XZ:0x6e6b16c0 (0x6ed416c0) (pid=0x494) 142 [State 0] LibraryCallMonitor: wcry.exe:0x401121 (0x401121) called msvcp60.dll!??1_Lockit@std@@QAE@XZ:0x6e6ddf70 (0x6ed6df70) (pid=0x494)
fork 后, State 1 调用的库函数如下:
1 2 3 4 5 6 7 8 9 146 [State 1] LibraryCallMonitor: wcry.exe:0x4081a7 (0x4081a7) called wininet.dll!InternetCloseHandle:0x630120c0 (0x76d820c0) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x4081ab (0x4081ab) called wininet.dll!InternetCloseHandle:0x630120c0 (0x76d820c0) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x40809f (0x40809f) called kernel32.dll!GetModuleFileNameA:0x77e2d92a (0x76a1d92a) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x4080a5 (0x4080a5) called msvcrt.dll!__p___argc:0x6ffa3ac9 (0x767a3ac9) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x407c56 (0x407c56) called msvcrt.dll!sprintf:0x6ff6d35c (0x7676d35c) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x407c68 (0x407c68) called advapi32.dll!OpenSCManagerA:0x77c72b08 (0x752c2b08) (pid=0x494) 147 [State 1] LibraryCallMonitor: wcry.exe:0x407c9b (0x407c9b) called advapi32.dll!CreateServiceA:0x77ca3434 (0x752f3434) (pid=0x494) 148 [State 1] LibraryCallMonitor: wcry.exe:0x407cb2 (0x407cb2) called advapi32.dll!StartServiceA:0x77ca381f (0x752f381f) (pid=0x494) ... ...
太多了,可以看到启动了服务,但是没有给出启动参数。看来想实现完整的监控要写很多 hook?
中间跑了很多次,都是还没有反应 bootstrap.sh 先中止了。分析了一下确实是因为 WannaCry 创建了子进程之后自己停止,所以 bootstrap.sh 退出导致 S2E 退出。我在 execute 函数中加了 sleep 3000
,并且在 wannacry-hook.dll 中把等待子进程的时间改成 1000 秒。最后截图留念,wannacry 启动成功: