- UID
- 65321
注册时间2010-2-1
阅读权限30
最后登录1970-1-1
龙战于野
TA的每日心情 | 怒 2021-3-15 02:34 |
---|
签到天数: 347 天 [LV.8]以坛为家I
|
以《硕思闪客精灵 企业版》为例子。PEiD载入,看区段,显然是Armadillo,现在用Armadillo Find Protector看一下有啥保护:
<- 02-12-2010 18:17:59 - [2.0] ->
G:\Program Files\SourceTec\SWFDecompiler_2.exe
Protected Armadillo
<-Find Protect
Protection system (Professional)
<Protection Options>
Standard protection or Minimum protection
Import Table Elimination
Strategic Code Splicing
<Backup Key Options>
Variable Backup Keys
<Compression Options>
Minimal/Fastest Compression
<Other Options>
Disable Monitoring Thread
<-Find Version
Version 7.00 26-10-2009
<- Elapsed Time 00h 00m 00s 453ms ->
复制代码
似乎是单进程的,那就好办了。果断SMC之。
我们先找到要爆破的地方,这个地方是lkou版主告诉我的,我自己没调试出来(!-_-)。在程序运行起来之后,需要Patch几个地址:
[0x4468E4]->0x37
[0x446738]->0x179E9
[0x44673C]->0xDE89000
复制代码
试一试,在入口点的时候patch掉这几处的代码果然可以变成了正版。lkou版主说他用了不到十分钟就搞掉了……我硬是没调出来。
下面有必要知道一些Armadillo的特点,Armadillo的壳主要是在一个ArmAccess.dll里边,外壳加载的时候首先调用VirtualAlloc分配一段内存,然后模拟PE加载器把DLL加载进去,然后把流程转移到DLL里,DLL完成主要的流程。DLL大概会做一点事情就是,首先是进行文件校验,然后处理IAT,最后解压代码啥的啥的。
SMC的流程是这样的:在DLL加载完毕后劫持流程,因为我们修改了文件,所以要绕过文件校验。之后是在壳解压原始代码之后进行Patch,相当于内存补丁。
所以,我们需要在三个地方插入代码:加载DLL完毕的时候,壳自校验的时候,原始代码解压完毕的时候。
首先说一下如何找DLL加载完毕的时机,OD载入程序,搜索字符串“SetFunctionAddresses”,会找到这里:
00BC40EB |> \6A 00 push 0x0
00BC40ED |. 6A 01 push 0x1
00BC40EF |. A1 4CC3C200 mov eax, dword ptr [0xC2C34C] ; 这里就保存着dll的基址
00BC40F4 |. 50 push eax
00BC40F5 |. FF15 50C3C200 call dword ptr [0xC2C350] ; call DLL 入口
00BC40FB |. 85C0 test eax, eax
00BC40FD |. 75 11 jnz short 00BC4110
复制代码
既然在00BC40EF从0xC2C34C处取出dll的基址,就一定有另外一个地方把dll的基址写入0xC2C34C。所以我们搜索常量,可以到这里:
00BC4D3A . A3 4CC3C200 mov dword ptr [0xC2C34C], eax
00BC4D3F 8B45 08 mov eax, dword ptr [ebp+0x8]
00BC4D42 8BE5 mov esp, ebp
00BC4D44 . 5D pop ebp
00BC4D45 . C3 retn
复制代码
很显然,这个时候把DLL的代码解压完毕,并把基址保存到了0xC2C34C里。我一般选择在00BC4D3F处SMC,这样可以更简单,而且不用考虑重定位。SMC代码里面eax就是基址了。记下00BC4D3F,作为第一处Patch的地址。
下面我们来找原始的文件校验值,bp OutputDebugStringA,运行两次之后返回,代码是这样的:
0287D82C FF15 4C928B02 call dword ptr [0x28B924C] ; kernel32.OutputDebugStringA
0287D832 C705 6C4A8D02 A4F7>mov dword ptr [0x28D4A6C], 0x28BF7A4
0287D83C 8B0D 1C938D02 mov ecx, dword ptr [0x28D931C] ; SWFDecom.00C1C4E0
0287D842 8B15 1C938D02 mov edx, dword ptr [0x28D931C] ; SWFDecom.00C1C4E0
0287D848 A1 1C938D02 mov eax, dword ptr [0x28D931C]
0287D84D 8B40 78 mov eax, dword ptr [eax+0x78]
0287D850 3342 58 xor eax, dword ptr [edx+0x58]
0287D853 3341 2C xor eax, dword ptr [ecx+0x2C]
0287D856 3345 F0 xor eax, dword ptr [ebp-0x10] ; ***********
复制代码
注意0287D856,输入dd ebp-0x10,看数据窗口:
0012F308 13388778
0012F30C 48963C67
0012F310 F76562B1
0012F314 10181326
0012F318 00000000
0012F31C 720DAEB2
复制代码
这五个值就是原始文件的校验值,只要我们在这里恢复文件校验,就可以任意的修改文件了。
接下来是找一找代码解压的时机,这里是跟他们学的,劫持VirtualProtect然后判断对应地址的数据是不是0就可以了。大家看代码就好了。
下面开始SMC。先让00BC4D3F处的代码跳到我们的SMC代码:
00BC4D3F - E9 BC620400 jmp 00C0B000 ; 跳到00C0B000
复制代码
在00C0B000处补上代码:
00C0B000 60 pushad ; 保存寄存器
00C0B001 54 push esp ; 分配一个栈空间
00C0B002 54 push esp ; 修改内存保护
00C0B003 6A 40 push 0x40 ; 可读可写可执行
00C0B005 68 00A00F00 push 0xFA000 ; buffer的大小
00C0B00A 8B4424 2C mov eax, dword ptr [esp+0x2C] ; 取出dll基址
00C0B00E 50 push eax ; 修改dll的属性
00C0B00F FF15 6CB0C100 call dword ptr [<&KERNEL32.VirtualProtect>] ; kernel32.VirtualProtect
00C0B015 58 pop eax
00C0B016 61 popad ; 堆栈平衡
00C0B017 C780 4C920B00 32B0C>mov dword ptr [eax+0xB924C], 00C0B032 ; Hook OutputDebugStringA
00C0B021 C780 54910B00 64B0C>mov dword ptr [eax+0xB9154], 00C0B064 ; Hook VirtualProtect
00C0B02B 8B45 08 mov eax, dword ptr [ebp+0x8] ; 恢复原来的代码
00C0B02E 8BE5 mov esp, ebp
00C0B030 5D pop ebp
00C0B031 C3 retn
00C0B032 8B0424 mov eax, dword ptr [esp] ; 调用OutputDebugStringA流程会到这里,首先取出返回地址
00C0B035 8178 1E 33425833 cmp dword ptr [eax+0x1E], 0x33584233 ; 然后判断是不是到校验的地方
00C0B03C 75 23 jnz short 00C0B061
00C0B03E C745 F0 B2AE0D72 mov dword ptr [ebp-0x10], 0x720DAEB2 ; 如果是,就恢复校验值
00C0B045 C745 E8 26131810 mov dword ptr [ebp-0x18], 0x10181326
00C0B04C C745 E4 B16265F7 mov dword ptr [ebp-0x1C], 0xF76562B1
00C0B053 C745 E0 673C9648 mov dword ptr [ebp-0x20], 0x48963C67
00C0B05A C745 DC 78873813 mov dword ptr [ebp-0x24], 0x13388778
00C0B061 C2 0400 retn 0x4 ; OutputDebugStringA只是一个反调试,返回就好
00C0B064 C74424 0C 40000000 mov dword ptr [esp+0xC], 0x40 ; 这里是Hook VirtualProtect,我们修改属性为可读可写可执行。
00C0B06C 803D E3684400 00 cmp byte ptr [0x4468E3], 0x0 ; 判断是否解压完毕
00C0B073 74 1B je short <jmp.&KERNEL32.VirtualProtect>
00C0B075 C605 E4684400 37 mov byte ptr [0x4468E4], 0x37 ; 开始补代码
00C0B07C C705 38674400 E9790>mov dword ptr [0x446738], 0x179E9
00C0B086 C705 3C674400 0090E>mov dword ptr [0x44673C], 0xDE89000
00C0B090 - FF25 6CB0C100 jmp dword ptr [<&KERNEL32.VirtualProtect>] ; kernel32.VirtualProtect,继续执行。
复制代码
其实原来的SMC代码比较麻烦,昨天晚上洗澡的时候突然觉悟了,其实可以写的更简单的。
谢谢观赏。
转自 CjwNull |
|