【文章标题】: WINDBG+IDA对某木马手脱nSPACK+LOADER部分分析
【文章作者】: 笨笨雄
【软件名称】: 灰鸽子
【下载地址】: 这东西,还是不放出来了
【使用工具】: WINDBG IDA LORDPE IMPORTREC FILEMON REGMON PEID VMWARE
【工具介绍】: WINDBG是微软出的调试器,R0下的,并且能双机调试。缺点是反汇编功能简单。IDA静态分析功能强大,缺点是动态调试功能简单。
【作者声明】: 论坛限制大,混个精华好办事,水平低,只好来新手区碰碰运气。刚啃完debugging tools for windows帮助文件里的debugger reference,写篇文章简单介绍WINDBG的使用。
----------------------------------------------------------------------
打开FILEMON跟REGMON,排除无关进程后运行木马LOADER。得知此木马通过在系统目录SYSTEM32下释放名为SERVER的文件并注册为服务作恶。
在已被感染的情况下,再次运行木马LOADER,可在FILEMON看到,先是确认SERVER的存在,然后设置文件属性,之后程序就退出了。
我猜在系统目录下建立一个假的SERVER,就对木马免疫了。(VMWARE这款虚拟机很方便还原快照,又回到无毒的环境了)
试了一下,失败了。假的SERVER被删了,然后重新建立SERVER。究竟是怎么分辨真假的?特征码识别?还是文件大小识别?为了找出对这一木马(特指这个文件,显然文件名可以随便改)的免疫方法,下面进行汇编级的分析。
----------------------------------脱壳--------------------------------
PEID查得nSPack 2.1 - 2.5 -> North Star/Liu Xing Ping [Overlay]
用WINDBG打开木马的LOADER
g $exentry
来到入口点。g命令是运行。$exentry是伪寄存器,调试器载入程序之后$exentry=EP
ba w4 0012ffc0
设置内存断点,ba代表内存断点,W代表写入,4代表4个字节,这里用ESP定律找OEP
连续g几次之后,来到下面,Access violation(非法访问)
eax=00000087 ebx=7ffde030 ecx=00010102 edx=ffffffff esi=00000000 edi=00084d99
eip=13203208 esp=0012ffa4 ebp=0012fff0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000202
image13140000+0xc3208:
13203208 0000 add byte ptr [eax],al ds:0023:00000087=??
看来是ANTI-DEBUG。向上滚动命令行窗口,找到最后一次能正确中断的地方
eax=00000000 ebx=7ffdf000 ecx=00010101 edx=ffffffff esi=00000000 edi=00084d98
eip=13203107 esp=0012ffa4 ebp=0012fff0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=0038 gs=0000 efl=00000206
image13140000+0xc3107:
13203107 e8fffeffff call image13140000+0xc300b (1320300b)
CRTL+SHIFT+F5重新开始,g $exentry来到入口点后ba e1 13203107
e代表运行,1代表字节,代表指令的长度(非操作数)。
g就可以直接断在13203107了,按F8跟进,ALT+7打开反汇编窗口
1320300b b818000000 mov eax,18h
13203010 648b18 mov ebx,dword ptr fs:[eax]
13203013 83c330 add ebx,30h
13203016 c3 ret
[fs:[18h] + 2]是PEB.BeingDebugged 标志,即7ffdf002,1代表被调试,0代表没有被调试
f 7ffdf002 l1 0
f代表写内存,l1代表长度为1个字节,后面是需要写进内存的数据
ba w4 0012ffc0
g,断在1314cb1b。
1314cb1a 55 push ebp
1314cb1b 8bec mov ebp,esp
这就是入口点了。
用LORDPE完整DUMP下来。运行IMPORTREC,修改入OEP为CB1A,自动查找IAT,结果没多少是可用的。右键菜单->高级命令->获取API调用。最小地址13140000,最大地址13150000。确定,现在可以看到很多无效的,也看到很多有效的,IAT似乎没加密。删掉无效的有点麻烦,没有删除的快捷键:(
按住SHIFT键选中所有无效的,右键菜单->删除指针,现在修复转存文件就OK了。
本来想介绍WINDBG本身的.dump命令,原文件就700K左右,可是DUMP下来居然有7M,不知道DUMP多了多少对于脱壳没意义的数据。用LORDPE DUMP下来的只有1M左右,经测试,至少可以顺利运行到感染你的机器了。
--------------------------------脱壳完毕------------------------------
关于下断的问题,我是直接查输入表,把所有跟文件操作有关的API都下了断。为了方便阅读,我把一些没意义的过程省略了。
用WINDBG打开已经脱壳的程序。g $exentry来到入口点
bp findfirstfilea下断,不分大小写,太好了,这在OLLYDBG可是不行的!
输入G,断在系统区域,ALT+6查看CALL STACK(调用栈)
00 0012fdf8 131463ce 00b91a1c 0012fe0c 00b91a1c kernel32!FindFirstFileA
CALL指令执行的时候会把返回地址压栈,CALL里面的第一条指令一般是PUSH EBP。所以堆栈段地址0012FXXX(XXX为任意数字)后一个数值便是返回地址了。在这个例子中131463ce 返回地址 00b91a1c 函数左边第一个参数
db 00b91a1c查看内存
00b91a1c 43 3a 5c 57 49 4e 4e 54-5c 73 79 73 74 65 6d 33 C:\WINNT\system3
00b91a2c 32 5c 73 65 72 76 72 65-00 00 00 00 16 00 00 00 2\servre........
一开始就断在正确的位置了,运气不错。用IDA打开程序,按G,输入131463ce,跳到下面sub_131463AE中。sub表示一个CALL
--------------------------sub_131463AE分析,可不看,直接跳到下一个分割线------------------------------
.nsp0:131463AE sub_131463AE proc near ; CODE XREF: sub_13146416+5p
.nsp0:131463AE
.nsp0:131463AE FileTime = FILETIME ptr -14Ch
.nsp0:131463AE LocalFileTime = _FILETIME ptr -0Ch
.nsp0:131463AE FatTime = word ptr -4
高级语言中的函数变量在堆栈中存在,EBP为基址加上偏移访问堆栈获得变量,为了方便阅读IDA分别为偏移命名
.nsp0:131463AE push ebp
.nsp0:131463AF mov ebp, esp
.nsp0:131463B1 add esp, 0FFFFFEB4h
.nsp0:131463B7 push ebx
.nsp0:131463B8 mov ebx, eax ;把EAX的值暂存EBX
.nsp0:131463BA lea eax, [ebp+FileTime]
.nsp0:131463C0 push eax ; lpFindFileData
.nsp0:131463C1 mov eax, ebx ;取回原来的值
.nsp0:131463C3 call sub_1314414E
用EAX作为传入传出参数,估计此CALL作用为对EAX的值修正,可不跟进
.nsp0:131463C8 push eax ; lpFileName
.nsp0:131463C9 call FindFirstFileA_0 ;查找文件
.nsp0:131463C9
.nsp0:131463CE cmp eax, 0FFFFFFFFh ;比较是否为-1,此处返回-1表示操作失败
.nsp0:131463D1 jz short loc_13146407 ;跳到函数最后
.nsp0:131463D1
.nsp0:131463D3 push eax ; hFindFile
.nsp0:131463D4 call FindClose_0 ;结束查找
.nsp0:131463D4
.nsp0:131463D9 test byte ptr [ebp+FileTime.dwLowDateTime], 10h
.nsp0:131463E0 jnz short loc_13146407
.nsp0:131463E2 lea eax, [ebp+LocalFileTime]
.nsp0:131463E5 push eax ; lpLocalFileTime
.nsp0:131463E6 lea eax, [ebp-138h]
.nsp0:131463EC push eax ; lpFileTime
.nsp0:131463ED call FileTimeToLocalFileTime ;转换文件时间的API
.nsp0:131463ED
.nsp0:131463F2 lea eax, [ebp+FatTime]
.nsp0:131463F5 push eax ; lpFatTime
.nsp0:131463F6 lea eax, [ebp-2]
.nsp0:131463F9 push eax ; lpFatDate
.nsp0:131463FA lea eax, [ebp+LocalFileTime]
.nsp0:131463FD push eax ; lpFileTime
.nsp0:131463FE call FileTimeToDosDateTime ;同上
.nsp0:131463FE
.nsp0:13146403 test eax, eax
.nsp0:13146405 jnz short loc_1314640E
.nsp0:13146405
.nsp0:13146407
.nsp0:13146407 loc_13146407: ; CODE XREF: sub_131463AE+23j
.nsp0:13146407 ; sub_131463AE+32j
.nsp0:13146407 mov dword ptr [ebp+FatTime], 0FFFFFFFFh ;返回-1
.nsp0:13146407
.nsp0:1314640E
.nsp0:1314640E loc_1314640E: ; CODE XREF: sub_131463AE+57j
.nsp0:1314640E mov eax, dword ptr [ebp+FatTime]
.nsp0:13146411 pop ebx
.nsp0:13146412 mov esp, ebp ;恢复堆栈
.nsp0:13146414 pop ebp
.nsp0:13146415 retn
.nsp0:13146415
.nsp0:13146415 sub_131463AE endp
-----------------------------sub_131463AE分析完毕----------------------------------
sub_131463AE功能:
1 寻找C:\WINNT\system32\servre文件,成功则对文件时间作修正
2 成功EAX=FatTime,失败EAX=-1
现在我们需要知道哪里调用此CALL
返回WINDBG,使用gu回到程序代码,再使用一次gu跳出此CALL
经过前面的分析之后,也可以用dd ebp显示堆栈信息(dd跟db都是内存显示的命令,只是显示格式不同,根据需要选择命令)
0012ff58 0012ffc0 13146420 7ffdf000 1314cbc4
0012ff68 0012ff74 1314cc62 0012ffc0 0012ffb4
0012ff78 1314ce18 0012ffc0 000862c8 00000000
13146420就是返回地址了
IDA按G,输入13146420,来到sub_13146416
------------------sub_13146416分析,可不看,直接跳到下一个分割线----------------------
.nsp0:13146416 sub_13146416 proc near ; CODE XREF: sub_1314B9BE+59p
.nsp0:13146416 ; sub_1314C6DE+C2p
.nsp0:13146416 ; sub_1314C6DE+FAp
.nsp0:13146416 ; .nsp0:1314CBBFp
.nsp0:13146416 ; .nsp0:1314CBE3p
.nsp0:13146416 ; .nsp0:1314CD57p ...
.nsp0:13146416 push ebx
.nsp0:13146417 mov ebx, eax ;由sub_131463AE分析可知
.nsp0:13146419 mov eax, ebx ;这两条指令相当于NOP
.nsp0:1314641B call sub_131463AE
.nsp0:1314641B
.nsp0:13146420 inc eax ;假如EAX返回-1,EAX为0
.nsp0:13146421 setnz al ;假如不为0,al被置为1
.nsp0:13146424 pop ebx
.nsp0:13146425 retn
.nsp0:13146425
.nsp0:13146425 sub_13146416 endp
-----------------------------sub_13146416分析完毕----------------------------------
sub_13146416功能: 修正为成功EAX=1,失败EAX=0
经分析可知1314cbc4是更上一层的返回地址
IDA按G,输入1314cbc4,来到入口函数,sub_13146416是loc_1314CBAC内调用的。
.nsp0:1314CBAC loc_1314CBAC: ; CODE XREF: .nsp0:1314CB9Ej
.nsp0:1314CBAC xor eax, eax ;EAX为0
.nsp0:1314CBAE push ebp
.nsp0:1314CBAF push offset s_SoiSjkSJI ; "轱i\xFF\xFF枋k\xFF\xFF桉?xFF\xFF?
.nsp0:1314CBB4 push dword ptr fs:[eax] ;保存上一个SEH处理函数
.nsp0:1314CBB7 mov fs:[eax], esp ;指向SEH处理函数
.nsp0:1314CBBA mov eax, dword_1314E964
.nsp0:1314CBBF call sub_13146416 ;搜索SERVER
.nsp0:1314CBC4 test al, al
.nsp0:1314CBC6 jz short loc_1314CC00 ;搜索不到就跳
.nsp0:1314CBC8 xor edx, edx
.nsp0:1314CBCA mov eax, dword_1314E964
.nsp0:1314CBCF call sub_1314644A ;设置文件属性为普通
.nsp0:1314CBD4 mov eax, dword_1314E964
.nsp0:1314CBD9 call sub_13146472 ;删除文件
.nsp0:1314CBDE mov eax, dword_1314E964
.nsp0:1314CBE3 call sub_13146416 ;再搜索SERVER
.nsp0:1314CBE8 test al, al
.nsp0:1314CBEA jz short loc_1314CC00 ;搜索不到就跳
.nsp0:1314CBEC push 0
.nsp0:1314CBEE call ExitProcess_0
注:sub_1314644A和sub_13146472都是直接调用SetFileAttributesA和DeleteFileA。没有什么好分析的
mov eax, dword_1314E964然后是CALL,出现次数频繁,现在看看那是什么
回到windbg,使用dd 1314E964
1314e964 00b91a1c 01010100 00000000 00b918ec
1314e974 00b918d8 00b91900 00000001 00000000
1314e984 00000000 00000000 00000000 00000000
还记得00b91a1c吗?findfirstfilea的第一个参数“C:\WINNT\system32\servre”的首个地址。
现在来看看loc_1314CC00,看到COPYFILEA
.nsp0:1314CC00 loc_1314CC00: ; CODE XREF: .nsp0:1314CBC6j
.nsp0:1314CC00 ; .nsp0:1314CBEAj
.nsp0:1314CC00 lea edx, [ebp-18h]
.nsp0:1314CC03 mov eax, dword_1314E964
.nsp0:1314CC08 call sub_131464DA
.nsp0:1314CC08
.nsp0:1314CC0D mov edx, [ebp-18h]
.nsp0:1314CC10 mov eax, offset dword_1314E9C4
.nsp0:1314CC15 call sub_13143D2E
.nsp0:1314CC15
.nsp0:1314CC1A mov eax, dword_1314E9C4
.nsp0:1314CC1F call sub_1314B4A2
.nsp0:1314CC1F
.nsp0:1314CC24 push 0
.nsp0:1314CC26 mov eax, dword_1314E964
.nsp0:1314CC2B call sub_1314414E
.nsp0:1314CC2B
.nsp0:1314CC30 push eax
.nsp0:1314CC31 lea edx, [ebp-1Ch]
.nsp0:1314CC34 xor eax, eax
.nsp0:1314CC36 call sub_13142856
.nsp0:1314CC36
.nsp0:1314CC3B mov eax, [ebp-1Ch]
.nsp0:1314CC3E call sub_1314414E
.nsp0:1314CC3E
.nsp0:1314CC43 push eax
.nsp0:1314CC44 call CopyFileA
返回WINDBG,输入g 1314CC44来到call CopyFileA,F8跟进
查看CALL STACK
00 0012ff54 1314cc49 00b91a78 00b91a1c 00000000 kernel32!CopyFileA
db 00b91a78
00b91a78 44 3a 5c b9 a4 d7 f7 5c-75 6e 70 61 63 6b 2e 65 D:\....\unpack.e
00b91a88 78 65 00 00 00 00 00 00-00 00 00 00 00 00 00 00 xe..............
db 00b91a1c
00b91a1c 43 3a 5c 57 49 4e 4e 54-5c 73 79 73 74 65 6d 33 C:\WINNT\system3
00b91a2c 32 5c 73 65 72 76 72 65-00 00 00 00 16 00 00 00 2\servre........
windbg中文显示不太好...中文目录名显示不出来
总结:由分析可知,程序先检查SERVER是否存在,存在则尝试删除该文件,删除失败则退出,本来就不存在或者删除成功就把自己复制到系统目录并改名字。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课