Armadillo脱壳知识和方法大全

2009/3/30 来源:www.arpun.com 作者:小白

近日对Armadillo壳很感兴趣, 缘于它的多种组合的变化, 但仔细看来, 其保护的解决方法又有相对固定。 方法无外乎那么几种脱壳方法(当然排除有key和cc), 本人在本论

坛已对标准壳的脱壳方法发贴, 但后来有所更新, 干脆总结在一块吧, 以方便大家。 大家可以复制下来, 放在手边, 脱壳时按步骤来。 我还是

一小鸟, 同大家一样在逐渐成长中, 有不对的地方和不成熟的地方, 望大家批评指正, 共同进步。

一、基本知识:

该壳有如下保护:

(1)Debug-Blocker(阻止调试器)--解决方法就是忽略所有异常, 隐藏好OD, 如果加载时, 老出错, 就多换几个OD试试。

(2)CopyMem-II(双进程保护)---解决方法是:用手动或者脚本使双变单。

(3) Enable Import Table Elimination(IAT保护) –解决方法是用工具ArmaDetach再次载入加壳程序, 记下子进程ID, 用另一OD载入, 利用断

点GetModuleHandleA, 找到Magic Jump, 修改Magic Jump, 得到正确的IAT。

(4)Enable Strategic Code Splicing(远地址跳) , 解决方法就是用Arminline工具。

(5) Enable Nanomites Processing(简称CC), 就是把一些retn代码变成CC(INT型), 解决方法:用Arminline工具或Enjoy工具。

(6)Enable Memory-Patching Protections(内存保护)

二、脱此类壳常用的断点:

1、WaitForDebugEvent(用于寻找非标准OEP和做补丁用)

2、WriteProcessMemory(用于寻找非标准OEP)

3、DebugActiveProcess(找子程)

4、OpenMutexA(双进程转单进程)

5、GetSystemTime(补丁KEY)

6、VirtualProtect(用于5.x)

7、CreateFileMappingA(用于5.x)

8、GetModuleHandleA/LoadLibraryA (用于找Magic Jump)

9、CreateThread(寻找OEP)

三、种类及脱壳方法

说明:对于此壳一般要隐藏OD。 如果按以下方法下断OD断不下来, 出错, 就多换几个OD试试, 在我脱壳中, 就有个情况, 下断点后, 老断不下

来, 多换了几个OD就成功了。

(一)单线程标准方式

具体方法:2次断点法加修改Magic Jump。

1、找Magic Jump

方法有二:

方法一、下断点Bp GetModuleHandleA/he GetModuleHandleA/bp GetModuleHandleA+5/he GetModuleHandleA+5, 按shift+f9运行, 当经过一个

call缓冲有点大时, 一般是在堆栈窗口出现ASCII "kernel32.dll"和ASCII "VirtualFree“后, 再运行一次, 出现"kernel32.dll", 就是返回

时机, 取消断点, 按alt+f9执行到返回。

方法二、也可以下bp LoadLibraryA断点, 当在堆栈窗口出现MSVBVM60.Dll函数时, 返回时机, 在kernel32.LoadLibraryA下面有一个跳转, 一

般情况下, 这个跳转比较大的话, 就改为jmp, 而跳转比较小的话, 就改nop)。 [注:下此断点的目的是找到Magic Jump, 修改Magic Jump目的

是避开的IAT的加密。 ]

2、找OEP

下断点bp GetCurrentThreadId/bp CreateThread, shift+f9运行, 中断后, 取消断点, Alt+F9返回, 单步执行, 看到一个call edi之类的。 F7

进入, 即到oep。 OD不要关!打开import--选择进程--OEP输入va--自动搜索IAT--获取输入表--显示无效函数--CUT!

(二) 双线程的标准壳

总体步骤:1、要双变单;2、处理IAT, 修改Magic Jump;3、寻找OEP;4、修复

1、双变单, 方法有三。

方法一:PATCH代码法

下断bp OpenMutexA, 断下后, ctrl+g到00401000, 将空数据改为如下代码:

0040100060 pushad

004010019C pushfd

00401002 68 A0FD1200 push xxxx(注:此处的xxxx为断下后mutex name前的数值。 )

0040100733C0 xor eax,eax

0040100950 push eax

0040100A50 push eax

0040100BE8 E694A677call KERNEL32.CreateMutexA

004010109D popfd

0040101161 popad

00401012- E9 8F9FA777jmp KERNEL32.OpenMutexA

点右键选择重建eip,f9运行, 断下后,取消断点,  ctrl+g到00401000, 恢复修改。

方法二, 下断点:bp OpenMutexA, SHIFT+F9, 断下后,  ALT+F9返回, 返回后, 将返回代码下面的第一个跳转改为相反跳转, 再次SHIFT+F9,

断下后, ALT+F9返回, 再次将返回代码下面的第一个跳转改为相反跳转。 然后再一次SHIFT+F9,取消断点, 至此,同样,双进程转单进程完毕!

方法三、除了用双变单的脚本外, 还可以用一个工具ARMADETACH, 将带壳的程序拖入, 记下子进程的ID。

2、处理IAT, 修改Magic Jump。

用OD附加该子进程, 加载后, ALT+F9返回, 修改前两个字节为加壳程序载入时的前两个字节。

下断点bpGetModuleHandleA,  Shift+F9运行, 一般是在堆栈窗口出现ASCII "kernel32.dll"和ASCII "VirtualFree“后, 再运行一次, 出现

"kernel32.dll", 就是返回时机, 中断后alt+f9返回,在KERNEL32.LoadLibraryA下面找到Magic Jump!修改为jmp。 再下断点bp 

GetCurrentThreadId/bp CreateThread(或往下拉找到两个salc, 在其上面的jmp上下断, Shift+F9, 断下!如果文件有校验, 则要撤消Magic 

Jump处的修改!打开内存镜像, 在00401000段下断。 运行, 中断后, 删除断点, alt+f9返回), F8单步走, 到第一个CALL ECX之类的东西时,

F7进入。 到oep。

注:(对于有些OD有一个字符串溢出漏洞, 尽量用一些修正些错误的OD, 有些程序需要处理Anti, 方法如下:下断点he OutputDebugStringA

断下后, 选中%s%之类的字符, 在数据窗口跟随, 点右键->二进制->使用00填充, 中断2次!都如上修改, 删除此断点!)

3、修复。

(三)CopyMem-ll +Debug-Blocke保护方式

1、先找OEP, 两个断点。 (1)断点bp WaitForDebugEvent,运行, 中断后看堆栈, 在一行有“pDebugEvent”字样的那一行右键点击“数据窗口

跟随”, 取消断点。 (2)bp WriteProcessMemory,运行, 中断后, 在数据窗口(要地址显示)发现oep。

2、patch代码, 解码。 方法:重新载入, bp WaitForDebugEvent,运行, 中断, 取消断点, alt+f9返回, CTRL+F搜索命令:or eax, 0FFFFFFF8

, 找到后, 先往上看, 可以看到两个CMP, 一个是“cmp dword ptr ss:[XXXX],0”在这里下硬件执行断点, Shift+F9运行, 中断后取消断点。

这时看信息窗口:SS[XXXXX]=00000000, 如果这个值不为0的话, 需要将其清0, 如果为0就不用了。 第二个CMP, cmp ecx,dword ptr ds:[XXXX]

, 下面开始解码。 在这里要记下几个地址:(1)cmp dword ptr ss:[XXXX],0前的地址和[]内的值。 (2)第二个CMP中[]中的值。 接着or eax

, 0FFFFFFF8处往下, 可以找到一处为and eax, 0FF的代码, 从这里开始Patch, 代码如下:

inc dword ptr ds:[] //第一个CMP内的值

mov dword ptr ds:[XXXX+4],1//XXXX为第二个CMP[]内的值

jmp XXXX//第一个CMP前的地址

修改好后, 去掉所有断点, 向下找到第一个CMP下面的跳转所跳到的地址, 来到这个地址, 下硬件执行断点, Shift+F9运行, 此时代码解压完毕

, 可以脱壳。

3、脱壳。 运行LordPE,将子进程dump出来, 这里的子进程就是LordPE第2个进程(有2个同名进程)。 Dump后用LordPE修改入口点为在第一步中查

到的OEP。

4、修复输入表、IAT的寻找

脱壳后不要急着去修复输入表, 得先把RVA数据获取, 用OD载入Dump出来的程序, 右键搜索二进制字符串, 输入FF25, 找到一个函数, 在数据窗

口跟随, 在数据窗口向上找到全是0的地方, 记下地址, 再向下找到全是0的地方, 记下地址。

5、加载子程序。

(1)找子程序pid的方法有二:

方法一:用OD载入原程序(脱壳前的程序), 下断点:bp DebugActiveProcess, 中断后看堆栈, 记下Processid后面的值(这个值不是每次都

相同的)。 OD不要关。

第二种方法就是用工具ArmaDetach, 将加壳程序拖入。 记下子程序的pid和前两个字节。

(2)另开一个OD, 附加Processid后面的值进程或用工具ArmaDetach所记下的进程id, 附加后, ALT+F9返回程序, 将前两个字节改为原程序载

入时的前两个字节。

6、下面的做法就和标准壳的一样了, 在附加的OD中:

双变单:方法有二。 其一:patch法。 其二修改跳转法。

方法一:下断点BP OpenMutexA(双变单), F9运行, 断下后, ctrl+g到00401000, 将空数据改为如下代码:

0040100060 pushad

004010019C pushfd

00401002 68 A0FD1200 push xxxx(注:此处的xxxx为断下后name前的数值。 )

0040100733C0 xor eax,eax

0040100950 push eax

0040100A50 push eax

0040100BE8 E694A677call KERNEL32.CreateMutexA

004010109D popfd

0040101161 popad

00401012- E9 8F9FA777jmp KERNEL32.OpenMutexA

点右键选择重建eip,f9运行, 断下后,取消断点,  ctrl+g到00401000, 恢复修改。

方法二:下断点BP OpenMutexA, SHIFT+F9运行, 断下后, ALT+F9返回, 返回后, 将返回代码下面的第一个跳转改为相反跳转, 再次SHIFT+F9

, 断下后, ALT+F9返回, 再次将返回代码下面的第一个跳转改为相反跳转。 然后再一次SHIFT+F9,取消断点, 至此,同样,双进程转单进程完毕!

此法相对简单, 另外适用于00401000空数据不能修改的程序。

(2)修改Magic Jump 。

下断BP GetModuleHandleA+5, 运行, 一般是在堆栈窗口出现ASCII "kernel32.dll"和ASCII "VirtualFree后, 再运行一次, 就是返回时机, 中

断后alt+f9返回,在KERNEL32.LoadLibraryA下面找到Magic Jump!修改为jmp。 清除所有断点, 再直接按F9运行, 出现暂停。 这时大功告成。

(3)用Imprec1.6f选择进程附加的那个进程, 填入OEP地址, 填第4步所记下的RAV, SIZE=1000, 不要按自动搜索IAT, 直接按获取输入表, 再

按显示无效地址, 剪掉修复抓取文件就OK了。

(四)全保护脱壳脱壳方法

1、双变单可以用以下方法, 也可以用脚本, 目的是双变单。 记下程序加载时的前两个字节。 运行脚本后, 记下OEP的前两个字节, OEP地址和子

进程ID。

2、用OD附加子进程, 加载后, ALT+F9返回, 修改前两个字节为脚本记载的OEP的前两个字节。

3、处理IATL输入表

方法:(1)用工具ARMADETACH, 将带壳的程序拖入, 记下子进程的ID。 (2)另开一OD, 附加该子进程, 加载后, ALT+F9返回, 修改前两个字

节为加壳程序载入时的前两个字节。 (3)修改Magic Jump , CTRL+G, 输入GetModuleHandleA, 在其下面的第一个跳转下硬件执行断点,

Shift+F9运行, 一般是在堆栈窗口出现ASCII "kernel32.dll"和ASCII "VirtualFree后, 再运行一次, 就是返回时机, 中断后alt+f9返回,在

KERNEL32.LoadLibraryA下面找到Magic Jump!修改为jmp。 往下拉找到两个salc, 在其上面的jmp上下断, Shift+F9, 断下!撤消Magic Jump处

的修改!CTRL+G, 输入GetCurrentThreadId/ CreateThread, 下断, 运行, 中断后, 删除断点, alt+f9返回, F8单步走, 到第一个CALL ECX之

类的东西时, F7进入。 (此时的OEP是伪OEP, 但此时的IAT是正确的。 先开的OEP是对的, 但IAT是错误的)。 (4)打开先前的OD, CTRL+B, 搜

索FF25, 在数据窗口跟随, 找到函数的起始位置, 选定1-3个, 二进制复制, 打开后面所开的OD, 打开内存镜像, 在此界面中点一下, 二进制搜

索, 将刚才复制的粘贴, 找到后, 在转存窗口, 找到函数的起始地址, 选定到末尾, 将选定的函数复制到先前开的OD的数据窗口, 要对整齐(

起点要一样), 这时, 后开的OD的任务完成(目的就是将未加密的IAT找到)。

4、用AMINLINE工具修复, 选择第一个OD所用的子进程, 在Code Splicing中开始Code的地址自动给填好了, 但长度需要设置一下, 大一些,

20000左右就可以了, 修复。 在IAT的长度要根据实际情况, 一般选1000即可, 依次进行修复, 修复后, 在OD中修复的地方都变成红色。

5、用Imprec修复, 无效指针CUT。

6、如果有类似自校验的, 则用AMINLINE工具中的nanomites选项修复。

网友评论
评论(...
全部评论