• 标 题:关于Armadillo 3.7“作品”的几点体会
  • 作 者:jingulong
  • 时 间:2004年3月19日 07:29
  • 链 接:http://bbs.pediy.com

Arma升级了,3.7,jwh51说他那里对用3.7和3.6加壳的程序的dump过程差不多,我这里却有些不同,是不是我哪里操作
不对?还有就是对iat的修复,不知下面的方法是否可取,看官,自己斟酌吧,不是之处,海涵。

OS: XP
工具: (改了名的)od
对象:goodmorning上传的经3.7加壳的notepad
1.anti od
程序利用Process32Next anti以下进程:
ollydbg
nrec.exe
n-rec.Vx      ;应该是n-rec.Vxd,它只核对文件名前 8个字节
n rec.Vx      
agoblin
lordpe
典型代码如:
...
0103DC33   LODS DWORD PTR DS:[ESI]            ;开始esi指向得到的进程名
0103DC34   OR EAX,20202020                    ;大写字符->小写字符 
0103DC39   STOS DWORD PTR ES:[EDI]
0103DC3A   LOOPD SHORT notepad.0103DC33
...
0103DCC4   CMP DWORD PTR DS:[EDI],796C6C6F    ;是olly吗?
0103DCCA   JNZ SHORT notepad.0103DCDA
0103DCCC   CMP DWORD PTR DS:[EDI+3],67626479  ;ydbg?
0103DCD3   JNZ SHORT notepad.0103DCDA
0103DCD5   JMP notepad.0103DECE
0103DCDA   MOV EDI,84C0
0103DCDF   ADD EDI,EBP
0103DCE1   CMP DWORD PTR DS:[EDI],6365726E
0103DCE7   JNZ SHORT notepad.0103DCF7
0103DCE9   CMP DWORD PTR DS:[EDI+4],6578652E
...
对付arma的这一招,你只要把od的名字改一改就可以了,暂时不要启动lordpe(或改名)。

2.oep
我这里用“传统”方法查找 oep失败:
对WaitForDebugEvent下断,得到pDebugEvent = 0012DA6C
再对WriteProcessMemory,断下后堆栈数据:
0012D8EC   00000050  |hProcess = 00000050 (window)
0012D8F0   01006000  |Address = 01006000
0012D8F4   00881FB0  |Buffer = 00881FB0
0012D8F8   00001000  |BytesToWrite = 00001000
0012D8FC   0012D91C  pBytesWritten = 0012D91C

这时0012DA6C处数据:
0012DA6C  70 F5 12 00 70 F5 12 00 CA 44 02 01 05 00 00 00  p?.p?.蔇...
0012DA7C  D8 1E 88 00 00 00 00 00 FC FE 12 00 00 00 00 00  ??.........
0012DA8C  19 3B 03 01 00 00 00 00 04 00 00 80 00 00 00 00  ;..........
0012DA9C  8C F7 56 5A 00 00 00 00 00 00 00 00 00 00 00 00  岟VZ............

1006420(oep)在哪里?看来arma这次升级对此法找 oep有所防备了。另寻它法吧,总不能搜索它的二进制值!
重新载入这个东东,隐藏od后对WaitForDebugEvent下断,断下后去掉断点再bp GetThreadContext,呵呵,来了:
0012D79C   01028408  /CALL to GetThreadContext from notepad.01028402
0012D7A0   00000058  |hThread = 00000058
0012D7A4   0012D7A8  pContext = 0012E86C
执行到函数结束时(retn 8)在od的Command处键入:d 12E86C+0b8,看到了:
0012E924  20 64 00 01 1B 00 00 00 02 02 01 00 54 F5 12 00   d.....T?.
记下 oep=1006420
有了 oep,dump时利用插件(谢谢jwh51),的确很方便。对WriteProcessMemory下断,断下后,
把8823D0(881FB0+(1006420-1006000))处的55 8b改成eb fe,把1026d2d处的call 1026da5 nop掉,执行程序,
这时可以dump了。
详细说明参见jwh51的文章
dump后记住把那个eb fe改回来(55 8b)。

3.iat
od载入dump下来的东东,代码窗口转到1006420,下滚鼠标看到:
01006549   CALL DWORD PTR DS:[100109C]              ; kernel32.GetStartupInfoA
100109C 应该位于 iat中了,follow in dump后可以看到从1001000开始的 iat:
01001000  CA 60 DF 77 70 DA 9A 00 65 1B DD 77 0B 58 DD 77  蔪遷p跉.e輜 X輜
01001010  EA 22 DD 77 D7 23 DD 77 78 D8 9A 00 D6 A6 9A 00  ?輜?輜x貧.枝?
01001020  1C 3A C7 77 F9 89 C8 77 1D 53 C7 77 B0 1B C7 77  :莣鶋葁S莣?莣
...
用ImportRec处理这段数据,稍加整理得到涉及 8个 dll,57个未解析出函数指针的 iat表,这 8
个 dll分别是:
1)advapi32.dll
2)gdi32.dll
3)kernel32.dll
4)?           ;从1001144开始第一个指针指向77C379DB
5)?           ;从1001194开始第一个指针指向7740FB28
6)user32.dll
7)?           ;从10012c4开始第一个指针指向73006818
8)?           ;从10012d4开始第一个指针指向763D6AC8
记下这个顺序,修复 iat有用。let's go
od再次载入这个notepad,对WaitForDebugEvent设断,执行程序,中断,这时不断按f9,当 edi
值连续发生如下变化,pause
0012E0DC->0104E8C8->0012E0DC (注意要连续)
这时用pupe(我用自己写的小工具)把子进程中Api函数VirtualProtect的Retn 10(c2 10 00)语句前2字节改
成eb fe, alt+f9将父进程从WaitForDebugEvent返回,再按“经典”方法使父进程与子进程断开,让 od
 attach上子进程,完成后按alt+f9走到eb fe处,改回来:eb fe->c2 10,再f8来到:
009C465F  PUSH 1
009C4661  POP EAX
009C4662  TEST EAX,EAX
009C4664  JE 009C4929
009C466A  AND WORD PTR SS:[EBP-1D7C],0
009C4672  AND DWORD PTR SS:[EBP-1D84],0
009C4679  AND DWORD PTR SS:[EBP-1D80],0
009C4680  MOV EAX,DWORD PTR SS:[EBP-1780]
009C4686  MOVSX EAX,BYTE PTR DS:[EAX]
009C4689  TEST EAX,EAX
009C468B  JNZ SHORT 009C46D1
009C468D  LEA ECX,DWORD PTR SS:[EBP-17C0]
009C4693  CALL 009A1040
...
这正是我们希望来到的代码区--处理 iat的地方!作如下修改:
1)9C46AE处的 MOV[EAX],ECX nop
2)9C4813的 JNZ 9C4854 也nop
3)9C4847处
   009C4847   CALL 009A9C72
   009C484C   POP ECX
   009C484D   POP ECX
   改成:
   009C4847   CALL kernel32.GetProcAddress
   009C484C   NOP
   009C484D   NOP

在9C4913(MOV[EAX],ECX)和9C49ed(CALL [9CB138] ; kernel32.VirtualProtect)设断,f9,断在9C4913时看到:
009C4913  MOV DWORD PTR DS:[EAX],ECX               ; comdlg32.FindTextW
此时的eax=009F9200,ecx=763CA8A5,结合前面ImportRec得到的顺序,看出它最先处理的是最后一个(第八个)
 dll(comdlg32.dll),arma并没有把它直接放到10012d4,而是009F9200!按f8,hex dump窗口转到9f9200
把这里的A5 A8 3C 76按二进制方式copy,去掉9C4913的断点,f9,断在CALL [9CB138]处,这时你可以从hex dump
中看到对comdlg32已经处理完毕,但9f9200处已经变成 00 00 00 00,这就是刚才copy的原因,paste it,ok,再
选定那里的数据块,Binary copy,打开记事本,粘贴,结果如此
A5 A8 3C 76 58 A8 3C 76 FC A7 3C 76 C8 6A 3D 76 B5 A8 3C 76 59 1A 3B 76 3F DE 3C 76 08 1E 3D 76
B7 44 3C 76 00 00 00 00
再次在9C4913下断,f9,看到:
009C4913    MOV DWORD PTR DS:[EAX],ECX               ; SHELL32.DragQueryFileW
(eax=009F9230 ecx=7740FB28)
呵呵,这次处理的是SHELL32.DLL,第一个函数指针7740FB28,对照ecx的值知道,这应该放到第五个位置!
同前,处理完这个 dll后粘贴到记事本中的是:
28 FB 40 77 CE 8A 4A 77 DB E3 49 77 41 52 41 77 00 00 00 00
要放到第一次粘贴到记事本数据的前面哦,第五个位置呀!(建议在前面标记上 5)

好了,每个 dll都可以从名称或ecx的值找到自己的位置,这样的操作只是简单重复进行就可以了。最后当arma异常
时把记事本中的数据复制到1001000,再借助ImpotREC,没有什么值得一说的了。

对了,如果要跨系统,把RestoreLastErr改成SetLatErr就行。