逆向集录_00_区别程序OEP特征总结,可跨平台

by admin on 2019年3月20日
  • 在解析/逆向
    程序时,即便事先知道那类程序的片段特征,那将会是占便宜的;
  • 分析/逆向
    程序,和写程序分化,比喻的话:写程序像在违法,分析/逆向
    程序就像在破案,对破案来讲,重在假想和演绎;

转载:

Delphi & BC++

动用Detect it
Easy工具鲜明软件应用的编写翻译器为Delphi也许是BC++,那五个编写翻译器的按钮特征码相同。
home88一必发 1
OD载入程序,反汇编窗口右键->查找->二进制字符串:
接下来在HEX窗口输入特征码,注意Delphi和BC++的特征码是一模一样的(“740E8BD38B83????????FF93????????”):
home88一必发 2
留神勾选整个块。

特征码中的问号代表专断数据。
在特征码的底下都会传下二个CALL,然后大家在各样特征码的下边包车型大巴CALL下断点:
home88一必发 3
逆向集录_00_区别程序OEP特征总结,可跨平台。接下来CTCR-VL+L,在具有的特征码下边包车型地铁CALL下断点。因为我们不驾驭是哪一个按钮,所以须求在种种按钮都下断点,假设程序相比小,很快,尽管程序相比大,按钮事件相比多,能够采取脚本来下断点。
逆向集录_00_区别程序OEP特征总结,可跨平台。断点下完之后,F9运转程序,然后点击关键的挂号之类的按钮,程序会停当前按钮的CALL处,然后F7进CALL,就能够找关键CALL和重要跳了。

先是大家先来说说壳的规律吧,简单说下就好,带壳程序运营之后,都会做什么事情啊?
(想要精通越来越多的朋友们就去读看雪四弟的《加密与解密(第②版)》吧)

特点1:VC链接器版本

工作必要要脱八个VMP壳,笔者是3个一直没接触过脱壳的人。须臾间那种心思碰着的人应当都理解!不可能硬着头皮找教程,7天看完了
《天草的壳的社会风气》尝试脱壳下边是作者的脱壳进度希望大牌多多指正!
壹 、准备工具,FEID(查壳工具)、DIE(查壳工具)、LordPE(dump工具)、ImpRec(IAT修复工具)、UIF(IAT修复工具)、CFF(文件优化学工业具)、OD(咱爱破解专版
调节和测试工具)
2、查壳 PEID
home88一必发 4 
区段显示是vmp1,看来是VMP壳编写语言还是无法鲜明上DIE
home88一必发 5 
浮现编制程序语言是VC++的,VMP壳
叁 、开OD准备脱壳、OD设置如下
home88一必发 6

VB

运用同样的方法寻找VB的特征码(“816C24”):
home88一必发 7
在各样jmp处下断点,然后运转程序,来到断点处,jmp跟过去之后即是按钮事件的处理进程了。

壹 、保存现场(pushad/popad,pushfd/popfd)>>贰 、获取壳自个儿索要的API地址>>三 、解密原程序各类区块>>肆 、IAT的开首化>>五 、重一直>>陆 、Hook-API>>七 、跳到 OEP

VS版本 链接器版本
VS2017 14.12
VS2015 14.0, 14.1
VS2013 12.0
VS2012 11.0
VS2010 10.0
VS2008 9.0
VS2005 8.0
VC2003 7.0, 7.1
VC6/VB6/E语言 6.0
VC5/BC++ 5.0
Delphi 2.25
VB5

4.20

 home88一必发 8

MFC

专注,使用MFC和VC++编写的主次,使用PEiD查壳时,都会显示是Visual
C++6.0的编写翻译器,两者的区分方法是,使用OD载入程序,在E窗口中,MFC的程序会调用3个mfc42.dll的动态链接库文件,而VC++的顺序不会调用这么些库。
home88一必发 9
载入MFC程序,在E窗口中双击mfc42.dll,跟进去,然后反汇编窗口中右键->查找->命令:
“sub
eax,0a”,找到之后,在特征码的上面会有几个je跳转,选中je命令行,然后按回车,程序会跟随到跳转处,来到指标地方,找上面包车型大巴三个CALL,下断点:
home88一必发 10
假定je跳转之后,没有CALL,这就绝不管那一个特征码,继续寻找下二个特征码,知道找到全数的CALL甘休。然后急速运行程序,点击按钮之后,程序会在断点处甘休,然后在上下文找关键CALL和重要跳即可。

 

 

home88一必发 11 
打开进度到进口看下
home88一必发 12 
4、跑OEP
什么也卡不懂,可是没什么知道是VMP壳就好办,直接CT本田CR-VL+G  输入 VirtualProtect
下断 如下图(假设提醒未知,先在内部存款和储蓄器窗口找到 kernel32.dll代码段
进去后在转到就到了)
home88一必发 13 
F9跑起来,那是会段下
home88一必发 14 
注意NewProtect 这项 等于 PAGE_READONLY 是停止,不然一贯F9
按慢点别跑飞了
home88一必发 15 
到040一千处看看,代码是还是不是曾经解码
home88一必发 16 
早已解码, 搜索特征码 EB0B85F375078BC6C1E0100BF0
home88一必发 17 
那是OEP第多个CALL的底部,依据他找到OEP 
home88一必发 18 
OEP 正是 00a6f7c8,然而那才是首先步 那时候DUMP 是没用的 因为VMP加密了IAT
我们要求还原他
5、还原IAT
随便找2个IAT调用函数跟一下,刚好OEP下边就有多少个 FF25 型的IAT
调用,跟进去看下
home88一必发 19 
或许什么都看不懂,不过没什么
既然是调用IAT函数,肯定会在某权且刻调到真实函数地址去的
继续跟下边把全数跟的流程贴上来
home88一必发 20 
home88一必发 21 
home88一必发 22 
home88一必发 23 
home88一必发 24 
那是漫天流程的其实履行的代码 ,今后分析下
01059D91    53              push ebx                     敬服环境
01059D92    66:0FB6DB       movzx bx,bl          垃圾代码
01059D96    66:BB 5D55      mov bx,0x555D   垃圾代码
01059D9A    BB 5AC27200     mov ebx,0072C25A 
 那才是终极对EBX操作所以上边两条都以没用的代码
00F3BBFF    8B9B 25697400   mov ebx,dword ptr ds:[ebx+0x746925]   
总计地址
01196B98    8D9B 5071F632   lea ebx,dword ptr
ds:[ebx+0x32F67150]  总括地址
00EA9FC2    871C24          xchg dword ptr ss:[esp],ebx 
 和栈顶沟通,并还原EBX的原始值
00F9FC9D    C2 0400         retn 0x4                  还原EBX
并再次回到函数
此时看下堆栈 栈顶出现真实函数的地方
<ignore_js_op>home88一必发 25 
00F9FC9D    C2 0400         retn 0x4      
分析下那条指令的执行流程,先EIP=栈顶的值 也正是实事求是函数地址,栈顶+4+4
懂汇编的人就会意识,栈顶+8的岗位保存是现阶段CALL的归来地址
那执行了那条指令后归来地址不是绝非了么?因为那个IAT调用 没加密前是
FF25型的 也正是 jmp [????????] 所以不须要回到地址
,而调用那么些IAT的时候
是有一个CALL的进CALL的时候就会PUSH再次来到地址到库房,所以那么些IAT处理的很巧妙!执行完真实函数后直接就回来到调用IATCALL的底下继续执行了。
看图片发现 这些CALL 上边有一条 RETN指令 看来这条
是VMP加上去的了,不过绝不粗大心了那条指令 因为那条指令很关键,VMP在得到IAT地址的结尾RETN的地点 会随机JMP到代码他添加的RETN 上,并不完全是在壳段
所以那么些RETN 要留到最终处理。
再找三个FF25 型的IAT调用看看
home88一必发 26 
跟进去看下,下边是执行流程代码
00FB7DC7    90              nop
00FB7DC8    0FB7D6          movzx edx,si        垃圾代码
00FB7DCB    66:0FBED1       movsx dx,cl       垃圾代码
00FB7DCF    5A              pop edx                   出栈             
  
00FB7DD0    871424          xchg dword ptr ss:[esp],edx       
   交流栈顶的值,还原 EDX原始值
00FB7DD3    52              push edx                            
 爱惜环境
00FB7DD4    66:0FBED1       movsx dx,cl     垃圾
00FB7DD8    0FB7D6          movzx edx,si      垃圾
00FB7DDB    BA B7757D00     mov edx,007D75B7     总结地址
010DFDAD    8B92 3D036900   mov edx,dword ptr ds:[edx+0x69033D]   
总括地址
0102B837    8D92 B52FE512   lea edx,dword ptr ds:[edx+0x12E52FB5] 
   总结地址
00EACB30    871424          xchg dword ptr ss:[esp],edx 
 函数实际地址给栈顶 并苏醒环境          
0115D36E    C2 0400         retn 0x4 
那么些FF25 CALL 的第六行 有个POP  edx 而进那么些CALL在此以前  有1个push edx
,能够见见 那些push edx 也是垃圾堆代码是 VMP本身加上上去的,看来VMP
会随机在前后 填充3个字节,在上头正是 PUSH 三个寄存器,在底下正是 retn
找一个 FF15型的CALL看看
home88一必发 27 
跟进去看下流程
010B27B9    BE B34E6E0B     mov esi,0xB6E4EB3    垃圾代码
00EFFC5B    5E              pop esi               出栈
00EEB9B0    873424          xchg dword ptr ss:[esp],esi   
交流栈顶的值,还原 ESI原始值
00F437BB    56              push esi   保存环境
00F8D827    BE 4B084800     mov esi,0048084B    总计地址
00FA55B3    8BB6 C005B900   mov esi,dword ptr
ds:[esi+0xB905C0]  总结地址
010E8053    8DB6 3F68AD31   lea esi,dword ptr ds:[esi+0x31AD683F]
总计地址
00F44191    873424          xchg dword ptr ss:[esp],esi 
 真实函数地址给栈顶,还原环境
0057A761    C3              retn 
其次行 pop esi  看来那个CALL 的push esi 是污物指令了,不过 发现那么些是retn 为啥不是,retn 04 呢?因为那个是 FF15 型调用,约等于 call
[????????]  要求履行完后回去到call 下边继续执行
再找1个FF15型调用看看
home88一必发 28 
跟进去看下流程
00E77D14    90              nop
00E77D15    51              push ecx            保存环境              
00E77D16    66:F7D1         not cx           垃圾代码
00E77D19    8B4C24 04       mov ecx,dword ptr ss:[esp+0x4]   
栈顶+4(调用CALL的归来地址)给ECX,
00FB7CFF    8D49 01         lea ecx,dword ptr ds:[ecx+0x1]   取
重回地址+1的值 给ECX
01013FB5    894C24 04       mov dword ptr
ss:[esp+0x4],ecx  重新写入到重回处
01013FB9    B9 A1598A00     mov ecx,008A59A1 计算地址
010566B2    8B89 94C36C00   mov ecx,dword ptr ds:[ecx+0x6CC394]
计算地址
00E95200    8D89 19378077   lea ecx,dword ptr ds:[ecx+0x77803719]
总计地址
00FEA363    870C24          xchg dword ptr
ss:[esp],ecx  真实函数地址给栈顶,还原环境       
010ABADE    C3              retn
以此 有点差异啊,很简单 看调用CALL 的上边有2个 RETN啊,这借使常规重回程序还不足跑飞啊,VMP巧妙的行使 4 5 6三行代码
就消除了,那写壳的人真是脑洞大开啊!
负有的IAT加密就像此完了啊??? NO  还有更脑洞大开的 往下看
home88一必发 29 
跟进去看看
0119D768    90              nop
0106B2C9    872C24          xchg dword ptr ss:[esp],ebp       
   交换栈顶的值,还原栈顶
00F3E26F    55              push ebp                            
 保存重临地址
00F3E270    F7D5            not ebp                              
垃圾代码
00F3E272    50              push eax                            
 保存环境
00F3E273    B8 D41D4300     mov eax,00431DD4  总结地址
00F3E278    66:8BEB         mov bp,bx  垃圾代码
00F3E27B    8B80 41F7BE00   mov eax,dword ptr
ds:[eax+0xBEF741]  总计地址
00F3E281    66:0F4FE8       cmovg bp,ax  垃圾代码
00F3E285    66:8BE8         mov bp,ax   垃圾代码
00F3E288    8D80 903F170C   lea eax,dword ptr
ds:[eax+0xC173F90]  总结地址
00F3E28E    0FB7E8          movzx ebp,ax 垃圾代码
00F3E291    8BE8            mov ebp,eax     真实函数地址给 EBP
00F3E293    58              pop eax   还原 寄存器
011B5D71    C3              retn
那是在干啥吧?? 咋把真实函数地址 给了 EBP呢? 看调用处的上面 有3个call ebp 掌握了吧 那是把   mov
xx,[????????]  整成了2个CALL哦,再来看下堆栈 调用处pop  EBP , CALL内
第一行
有把栈顶的值还原了,然后把函数的回来地址重新PUSH进去,那里处理的很抢眼,全体调用处的 pop ebp也是污物指令,那就完了???NO还有往下看
home88一必发 30 
跟进去看下
00E97E5D    90              nop
00E97E5E    0FBFDB          movsx ebx,bx  垃圾代码
010C1083    50              push eax                    保存环境     
010C1084    8B4424 04       mov eax,dword ptr ss:[esp+0x4]    
 获取当前CALL的回到地址给EAX
00E2EB3F    8D40 01         lea eax,dword ptr ds:[eax+0x1] 
 获取当前CALL再次来到地址+1给EAX
00E2EB42    0F45DB          cmovne ebx,ebx    垃圾代码
00E2EB45    66:0FB6DB       movzx bx,bl  垃圾代码
00E2EB49    894424 04       mov dword ptr
ss:[esp+0x4],eax  保存重返地址
00E2EB4D    B8 012C4300     mov eax,00432C01 总括地址
00E2EB52    66:0FBEDB       movsx bx,bl 垃圾代码
00E2EB56    66:8BDF         mov bx,di 垃圾代码
01170378    8B80 F58CC000   mov eax,dword ptr ds:[eax+0xC08CF5]
总计地址
0117037E    0FB7DC          movzx ebx,sp 垃圾代码
01170381    0F41DE          cmovno ebx,esi      垃圾代码
01170384    F6D7            not bh 垃圾代码
01170386    8D80 145A2C32   lea eax,dword ptr ds:[eax+0x322C5A14]
计算地址
0117038C    B3 85           mov bl,0x85 垃圾代码
0117038E    8ADE            mov bl,dh 垃圾代码
01170390    8BD8            mov ebx,eax   真实函数地址给 EBX          
   
01170392    0FBFC2          movsx eax,dx 垃圾代码
01170395    C6C4 E2         mov ah,0xE2 垃圾代码
01170398    0FC8            bswap eax             垃圾代码            
0117039A    58              pop eax      还原环境                    
0117039B    C3              retn
认真看 了下面的一对,那里不难领悟了吧, 4 5 8行处理调用处的 下边 retn
的,函数是获取 EBX的调用值的

易语言

瞩目,易语言编写的顺序,使用PEiD查壳时,展现的编写翻译器也是Visual
C++6.0,使用OD载入程序,直接在反汇编窗口中右键->查找->二进制字符串,输入易语言的特征码:“FF
25”,借使可以找到,就认证是易语言编写的程序。
易语言体:
home88一必发 31
能够看来有一堆的jmp指令,以上就能看清是易语言程序。

下一步查找易语言的按钮事件:二进制字符串“FF 55 FC 5F
5E»ò(e-debug)”,找到之后,会到来CALL处,直接下断:
home88一必发 32
搜索剩下的,全数地点都下断点,然后F9运行程序早先调节和测试。

易语言程序还是可以运用另一种方法来探寻按钮事件,使用E-debug工具:
home88一必发 33
使用OPEN载入易语言程序,然后点击START,运行程序,点击按钮,会显得事件爆发的地点:
home88一必发 34
记录事件发生的地址,然后选取OD载入程序,跟踪到这一个地点下断点:
Ctrl+G,输入要跟随的表明式,输入刚才记录的地点,下断点:
home88一必发 35
F9运维程序,触发断点事件,即可断在此处。

第②大家先用DIE来查一下带壳程序是怎么样语言编写的,然后再用OD载入。

 

共计6种 IAT相关的处理,所以自身是 一边写脚本一边骂写
VMP壳的人,要不要如此坑啊,小编要的脱的次序尤其大 跑2回要
3个小时,作者也不记得笔者跑了略微遍了!哎!说来都是泪,新手正是如此呀!不多说了上边贴上脚本!必要的团结去下!

VC++

应用PEiD查壳,查找的编译器为VC++6.0,假使找不到易语言和MFC的标志,那就足以判定是vc++写的主次,按钮事件查找方法,直接OD载入程序,在反汇编窗口右键->查找->全部命令,输入特征码:“sub
eax,0a”:
home88一必发 36
双击跟进去,在下边会有一个je:
home88一必发 37
当选之后,回车,跟过去,在底下的CALL下断点:
home88一必发 38
依据上边的情势找到全部的CALL下断点。
接下来F9运转程序,点击按钮,程序来到断点处,F7跟进去,注意,进去之后还不是骨干按键处理程序,按四遍F8之后,才来到大旨代码处:
home88一必发 39

在脱壳在此之前呢,大家必然要通晓各样语言的OEP特色是怎么样,免获得时候就算到了OEP,自个儿都不了解,那可就喜剧了,那里列出各样语言的OEP(请忽略地址):

 

home88一必发,6、用UIf 修复IAT 
7、用lodepe dump
8、用imprec 修复IAT
九 、用cff 去掉壳段
时至后天VMP脱壳完结!

万能断点

不必要驾驭程序行使的编译器和编写翻译语言,直接OD载入程序,直接运维程序,输入假码之后,不要点击按钮:
home88一必发 40
查看user32模块:
home88一必发 41
到来user32模块然后,搜索特征码,右键->查找->二进制字符串:“F3A58BC883E103F3AUDIE8”
home88一必发 42
接下来下断点,找到全部的都要下断点。然后回到程序,点击按钮,程序暂停,重临OD,alt+F9,执行到用户代码:
home88一必发 43
下一场就到了按键事件处理的代码了。

 

 

VC++:

 

1
2
3
4
5
6
7
8
9
00496EB8 >/$  55            PUSH EBP                        
00496EB9  |.  8BEC          MOV EBP,ESP
00496EBB  |.  6A FF         PUSH -1
00496EBD  |.  68 40375600   PUSH Screensh.00563740
00496EC2  |.  68 8CC74900   PUSH Screensh.0049C78C              
00496EC7  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00496ECD  |.  50            PUSH EAX
00496ECE  |.  64:8925 00000>MOV DWORD PTR FS:[0],ESP
00496ED5  |.  83EC 58       SUB ESP,58

 

VB:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
00401166  - FF25 6C104000   JMP DWORD PTR DS:[<&MSVBVM60.#100>]      ; MSVBVM60.ThunRTMain
0040116C >  68 147C4000     PUSH PACKME.00407C14                     ;这是第一种入口格式
00401171    E8 F0FFFFFF     CALL <JMP.&MSVBVM60.#100>
00401176    0000            ADD BYTE PTR DS:[EAX],AL
00401178    0000            ADD BYTE PTR DS:[EAX],AL
0040117A    0000            ADD BYTE PTR DS:[EAX],AL
0040117C    3000            XOR BYTE PTR DS:[EAX],AL
 
00401FBC >  68 D0D44000        push dumped_.0040D4D0
00401FC1    E8 EEFFFFFF        call <jmp.&msvbvm60.ThunRTMain>        ;这是第二种入口格式
00401FC6    0000               add byte ptr ds:[eax],al
00401FC8    0000               add byte ptr ds:[eax],al
00401FCA    0000               add byte ptr ds:[eax],al
00401FCC    3000               xor byte ptr ds:[eax],al
00401FCE    0000               add byte ptr ds:[eax],al

 

BC++:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0040163C > $ /EB 10         JMP SHORT BCLOCK.0040164E
0040163E     |66            DB 66                                    ;  CHAR 'f'
0040163F     |62            DB 62                                    ;  CHAR 'b'
00401640     |3A            DB 3A                                    ;  CHAR ':'
00401641     |43            DB 43                                    ;  CHAR 'C'
00401642     |2B            DB 2B                                    ;  CHAR '+'
00401643     |2B            DB 2B                                    ;  CHAR '+'
00401644     |48            DB 48                                    ;  CHAR 'H'
00401645     |4F            DB 4F                                    ;  CHAR 'O'
00401646     |4F            DB 4F                                    ;  CHAR 'O'
00401647     |4B            DB 4B                                    ;  CHAR 'K'
00401648     |90            NOP
00401649     |E9            DB E9
0040164A   . |98E04E00      DD OFFSET BCLOCK.___CPPdebugHook
0040164E   > \A1 8BE04E00   MOV EAX,DWORD PTR DS:[4EE08B]
00401653   .  C1E0 02       SHL EAX,2
00401656   .  A3 8FE04E00   MOV DWORD PTR DS:[4EE08F],EAX
0040165B   .  52            PUSH EDX
0040165C   .  6A 00         PUSH 0                                   ; /pModule = NULL
0040165E   .  E8 DFBC0E00   CALL <JMP.&KERNEL32.GetModuleHandleA>    ; \GetModuleHandleA
00401663   .  8BD0          MOV EDX,EAX

 

Delphi:

 

1
2
3
4
5
6
7
8
9
10
00509CB0 > $  55            PUSH EBP
00509CB1   .  8BEC          MOV EBP,ESP
00509CB3   .  83C4 EC       ADD ESP,-14
00509CB6   .  53            PUSH EBX
00509CB7   .  56            PUSH ESI
00509CB8   .  57            PUSH EDI
00509CB9   .  33C0          XOR EAX,EAX
00509CBB   .  8945 EC       MOV DWORD PTR SS:[EBP-14],EAX
00509CBE   .  B8 20975000   MOV EAX,unpack.00509720
00509CC3   .  E8 84CCEFFF   CALL unpack.0040694C

 

易语言:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
格式一:
00401000 >  E8 06000000     call dump_.0040100B
00401005    50              push eax
00401006    E8 BB010000     call <jmp.&KERNEL32.ExitProcess>
0040100B    55              push ebp
0040100C    8BEC            mov ebp,esp
0040100E    81C4 F0FEFFFF   add esp,-110
00401014    E9 83000000     jmp dump_.0040109C
00401019    6B72 6E 6C      imul esi,dword ptr ds:[edx+6E],6C
0040101D    6E              outs dx,byte ptr es:[edi]
 
格式二
00403831 >/$  55            PUSH EBP
00403832  |.  8BEC          MOV EBP,ESP
00403834  |.  6A FF         PUSH -1
00403836  |.  68 F0624000   PUSH Nisy521.004062F0
0040383B  |.  68 A44C4000   PUSH Nisy521.00404CA4                   
00403840  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00403846  |.  50            PUSH EAX
00403847  |.  64:8925 00000>MOV DWORD PTR FS:[0],ESP
 
5.0以后独立编译的入口:
 
0045C12D >/$  55            push ebp
0045C12E  |.  8BEC          mov ebp,esp
0045C130  |.  6A FF         push -0x1
0045C132  |.  68 087D4B00   push notebook.004B7D08
0045C137  |.  68 14E94500   push notebook.0045E914                      
0045C13C  |.  64:A1 0000000>mov eax,dword ptr fs:[0]
0045C142  |.  50            push eax
0045C143  |.  64:8925 00000>mov dword ptr fs:[0],esp
0045C14A  |.  83EC 58       sub esp,0x58
0045C14D  |.  53            push ebx
0045C14E  |.  56            push esi
0045C14F  |.  57            push edi
0045C150  |.  8965 E8       mov [local.6],esp
0045C153  |.  FF15 A4C14700 call dword ptr ds:[<&KERNEL32.GetVersion>;  kernel32.GetVersion
0045C159  |.  33D2          xor edx,edx
0045C15B  |.  8AD4          mov dl,ah
0045C15D  |.  8915 BCB44E00 mov dword ptr ds:[0x4EB4BC],edx
0045C163  |.  8BC8          mov ecx,eax
0045C165  |.  81E1 FF000000 and ecx,0xFF
0045C16B  |.  890D B8B44E00 mov dword ptr ds:[0x4EB4B8],ecx
0045C171  |.  C1E1 08       shl ecx,0x8
0045C174  |.  03CA          add ecx,edx
0045C176  |.  890D B4B44E00 mov dword ptr ds:[0x4EB4B4],ecx
0045C17C  |.  C1E8 10       shr eax,0x10
0045C17F  |.  A3 B0B44E00   mov dword ptr ds:[0x4EB4B0],eax
0045C184  |.  6A 01         push 0x1
0045C186  |.  E8 354B0000   call notebook.00460CC0

 

MASM32 / TASM32入口:

特征2:OEP

1
2
3
4
5
6
7
8
9
00401258 >/$  6A 00         push 0                                   ; /pModule = NULL
0040125A  |.  E8 47000000   call <jmp.&kernel32.GetModuleHandleA>    ; \GetModuleHandleA
0040125F  |.  A3 00304000   mov dword ptr ds:[403000],eax
00401264  |.  6A 00         push 0                                   ; /lParam = NULL
00401266  |.  68 DF104000   push dump.004010DF                       ; |DlgProc = dump.004010DF
0040126B  |.  6A 00         push 0                                   ; |hOwner = NULL
0040126D  |.  6A 65         push 65                                  ; |pTemplate = 65
0040126F  |.  FF35 00304000 push dword ptr ds:[403000]               ; |hInst = NULL
00401275  |.  E8 56000000   call <jmp.&user32.DialogBoxParamA>       ; \DialogBoxParamA

a0) VB5:

VC8入口:

【VB5】的OEP平衡堆栈是 sub
esp,0x54

1
2
3
4
5
6
7
8
9
00401258 >/$  6A 00         push 0                                   ; /pModule = NULL
0040125A  |.  E8 47000000   call <jmp.&kernel32.GetModuleHandleA>    ; \GetModuleHandleA
0040125F  |.  A3 00304000   mov dword ptr ds:[403000],eax
00401264  |.  6A 00         push 0                                   ; /lParam = NULL
00401266  |.  68 DF104000   push dump.004010DF                       ; |DlgProc = dump.004010DF
0040126B  |.  6A 00         push 0                                   ; |hOwner = NULL
0040126D  |.  6A 65         push 65                                  ; |pTemplate = 65
0040126F  |.  FF35 00304000 push dword ptr ds:[403000]               ; |hInst = NULL
00401275  |.  E8 56000000   call <jmp.&user32.DialogBoxParamA>       ; \DialogBoxParamA

【VB5】的OEP第一个API调用是GetStartupInfoA

 

【VB5】程序的IAT引用,都是FF15型的

脱壳方法:

home88一必发 44

明亮了进口我们就开端脱壳吧!

home88一必发 45

脱壳方法一:单步跟踪,其实正是f8,f7合作啦

a1) VB6

亟需专注的几点:当你遇上近Call的时候须求用f7跟进;当您赶上远Call的时候,用f8跳过就行;当遇到循环的时候,直接用f4跳出;当境遇大的跳转就要注意了,不慢就到OEP了

【VB6】的OEP平衡堆栈是
sub esp,0x4C

我们拿《加密与解密》的RebPE.exe举栗子,die查VC++写的,来探视吧:

【VB6】的OEP第一个API调用是GetStartupInfoA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
00413000 >  60              pushad                                   ; 刚进来
00413001    E8 C2000000     call RebPE.004130C8                      ; 这call很近吧,我们f7进去
================================================================================================进来了
004130C8    5D              pop ebp                                  ; RebPE.00413006
004130C9    81ED 06000000   sub ebp,0x6                              ; 进来以后就f8跟吧
004130CF    8B85 C0000000   mov eax,dword ptr ss:[ebp+0xC0]          
004130D5    0BC0            or eax,eax
=================================================================================================用我单身狗多年练就的手速开始疯狂f8
00150028    8B06            mov eax,dword ptr ds:[esi]               ; kernel32.GetProcAddress
0015002A    8907            mov dword ptr ds:[edi],eax               ; kernel32.GetProcAddress
0015002C    83C6 04         add esi,0x4
0015002F    83C7 04         add edi,0x4
00150032  ^ E2 F4           loopd short 00150028                     ; 看到这里,这是个循环,我们直接下一条选中f4跳出循环
00150034    8D85 37010000   lea eax,dword ptr ss:[ebp+0x137]
0015003A    8982 55030000   mov dword ptr ds:[edx+0x355],eax         ; kernel32.GetProcAddress
=================================================================================================
001500DE    68 00800000     push 0x8000
001500E3    6A 00           push 0x0
001500E5    56              push esi
001500E6    FF95 5D030000   call dword ptr ss:[ebp+0x35D]            ; kernel32.VirtualFree
001500EC    5B              pop ebx                                  ; ntdll.7C930460
001500ED    83C3 0C         add ebx,0xC
001500F0  ^ EB B3           jmp short 001500A5
001500F2    8B85 8D020000   mov eax,dword ptr ss:[ebp+0x28D]         ; 上面jmp又是个向上跳转,在这条f4跳出
001500F8    0BC0            or eax,eax
=================================================================================================
00150270    8B85 89020000   mov eax,dword ptr ss:[ebp+0x289]
00150276    0385 51030000   add eax,dword ptr ss:[ebp+0x351]         ; RebPE.00400000
0015027C    0185 84020000   add dword ptr ss:[ebp+0x284],eax         ; RebPE.00401130
00150282    61              popad                                    ; 注意这里有个popad,看到他就离OEP不远了,因为popad是还原现场用的
00150283    68 00000000     push 0x0
00150288    C3              retn
================================================================================================
00401130      55            db 55                                    ;  来到了这里,用ctrl+A分析下
00401131      8B            db 8B
00401132      EC            db EC
00401133      6A            db 6A                                    ;  CHAR 'j'
00401134      FF            db FF
00401135      68            db 68                                    ;  CHAR 'h'
================================================================================================分析好了,对比下上面的入口,正好就是OEP了
00401130  /.  55            push ebp                                 ;  来到了这里,用ctrl-A分析下
00401131  |.  8BEC          mov ebp,esp
00401133  |.  6A FF         push -0x1
00401135  |.  68 B8504000   push RebPE.004050B8
0040113A  |.  68 FC1D4000   push RebPE.00401DFC                      ;  SE 处理程序安装
0040113F  |.  64:A1 0000000>mov eax,dword ptr fs:[0]

【VB6】程序的IAT引用,都是FF15型的

 

 home88一必发 46

脱壳方法二:最终2次尤其法

home88一必发 47

1
2
3
4
5
1、在od的调试选项把异常的那个对话框所有异常的勾选全部去掉,ctrl+f2重新载入
2、反复按shift+f9,记录你按下的次数n
3、重新载入,这次按n-1次shift+f9
4、看堆栈,有个se处理程序,反汇编跟随
5、单步跟踪,直到有大跳转

b0) Delphi

 

【Delphi】OEP上边是三个地点
【Delphi】OEP处
有5个CALL
【Delphi】OEP
5个CALL之后,全是0
【Delphi】OEP处第二个CALL有GetModuleHandleA调用
【Delphi】的IAT调用是
FF25形式的

脱壳方法三:四遍断点法(内部存款和储蓄器镜像法):外壳会先解压各样区段,然后再跳回代码段执行,依照这么些规律:

home88一必发 48

1
2
3
4
1、在od的调试选项把异常的那个对话框所有异常的勾选全部选中
2、alt+m查看内存,然后再在资源段下一次f2断点,f9断下(目的是断下后确定壳解压处理了text段)
3、接下来再在text段下一次f2断点,f9断下(此时就说明开始访问text段了)
4、单步跟踪,直到大跳转

home88一必发 49

 

b1) BC++

脱壳方法四:ESP定律:外壳在开头的时候一定要保留环境(例如pushad),截止的时候还原环境(例如popad),最根本的是堆栈一定要平衡,那样,当执行pushad后,大家就足以在ESP下断点:

【BC++】
二进制特征:EB1066623亚洲龙32B2B484F4F4B90
【BC++】
OEP的首先个API调用是 GetModuleHandleA
【BC++】 IAT调用是
FF25形式的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
EAX 00000000                                              ;这是执行pushad后各个寄存器的值
ECX 0012FFB0
EDX 7C92E514 ntdll.KiFastSystemCallRet
EBX 7FFD5000
ESP 0012FFA4                                              ;我们在0012fff0处下个硬件断点,然后运行
EBP 0012FFF0
ESI 7C9A0620 ntdll.7C9A0620
EDI 7C930460 ntdll.7C930460
EIP 00413001 RebPE.00413001
================================================================================================
00150283    68 30114000     push 0x401130                 ;断在这里了,我们单步跟踪
00150288    C3              retn
00150289    3011            xor byte ptr ds:[ecx],dl
0015028B    0000            add byte ptr ds:[eax],al
0015028D    0100            add dword ptr ds:[eax],eax
================================================================================================到达OEP
00401130    55              push ebp
00401131    8BEC            mov ebp,esp
00401133    6A FF           push -0x1
00401135    68 B8504000     push RebPE.004050B8
0040113A    68 FC1D4000     push RebPE.00401DFC
0040113F    64:A1 00000000  mov eax,dword ptr fs:[0]
00401145    50              push eax

home88一必发 50

脱壳方法五:直接搜索popad法

c)
VC6/E语言(通过分析,发现双方特征一致,能够判断E语言和VC6如出一辙)

那方式原理尤其不难,既然popad是复苏环境,那么直接搜索ctrl+f搜索popad,然后下f2断点,运转断下就好了。

【VC6】的OEP平衡堆栈是
sub esp,0x58 或 sub esp,0x68或add esp, -0x5C

当然,那种措施有一点都不小的局限性,只适合UPX,ASPACK等少量壳。

【VC6】的OEP第一个API调用是GetVersion

 

【VC6】程序的IAT引用,都是FF15型的

脱壳方法六:仿照跟踪法

home88一必发 51

tc的意味:Trace in till
condition 跟踪进入直到条件满足

d) VS2013

eip是当前命令指针

【VS2013】开始处,call
xxx; jmp xxx;
【VS二零一一】的OEP平衡堆栈是sub
esp, 0x44
【VS2013】的OEP第一个API调用是GetStartupInfoW
【VS2013】程序的IAT引用,都是FF15型的

1
2
3
4
5
6
7
8
9
10
11
12
13
1、在od的调试选项把异常的那个对话框所有异常的勾选全部选中
2、alt+m查看内存,然后再在资源段下一次f2断点,f9断下(目的是断下后确定壳解压处理了text段)
3、接下来再在text段下一次f2断点,f9断下(此时就说明开始访问text段了)
================================================================================================ 以上方法就是两次断点,不同的是下面不再单步跟踪了,而是模拟跟踪
alt+m去看下内存,里面在程序领空会有一个sfx 输入表,像这样:
00400000   00001000   RebPE                 PE 文件头                
00401000   00004000   RebPE      .text      代码                    
00405000   00001000   RebPE      .rdata     数据                   
00406000   00003000   RebPE      .data                           
00409000   0000A000   RebPE      .rsrc      资源                      
00413000   00007000   RebPE      .pediy     SFX,输入表            ;我们记住这个地址00413000
================================================================================================   
之后我们在command命令行插件中输入tc eip<00413000 回车,看到左上角状态变成了‘跟踪’,接下来就是等程序自动跳到OEP了

home88一必发 52

 

home88一必发 53

脱壳方法七:sfx法,那措施就是太慢了

home88一必发 54

1
2
3
4
5
6
7
8
9
10
1、在od的调试选项把异常的那个对话框所有异常的勾选全部选中
2、在od的调试选项在SFX的那个选项卡选中 “字节方式跟踪真正入口处(速度非常慢)”
3、重新载入,漫长的等待过后就到达OEP了
=================================================================================================等待过后
00401130  /.  55            push ebp                                 ;  SFX 代码真正入口点
00401131  |.  8BEC          mov ebp,esp
00401133  |.  6A FF         push -0x1
00401135  |.  68 B8504000   push RebPE.004050B8
0040113A  |.  68 FC1D4000   push RebPE.00401DFC                      ;  SE 处理程序安装
0040113F  |.  64:A1 0000000>mov eax,dword ptr fs:[0]

 

 

这几个特点,会对分析程序起到一定的帮衬意义,那里,并从未完全列出整个的主流程序,希望引玉之砖吧;

脱壳方法八:一步到达法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1、od载入后运行
2、我们去堆栈的最下面,开始向上找,找第一个程序领空地址的
=================================================================================================
0012FFA4  |FFFFFFFF
0012FFA8  |0012FF4C
0012FFAC  |0012FFF0
0012FFB0  |0012FFE0  指向下一个 SEH 记录的指针
0012FFB4  |00401DFC  SE处理程序
0012FFB8  |004050B8  RebPE.004050B8                          ;就是这个,RebPE是程序名,注意左边有个框把这段给框起来了,说明这是一个函数堆栈
0012FFBC  |00000000
0012FFC0  \0012FFF0
0012FFC4   7C816037  返回到 kernel32.7C816037
0012FFC8   7C930460  返回到 ntdll.7C930460
0012FFCC   7C9A0620  ntdll.7C9A0620
=================================================================================================我们继续向上翻,找这个框的开头
 
0012FF14  |00000000
0012FF18  |7FFDE000
          \
向下找,‘返回到’的,这个例子有3个
0012FF1C  /0012FFC0                                                      ;这个就是函数的头部了
0012FF20  |0040101B  返回到 RebPE.0040101B 来自 user32.DialogBoxParamA    ;这个肯定不是,user32.DialogBoxParamA
0012FF24  |00400000  RebPE.00400000
0012FF28  |00000065
0012FF2C  |00000000
0012FF30  |00401080  RebPE.00401080
0012FF38  |004011FE  返回到 RebPE.004011FE 来自 RebPE.00401000            ;排除第一个和第三个,也只剩下这个了,我们右键反汇编跟随
0012FF3C  |00400000  RebPE.00400000
0012FF40  |00000000
0012FF44  |002823C8
0012FF48  |0000000A
0012FF4C  |7C930460  返回到 ntdll.7C930460                                ;这个也肯定不是,都跑系统领空去了
0012FF50  |7C9A0620  ntdll.7C9A0620
0012FF54  |7FFDD000
=================================================================================================反汇编跟随后,向上找断首,就是OEP了
00401130  /.  55            push ebp
00401131  |.  8BEC          mov ebp,esp
00401133  |.  6A FF         push -0x1
00401135  |.  68 B8504000   push RebPE.004050B8
0040113A  |.  68 FC1D4000   push RebPE.00401DFC                      ;  SE 处理程序安装
0040113F  |.  64:A1 0000000>mov eax,dword ptr fs:[0]
00401145  |.  50            push eax
00401146  |.  64:8925 00000>mov dword ptr fs:[0],esp
0040114D  |.  83EC 58       sub esp,0x58
00401150  |.  53            push eb

 

以上正是本人精通的徒手脱壳的艺术了,不是每种方法都试用全部的壳,怎么说呢,挨个试试吧。

当然也可以脱壳机恐怕用一堆脚本,可是那篇文章的宗旨是‘徒手’脱壳,就列出那二种艺术,假使有怎么着窘迫的,还请指正

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图