一直用LordPE作为PE文件分析器,习惯了。最近升级了系统到win10,发现LordPE用不了了,崩溃。后来调试发现是LordPeFix.dll的一个bug,它修改了Procs.dll,在GetNumberOfProcesses的一处call之前改大了栈缓冲区的长度参数,但缓冲区没有相应改大,于是在call中覆盖了返回地址,发生了崩溃。具体调试过程简单写一下。
用windbg调挂上LordPE_hh.exe,F5后崩溃,发现eip是一个奇怪的eip指针:
(10c04.571c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000000e2 ebx=00000000 ecx=76bfb79e edx=00540000 esi=75806c40 edi=0019f798
eip=000022e0 esp=0019f754 ebp=ffffffff iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010216
000022e0 ?? ???
k命令显示不了调用栈了: 0:000> k
# ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 0019f750 00000000 0x22e0
于是,dds esp l 100,看了一下调用栈,找到最近的LordPE主模块的调用栈:
0019fa14 004058b4 LordPE_hh+0x58b4
于是 ub 004058b4
LordPE_hh+0x5899:
00405899 a324e54100 mov dword ptr [LordPE_hh+0x1e524 (0041e524)],eax
0040589e 50 push eax
0040589f 6a01 push 1
004058a1 6803100000 push 1003h
004058a6 8b0d48e64100 mov ecx,dword ptr [LordPE_hh+0x1e648 (0041e648)]
004058ac 51 push ecx
004058ad ffd3 call ebx
004058af e85c060000 call LordPE_hh+0x5f10 (00405f10)
重新加载程序,并在
004058b4 之前的call处下断点:bu
004058af,F5运行:
Breakpoint 0 hit
eax=00000000 ebx=75806c40 ecx=00345000 edx=00000000 esi=002121f0 edi=6de812f0
eip=004058af esp=0019fa18 ebp=0019fa94 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
LordPE_hh+0x58af:
004058af e85c060000 call LordPE_hh+0x5f10 (00405f10)
F10,不进call,果然又崩溃了:
(10c04.571c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=000000e2 ebx=00000000 ecx=76bfb79e edx=00540000 esi=75806c40 edi=0019f798
eip=000022e0 esp=0019f754 ebp=ffffffff iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010216
000022e0 ?? ???
然后重新加载,并F11跟进去继续调,发现崩溃在这个call里:
LordPE_hh+0x5f94:
00405f94 e8fb220100 call LordPE_hh+0x18294 (00418294)
00405f99 8bf8 mov edi,eax
重新加载进程,F11跟进去,发现进入了另一个dll的空间:procs!GetNumberOfProcesses
eax=00000000 ebx=00000000 ecx=00000000 edx=00000001 esi=75806c40 edi=0019f798
eip=00418294 esp=0019f750 ebp=ffffffff iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
LordPE_hh+0x18294:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for E:\Tools\LPE-DLX\procs.dll -
00418294 ff25fc924100 jmp dword ptr [LordPE_hh+0x192fc (004192fc)] ds:002b:004192fc={procs!GetNumberOfProcesses (20001200)}
0:000> dd esp l 1
0019f750 00405f99
记下返回地址是
00405f99,此处
0019f750
下写入断点,F5运行,看是谁写坏的栈:
eax=000022e0 ebx=0019f560 ecx=0000007c edx=0002aed0 esi=0048db28 edi=00000100
eip=76bfb764 esp=0019f3e0 ebp=0019f41c iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
KERNELBASE!K32EnumProcesses+0x74:
76bfb764 8b5de0 mov ebx,dword ptr [ebp-20h] ss:002b:0019f3fc=00450000
断下了,K命令显示一下调用栈:
# ChildEBP RetAddr
00 0019f41c 200012a5 KERNELBASE!K32EnumProcesses+0x74
WARNING: Stack unwind information not available. Following frames may be wrong.
01 0019f430 6de3a061 procs!GetNumberOfProcesses+0xa5
原来是
K32EnumProcesses写坏的。那么问题来了,谁调用的它?看一下返回地址处的汇编代码:
ub 200012a5
procs!GetNumberOfProcesses+0x86:
20001286 81c41c030000 add esp,31Ch
2000128c c3 ret
2000128d 8d442404 lea eax,[esp+4]
20001291 8d8c2430010000 lea ecx,[esp+130h]
20001298 50 push eax
20001299 6800040000 push 400h
2000129e 51 push ecx
2000129f ff15ec240020 call dword ptr [procs!GetModuleHandleEx+0x48c (200024ec)]
IDA打开procs.dll,找一下对应的位置:
.text:2000128D 8D 44 24 04 lea eax, [esp+220h+var_21C]
.text:20001291 8D 8C 24 30 01 00 00 lea ecx, [esp+220h+var_F0]
.text:20001298 50 push eax
.text:20001299 68 F0 00 00 00 push 0F0h
.text:2000129E 51 push ecx
.text:2000129F FF 15 EC 24 00 20 call dword_200024EC
发现
20001299处的代码,文件中是push f0,但内存中却是push 400。看来有smc。
再次重新加载进程,
2000129a 处下断点内存断点,看看是谁改的代码段:
ba w1 2000129a
F5跑起来,Breakpoint 0 hit
eax=0019f8a4 ebx=00000000 ecx=00000400 edx=2000129a esi=000287dc edi=0019f8ec
eip=00022afc esp=0019f87c ebp=0019f88c iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000297
LordPeFix+0x2afc:
00022afc c3 ret
往上翻看代码:
0:000> ub eip
LordPeFix+0x2aea:
00022aea c3 ret
00022aeb 668b08 mov cx,word ptr [eax]
00022aee 8a4002 mov al,byte ptr [eax+2]
00022af1 66890a mov word ptr [edx],cx
00022af4 884202 mov byte ptr [edx+2],al
00022af7 c3 ret
00022af8 8b08 mov ecx,dword ptr [eax]
00022afa 890a mov dword ptr [edx],ecx
看ecx和edx的值:
0:000> r ecx
ecx=00000400
0:000> r edx
edx=2000129a
果然是这里改了procs.dll的代码段。
回看文件中原代码,看看这次
LordPeFix
修改的意义是什么?
.text:20001291 8D 8C 24 30 01 00 00 lea ecx, [esp+220h+var_F0]
.text:20001298 50 push eax
.text:20001299 68 F0 00 00 00 push 0F0h
.text:2000129E 51 push ecx
.text:2000129F FF 15 EC 24 00 20 call dword_200024EC
可以看到,ecx指向栈缓冲区,F0是这个缓冲区长度。
LordPeFix改大了缓冲区长度值,但没改大缓冲区本身。那问题就简单了,把缓冲区本身也改长一些就够了。这个缓冲区是个栈变量,是在函数开头分配的,栈空间一共分了21C字节:
.text:20001200 GetNumberOfProcesses proc near ; DATA XREF: .text:off_20002698o
.text:20001200
.text:20001200 var_21C = dword ptr -21Ch
.text:20001200 var_218 = dword ptr -218h
.text:20001200 var_F0 = byte ptr -0F0h
.text:20001200
.text:20001200 A1 FC 24 00 20 mov eax, dword_200024FC
.text:20001205 81 EC 1C 02 00 00 sub esp, 21Ch
LordPeFix 将F0改为400,一共改大了不到400H字节。那么我们把21C直接加上400h字节,成为61C,就足够了:
即把 sub esp, 21Ch, 改为 sub esp 61Ch。同时函数返回前别忘记把add esp,21C,改为add esp,61C,配平堆栈避免崩溃,ret指令有好几处,都要改。改完类似这个样子:
.text:20001200 mov eax, dword_200024FC
.text:20001205 sub esp, 61Ch
...
.text:20001224 add esp, 61Ch
...
其他的retn
...
最后对比一下改了哪几处:
fc /b PROCS_OLD.DLL PROCS.DLL
正在比较文件 PROCS_OLD.DLL 和 PROCS.DLL
00000608: 02 06
00000627: 02 06
00000650: 02 06
00000689: 02 06
000006AD: 02 06
000006BC: 02 06
OK,收工,PE编辑器又可以用了。
================================================================================
晚上又看了一下,其实是LordPeFix的一个bug,这个模块已经修改过21c为31c,不过还是改得过小。改成61c就够了。这样procs.dll就不用改了。
CODE:00403ADB cmp [ebp+var_14], 21Ch
CODE:00403AE2 jnz loc_403F0C
CODE:00403AE8 cmp [ebp+var_10], 0F0h
CODE:00403AEF jnz loc_403F0C
CODE:00403AF5 cmp [ebp+var_C], 41E660h
CODE:00403AFC jnz loc_403F0C
CODE:00403B02 mov eax, ds:dword_4057AC
CODE:00403B07 add eax, 21Ch
CODE:00403B0C mov [ebp+var_8], eax
DATA:004057AC dword_4057AC dd 100h ; DATA XREF: Fix+E2r
DATA:004057AC ; sub_403F1C+11r
上面100改为400,即21c+100改为21c+400:
正在比较文件 LordPeFix_OLD.dll 和 LORDPEFIX.DLL
00003DAD: 01 04
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2018-12-14 21:00
被NoneName编辑
,原因: 补漏