恶意代码分析实战

静态分析

查看可执行文件/DLL文件编译时间:PETool查看PE文件头,找到_IMAGE_NT_HEADERS.FileHeader.TimeDateStamp。

当导入表存在WS2_32.dll,则有联网行为。ADVAPI32.dll中存在创建服务和提权API。ole32.dll可创建COM实例。

通用脱壳机linxerUnpacker可脱FSG壳。

判断PE文件为EXE还是DLL:PETools文件头->特征值,看DLL复选框是否勾选。

恶意代码检测Vmware原理:in(0xED)指令与魔术字符串“VMXH”进行检测。另一种遍历HKLM\SYSTEM\CurrentControlSet\Control\Device以查找vmware值。也有其他各种老六行为。

CreateToolhelp32Snapshot进程、线程拍摄快照。

动态分析

运行DLL:

1
rundll32 *.dll,导出表函数名

用RegShot记录注册表操作。注册表创建服务路径:HKLM\SYSTEM\ControlSet001\Services\服务名,重要参数:ImagePath、DisplayName、Description

COM模型

导入表中含有OLE32.DLL和OLEAUT32.DLL,重要API:CoCreateInstance、OleInitialize、OleUninitialize。具体使用的对象需要确定riid和rclsid。riid需要上网查,rclsid可从这里找:KLM\SOFTWARE\Classes\CLSID\。

后门

DLL映射组合拳:CrreateFileA、CreateFileMappingA、MapViewOfFile,IsBadReadPtr判断映射内存区域权限。

1
2
3
repne scasb ;等于strlen
rep movsd ;等于memcpy esi->edi
rep movsb

计划任务

NetScheduleJobAdd着重第二个Buffer参数。

资源区

msgina32.dll获取登录凭证。

sfc_os.dll为Windows文件保护机制模块。通过LoadLibraryA调用该模块后,所调用的函数为第二个参数lpProcName,其中编号为2号的函数没有公开(其实为禁用Windows文件保护机制函数)。

SMTP

属于TCP,“RCPT TO: <”指令为收件人。

添加注册表项在“HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs”时,能被所有加载user32.dll的程序加载。

用户态ROOTKIT-HOOK

准备时,先检测在哪个进程中运行GetCurrentThreadId,并提取。比较需要HOOK的进程,组合拳CreateToolhelp32Snapshot->Thread32First与Thread32Next遍历,找到后除自己进程其余SuspendThread,结束后再次遍历并ResumeThread。

模块载入:GetModuleHandleA、LoadLibraryA、GetProcAddress

核心方法,在原指令前增加无条件跳转jmp,结束后再返回原地址,前后VirtualProtect修改内存权限。

1
2
3
4
mov edx,[ebp+lpAddress]
mov byte ptr [edx],0E9h ;写入机器码E9
mov eax,[ebp+var_4]
mov [eax+1],ecx

另一种跳转方法:地址在eax中,再jmp eax。

键盘勾子

导入表有USER32.DLL中的GetAsyncKeyState和GetForegroundWindow。

UnmapViewOfFile后,任何对映射所作出的操作会被写入磁盘。

可能通过SetWindowsHookExA、UnhookWindowsHookEx的方式,前者第一个参数idHook为0x0Dh时代表键盘挂钩。

进程注入

留意的KERNEL32.DLL中的API:CreateRemoteThread、WriteProcessMemory、VirtualAllocEx

进程替换

进程创建及进程上下文修改:CreateProcessA、GetThreadContext、SetThreadContext。对内存空间修改:ReadProcessMemory、WriteProcessMemory。对资源操作:LoadResource、LockResource、SizeofResource。

当CreateProcessA的第6个参数dwCreationFlags为4时创建但不启动。

被替换的进程为CreateProcessA的第一个参数lpApplicationName

时间差反调试

原理:较多时间浪费在异常处理。

QueryPerformanceCounter、GetTickCount获取精确时间。

将eip赋予eax:

1
2
call $+5
pop eax

UPX手脱复盘

pushad以下控制流只向下跳,忽略回跳,找到一个大jmp,跳过去即为OEP。

importREC修复导出表,个人喜欢Scylla。

shellcode

推荐命令行工具scdbg,运行后可统计出所有Win32API调用记录及其参数。

PDF

工具PDFStreamDumper可自动找出相应shellcode及漏洞。

内核调试

随机数相关注册表操作:写HKLM\SOFTWARE\Microsoft\Cryptography\RNG\Seed。

CreateServiceA的第5个参数dwServiceType为1时表示加载到内核。StartServiceA启动,ControlService第2个参数dwControl为1时启动卸载程序。

Windbg:

1
2
3
4
5
6
7
8
bp 00401080 #该地址设置断点
g #运行
!drvobj 服务名 #获取驱动对象
!object \Driver #获取所有驱动列表
dt _DRIVER_OBJECT 81f34550 #以指定的结构解析对象 观察驱动卸载地址DriverUnload 并可在IDA中重设基地址为DriverStart
bp 0xf8dd0486
g
p #单步走

SSDT

系统服务描述表,用WinDBG

1
2
3
4
5
6
dd KeServiceDescriptionTable #第二列为地址 第4列为大小 第5列为参数
dd 80502b8c #获取指定地址SSDT
#以上两条合并写法,显示0x100条结果:dd dwo(KeServiceDescriptionTable) L100
u 8059a948 #获取SSDT表中该地址对应对象及部分代码

lm #查看模块信息 找到ROOTKIT隐藏模块的大约位置 找到SSDT表相应地址并查看

ROOTKIT文件隐藏原理:获取枚举链该文件的前驱后继两个文件,将前驱连续两次加上FILE_BOTH_DIR_INFORMATION的偏移量NextEntryOffset实现目标文件的脱链。

卸载服务方法:

1
2
sc query "服务名"
sc delete "服务名"

进程隐藏

WinDBG启动,dd查看驱动服务信息后查看请求处理表:

1
dd 820df7e0+0x038 L1c #+0x038代表MajorFunction

发现请求处理表中大部分为0x804f454a,尝试获取该信息:

1
ln 804f454a

IopInvalidDeviceRequest表示该驱动对该信号的处理方式缺省,其余信号可查看wdm.h,重要的有启动0、终止2、控制0E。

IoGetCurrentProcess所需参数为_EPROCESS结构,该结构并未公开,尝试WinDBG获取:

1
dt _eprocess

与文件隐藏原理相同:脱链技术

双向链表为_EPROCESS的_LIST_ENTRY结构

x64之路

WinDBG导出寄存器值:

1
da rcx

是否在x64系统上以x32运行:IsWow64Process。

如果在IMAGE_NT_HEADERS->UNAGE_FILE_HEADER中设置了IMAGE_FILE_32BIT_MACHINE则确定了以32位编译的。