书本习题
题目
- DLLMain的地址是什么?
- 使用Imports窗口并浏览到gethostbyname,导入函数定位到什么地址?
- 有多少函数调用了gethostbyname?
- 将精力集中在位于0x10001757处的对gethostbyname的调用,你能找出哪个DNS请求将被触发吗?
- IDA Pro 识别了在0x10001656处的子过程中的多少个局部变量?
- IDA Pro识别了在0x10001656处的子过程中的多少个参数?
- 使用Strings窗口,来在反汇编中定位字符串 \cmd.exe /c, 它位于哪儿?
- 在引用 \cmd.exe /c的代码所在区域发生了什么?
- 在同样的区域,在0x100101C8处,看起来dword_1008E5C4好像是一个全局变量,它帮助决定走哪条路径。那恶意代码是如何设置dword_1008E5C4的呢?(提示:使用交叉引用)
- 在位于0x1000FF58处的子过程中的几百行指令中,一系列使用memcmp来比较字符串的比较。如果对robotwork的字符串比较是成功的(当memcmp返回0),会发生什么?
- PSLIST导出函数做了什么?
- 使用图模式来绘制出对sub_10004E79的交叉引用图。当进入这个函数时,哪个API函数可能被调用?仅仅基于这些API函数,你会如何重命名这个函数?
- DllMain直接调用了多少个Windows API?多少个在深度为2时被调用?
- 在0x10001358处,有一个对Sleep(一个使用一个包含要睡眠的毫秒数的参数的API函数)的调用。顺着代码向后看,如果这段代码执行,这个程序会睡眠多久?
- 在0x10001701处是一个对socket的调用,它的3个参数是什么?
- 使用MSDN页面的socket和IDA Pro中的命名符号常量,你能使参数更有意义吗?修改后,参数是什么?
- 搜索in指令(opcode 0xED)的使用。这个指令和一个魔术字符串VMXh用来进行Vmware检测。在这个恶意代码中被使用了吗?使用对执行in指令函数的交叉引用,能发现进一步检测Vmware的证据吗?
- 将你的光标跳转到0x1001D988处,你发现了什么?
- 如果你安装了IDA Python插件(包括IDA Pro的商业版本插件),运行Lab05-01.py,一个IDA Pro Python脚本(确定光标是在0x1001D988处),在运行该脚本后发生了什么?
- 将光标放于同一位置,你如何将这个数据转成一个单一的ASCII字符串?
- 使用一个文本编辑器打开这个脚本。它是如何工作的?
分析
DLLMain的地址是什么?
如图,0x1000D02E
使用Imports窗口并浏览到gethostbyname,导入函数定位到什么地址?
0X100163CC
有多少函数调用了gethostbyname?
如图,9个函数调用了gethostbyname
由函数调用导致的交叉引用使用后缀p(看做是Procedure)。
跳转交叉引用使用后缀j(看做是Jump)。
读取交叉引用使用后缀r(看做是Read)。
写入交叉引用使用后缀w(看做是Write)。
偏移量交叉引用使用后缀o(看做是Offset)。
将精力集中在位于0x10001757处的对gethostbyname的调用,你能找出哪个DNS请求将被触发吗?
双击跳转,F5反编译,如下图

双击off_10019040跳转,如图
由于参数是off_10019040[0]+13
,即从第14个字符处开始,所以DNS请求为pics.praticalmalwareanalysis.com
IDA Pro 识别了在0x10001656处的子过程中的多少个局部变量?
如图,共识别24个变量
IDA Pro识别了在0x10001656处的子过程中的多少个参数?
如图,识别了一个参数LPVOID lpThreadParameter
使用Strings窗口,来在反汇编中定位字符串 \cmd.exe /c, 它位于哪儿?
如下图,100095B34
在引用 \cmd.exe /c的代码所在区域发生了什么?
双击跳转
F5反编译,可以看到判断了dword_1008e5c4的值,若是,则将commandline
变量与字符串\cmd.exe /c
连接,若否,则与字符串\command.exe /c
连接。猜测是根据系统版本进行了判断,以确保文件名正确。
command.exe是win9x的,cmd.exe是winNT/2k/xp/2003的。cmd是windows的命令行,支持长文件名,且cmd.exe本身是一个32位的程序,command是dos遗留下来的,不支持长文件名,而command.exe本身是一个16位的程序。
此外,根据函数中出现的代码及字符串推测,该函数部分作用为打印程序启动时的欢迎用户字符串及调用cmd。
在同样的区域,在0x100101C8处,看起来dword_1008E5C4好像是一个全局变量,它帮助决定走哪条路径。那恶意代码是如何设置dword_1008E5C4的呢?
查看xref,可以看到在图示地址处有一个写入交叉引用的操作
跳转,F5反编译,得到赋值代码如下
该赋值函数的代码如下:
BOOL sub_10003695()
{
struct _OSVERSIONINFOA VersionInformation; // [esp+0h] [ebp-94h]
VersionInformation.dwOSVersionInfoSize = 148;
GetVersionExA(&VersionInformation); //获取系统版本信息
return VersionInformation.dwPlatformId == 2;
}
微软官方对OSVERSIONINFOA
结构中dwPlatformId的
说明如下:
值 | 含义 |
---|---|
VER_PLATFORM_WIN32_NT 2 | 操作系统是Windows 7,Windows Server 2008,Windows Vista,Windows Server 2003,Windows XP或Windows 2000。 |
综上,当操作系统是上述列表中的windows时,dword_1008E5C4被赋值为1,否则为0。亦即,当操作系统为windows 2000及以上时,commandline变量被赋值为\cmd.exe /c
,否则被赋值为\command.exe /c
字符串。
在位于0x1000FF58处的子过程中的几百行指令中,一系列使用memcmp来比较字符串的比较。如果对robotwork的字符串比较是成功的(当memcmp返回0),会发生什么?
定位,跳转,F5反编译,可以看到执行了sub_100052a2函数。
该函数关键代码如下
//sub_100052a2()
if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, aSoftwareMicros, 0, 0xF003Fu, &phkResult) )
// aSoftwareMicros='SOFTWARE\Microsoft\Windows\CurrentVersion'
//打开指定注册表项,若失败,则返回
return RegCloseKey(phkResult);
if ( !RegQueryValueExA(phkResult, aWorktime, 0, &Type, &Data, &cbData) )
//aWorkTime='WorkTime'
//如果存在worktime子项,则执行以下代码
{
v2 = atoi((const char *)&Data);
//把字符串转换为int值,其中data是指向该项注册表的指针
sprintf(&Dest, aRobotWorktimeD, v2);
//换行并输出'[Robot_WorkTime :] %d',%d=v2
v3 = strlen(&Dest);
sub_100038EE(s, (int)&Dest, v3);
//发送至socket
}
memset(&Data, 0, 0x200u);
//将&data所指的内存空间初始化为0
if ( !RegQueryValueExA(phkResult, aWorktimes, 0, &Type, &Data, &cbData) )
//aWorkTimes='WorkTimes'
//其余同上
{
v4 = atoi((const char *)&Data);
sprintf(&Dest, aRobotWorktimes, v4);
v5 = strlen(&Dest);
sub_100038EE(s, (int)&Dest, v5);
}
return RegCloseKey(phkResult);
综上,若比较成功,则会向socket发送两个注册表键值,分别为HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WorkTime
和HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WorkTimes
PSLIST导出函数做了什么?
代码如下
int __stdcall PSLIST(int a1, int a2, char *Str, int a4)
{
int result; // eax
dword_1008E5BC = 1;
result = sub_100036C3();
//return VersionInformation.dwPlatformId == 2 && VersionInformation.dwMajorVersion >= 5
//判断系统版本是否为windows2000及以上
if ( result )
{
if ( strlen(Str) )
result = sub_1000664C(0, Str);
//猜测发送进程列表&详细信息,分析见下
else
result = sub_10006518(0);
}
dword_1008E5BC = 0;
return result;
}
sub_1000664C
该函数部分代码如下
多次调用的sub_100038BB函数如下,可以看到向socket发送了传递的char
*Str参数
而给Dest变量赋值的语句中可以看到th32ProcessID等字样,结合CreateToolhelp32Snapshot、Process32First等函数,猜测sub_1000664C函数的作用是向socket发送特定进程(或进程列表)及详细信息,包括进程id,进程名及线程数等。
sub_10006518
部分代码如下
调用的sub_1000620C函数如下
猜测是采用追加方式将进程信息写入了xinstall.dll文件。
综上,该函数检测了运行环境是否为特定windows系统后对Str参数的长度做了判断,若为0,则将进程信息记录在xinstall.dll文件中;若不为0,则将进程信息通过socket发送。
使用图模式来绘制出对sub_10004E79的交叉引用图。当进入这个函数时,哪个API函数可能被调用?仅仅基于这些API函数,你会如何重命名这个函数?
可以看到这些函数可能被调用
其中GetSystemDefaultLangID返回系统区域设置的语言标识符,在第10题中已分析过sub_100038EE,因此猜测该函数作用是向socket发送系统区域设置的语言标识符,可以重命名为sendSystemLanguageID。
DllMain直接调用了多少个Windows API?多少个在深度为2时被调用?
设置递归深度
如图,直接调用了四个Windows API
同理可得深度2的部分调用如图
数了一下好像是33个?
在0x10001358处,有一个对Sleep(一个使用一个包含要睡眠的毫秒数的参数的API函数)的调用。顺着代码向后看,如果这段代码执行,这个程序会睡眠多久?
跳转,反编译,得到代码如图
其中off_10019020取值为[This is CTI]30
,又因参数为off_10019020[0]+13
,因此v14=atoi('30'),即程序会睡眠30秒。
在0x10001701处是一个对socket的调用,它的3个参数是什么?
跳转,反汇编可得参数分别为2,1,6

使用MSDN页面的socket和IDA Pro中的命名符号常量,你能使参数更有意义吗?修改后,参数是什么?
MSDN对socket的定义如下
SOCKET WSAAPI socket(
int af,
int type,
int protocol
);
现将上题中参数对应取值及含义摘录如下表:
取值 | 含义 |
---|---|
AF_INET 2 | Internet协议版本4(IPv4)地址系列。 |
SOCK_STREAM 1 | 一种套接字类型,提供带有OOB数据传输机制的顺序,可靠,双向,基于连接的字节流。此套接字类型使用传输控制协议(TCP)作为Internet地址系列(AF_INET或AF_INET6)。 |
IPPROTO_TCP 6 | 传输控制协议(TCP)。当af参数为AF_INET或AF_INET6且类型参数为SOCK_STREAM时,这是一个可能的值。 |
因此可以重命名为AF_INET、SOCK_STREAM、IPPROTO_TCP,如图
搜索in指令(opcode 0xED)的使用。这个指令和一个魔术字符串VMXh用来进行Vmware检测。在这个恶意代码中被使用了吗?使用对执行in指令函数的交叉引用,能发现进一步检测Vmware的证据吗?
搜索找到in指令
双击跳转,可以在下一条指令里看到VMXh字样
可以看到有三个函数对该函数进行了交叉引用
此处以InstallRT为例,部分代码如下
if ( atoi(off_10019034[0] + 13) && ((unsigned __int8)sub_10006119() || sub_10006196()) )
//检测是否在虚拟机中运行
//sub_10006119()检测VPC虚拟机,sub_10006196()检测VM虚拟机
{
sub_10003592(unk_1008E5F0);
sub_10003592(aFoundVirtualMa);
//aFoundVirtualMa=Found Virtual Machine,Install Cancel
result = sub_10005567(Format);
}
else
{
atoi(off_1001902C[0] + 13);
result = sub_1000D3D0(a3);
}
return result;
其中sub_10003592函数如下
猜测sub_10003592作用是将参数字符串写入xinstall.log。另两处对sub_10006196()的调用也大同小异,不做重复说明。
综上所述,该指令在恶意代码中被使用了,且可以进一步发现检测虚拟机的证据。若检测到虚拟机,则终止安装并将记录写入xinstall.log文件。
将你的光标跳转到0x1001D988处,你发现了什么?
如果你安装了IDA Python插件(包括IDA Pro的商业版本插件),运行Lab05-01.py,一个IDA Pro Python脚本(确定光标是在0x1001D988处),在运行该脚本后发生了什么?
将光标放于同一位置,你如何将这个数据转成一个单一的ASCII字符串?
使用一个文本编辑器打开这个脚本。它是如何工作的?
其他发现
dllmain -> sub_10001365 -> sub_1000208F
//StartEXS
WSAStartup(0x202u, &WSAData);
hdc = CreateDCA(pwszDriver, 0, 0, 0);
v4 = GetDeviceCaps(hdc, 8);
v5 = GetDeviceCaps(hdc, 10);
InitializeCriticalSection(&CriticalSection);
result = (char *)operator new(4 * v5 * v5);
v25 = result;
GetDeviceCaps()
参数 | 含义 | |
---|---|---|
HORZRES | 8 | 可打印区域宽度,像素 |
VERTRES | 10 | 可打印区域高度,像素 |