;前两天拿到一个外挂,还不错,就想研究一下. 遂欲脱壳.
;按照peid的检测结果,这应该是一个某人0.7x的壳. 我没用过那个壳,不知道到底是不是0.7x,不过跟踪起来,发现与以前的老版本区别似乎不是很大.不过这个帖子发在pediy不知道会不会被删  
;跟踪的流程大致如下
;============================================
;1.在程序段的壳中运行,一路很多类似于"add reg, 4";"xor [reg], key" 的代码,把后面的代码进行解码. 这一段直接F4过去就是了. 
;最后VirtualAlloc申请一段内存,把解码后的壳代码放入. 然后跳到缓冲区执行. 这一步基本上对调试没有任何的阻力.
;============================================
;2.在缓冲区中执行. 一段很长的垃圾seh代码,对解码没有任何实质作用,仅仅是反跟踪. 我们直接找:MOV DWORD PTR FS:[0],ESP"这样的用来设置seh函数的语句,
;一路上F4过去就是.
;============================================
;3.在这个版本的壳中,最巧妙的就是它的4个关键SEH. 接下来我们遇到了第一个.
;这个seh对反跟踪效果非常的好. 它首先利用一个int3中断进入seh, 设置4个单步断点于dr寄存器中. 然后分别在四个单步中断处完成解码的相应操作,
;最后经过一个除0异常进入seh,设置好dr寄存器的值后,拆除seh.
;    我们如果在4个单步断点之间进行软硬件中断调试,是不太可行的. 
;    a.软件: 很多代码没有解密,无法对其进行软件中断
;    b.硬件: dr寄存器被占用,根本无法使用硬件中断
;所以,我们唯一的办法只有在它最后一次进入seh之后的代码上下软件断点"CMP EAX,CD000094". 幸好,这段代码部分没有加密,不然就根本无法跟踪下去了.
;然后,出第一个seh中断. 这个时候,我们必须把dr寄存器中的值记录下来,因为在第二个seh中要用到. 除非,你在第一个和第二个seh之间不进行中断.
;============================================
;4.经过了第一个seh,长征才刚刚开始.接下来我们来到了第二个seh.
;这个seh就是利用上个seh最后的寄存器值,对一段代码进行解码. 在一个循环当中,n次进入这个seh. 没什么太大的难度,头一次进入这个seh时
;恢复好dr寄存器值,然后找到拆除这个seh的代码,软件中断,F9过去就是了.
;============================================
;5.接下来,壳要对原始程序进行解压缩
;    a. 它利用一段20字节的代码对原始程序进行解压缩,而这20字节的内容是加密过的. 所以首先的把这20字节内容给解密了.
;    在这个过程中,它用到了一个全局变量--在全局heap_addr+0c处的一个字节. 它用这个字节来对上面提到的20字节内容进行了解码.
;    b. 然后,对原始程序进行解码.
;    c. 再用那20字节,对解码后的原始程序进行解压缩. 完毕.
;============================================
;6.然后是对iat的处理.
;经过壳的iat处理,形成了下面的一个调用过程.
;
;iat中地址    -->    |Hook_proc:
;Hook_proc        |PUSH DWORD PTR DS:[Hook_proc+1C]
;            |XOR DWORD PTR SS:[ESP],key
;            |ret;                    ->    |Stub_proc:
;            |                        |api_start_code
;            |Hook_proc+1C:                    |...
;            |Stub_proc_xor_key                |api_some_code
;                                    |push api_next_code_addr
;                                    |ret
;经过我们对壳代码的修改,应该使其变成下面的一个形式
;
;iat中地址    -->    |Hook_proc:
;Hook_proc        |PUSH DWORD PTR DS:[Hook_proc+1C]
;            |XOR DWORD PTR SS:[ESP],key
;            |ret;                    ->    |Stub_proc:
;            |                        |push api_start_addr
;            |Hook_proc+1C:                    |ret
;            |Stub_proc                    
;
;那么我们就可以通过自己编写一段代码来遍历iat, 找回每一个api_start_addr
;
;============================================
;7.对程序文件的校验
;这个没什么好说的,两个值改成相等就行
;============================================
;8.对mainform的处理
;壳把mainform的数据移到壳当中去了.包括VMT和Field_Table,Class_Info之类的delphi数据结构. 我们需要把它移回原始程序代码段. 
;详见hexer的脱壳文章.我这里只有过程而没有讲原因.
;============================================
;9.对代码段中部分的 "mov 寄存器, [地址A]"语句的替换.
;我是在所有其他工作都做完后,脱壳发现运行不了,才注意到壳还有这么一手的.
;    它把代码段中部分的 "mov 寄存器, [地址A]"语句给替换成了"call [地址B]", 语句都为6个字节长度
;    地址B处于400000--401000文件头部范围内. 而在 地址B 处是这样的代码 " jmp [地址C]"
;    地址C 处则是原来的"mov 寄存器, [地址A]""ret"
;这个也好办,在oep处,写一段代码,遍历程序代码段,替换回来就行了. 它能弄过去,我们就能弄回来
;============================================
;10.第三个seh
;这个seh没有什么特别的,只是需要把第二个seh最后的dr寄存器值保留下来到这里,不然会出错.
;============================================
;11.第四个seh. 这也是壳中最精彩的一个seh
;没有用到前面的seh留下来的dr寄存器值了.但其中通过修改eip的值,来控制程序的走向--从一个异常走向另一个异常. 一共经过了7个异常(另外一个程序好像是8个),
;才拆掉此seh. 对付此seh的办法是在此seh返回的语句下软件断点,然后每次运行到此处时,查看TIB中的regEIP值,如果seh出去的地方附近有拆除seh的代码,就跟出去,
;如果没有,还是不要浪费时间了.
;============================================
;12.stolen code
;写过delphi程序的人都知道,delphi程序有一个框架. Application.Initialize; Application.CreateForm; Application.run. (好像是这样的,不太记得了)
;hying壳就是把那个框架代码给偷到壳里头来了. 可能是因为这个框架每个delphi程序都类似,所以比较好偷.
;这个其实也很简单,找到壳内相当于框架入口(也就是oep)的代码位置,把它后面的代码等效还原就好了. 然后我们直接跳到框架处,也就是oep处执行.
;
;ok原理就到这里了,下面我们开始脱...

;1.在程序段的壳中运行
007970F4    5D              POP EBP                                  ; main.00797000

007971A7    E8 94010000     CALL main.00797340            ;代码解密函数么?

00797162    FFE2            JMP EDX                ;跳到370000
;2.进入缓冲区执行
00370018    64:FF35 0000000>PUSH DWORD PTR FS:[0]        ;开始一段很长的seh,没有任何实质作用
0037001F    64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00370026    74 03           JE SHORT 0037002B


003709CA    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

0037132F    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

0037191C    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

00372269    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

00372A2E    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

00372B8D        64:8925 0000000>MOV DWORD PTR FS:[0],ESP

00372C8F        E8 03000000     CALL 00372C97

00372CF0    64:8925 0000000>MOV DWORD PTR FS:[0],ESP

00372D55    64:FF35 0000000>PUSH DWORD PTR FS:[0]
;垃圾SEH结束

;这里遇到了一个SEH异常
003744A8    F8              CLC
;堆栈
;0012FF9C  /0012FFE0  Pointer to next SEH record
;0012FFA0  |003733AC  SE handler
;调试寄存器
;DR0 003744A8
;DR1 0037473C
;DR2 003748E5
;DR3 00374A7E
;DR6 FFFF0FF0
;DR7 00000555

;3733AC ★第一个SEH函数================================================

003733F9    3D 03000080     CMP EAX,80000003
003733FE    0F85 A9020000   JNZ 003736AD

003736AD    3D 1D0000C0     CMP EAX,C000001D
003736B2    0F85 8E010000   JNZ 00373846

00373846    3D 04000080     CMP EAX,80000004
0037384B    0F85 B6050000   JNZ 00373E07

00373E07    3D 940000CD     CMP EAX,CD000094                ;这里应该是最后一次进入这个SEH函数,除0错误
00373E0C    23ACAB 121617A9 AND EBP,DWORD PTR DS:[EBX+EBP*4+A9171612>
...
00373F9E    C3              RETN
;结束时,寄存器的值
;FLAG      00010017
;dr0       0FFF0123
;dr1       0FFF4567
;dr2       0FFF89AB
;dr3       0FFFCDEF
;dr6       FFFF0FF0
;dr7       00000555
;EIP    374C25

;第一个SEH函数结束跳到这里
00374C26    64:8F05 0000000>POP DWORD PTR FS:[0]                    
00374C2D    58              POP EAX

00374C4B    33D2            XOR EDX,EDX                            
00374C4D    F7E6            MUL ESI
00374C4F    05 78563412     ADD EAX,12345678
00374C54    83D2 00         ADC EDX,0
00374C57    F7F3            DIV EBX
00374C59    58              POP EAX
00374C5A    32C2            XOR AL,DL
00374C5C    50              PUSH EAX
00374C5D    4C              DEC ESP                    ;<--用ESP当做指针
00374C5E    8BC2            MOV EAX,EDX
00374C60  ^ E2 E9           LOOPD SHORT 00374C4B            ;对后面一段代码解码374C62--...
00374C62    8BE7            MOV ESP,EDI                    ;恢复ESP
;========================================================
00374C64    E8 5B030000     CALL 00374FC4                ;准备安装SEH函数(★第二个SEH函数)
;★第二个SEH函数
00374C69    8B4C24 0C       MOV ECX,DWORD PTR SS:[ESP+C]        ;其中要对dr寄存器进行操作,所以之前要恢复到第一个SEH函数最后的dr寄存器值
00374C6D    9C              PUSHFD
00374C6E    6A 03           PUSH 3
...
00374CC7    8B81 B0000000   MOV EAX,DWORD PTR DS:[ECX+B0]        ;regEAX
00374CCD    8B51 04         MOV EDX,DWORD PTR DS:[ECX+4]        ;dr0

00374CFD    F6D0            NOT AL
00374D16    32C2            XOR AL,DL
00374D1F    66:25 FF00      AND AX,0FF
00374D4C    66:03D0         ADD DX,AX
00374D7A    66:C1CA 03      ROR DX,3
00374DA8    66:8951 04      MOV WORD PTR DS:[ECX+4],DX            ;设置dr0

00374DD6    66:3151 08      XOR WORD PTR DS:[ECX+8],DX            ;dr1
;出第二个SEH函数


00374FC4    64:FF35 0000000>PUSH DWORD PTR FS:[0]
00374FCB    64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00374FD2    8DB5 C5414000   LEA ESI,DWORD PTR SS:[EBP+4041C5]
00374FD8    B9 1F050000     MOV ECX,51F
00374FDD    8A0431          MOV AL,BYTE PTR DS:[ECX+ESI]
00374FE0    CC              INT3
00374FE1    90              NOP
00374FE2    880431          MOV BYTE PTR DS:[ECX+ESI],AL
00374FE5  ^ E2 F6           LOOPD SHORT 00374FDD            ;循环. 实际上是利用第二个SEH函数对一段代码解码
00374FE7    64:8F05 0000000>POP DWORD PTR FS:[0]            ;37550D--375A2C
00374FEE    58              POP EAX
;最后一次出第二个SEH函数,调试寄存器的值为
;DR0 0FFF0195
;DR1 0FFF35B6
;DR2 0FFF8C3D
;DR3 0FFFCDEF
;DR6 FFFF0FF0
;DR7 00000555

...
;接下来开始出现代码入栈执行
...
;下面要取得一些函数的地址,看来是壳要用到=============================
0037514C    8DB5 94184100   LEA ESI,DWORD PTR SS:[EBP+411894]
00375152    56              PUSH ESI                    ;ESI 382BDC ASCII "KERNEL32.dll"

00375173    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA

0037517F   /E9 3AD00000     JMP 003821BE                ;看来这里就是'调用jmp'了


00375331   /E9 88CE0000     JMP 003821BE                ;调用38290F,类似于GetProcAddress
;堆栈
;0012FF94   00375337
;0012FF98   7C800000  kernel32.7C800000
;0012FF9C   003830E4  ASCII "CloseHandle"
;0012FFA0   00000022

0037533B    8903            MOV DWORD PTR DS:[EBX],EAX
0037533D    03D9            ADD EBX,ECX
0037533F    43              INC EBX
00375340    59              POP ECX
00375341  ^\E2 A2           LOOPD SHORT 003752E5            ;下一个函数
;这里的函数列表: CloseHandle, CreateFileA, CreateFileMappingA, CreateThread, DeleteFileA, ExitProcess, FindResourceA...

00375343    8DB5 E4174100   LEA ESI,DWORD PTR SS:[EBP+4117E4]
;Address=00382B2C, (ASCII "USER32.dll")
003754B9    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA
003754C5   /E9 F4CC0000     JMP 003821BE                ;这里没有Get到...

003754F0    8B85 44174100   MOV EAX,DWORD PTR SS:[EBP+411744]        ; kernel32.LoadLibraryA
003754FC   /E9 BDCC0000     JMP 003821BE
;下面又是和上面的kernel32相同,从中取得一些api的地址
...
00375598    49              DEC ECX
00375599  ^ 0F85 6FFFFFFF   JNZ 0037550E                ;下一个函数        

0037559F    8DB5 BA1A4100   LEA ESI,DWORD PTR SS:[EBP+411ABA]

...
00375599  ^\0F85 6FFFFFFF   JNZ 0037550E                ;还单独取得了wsprintfA的地址,为什么?

0037559F    8DB5 BA1A4100   LEA ESI,DWORD PTR SS:[EBP+411ABA]
;Address=00382E02, (ASCII "WS2_32.DLL")
...
003757C9  ^\E2 A1           LOOPD SHORT 0037576C
003757CB    8DB5 E31A4100   LEA ESI,DWORD PTR SS:[EBP+411AE3]
;Address=00382E2B, (ASCII "advapi32.dll")
...
003759F2    59              POP ECX
003759F3  ^ E2 A1           LOOPD SHORT 00375996

;======================================================
00375A15    8B85 5E194100   MOV EAX,DWORD PTR SS:[EBP+41195E]        ; kernel32.GetCurrentThread

00375A4B    8B85 321A4100   MOV EAX,DWORD PTR SS:[EBP+411A32]        ; kernel32.SetThreadPriority

00375AE0    8B85 5C174100   MOV EAX,DWORD PTR SS:[EBP+41175C]        ;400000
00375AE6    0340 3C         ADD EAX,DWORD PTR DS:[EAX+3C]        ;pe头

00375DC0    8B85 96194100   MOV EAX,DWORD PTR SS:[EBP+411996]        ; kernel32.GetProcessHeap    噢,看来要开始对原程序解码了
;返回值00140000
00375DFD    8A40 0C         MOV AL,BYTE PTR DS:[EAX+C]            ;
;DS:[0014000C]=62 ('b')        又到了这个解码的关键地方了,难道还要把14000C改为02么?
00375E2A    24 40           AND AL,40
00375E56    F6D0            NOT AL
00375E82    8DB5 591D4100   LEA ESI,DWORD PTR SS:[EBP+411D59]
00375EB2    B9 20000000     MOV ECX,20
00375F0A    3006            XOR BYTE PTR DS:[ESI],AL
00375F35    46              INC ESI
00375F60  ^\E2 80           LOOPD SHORT 00375EE2            ;对这一段20byte的数据解码,然后用这一段数据作为原程序代码解码的key

00375F86    8DB5 9A1C4100   LEA ESI,DWORD PTR SS:[EBP+411C9A]
00375F8C    46              INC ESI

;开始检测debugger=============================================
003760E4    51              PUSH ECX                    ;9
003760E5    56              PUSH ESI                    ;00382FE3
003760E6    AC              LODS BYTE PTR DS:[ESI]

003760E9    F6D0            NOT AL                    ;噢~ \\.\NTICE
003760EB    8846 FF         MOV BYTE PTR DS:[ESI-1],AL
003760EE    AC              LODS BYTE PTR DS:[ESI]
003760EF    0AC0            OR AL,AL
003760F1  ^ 75 F6           JNZ SHORT 003760E9

00376154    8B85 AF184100   MOV EAX,DWORD PTR SS:[EBP+4118AF]        ; kernel32.CreateFileA

003761F6    F6D0            NOT AL
003761F8    8846 FF         MOV BYTE PTR DS:[ESI-1],AL
003761FB    AC              LODS BYTE PTR DS:[ESI]
003761FC    0AC0            OR AL,AL
003761FE  ^ 75 F6           JNZ SHORT 003761F6                ;又把\\.\NTICE加密了

                push 9
                pop ecx
0037628C    0BC9            OR ECX,ECX
0037628E  ^ 0F85 50FEFFFF   JNZ 003760E4

;准备调用ZwSetInformationThread==============================
00376B52    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA
;堆栈
;0012FF9C   00376B64    'ntdll.dll'
;0012FFA0   00376B28  RETURN to 00376B28 from 00376B32

00376CFC   /E9 BDB40000     JMP 003821BE                ;调用38290F
;堆栈
;0012FF98   00376D02  'ZwSetInformationThread'
;0012FF9C   7C920000  ntdll.7C920000
;0012FFA0   00376CB8  RETURN to 00376CB8 from 00376CCF    

00376EF5    8B85 5E194100   MOV EAX,DWORD PTR SS:[EBP+41195E]        ; kernel32.GetCurrentThread

00376F17   /E9 13B80000     JMP 0038272F                ;调用ZwSetInformationThread?
;堆栈
;0012FF90   00376F1D
;0012FF94   FFFFFFFE
;0012FF98   00000011
;0012FF9C   00000000
;0012FFA0   00000000

;准备开始对程序代码解码====================================
00376F1D    8D1D 3F204100   LEA EBX,DWORD PTR DS:[41203F]
00376F23    833C2B 00       CMP DWORD PTR DS:[EBX+EBP],0
00376F3E  ^\73 EF           JNB SHORT 00376F2F
00376F2F   /0F84 4F0C0000   JE 00377B84                    ;解码完毕,从这里跳走

00376FE8    03B5 5C174100   ADD ESI,DWORD PTR SS:[EBP+41175C]        ; main.00400000
0037701B    8BFE            MOV EDI,ESI                              ; main.00401000

003770F9    E8 0AA60000     CALL 00381708                ;调用原程序代码解码函数

00377306    8B85 54174100   MOV EAX,DWORD PTR SS:[EBP+411754]        ; kernel32.VirtualAlloc
;返回值C90000

0037792E   /E9 8BA80000     JMP 003821BE                ;调用00797165, 解压缩函数
;堆栈
;0012FF98   00377934
;0012FF9C   00382A98
;0012FFA0   00C90000    解压到C90000

00377934   /EB 49           JMP SHORT 0037797F                ;返回到这里

003779B5    51              PUSH ECX
003779B6    C1E9 02         SHR ECX,2
003779B9    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
;ECX=000C5C00 (decimal 809984.)
;DS:[ESI]=[00C90000]=00000000
;ES:[EDI]=[00401000]=0000DCD8
003779BB    59              POP ECX
003779BC    83E1 03         AND ECX,3
003779BF    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI];把解压缩后的数据移回代码段

00377AEB    8B85 58174100   MOV EAX,DWORD PTR SS:[EBP+411758]                 ; kernel32.VirtualFree

00377B58    83C3 0C         ADD EBX,0C
;EBX=0041203F (main.0041203F)
;=============================================================
;程序原代码解压缩完毕,跳到这里
00377B84    8DB5 0B6A4000   LEA ESI,DWORD PTR SS:[EBP+406A0B]

00377CD9    87E6            XCHG ESI,ESP            ;又准备用ESP进行解码了, 377D54--3800B7
00377CDB    B9 64830000     MOV ECX,8364
                pop eax
00377CE7    F6D0            NOT AL
00377CF1    83C4 04         ADD ESP,4
00377CF4    50              PUSH EAX
00377CFB    44              INC ESP
00377D01  ^\E2 DD           LOOPD SHORT 00377CE0
00377D03    87E6            XCHG ESI,ESP            ;解码完毕到这里

;下面开始处理iat=======================================
00377D33    8B85 54174100   MOV EAX,DWORD PTR SS:[EBP+411754]        ; kernel32.VirtualAlloc
;返回值EAX=C90000

003788C7    0BFF            OR EDI,EDI                    ;6
003788C9    75 05           JNZ SHORT 003788D0                
003788CB    E9 8F370000     JMP 0037C05F                ;iat处理完毕后这里跳出去

00378A45    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA
;堆栈
;0012FF9C   00378A58
;0012FFA0   003837A4  ASCII "advapi32.dll"

00379194    33C0            XOR EAX,EAX
00379196    AC              LODS BYTE PTR DS:[ESI]
00379197    EB 07           JMP SHORT 003791A0
00379199    C0C0 03         ROL AL,3
0037919C    F6D0            NOT AL
0037919E    AA              STOS BYTE PTR ES:[EDI]
0037919F    AC              LODS BYTE PTR DS:[ESI]
003791A0    0BC0            OR EAX,EAX
003791A2  ^ 75 F5           JNZ SHORT 00379199
003791A4    AA              STOS BYTE PTR ES:[EDI]            ;把api的名字解码到3830E4
003791A5    9C              PUSHFD

00379340   /E9 798E0000     JMP 003821BE                ;调用38290F, GetProcAddress
;0012FF90   00379347
;0012FF94   77DA0000  ADVAPI32.77DA0000
;0012FF98   003830E4  ASCII "RegQueryValueExA"
;0012FF9C   003837B6
;0012FFA0   00000003

00379347    E8 F0960000     CALL 00382A3C                ;检查是否函数头是否为CC

0037949B    8907            MOV DWORD PTR DS:[EDI],EAX               ; ADVAPI32.RegQueryValueExA
0037949D    5A              POP EDX
0037949E    0FB642 FF       MOVZX EAX,BYTE PTR DS:[EDX-1]
003794A2    03D0            ADD EDX,EAX
003794A4    42              INC EDX                    ;到下一个函数
003794A5    59              POP ECX
003794A6    49              DEC ECX                    ;ECX=3
003794A7  ^ 0F85 B1F9FFFF   JNZ 00378E5E                ;这里的3个函数都是注册表相关函数..
003794AD    E9 A82B0000     JMP 0037C05A

00378A45    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA
;0012FF9C   00378A58
;0012FFA0   003837F0  ASCII "oleaut32.dll"

0037949B    8907            MOV DWORD PTR DS:[EDI],EAX               ; oleaut32.SysFreeString -> 6F726C
0037949D    5A              POP EDX
0037949E    0FB642 FF       MOVZX EAX,BYTE PTR DS:[EDX-1]
003794A2    03D0            ADD EDX,EAX
003794A4    42              INC EDX
003794A5    59              POP ECX
003794A6    49              DEC ECX
003794A7  ^ 0F85 B1F9FFFF   JNZ 00378E5E
003794AD    E9 A82B0000     JMP 0037C05A

;上面是不要加密的api,下面是需要加密的api
003797A6    8B3A            MOV EDI,DWORD PTR DS:[EDX]
003797A8    03BD 5C174100   ADD EDI,DWORD PTR SS:[EBP+41175C]
003797AE    891F            MOV DWORD PTR DS:[EDI],EBX
003797B0    83C3 20         ADD EBX,20
003797B3    0FB642 04       MOVZX EAX,BYTE PTR DS:[EDX+4]
003797B7    0AC0            OR AL,AL
003797B9    75 02           JNZ SHORT 003797BD

003797BD    03D0            ADD EDX,EAX
003797BF    83C2 06         ADD EDX,6
003797C2    49              DEC ECX
003797C3    0BC9            OR ECX,ECX
003797C5  ^ 75 DF           JNZ SHORT 003797A6            ;这一段,在iat中写入hook函数的地址

;开始构造hook函数
0037982E    66:C707 FF35    MOV WORD PTR DS:[EDI],35FF        ;PUSH DWORD PTR DS:[0]
00379982    C747 06 8134240>MOV DWORD PTR DS:[EDI+6],243481    ;XOR DWORD PTR SS:[ESP],0
00379AD8    8947 02         MOV DWORD PTR DS:[EDI+2],EAX    ;hook_proc+1C
00379B08    C647 0D C3      MOV BYTE PTR DS:[EDI+D],0C3        ;ret
00379B0D    0F31            RDTSC                ;取时间戳作为加密stub_proc地址的key

00379C81    8947 09         MOV DWORD PTR DS:[EDI+9],EAX    ;把key作为xor的一个操作数

00379C85    83C7 20         ADD EDI,20
00379C88    49              DEC ECX
00379C89    0BC9            OR ECX,ECX
00379C8B  ^ 0F85 6DFBFFFF   JNZ 003797FE            ;构造下一个hook函数

;===============计算stub_proc的地址
00379C93    83C2 04         ADD EDX,4
00379C96    51              PUSH ECX
00379C97    0FB602          MOVZX EAX,BYTE PTR DS:[EDX]
00379C9A    0BC0            OR EAX,EAX
00379C9C    0F85 EF090000   JNZ 0037A691

0037A955    8D95 9C1D4100   LEA EDX,DWORD PTR SS:[EBP+411D9C]        ;得到了当前要的到地址的api名
;Address=003830E4, (ASCII "WSAStartup")
0037A95B    52              PUSH EDX                    ;从这里跳到★★,不作字符串比较,不从壳内取api地址
;...
0037AC22    8B85 C0194100   MOV EAX,DWORD PTR SS:[EBP+4119C0]        ; kernel32.lstrcmpA  做字符串比较,如果相同,就从壳内取api地址

0037AC35    85C0            TEST EAX,EAX                 ;.. n次比较
0037AC37    75 0B           JNZ SHORT 0037AC44

0037AF0B    8B85 C0194100   MOV EAX,DWORD PTR SS:[EBP+4119C0]        ; kernel32.lstrcmpA

;...
0037B905    5A              POP EDX                    ;最后一次strcmp出来到这里
0037B906    85C0            TEST EAX,EAX
0037B908    75 0B           JNZ SHORT 0037B915

;★★:
0037B915    52              PUSH EDX                    ;EDX=3830E4
0037B916    56              PUSH ESI

;调用一个函数,取得api的地址
0037B943   /E9 76680000     JMP 003821BE                ;调用0038290F
;0012FF90   0037B949
;0012FF94   71A40000    module handle
;0012FF98   003830E4    ASCII "WSACleanup"
;0012FF9C   0038449A
;0012FFA0   00000019
;返回值EAX=71A24428  WS2_32.WSACleanup
;返回到这里
0037B949    8B9D C7204100   MOV EBX,DWORD PTR SS:[EBP+4120C7]

0037B95A    E8 C5690000     CALL 00382324                ;建立stub_proc
;0012FF8C   00C90000  |Arg1 = 00C90000                    ;返回值EAX=stub_proc+1
;0012FF90   71A24428  |Arg2 = 71A24428
;0012FF94   00000000  \Arg3 = 00000000
;===========
;进入这个函数
    00382324    60              PUSHAD
    00382325    8B7C24 24       MOV EDI,DWORD PTR SS:[ESP+24]
    00382329    8B7424 28       MOV ESI,DWORD PTR SS:[ESP+28]
    0038232D    66:8B06         MOV AX,WORD PTR DS:[ESI]            ;从这里跳到▲

;构造stub_proc的时候,最后到这里
;▲
    003826DD    C607 68         MOV BYTE PTR DS:[EDI],68            ;push xx
    003826E0    8977 01         MOV DWORD PTR DS:[EDI+1],ESI        ;push WS2_32.71A24437
    003826E3    C647 05 C3      MOV BYTE PTR DS:[EDI+5],0C3            ;ret
    003826E7    83C7 06         ADD EDI,6
    003826EA    897C24 FC       MOV DWORD PTR SS:[ESP-4],EDI
    003826EE    837C24 2C 00    CMP DWORD PTR SS:[ESP+2C],0
;===========

0037B95F    2B85 C7204100   SUB EAX,DWORD PTR SS:[EBP+4120C7]
0037B965    8985 CB204100   MOV DWORD PTR SS:[EBP+4120CB],EAX
0037B96B    60              PUSHAD
0037B96C    3D C01F0000     CMP EAX,1FC0                ;看是不是buffer不够
0037B971    0F86 8A010000   JBE 0037BB01                ;够就跳走

0037BC52    8BC3            MOV EAX,EBX                    ;EBX为 stub_proc的地址
0037BC54    3347 09         XOR EAX,DWORD PTR DS:[EDI+9]        
0037BDA6    8947 1C         MOV DWORD PTR DS:[EDI+1C],EAX        ;加密后写入hook_proc

0037BEF9    0FB642 FF       MOVZX EAX,BYTE PTR DS:[EDX-1]
0037BEFD    03D0            ADD EDX,EAX
0037BEFF    42              INC EDX
0037BF00    83C7 20         ADD EDI,20

0037C052    59              POP ECX
0037C053    49              DEC ECX
0037C054  ^ 0F85 39DCFFFF   JNZ 00379C93                ;下一个
0037C05A  ^ E9 17C7FFFF     JMP 00378776

;==========================================================
;iat处理完毕
;上面的iat处理,实际上是形成了这样的一个调用过程
;
;iat中地址    -->    |Hook_proc:
;            |PUSH DWORD PTR DS:[Hook_proc+1C]
;            |XOR DWORD PTR SS:[ESP],key
;            |ret;                    ->    |Stub_proc:
;            |                        |api_start_code
;            |Hook_proc+1C:                    |...
;            |Stub_proc_xor_key                |api_some_code
;                                    |push api_next_code_addr
;                                    |ret
;
;
;
;
;调用ZwQueryInformationProcess=============================
0037C05F    E8 0A000000     CALL 0037C06E

0037C08E    8B85 48174100   MOV EAX,DWORD PTR SS:[EBP+411748]        ; kernel32.GetModuleHandleA
;0012FF9C   0037C0A0
;0012FFA0   0037C064  ASCII "ntdll.dll"


0037C243   /E9 765F0000     JMP 003821BE
;0012FF98   0037C249
;0012FF9C   7C920000  ntdll.7C920000
;0012FFA0   0037C1FC  ASCII "ZwQueryInformationProcess"

0037C398    0BC0            OR EAX,EAX                               ; ntdll.ZwQueryInformationProcess
0037C39A    0F84 45080000   JE 0037CBE5                    ;在这里干掉它, 我们把 EAX置0

;开始进行校验和验证============================================
0037D2AE    8B85 82194100   MOV EAX,DWORD PTR SS:[EBP+411982]        ; kernel32.GetModuleFileNameA
;0012FE94   0037D2C0
;0012FE98   00400000  ASCII "MZP"
;0012FE9C   0012FEA4   

0037D429    8B85 AF184100   MOV EAX,DWORD PTR SS:[EBP+4118AF]        ; kernel32.CreateFileA

0037D468    8B85 29194100   MOV EAX,DWORD PTR SS:[EBP+411929]        ; kernel32.GetFileSize

0037D4AF    8B85 BC184100   MOV EAX,DWORD PTR SS:[EBP+4118BC]        ; kernel32.CreateFileMappingA

0037D4DC    8B85 D8194100   MOV EAX,DWORD PTR SS:[EBP+4119D8]        ; kernel32.MapViewOfFile

0037D509    E8 983C0000     CALL 003811A6                ;计算校验和
;返回值EAX=F219B48A
0037D50F    3385 70174100   XOR EAX,DWORD PTR SS:[EBP+411770]
0037D515    C1C8 03         ROR EAX,3
0037D518    8BF0            MOV ESI,EAX                    ;最后的结果DE5AB7CE
0037D51A    8B85 68174100   MOV EAX,DWORD PTR SS:[EBP+411768]

0037D66F    0340 3C         ADD EAX,DWORD PTR DS:[EAX+3C]        ;EAX指向pe头
0037D672    8B78 FC         MOV EDI,DWORD PTR DS:[EAX-4]        ;pe头-4,原校验和 DE5AB7CE

0037D69B    8B85 561A4100   MOV EAX,DWORD PTR SS:[EBP+411A56]        ; kernel32.UnmapViewOfFile

0037D6D3    8B85 A2184100   MOV EAX,DWORD PTR SS:[EBP+4118A2]        ; kernel32.CloseHandle

0037D706    8B85 A2184100   MOV EAX,DWORD PTR SS:[EBP+4118A2]        ; kernel32.CloseHandle

0037D872    3BF7            CMP ESI,EDI                    ;在这里比较校验结果
0037D874    0F85 F65E0000   JNZ 00383770

;这一段好像对代码段进行了处理,什么意思呢=========================================
0037DB40    66:8B06         MOV AX,WORD PTR DS:[ESI]            ;ESI=401000
0037DB43    3C E8           CMP AL,0E8
0037DB45    0F85 C0010000   JNZ 0037DD0B

0037DD0B    3C E9           CMP AL,0E9
0037DD0D    0F85 C0010000   JNZ 0037DED3

0037DED3    3C 0F           CMP AL,0F
0037DED5    0F85 D0010000   JNZ 0037E0AB




0037E0AB    46              INC ESI
0037E0AC    49              DEC ECX
0037E0AD    81F9 00000080   CMP ECX,80000000
0037E0B3  ^ 0F82 87FAFFFF   JB 0037DB40
;========================================

0037E0B9    8D85 DCCE4000   LEA EAX,DWORD PTR SS:[EBP+40CEDC]

0037E20F    8B85 B4194100   MOV EAX,DWORD PTR SS:[EBP+4119B4]        ; kernel32.GetVersion

0037E24A    8B85 36194100   MOV EAX,DWORD PTR SS:[EBP+411936]        ; kernel32.GetCurrentProcess

0037E3D1    8B85 49194100   MOV EAX,DWORD PTR SS:[EBP+411949]        ; kernel32.GetCurrentProcessId

0037E53F    8B85 18194100   MOV EAX,DWORD PTR SS:[EBP+411918]        ; kernel32.GetCommandLineA

0037E57E    8B85 70194100   MOV EAX,DWORD PTR SS:[EBP+411970]        ; kernel32.GetModuleHandleA
;0012FF9C   0037E590
;0012FFA0   00000000

0037E843    E8 DC3A0000     CALL 00382324                ;干吗的? 先放着
;0012FF98   00383307  |Arg1 = 00383307
;0012FF9C   71A26233  |Arg2 = 71A26233        WS2_32.WSASend
;0012FFA0   00000000  \Arg3 = 00000000

0037E84A    FFB5 CF1A4100   PUSH DWORD PTR SS:[EBP+411ACF]           ; WS2_32.WSARecv

0037E857    E8 C83A0000     CALL 00382324
;0012FF98   00383307  |Arg1 = 00383347
;0012FF9C   71A26233  |Arg2 =            WS2_32.WSARecv
;0012FFA0   00000000  \Arg3 = 00000000

0037E890    8B85 BC184100   MOV EAX,DWORD PTR SS:[EBP+4118BC]        ; kernel32.CreateFileMappingA
;0012FF88   0037E8A2
;0012FF8C   FFFFFFFF
;0012FF90   00000000
;0012FF94   00000004
;0012FF98   00000000
;0012FF9C   00000100
;0012FFA0   0038311C  ASCII "ShellTmpMap"

0037E8DD    8B85 D8194100   MOV EAX,DWORD PTR SS:[EBP+4119D8]        ; kernel32.MapViewOfFile
;返回值EAX=F70000    去看看,是空的?

0037E911    64:FF35 3000000>PUSH DWORD PTR FS:[30]            ;检测应用程序级debugger
0037E918    58              POP EAX
0037E919    0FB658 02       MOVZX EBX,BYTE PTR DS:[EAX+2]
0037E91D    0ADB            OR BL,BL
0037E91F    0F85 4B4E0000   JNZ 00383770
0037E925    E9 77010000     JMP 0037EAA1

;SEH又来了===============================================
0037EF24    E8 0E000000     CALL 0037EF37
0037EF29    8B4C24 0C       MOV ECX,DWORD PTR SS:[ESP+C]
0037EF2D    8381 B8000000 0>ADD DWORD PTR DS:[ECX+B8],2            ;仅仅是改变eip
0037EF34    33C0            XOR EAX,EAX
0037EF36    C3              RETN

0037EF37    64:FF35 0000000>PUSH DWORD PTR FS:[0]
0037EF3E    64:8925 0000000>MOV DWORD PTR FS:[0],ESP
0037EF45    33C0            XOR EAX,EAX
0037EF47    CD 01           INT 1
0037EF49    40              INC EAX
0037EF4A    40              INC EAX
0037EF4B    0BC0            OR EAX,EAX
0037EF4D    64:8F05 0000000>POP DWORD PTR FS:[0]
0037EF54    58              POP EAX

;对mainform的处理=================================
0037F253    8B1E            MOV EBX,DWORD PTR DS:[ESI]            ;
0037F25A    039D 5C174100   ADD EBX,DWORD PTR SS:[EBP+41175C]        ;EBX=00537B00

0012FF94    31C9            XOR ECX,ECX
0012FF96    890E            MOV DWORD PTR DS:[ESI],ECX
0012FF98    83C6 04         ADD ESI,4
0012FF9B    8933            MOV DWORD PTR DS:[EBX],ESI            ;我们要做的是吧3891F3--38A7DE,复制到53904D--53A638,长度为15EB,  再把ESI这个指针给替换掉
;ESI=003891F3
;DS:[00537B00]=00000000
0012FF9D    0FB70E          MOVZX ECX,WORD PTR DS:[ESI]
0012FFA0    46              INC ESI
0012FFA1    46              INC ESI
0012FFA2    C3              RETN
;
;为mainform中的数据做重定位处理?
0037F504    8B95 80174100   MOV EDX,DWORD PTR SS:[EBP+411780]
0037F50A   /EB 0C           JMP SHORT 0037F518

0037F50C    2956 02         SUB DWORD PTR DS:[ESI+2],EDX                    ; main.00400000    ESI=3891F3
0037F50F    015E 02         ADD DWORD PTR DS:[ESI+2],EBX                    ; main.00400000
0037F512    0FB706          MOVZX EAX,WORD PTR DS:[ESI]
0037F515    03F0            ADD ESI,EAX
0037F517    49              DEC ECX
0037F518    0BC9            OR ECX,ECX
0037F51A  ^ 75 F0           JNZ SHORT 0037F50C
;mainform处理结束======================================

0037F54A    8B85 54174100   MOV EAX,DWORD PTR SS:[EBP+411754]               ; kernel32.VirtualAlloc
;返回值F80000

0037F56C    64:FF35 3000000>PUSH DWORD PTR FS:[30]
0037F573    58              POP EAX

0037F6C7    8B40 0C         MOV EAX,DWORD PTR DS:[EAX+C]
0037F6CA    8B40 0C         MOV EAX,DWORD PTR DS:[EAX+C]
0037F6CD    C740 20 0010000>MOV DWORD PTR DS:[EAX+20],1000            ;anti dump


0037F8B9    8B85 771A4100   MOV EAX,DWORD PTR SS:[EBP+411A77]               ; kernel32.VirtualProtect


;==================================
0037FBA0    0FB706          MOVZX EAX,WORD PTR DS:[ESI]

0037FBCB    03C3            ADD EAX,EBX                    ;EBX=385EE3 表基址?
0037FBF8    0110            ADD DWORD PTR DS:[EAX],EDX            ;EDX=386EA3 表中每个被索引到的元素都要加上一个值

0037FC22    83C1 02         ADD ECX,2
0037FC50    83C6 02         ADD ESI,2                    ;word数组, 数组元素为表的索引

0037FC77    3B8D C4174100   CMP ECX,DWORD PTR SS:[EBP+4117C4]        ;数组的size
0037FC7D  ^ 0F82 15FFFFFF   JB 0037FB98


0037FC9F    66:813E FF35    CMP WORD PTR DS:[ESI],35FF
0037FCA4    75 0B           JNZ SHORT 0037FCB1
0037FCA6    0146 02         ADD DWORD PTR DS:[ESI+2],EAX
0037FCA9    0146 07         ADD DWORD PTR DS:[ESI+7],EAX
0037FCAC    83C6 0C         ADD ESI,0C
0037FCAF    EB 06           JMP SHORT 0037FCB7
0037FCB1    0146 02         ADD DWORD PTR DS:[ESI+2],EAX                    ; main.00400000
0037FCB4    83C6 07         ADD ESI,7
0037FCB7    49              DEC ECX
0037FCB8    0BC9            OR ECX,ECX
0037FCBA  ^ 75 E3           JNZ SHORT 0037FC9F
;上面一个循环之后,形成了这样的一段代码=========================================
;00386EAA    8B1D E4855700   MOV EBX,DWORD PTR DS:[5785E4]
;00386EB0    C3              RETN
;00386EB1    8B35 E4855700   MOV ESI,DWORD PTR DS:[5785E4]
;00386EB7    C3              RETN
;00386EB8    8B15 1C865700   MOV EDX,DWORD PTR DS:[57861C]
;00386EBE    C3              RETN
;00386EBF    8B1D 1C865700   MOV EBX,DWORD PTR DS:[57861C]
;...
;=========================================

0037FD1B    8B85 54174100   MOV EAX,DWORD PTR SS:[EBP+411754]               ; kernel32.VirtualAlloc
;返回值00F90000

0037FD58    8BF8            MOV EDI,EAX

0037FD84    8BB5 5C174100   MOV ESI,DWORD PTR SS:[EBP+41175C]               ; main.00400000

0037FDB4    2B85 5C174100   SUB EAX,DWORD PTR SS:[EBP+41175C]               ; main.00400000

0037FDE5    8746 3C         XCHG DWORD PTR DS:[ESI+3C],EAX            ;恩?这是干吗,把pe头指针给改了?改到缓冲区去了
;EAX=00B90000        
;DS:[0040003C]=00000100
0037FE3D    B9 00010000     MOV ECX,100
0037FE6D    C1E9 02         SHR ECX,2
0037FE70    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
;ECX=00000040 (decimal 64.)
;DS:[ESI]=[00400100]=00004550
;ES:[EDI]=[00F90000]=00000000
0037FE72    59              POP ECX
0037FE73    83E1 03         AND ECX,3
0037FE76    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
0037FE78    EB 4E           JMP SHORT 0037FEC8

0037FF92    51              PUSH ECX
0037FF93    C1E9 02         SHR ECX,2
0037FF96    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]        ;把文件头给改了?
;ECX=000003F0 (decimal 1008.)
;DS:[ESI]=[00385EE3]=00386EA3
;ES:[EDI]=[00400040]=0E0010BA
0037FF98    59              POP ECX
0037FF99    83E1 03         AND ECX,3
0037FF9C    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
0037FF9E    EB 22           JMP SHORT 0037FFC2
;=============================
;上面这段代码37FBA0--37FF9E, 把代码段中部分的 "mov 寄存器, [地址A]"语句给替换成了"call [地址B]", 语句都为6个字节长度
;地址B处于400000--401000文件头部范围内. 而在 地址B 处是这样的代码 " jmp [地址C]"
;地址C 处则是原来的"mov 寄存器, [地址A]""ret"
;处理方法是在oep处写一段代码,搜索整个代码段,把被替换掉的代码给找回来就行了.
;=============================

0037FFEC    8B85 E7194100   MOV EAX,DWORD PTR SS:[EBP+4119E7]               ; kernel32.OutputDebugStringA
;0012FF9C   0037FFFF
;0012FFA0   0037FFC7  RETURN to 0037FFC7 from 0037FFCC
0037FFF8   /E9 C1210000            JMP 003821BE



0038000E    AC              LODS BYTE PTR DS:[ESI]
0038000F    2C 80           SUB AL,80
00380011    AA              STOS BYTE PTR ES:[EDI]
00380012    49              DEC ECX
00380013    0BC9            OR ECX,ECX
00380015  ^ 75 F7           JNZ SHORT 0038000E                ;开始解出i am....了
00380017    8DB5 051D4100   LEA ESI,DWORD PTR SS:[EBP+411D05]            

003800AF    010C38          ADD DWORD PTR DS:[EAX+EDI],ECX        ;ECX=0 ?
003800B2    AD              LODS DWORD PTR DS:[ESI]
003800B3    0BC0            OR EAX,EAX
003800B5  ^ 75 F8           JNZ SHORT 003800AF
003800B7    8B85 CC174100   MOV EAX,DWORD PTR SS:[EBP+4117CC]



0038042D    B9 0FFD0000     MOV ECX,0FD0F
0038045F    C1E9 02         SHR ECX,2
00380464    AD              LODS DWORD PTR DS:[ESI]            ;00372D79
00380465    3185 A0174100   XOR DWORD PTR SS:[EBP+4117A0],EAX        ;SS:[382AE8]
0038046B    49              DEC ECX
0038046C    0BC9            OR ECX,ECX
0038046E  ^ 75 F4           JNZ SHORT 00380464
;最后出循环时
;00382AE8  61 60 B8 09              a`?.

0038049A    8948 02         MOV DWORD PTR DS:[EAX+2],ECX
;ECX=003816A6
;DS:[004C356B]=00909313

003804A3    E8 48000000     CALL 003804F0
;★第三个SEH函数=========================
;其中用到了dr寄存器,要把上次SEH末尾时的dr寄存器值设置好
003804A8    8B4C24 0C       MOV ECX,DWORD PTR SS:[ESP+C]
003804AC    FF81 B8000000   INC DWORD PTR DS:[ECX+B8]

;...
;第三个SEH函数出去之后,没有改变dr寄存器内的值,与出第二个SEH函数时相同
;=========================
003804F2    64:FF31         PUSH DWORD PTR FS:[ECX]
003804F5    64:8921         MOV DWORD PTR FS:[ECX],ESP            ;安装第三个SEH函数
003804F8    CC              INT3
003804F9    90              NOP
003804FA    64:8F01         POP DWORD PTR FS:[ECX]            ;从第三个SEH函数出来到这里
003804FD    83C4 04         ADD ESP,4


003807C6    83F9 01                CMP ECX,1
003807C9    0F85 EB020000          JNZ 00380ABA


00380C30    8BB5 B71F4100          MOV ESI,DWORD PTR SS:[EBP+411FB7]
00380C36    03B5 5C174100          ADD ESI,DWORD PTR SS:[EBP+41175C]    ;401000
00380C3C    8B8D BB1F4100          MOV ECX,DWORD PTR SS:[EBP+411FBB]    ;171000
00380C42    E8 5F050000            CALL 3811A6                ;计算校验和


00380C47    8985 74174100          MOV DWORD PTR SS:[EBP+411774],EAX
;返回值7EA93C42


;第四个SEH出现... =====================================
0038354B    8BD4                   MOV EDX,ESP
0038354D    60                     PUSHAD
0038354E    8B7A 0C                MOV EDI,DWORD PTR DS:[EDX+C]
00383551    8BAF B4000000          MOV EBP,DWORD PTR DS:[EDI+B4]

00383561    3B03                   CMP EAX,DWORD PTR DS:[EBX]        ;这个地方一定要相等,如果不相等就是出错了
00383563    0F85 70010000          JNZ 003836D9
;Stack DS:[0012FCB4]=C0000005
;EAX=C0000005

003836DD    C3                     RETN
;第一次C0000005返回时 dr0=380DF9 eip=380DF8
;第二次80000004返回时 dr全为0 eip=380DF9
;第三次80000003返回时 dr0=37E54C eip=37E54B
;第四次80000004返回时 dr全为0 eip=37E54C
;第五次80000004返回时 dr全为0 eip=37E21B
;第六次C0000094返回时 dr全为0 eip=37D4E9    除零错误
;第六次C0000095返回时 dr全为0 eip=37D435
;第七次C000008C返回时 dr全为0 eip=37B998    数组越界
;===========================================

00380DE6    64:FF35 00000000       PUSH DWORD PTR FS:[0]
00380DED    64:8925 00000000       MOV DWORD PTR FS:[0],ESP        ;安装SEH
;0012FF9C   0012FFE0  Pointer to next SEH record
;0012FFA0   0038354B  SE handler
00380DF4    33C0                   XOR EAX,EAX
00380DF6    8B00                   MOV EAX,DWORD PTR DS:[EAX]
00380DF8    90                     NOP
00380DF9    90                     NOP
00380DFA    CC                     INT3
00380DFB  ^ EB FB                  JMP SHORT 00380DF8
;...
;第七次从SEH函数返回时,到这里
0037B998    64:8F05 00000000       POP DWORD PTR FS:[0]            ;解除SEH
0037B99F    58                     POP EAX
;==========================================

0037B5CC    B8 E3204100            MOV EAX,4120E3
0037B5D1    8906                   MOV DWORD PTR DS:[ESI],EAX                       ; main.004120E3
;EAX=004120E3 (main.004120E3)
;DS:[00383427]=0038352B

0037B5F3    8B85 5E194100          MOV EAX,DWORD PTR SS:[EBP+41195E]                ; kernel32.GetCurrentThread

0037B777    8B85 321A4100          MOV EAX,DWORD PTR SS:[EBP+411A32]                ; kernel32.SetThreadPriority

0037733A    8B85 25184100          MOV EAX,DWORD PTR SS:[EBP+411825]                ; USER32.EnableWindow

003774C2    61                     POPAD                        ;噢噢~ 好像快到oep了
003774C3    50                     PUSH EAX                        ;dump时,要从这里跳到★oep

;stolen code, 一般delphi程序为5个call. 这个bt有7个call
0038A7E2    55                     PUSH EBP                        ;push ebp
0038A7E6    54                     PUSH ESP
0038A7E7    5D                     POP EBP                        ;mov ebp, esp

0038A7EC    54                     PUSH ESP
0038A7ED    830424 F0              ADD DWORD PTR SS:[ESP],-10
0038A7F1    5C                     POP ESP                        ;add esp, -10

0038A7F4    68 54175700            PUSH 571754
0038A7F9    58                     POP EAX                        ;mov eax, 571754

0038A7FF    E8 02000000            CALL 0038A806                    ;把返回地址38A804压栈
0038A804    EB 11                  JMP SHORT 0038A817

0038A806    50                     PUSH EAX                        ;为下面的xchg作准备
0038A807    E8 04000000            CALL 0038A810                    
0038A80C    C471 40                LES ESI,FWORD PTR DS:[ECX+40]            

0038A810    58                     POP EAX                        ;第一proc ptr [38A80C]
0038A811    8B00                   MOV EAX,DWORD PTR DS:[EAX]                
0038A813    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A816    C3                     RETN                            ;call 4071C4
;=============

0038A81C    E8 04000000            CALL 0038A825
0038A821    4C                     DEC ESP
0038A822    73 57                  JNB SHORT 0038A87B

0038A825    58                     POP EAX                        ;[38A821]
0038A826    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, 57734C
0038A828    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, [eax]
0038A82C    FF30                   PUSH DWORD PTR DS:[EAX]
0038A82E    58                     POP EAX                        ;mov eax, [eax]
    
0038A832    E8 02000000            CALL 0038A839                    ;把返回地址38A837压栈
0038A837    EB 11                  JMP SHORT 0038A84A

0038A839    50                     PUSH EAX
0038A83A    E8 04000000            CALL 0038A843
0038A83F    60                     PUSHAD
0038A840    B7 46                  MOV BH,46

0038A843    58                     POP EAX                        ;第二proc ptr [0038A83F]
0038A844    8B00                   MOV EAX,DWORD PTR DS:[EAX]
0038A846    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A849    C3                     RETN                            ;call 46B760
;=============
0038A84C    FF35 A86D5700          PUSH DWORD PTR DS:[576DA8]                       
0038A852    59                     POP ECX                        ;mov ecx, [576DA8]

0038A858    E8 04000000            CALL 0038A861
0038A85D    4C                     DEC ESP
0038A85E    73 57                  JNB SHORT 0038A8B7

0038A861    58                     POP EAX                        ;
0038A862    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, 57734C
0038A864    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, [eax]
0038A869    FF30                   PUSH DWORD PTR DS:[EAX]
0038A86B    58                     POP EAX                        ;mov eax, [eax]

0038A86E    FF35 E87A5300          PUSH DWORD PTR DS:[537AE8]                
0038A874    5A                     POP EDX                        ;mov edx, [537AE8]

0038A879    E8 02000000            CALL 0038A880                    ;把返回地址38A87E压栈
0038A87E    EB 11                  JMP SHORT 0038A891

0038A880    50                     PUSH EAX
0038A881    E8 04000000            CALL 0038A88A
0038A886  ^ 78 B7                  JS SHORT 0038A83F                    ;第三proc ptr
0038A888    46                     INC ESI

0038A88A    58                     POP EAX
0038A88B    8B00                   MOV EAX,DWORD PTR DS:[EAX]                
0038A88D    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A890    C3                     RETN                            ;call 46B778
;=============
0038A895    FF35 DC6B5700          PUSH DWORD PTR DS:[576BDC]        
0038A89B    59                     POP ECX                        ;mov ecx, [576BDC]

0038A8A1    E8 04000000            CALL 0038A8AA
0038A8A6    4C                     DEC ESP
0038A8A7    73 57                  JNB SHORT 0038A900

0038A8AA    58                     POP EAX
0038A8AB    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, 57734C
0038A8AD    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, [eax]
0038A8B3    FF30                   PUSH DWORD PTR DS:[EAX]
0038A8B5    58                     POP EAX                        ;mov eax, [eax]

0038A8BB    FF35 74405200          PUSH DWORD PTR DS:[524074]                
0038A8C1    5A                     POP EDX                        ;mov edx, [524074]

0038A8C5    E8 02000000            CALL 0038A8CC                    ;把返回地址38A8CA压栈
0038A8CA    EB 11                  JMP SHORT 0038A8DD

0038A8CD    E8 04000000            CALL 0038A8D6
0038A8D2  ^ 78 B7                  JS SHORT 0038A88B                    ;第四proc ptr
0038A8D4    46                     INC ESI

0038A8D6    58                     POP EAX                            
0038A8D7    8B00                   MOV EAX,DWORD PTR DS:[EAX]
0038A8D9    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A8DC    C3                     RETN                            ;call 46B778
;=============
0038A8E0    FF35 30765700          PUSH DWORD PTR DS:[577630]                
0038A8E6    59                     POP ECX                        ;mov ecx, [577630]

0038A8EC    E8 04000000            CALL 0038A8F5
0038A8F1    4C                     DEC ESP
0038A8F2    73 57                  JNB SHORT 0038A94B

0038A8F5    58                     POP EAX
0038A8F6    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, 57734C
0038A8F8    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, [eax]
0038A8FD    FF30                   PUSH DWORD PTR DS:[EAX]
0038A8FF    58                     POP EAX                        ;mov eax, [eax]

0038A903    FF35 A0755300          PUSH DWORD PTR DS:[5375A0]                
0038A909    5A                     POP EDX                        ;mov edx, [5375A0]

0038A90D    E8 02000000            CALL 0038A914                    ;把返回地址38A912压栈
0038A912    EB 11                  JMP SHORT 0038A925                    

0038A914    50                     PUSH EAX
0038A915    E8 04000000            CALL 0038A91E
0038A91A  ^ 78 B7                  JS SHORT 0038A8D3                    ;第五proc ptr
0038A91C    46                     INC ESI

0038A91E    58                     POP EAX                        
0038A91F    8B00                   MOV EAX,DWORD PTR DS:[EAX]                
0038A921    870424                 XCHG DWORD PTR SS:[ESP],EAX                
0038A924    C3                     RETN                            ;call 46B778

;=============
0038A928    E8 04000000            CALL 0038A931
0038A92D    4C                     DEC ESP
0038A92E    73 57                  JNB SHORT 0038A987

0038A931    58                     POP EAX                        
0038A932    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, 57734C
0038A934    8B00                   MOV EAX,DWORD PTR DS:[EAX]                ;mov eax, [eax]
0038A939    FF30                   PUSH DWORD PTR DS:[EAX]
0038A93B    58                     POP EAX                        ;mov eax, [eax]

0038A93E    E8 02000000            CALL 0038A945                    ;把返回地址38A943压栈
0038A943    EB 11                  JMP SHORT 0038A956

0038A945    50                     PUSH EAX
0038A946    E8 04000000            CALL 0038A94F
0038A94B    F8                     CLC                            ;第六proc ptr
0038A94C    B7 46                  MOV BH,46

0038A94F    58                     POP EAX                        
0038A950    8B00                   MOV EAX,DWORD PTR DS:[EAX]
0038A952    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A955    C3                     RETN                            ;call 46B7F8
;=============
0038A959    E8 02000000            CALL 0038A960                    ;把返回地址38A95E压栈
0038A95E    EB 11                  JMP SHORT 0038A971                    

0038A960    50                     PUSH EAX
0038A961    E8 04000000            CALL 0038A96A
0038A966    184B 40                SBB BYTE PTR DS:[EBX+40],CL                ;第七proc ptr

0038A96A    58                     POP EAX                        
0038A96B    8B00                   MOV EAX,DWORD PTR DS:[EAX]
0038A96D    870424                 XCHG DWORD PTR SS:[ESP],EAX
0038A970    C3                     RETN                            ;call 404B18


;======================最后还原出来的stolen code是这样的
;★oep:
00578000    55               PUSH EBP
00578001    8BEC             MOV EBP,ESP
00578003    83C4 F0          ADD ESP,-10
00578006    B8 54175700      MOV EAX,main.00571754
0057800B    E8 B4F1E8FF      CALL main.004071C4
00578010    B8 4C735700      MOV EAX,main.0057734C
00578015    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578017    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578019    E8 4237EFFF      CALL main.0046B760
0057801E    8B0D A86D5700    MOV ECX,DWORD PTR DS:[576DA8]                    ; main.005DCC84
00578024    B8 4C735700      MOV EAX,main.0057734C
00578029    8B00             MOV EAX,DWORD PTR DS:[EAX]
0057802B    8B00             MOV EAX,DWORD PTR DS:[EAX]
0057802D    8B15 E87A5300    MOV EDX,DWORD PTR DS:[537AE8]                    ; main.00537B34
00578033    E8 4037EFFF      CALL main.0046B778
00578038    8B0D DC6B5700    MOV ECX,DWORD PTR DS:[576BDC]                    ; main.005DC990
0057803E    B8 4C735700      MOV EAX,main.0057734C
00578043    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578045    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578047    8B15 74405200    MOV EDX,DWORD PTR DS:[524074]                    ; main.005240C0
0057804D    E8 2637EFFF      CALL main.0046B778
00578052    8B0D 30765700    MOV ECX,DWORD PTR DS:[577630]                    ; main.005DCC7C
00578058    B8 4C735700      MOV EAX,main.0057734C
0057805D    8B00             MOV EAX,DWORD PTR DS:[EAX]
0057805F    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578061    8B15 A0755300    MOV EDX,DWORD PTR DS:[5375A0]                    ; main.005375EC
00578067    E8 0C37EFFF      CALL main.0046B778
0057806C    B8 4C735700      MOV EAX,main.0057734C
00578071    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578073    8B00             MOV EAX,DWORD PTR DS:[EAX]
00578075    E8 7E37EFFF      CALL main.0046B7F8                    ;Application.Run
0057807A    E8 99CAE8FF      CALL main.00404B18
;======================

;最后,在oep处完成我们上面原理部分第9步的处理,就一切ok了. dump再importrec修复.



;附上处理iat和"mov 替换"的代码
;1.iat
    pushad
    pushfd
    mov eax, 6F7190        ;iat起始处
    mov ecx, 6F79C4        ;iat结尾处
@@loop:
    add eax, 4
    cmp eaxecx
    ja @@end
    cmp [eax], 0
    je @@loop
    cmp [eax], DA0000
    ja @@loop
    mov esi, [eax]
    mov esi, [esi+1c]
    mov esi, [esi+1]
    mov [eax], esi
    jmp @@loop
@@end:
    popfd
    popad

;2.mov替换
    pushad
    pushfd

    mov eax, 401000
    sub eax, 1
    mov edx, 718000
    sub edx, 2
@@loop:
    add eax, 1
    cmp eaxecx
    ja @@end
    cmp WORD ptr [eax], 15FF
    jne @@loop
    mov edieax
    mov esi, [eax+2]
    add eax, 1
    cmp esi, 401000
    jnb @@loop
    mov esi, [esi]
    mov ecx, 6
    rep movsb [edi], [esi]
    jmp @@loop
@@end:
    popfd
    popad



;special thanx to heXer, 老菜鸟, loveboom, csjwaman && 老罗的代码着色器.