• 标 题:猜---帮我战胜ExeCryptor
  • 作 者:jingulong
  • 时 间:2004年3月04日 06:33
  • 链 接:http://bbs.pediy.com

前几天,Fly问我能不能搞ExeCryptor的NotePad,看了一阵就放弃了,其中那个 call eax 每次都让偶无功而返。今天算是旧话重提了。
  为了这个程序,先改改od吧,因为她像慈祥的老人,过程中老是不断提醒你--->那个有点烦人的对话框!由于这里每次都选择"yes",好吧,让我们对od说,“谢谢,知道了”。LordPe打开od,把RVA=34052处的75改成eb。(记住今后改回来哦)
od载入程序,隐藏od,Exceptions默认选项除了Memory access violation全打勾,F9执行。程序在4FC74B停下:
004FC74B   F0:0FC7C8        LOCK CMPXCHG8B EAX                       ; Illegal use of register
这里的问题就是未修改的od每次都要给提示性警告的“LOCK CMPXCHG8B may crash some processors when excuted!”。以前对此的解决方案有两个:1.shinegood修改函数的入口代码为 ret使程序到不了这里;2.tDasm把这里的F0改成cc。我们就直接shift+f9!
呵呵,咋又来到这里?哦,这是第二次了,Alt+O打开Debug options对话框,在ignore...custom exceptions...中加上这个异常(C000001E),再shift+f9,(不短的)一段时间后停在:
004FDFF4   8ED3             MOV SS,BX
按三次shift+f9,停在:
004FF26D   IMUL EDX,DWORD PTR DS:[ESI+B240483],0BE8C3                  ;注意这条语句
如再shift+f9差不多就crash了,这里让我们分析一下栈中数据:

0012FF5C   004FC347  |RETURN to EXECrypt.004FC347 from EXECrypt.004FC354
0012FF60  /0012FF7C  |Pointer to next SEH record
0012FF64  |004FF00D  |SE handler
0012FF68  |004FC35C  |RETURN to EXECrypt.004FC35C from EXECrypt.004FEF70
0012FF6C  |004FC347  |RETURN to EXECrypt.004FC347 from EXECrypt.004FC354
0012FF70  |004FE0BE  |RETURN to EXECrypt.004FE0BE from EXECrypt.004FE0CB
0012FF74  |004FE113  |RETURN to EXECrypt.004FE113 from EXECrypt.004FC327
0012FF78  |004FE076  |RETURN to EXECrypt.004FE076 from EXECrypt.004FE081
0012FF7C   012FFE0  |Pointer to next SEH record
0012FF80   004FDD6E  |SE handler
0012FF84   77E756DB  |kernel32.GetModuleHandleA
0012FF88   77E7564B  |kernel32.GetProcAddress
0012FF8C   77E78023  |kernel32.LoadLibraryA
0012FF90   77E7AB8C  |kernel32.FreeLibrary
0012FF94   77E780E8  |kernel32.VirtualProtect

首先当然是SE handler指示的代码段了,在4ff00d处设断,shift+f9,断下后单步跟踪看出,这个异常处理函数主要完成的功能是修改异常处理后的返回地址(异常发生地址+7),在返回处(4FF274=4FDFF4+7)设断,f9,回到:
004FF274   E8 0B000000      CALL EXECrypt.004FF284
去掉断点,按f7两次看到:
004FF287   FFD0             CALL EAX
小心啊,这就是以前令我无法continue的语句,此时 eax=0 !(不知直接运行程序时这里是怎样通过的?)
这时只好让我们猜程序在这里要干什么(eax的值应该是多少)了,当然不能乱猜的。再看堆栈数据,非常有意思,栈顶数据004FC347和[esp+10]处的相同,设想这是函数(eax)的参数,鼠标选中它Follow in dump,给出:
004FC347  6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00           kernel32.dll.
如果是参数,只有这一个(为啥,下面就是SEH chain pointer了),什么函数用这样的参数,呵呵,聪明的你一定想到了!看,堆栈中不是明明白白躺着那个函数吗!
0012FF84   77E756DB  |kernel32.GetModuleHandleA
试试,把这个值复制给 eax,f8后再f7跟吧(摸到石头过河啊)。几下就来到:
004FF310   FF7424 10        PUSH DWORD PTR SS:[ESP+10]
004FF314   50               PUSH EAX                                       ; kernel32.77E60000
eax中就是kernel32的handle了,[esp+10]中呢?follow in dump看到的是:
004FE0BE  4C 6F 61 64 4C 69 62 72 61 72 79 41 00           LoadLibraryA.
两个数按这样顺序入栈,应该是为那个函数准备数据吧?跟吧,两下f7走到:
004FF337   89C2             MOV EDX,EAX                                    ; kernel32.77E60000
004FF339   B8 01000000      MOV EAX,1
004FF33E   FE00             INC BYTE PTR DS:[EAX]
这里当然又该异常了(eax=1),在4ff33e+7=4FF345 处下断,断点处停下后去掉断点再跟,4F377处又异常(
语句 MOV EAX,[EAX] ;eax=4),4FF377+7=4ff37e设断,shift+f9后断下,这时eax=10,语句是:
004FF37E   OR EAX,EAX
004FF380   JNZ SHORT EXECrypt.004FF3BC
004FF382   IMUL EDX,DWORD PTR DS:[ESI+B240483],0BE8C3                ;再注意这语句
对照前面004FF26D的语句会发现,004FF382这条和它相同,联想到刚才我们做的,我把 eax的值改成了 0(不然就被jnz这条语句跳过了)。
按“计划”在004FF382这里异常,在004FF382+7=004FF389处设断,shift+f9后去掉断点单步来到
004FF39C   FFD0                CALL EAX                     ;eax=0
这时堆栈顶部正好是要用的两个参数,把12ff88中的77E7564B复制到eax中,f8再一路f7就走出令人烦心的这段程序(过草地?)。来到:
004FF6BE  PUSH ECX
004FF6BF  MOV ECX,6FB
004FF6C4  PUSH EAX
004FF6C5  MOV EAX,34F118C0
004FF6CA  PUSH EBX
004FF6CB  MOV EBX,EXECrypt.004FF6BD
004FF6D0  ADD BYTE PTR DS:[EBX],AL
004FF6D2  ROR EAX,7
004FF6D5  SUB EAX,31771F43
004FF6DA  XOR EAX,1F6131A9
004FF6DF  SUB EAX,9CAD5D2C
004FF6E4  DEC EBX
004FF6E5  ROR EAX,0A
004FF6E8  ADD EAX,19FE6378
004FF6ED  LOOPD SHORT EXECrypt.004FF6D0
这是一段代码变形程序,把我们刚才走过的“草地”毁掉!
四方面军过两次草地就很苦了,tnnd,你会发现程序要在这“草地”上来回溜达 n次!如果每次都这样走,那趁早拔下插头,
“仰天长啸”吧。
   想想,在“草地”里都干了些啥?--->两件事:
   a.调用栈中12ff84处指示的函数->GetModuleHandleA
   b.调用12ff88处指示的函数->GetProcAddress
(每次的参数都在栈中)
为了避免草地之苦,让我们写一段来代替“草地”吧。注意“草地”每次都要“恢复”后进入,故在下一次进入时于入口不远处(4fefc6)键入:
mov eax,[esp]
xchg eax,[esp+8]
xchg eax,[esp+4]
mov [esp],eax                           ;以上是把参数置换到栈顶
call [12ff84]
push eax
call [12ff88]
jmp 4ff6be
(所谓“下次进入”,即在4fefc1处设断,断下后去掉断点再置光标于4fefc3按f4)
ok,let's go on. 
F9执行程序,在4FE87C和4B58E4停下都 shift+f9 pass 过去,下一次停在4FECA0时小心了:
004FECA0   8B40 10            MOV EAX,DWORD PTR DS:[EAX+10]
004FECA3   E8 0B000000        CALL EXECrypt.004FECB3
再pass就crash。没法,只好再来猜猜看。观察堆栈中数据:
0012FBC4   00401000  |EXECrypt.<ModuleEntryPoint>                          ;[esp]=401000,呵呵
0012FBC8   000B4E00  |                                                     ;一个数?看看Memory,略小于code段的size(B5000)!
0012FBCC   00000040  |                                                     ;40作为某个函数的参量,应该有印象吧
0012FBD0   004FEC08  |RETURN to EXECrypt.004FEC08 from EXECrypt.004FEC17     
0012FBD4   77F92538  |RETURN to ntdll.77F92538                             ;2K下这个返回地址是什么地球人都知道
这应该是准备调用什么函数吧,该函数游四个参数,想来想去就想到那个壳代码常用到的函数,yes!VirtualProtect。
这个函数地址不是躺在栈中吗!那么哪里调用呢?假设这里不是异常(当然脑壳有点昏,这不是异常了吗?管它!),于是试着把光标移到下一行call处回车,看到:
004FECB3   83C4 04            ADD ESP,4
004FECB6   FFD0               CALL EAX
呵呵,call eax , 改!把栈中12FF94处的77E780E8复制到 eax,跳过4feca0,从4feca3处单步,走到4FECB6时f8走过,再f7到4fed30 loop 语句,光标置于(下一条语句)4fed32按f4,之后一路f7(rep 语句时f8)把你送到“光明之颠(fly 语录)”---->4b58e4
004B58E4   55                 PUSH EBP
004B58E5   8BEC               MOV EBP,ESP
004B58E7   83C4 E8            ADD ESP,-18
004B58EA   53                 PUSH EBX
004B58EB   56                 PUSH ESI
004B58EC   57                 PUSH EDI
004B58ED   33C0               XOR EAX,EAX
004B58EF   8945 E8            MOV DWORD PTR SS:[EBP-18],EAX
004B58F2   8945 EC            MOV DWORD PTR SS:[EBP-14],EAX
004B58F5   8945 F0            MOV DWORD PTR SS:[EBP-10],EAX
004B58F8   B8 74564B00        MOV EAX,EXECrypt.004B5674
004B58FD   E8 AA0EF5FF        CALL EXECrypt.004067AC
delphi?
光标移到4b58fd   CALL EXECrypt.004067AC回车,看看,果然是DELPHI!!!

LordPE、ImportRec,没啥好说的了,一切,都是“流水作业”!
Over,谢谢你花时间看完。

走在街上常看到某公司的广告,人类失去联想,世界将会怎样!!!