首页
社区
课程
招聘
Arm3.70a with IAT Elimination脱壳
2004-10-25 18:48 10203

Arm3.70a with IAT Elimination脱壳

2004-10-25 18:48
10203
好久没怎么脱过壳,最近碰到一个软件是用arm加的壳,用到了arm的输入表乱序和远地址跳转,只有找些资料来补课,略有些心得,还望指正。

下面以某软件为例,这个是arm3.70a加的壳,单进程,用了输入表乱序和远地址跳转。某软件已经是双进程CC壳了,还不敢碰,:(

第1部分:准备工作&抵达OEP

先需要找到一些基本数据
1. OEP
设断点he SetProcessWorkingSetSize断下后再设断点he GetCurrentThreadId
断下后,Ctrl+F9返回,去除这两个断点,向下看,看到那个call edi了没,在按F2那里设个断点
断下后,F7跟入,就来到OEP了
记住: OEP=004E8850

2. magicjump
好几个地方修改跳转都可以放置arm破坏输入表的,都可以称之为magicjump
来看arm处理输入表的流程
先将一些预设的api经过处理
然后在读入输入表时候,比较api名称是否为壳中处理过的api名称
如果相同则将该地址指向壳中的函数地址,程序所得到的地址就指向壳里了,importRec就识别不出该

api了

这个虽然代码比较长,不过流程还算清楚,可以跟上几遍就大概知道是怎么回事了
因为相关文章比较多,这里简单看一下

00DC96FD    8D85 B4FEFFFF   LEA EAX,DWORD PTR SS:[EBP-14C]
00DC9703    50              PUSH EAX
00DC9704    FF15 C8B0DE00   CALL DWORD PTR DS:[DEB0C8]               ;

kernel32.GetModuleHandleA
00DC970A    8B0D C04CDF00   MOV ECX,DWORD PTR DS:[DF4CC0]
00DC9710    89040E          MOV DWORD PTR DS:[ESI+ECX],EAX
00DC9713    A1 C04CDF00     MOV EAX,DWORD PTR DS:[DF4CC0]
00DC9718    393C06          CMP DWORD PTR DS:[ESI+EAX],EDI
00DC971B    75 16           JNZ SHORT 00DC9733
00DC971D    8D85 B4FEFFFF   LEA EAX,DWORD PTR SS:[EBP-14C]
00DC9723    50              PUSH EAX
00DC9724    FF15 D0B0DE00   CALL DWORD PTR DS:[DEB0D0]               ;

kernel32.LoadLibraryA
00DC972A    8B0D C04CDF00   MOV ECX,DWORD PTR DS:[DF4CC0]
00DC9730    89040E          MOV DWORD PTR DS:[ESI+ECX],EAX
00DC9733    A1 C04CDF00     MOV EAX,DWORD PTR DS:[DF4CC0]
00DC9738    393C06          CMP DWORD PTR DS:[ESI+EAX],EDI
00DC973B    0F84 AD000000   JE 00DC97EE                           //magicjump 记录该地址


00DC9741    33C9            XOR ECX,ECX

如果是dll可能还需要更改这个地址,od载入dll基地址为10000000,而输入表在该地址以下
造成在ImportRec设不了IAT RVA地址

00DE489D    8B85 1CE8FFFF   MOV EAX,DWORD PTR SS:[EBP-17E4]       //保存当前IAT指针
00DE48A3    8B8D 80E2FFFF   MOV ECX,DWORD PTR SS:[EBP-1D80]
00DE48A9    8908            MOV DWORD PTR DS:[EAX],ECX            //一个api地址写入IAT
00DE48AB    8B85 1CE8FFFF   MOV EAX,DWORD PTR SS:[EBP-17E4]
00DE48B1    83C0 04         ADD EAX,4
00DE48B4    8985 1CE8FFFF   MOV DWORD PTR SS:[EBP-17E4],EAX
对[EBP-17E4]来设内存写断点,可以找到这里
00DE453B    8B8D F0E6FFFF   MOV ECX,DWORD PTR SS:[EBP-1910]       //保存IAT的首地址,记录

该地址值00E9A880
00DE4541    8D0481          LEA EAX,DWORD PTR DS:[ECX+EAX*4]
00DE4544    8985 1CE8FFFF   MOV DWORD PTR SS:[EBP-17E4],EAX       //载入下一个dll的IAT中

首地址

3.antidump
OD把原代码中一些代码,jmp较高的地址了 如jmp 03171000,造成lordpe dump文件时候,这段代码丢

失,
该地址是不是固定的。
可以直接下断VirtualAlloc,查看申请地址值,如果比较大就需要注意了,返回后代码类似下面
00DE2612    6A 40           PUSH 40
00DE2614    68 00200000     PUSH 2000
00DE2619    FFB5 70E6FFFF   PUSH DWORD PTR SS:[EBP-1990]
00DE261F    FF35 3092DF00   PUSH DWORD PTR DS:[DF9230]
00DE2625    FF15 A0B1DE00   CALL DWORD PTR DS:[DEB1A0]               ;

kernel32.VirtualAlloc
00DE262B    8985 78E6FFFF   MOV DWORD PTR SS:[EBP-1988],EAX
00DE2631    83BD 78E6FFFF 0>CMP DWORD PTR SS:[EBP-1988],0
00DE2638    74 33           JE SHORT 00DE266D
00DE263A    6A 40           PUSH 40
00DE263C    68 00100000     PUSH 1000
00DE2641    FFB5 70E6FFFF   PUSH DWORD PTR SS:[EBP-1990]
00DE2647    FF35 3092DF00   PUSH DWORD PTR DS:[DF9230]
00DE264D    FF15 A0B1DE00   CALL DWORD PTR DS:[DEB1A0]               ;

kernel32.VirtualAlloc
00DE2653    8985 78E6FFFF   MOV DWORD PTR SS:[EBP-1988],EAX          //保存codesplit 首地

址 在这里断下修改eax值到一较低地址我选择写到arm的adata节

00DE2659    83BD 78E6FFFF 0>CMP DWORD PTR SS:[EBP-1988],0
00DE2660    74 0B           JE SHORT 00DE266D

记录CodeSplit addr=00DE2653

4. 用脚本来走到OEP
因为要修改的地方比较多,而且后面我们调试脚本难免要重复工作,所以还是写个od脚本吧,可以节省点体力 :)
因为要向rdata段写IAT数据,所以先将该段内存设为可写
Memory窗口选中该段,右键set access ->full access
//脚本1,直达OEP,顺便处理magicjump和antidump
var NewIatHead
var NewSplitCodeHead
var SetIatHead
var SetSplitCodeHead
var IatOver
var MagicJmp
var OEP

var bSplitCodeOver
var bIatOver
var pTempAddr

var VirtualAlloc


//需要填入的信息内容
mov NewIatHead, 5CA000
mov NewSplitCodeHead, 674000
mov MagicJmp, 00DC973B
mov SetIatHead, 00DE453B
mov IatOver, 00DE498E
mov SetSplitCodeHead, 00DE2653
mov OEP, 004E8850


//变量初始化
mov bIatOver, 0
mov bSplitCodeOver, 0

//获得VirtualAlloc首地址
gpa "VirtualAlloc", "kernel32.dll" 
mov VirtualAlloc, $RESULT

BPHWS VirtualAlloc, "x"
run
BPHWC VirtualAlloc

//此时,壳内存代码已分配
//开始设断点
BPHWS MagicJmp, "x"  //magicjump之处
//BPHWS 00994704, "x"  写入内存时
BPHWS SetIatHead, "x"  //载入输入表首地址时候
BPHWS IatOver, "x"  //处理完所有dll
BPHWS SetSplitCodeHead, "x"  //申请高位内存处,需更改返回eax为一段低位内存 

eoe _Exception
eob _Break
run 

//遇例外继续执行
_Exception: 
esto
 
//处理断点中断
_Break:
cmp eip, SetIatHead
je _SetIatHead
cmp eip, MagicJmp
je _MagicJmp
cmp eip, IatOver
je _IATOver
cmp eip, SetSplitCodeHead
je _SetSplitCodeHead
jmp _InvalidBreak


//设置新的IAT首地址
/*
00DE453B    8B8D F0E6FFFF   MOV ECX,DWORD PTR SS:[EBP-1910]       //保存IAT的首地址
00DE4541    8D0481          LEA EAX,DWORD PTR DS:[ECX+EAX*4]
00DE4544    8985 1CE8FFFF   MOV DWORD PTR SS:[EBP-17E4],EAX       //当前IAT指针
*/
_SetIatHead:
mov pTempAddr, ebp
sub pTempAddr, 1910          //看上面数据
mov [pTempAddr], NewIatHead
log NewIatHead
BPHWC SetIatHead
run 

//修改magicjump, 来得到原始的IAT
_MagicJmp:
mov !ZF, 1     //修改magicjump
run 

//maigcjump处理完毕
_IATOver:
BPHWC MagicJmp
BPHWC IatOver
mov bIatOver, 1
cmp bSplitCodeOver,1
je _FixOver
run 

//设置新的保存CodeSplit代码的首地址
/*
00DE263A    6A 40           PUSH 40
00DE263C    68 00100000     PUSH 1000
00DE2641    FFB5 70E6FFFF   PUSH DWORD PTR SS:[EBP-1990]
00DE2647    FF35 3092DF00   PUSH DWORD PTR DS:[DF9230]
00DE264D    FF15 A0B1DE00   CALL DWORD PTR DS:[DEB1A0]               ; 

kernel32.VirtualAlloc
00DE2653    8985 78E6FFFF   MOV DWORD PTR SS:[EBP-1988],EAX          //保存antidump首地址
00DE2659    83BD 78E6FFFF 0>CMP DWORD PTR SS:[EBP-1988],0
00DE2660    74 0B           JE SHORT 00DE266D
*/
_SetSplitCodeHead:
mov eax, NewSplitCodeHead
mov bSplitCodeOver, 1
BPHWC SetSplitCodeHead
cmp bIatOver,1
je _FixOver
run 

//其它未处理的断点
_InvalidBreak:
log eip
msg "Invalid Break"
ret



//IAT,AntiDump处理完毕
//准备跳往OEP
_FixOver:
eoe _Continue
eob _End
BPHWS OEP, "x"
run

_Continue: 
esto 

_End:
BPHWC OEP
msg "Success!"
ret



第2部分. 修复IAT乱序

1, 关于IAT乱序
arm从3.60开始添加了新的功能输入表乱序(ImportTable Elimination)
再我们修改了magicjmp后得到漂亮的IAT, 可惜马上就被arm给破坏了,将顺序打乱,而且算法有些复

杂,不好反求。

00DE498E    8B85 FCE6FFFF   MOV EAX,DWORD PTR SS:[EBP-1904]         //上面的脚本中IatOver

地址
00DE4994    8985 F4CFFFFF   MOV DWORD PTR SS:[EBP-300C],EAX
00DE499A    FFB5 F4CFFFFF   PUSH DWORD PTR SS:[EBP-300C]
00DE49A0    E8 855E0000     CALL 00DEA82A                            ; JMP to msvcrt.??

3@YAXPAX@Z
00DE49A5    59              POP ECX
00DE49A6    83BD F0E6FFFF 0>CMP DWORD PTR SS:[EBP-1910],0
...
00DE4AA2    8985 64E1FFFF   MOV DWORD PTR SS:[EBP-1E9C],EAX
00DE4AA8    8B85 60E1FFFF   MOV EAX,DWORD PTR SS:[EBP-1EA0]
00DE4AAE    8D0485 04000000 LEA EAX,DWORD PTR DS:[EAX*4+4]
00DE4AB5    50              PUSH EAX
00DE4AB6    8B85 F0E6FFFF   MOV EAX,DWORD PTR SS:[EBP-1910]
00DE4ABC    83C0 04         ADD EAX,4
00DE4ABF    50              PUSH EAX
00DE4AC0    FFB5 F0E6FFFF   PUSH DWORD PTR SS:[EBP-1910]
00DE4AC6    FF15 D4B2DE00   CALL DWORD PTR DS:[DEB2D4]               ; msvcrt.memmove  //

将IAT向前循环移动2个DWORD,打乱IAT
00DE4ACC    83C4 0C         ADD ESP,0C
00DE4ACF    8B85 60E1FFFF   MOV EAX,DWORD PTR SS:[EBP-1EA0]
00DE4AD5    8B8D F0E6FFFF   MOV ECX,DWORD PTR SS:[EBP-1910]
00DE4ADB    8B95 64E1FFFF   MOV EDX,DWORD PTR SS:[EBP-1E9C]
00DE4AE1    891481          MOV DWORD PTR DS:[ECX+EAX*4],EDX
00DE4AE4  ^ E9 47FFFFFF     JMP 00DE4A30

使得我们在ImportRec中看到这样排列的IAT,从而无法生成新的输入表
1        001CA0D0        kernel32.dll        01A7        GetProfileIntA
1        001CA0D4        comctl32.dll        002B        ImageList_AddMasked
1        001CA0D8        user32.dll        005B        CreateIconIndirect
1        001CA0DC        user32.dll        00F7        GetClassInfoA
1        001CA0E0        gdi32.dll        01CE        LineTo
1        001CA0E4        user32.dll        008F        DefWindowProcA
1        001CA0E8        kernel32.dll        015C        GetFileSize
1        001CA0EC        gdi32.dll        01BA        GetTextFaceA
1        001CA0F0        gdi32.dll        01C3        GetWindowExtEx

2. 整理IAT
在Ricardo Narvaja的203-208教程中给出了一个很脚本,用来整理IAT,生成一个新的排列整齐的IAT,

原来的IAT中的地址值则改为指针指向这个新IAT表中的项,这个脚脚本说明参见Ricardo的207教程。里面跳转有点多,我估摸着加了点注释。

举例
原先IAT中一项为
005CA000  45 2D E1 77                                      E-狩今
在运行脚本后
005CA000  D0 AD 5C 00                                      协\.?
005CADD0  45 2D E1 77                                      E-狩p
当然这样做以后,call所调用的地址就不对了
call [005CA000]     // 77E12D45call Kernel32.SetUnhandledExceptionFilter
故而Ricardo 在OEP处插入了一段程序来,将排列好的IAT,再次还原到原先打乱的状态,不过这样出

来的程序在静态反编译时,函数会识别不出,不便于分析。
在下面1节将会采用一段脚本来处理这个问题
在OEP处运行

//脚本2,将ARM混乱的IAT重新整理
//来自Ricardo Narvaja的207号教程,略做修改

var it
var it2
var x
var y
var pit
var pit2
var dll              
var dll1            
var pitt
var it1_end
var base
var savecode

//需要设定的内容
mov it,5CA000        //混乱IAT首址
mov it1_end,5CAD90    //混乱IAT末址
mov it2,5CADD0        //待存放整理后的IAT首址

//
mov savecode,[eip]   //保存当前eip指向内容
mov [eip], #EBFE#    //jmp eip,由于整理IAT比较慢,用于待会刷新界面,防界面假死 

gmi eip, MODULEBASE    //取主文件的基址
log $RESULT
mov base,$RESULT

INICIO:              //初始化
mov pitt,it          //pitt指向当前正在处理api地址,其前所有api均被处理完毕
                     //pitt每一轮增加4,当其等于混乱后IAT末址时,则该脚本运行结束
COMIENZO:
add pit,it
add pit2,it2

SEGUIMOS: //WE FOLLOWED  新的循环开始

add pit,x
add pit2,y
cmp pit,it1_end
log pit
log x
log y
je FIN
cmp pit,it1_end
ja FIN

gmi [pit], MODULEBASE    //取该api对应的模块基址
log $RESULT
log dll1
cmp pit,pitt
jne NOPRIMERA

cmp $RESULT,base       //该地址处api,是否已被处理过,若被处理过则其基址为主文件基址base
je PIRULO              //处理过则跳转到下一轮

cmp $RESULT,dll1       //这两句好像没用,如果前1个dll已被处理过,这里根本不会跳转
je IGUALES
mov dll, $RESULT
log dll
jmp NOPRIMERA

NOPRIMERA:       //not first
cmp $RESULT,dll
jne NOGUARDO

//该地址处api,是否已被处理过,若被处理过则其基址
//例如,处理后该005CA000处内容为005CADD0,取其对应模块基址为为主文件基址base
cmp $RESULT,base     
je NOGUARDO          //处理过则跳转到下一轮
mov [pit2], [pit]    //将混乱后IAT保存api移入新地址,原地址存放指针指向新地址 
mov [pit], pit2
mov x,4
mov y,4
jmp FINLOOP

NOGUARDO:    //I do not keep
mov x,4
mov y,0
jmp FINLOOP

FINLOOP:      //1轮小循环结束
log pit
log pit2
jmp SEGUIMOS


IGUALES: //EQUAL 没啥用?
mov x,4
mov y,0
jmp FINLOOP


FIN:              //1个dll处理完毕
mov [pit2],0
mov dll1,dll
sto              //防界面假死,刷新od界面
xor x,x
xor y,y
add pitt,4
cmp dll,base
je SALTO

add pit2,4

SALTO:          //JUMP
mov pit,pitt
cmp pitt,it1_end
je FINISH
cmp pitt,it1_end
ja FINISH
log pit
log pit2
log pitt
jmp SEGUIMOS

FINISH:            //所有dll都已被处理完毕
mov [eip],savecode //保存当前eip指向内容
MSG "TERMINAMOS"
log pitt
ret

PIRULO:         //该地址api所在dll已被处理过,故跳过该地址,重新开始一轮
add pitt,4
jmp NOPRIMERA


3. 修复代码段调用
在Ricardo的教程中在OEP处插入了一段程序来,将排列好的IAT,再次还原到原先打乱的状态,不过这

样出来的程序在反编译时,不能自动识别出调用的函数,颇为不爽。
我们来想办法来解决这个问题。

我们在程序中随便找一个api调用,比如这个
004E8873    8965 E8         MOV DWORD PTR SS:[EBP-18],ESP
004E8876    FF15 E4AC5C00   CALL DWORD PTR DS:[5CACE4]               ;

kernel32.GetVersion

004E8876  FF 15 64 B5 E9 00                                ?d甸.3

设硬件写DWORD断点004E8878,来看看壳是什么时候在代码段写入的该api地址

重新运行程序,第1次断下时是代码段解压,在第二次断下时候
00DE553A    8B85 E4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F1C]
00DE5540    40              INC EAX
00DE5541    8985 E4D0FFFF   MOV DWORD PTR SS:[EBP-2F1C],EAX
00DE5547    8B85 E4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F1C]
00DE554D    8B8D 30E8FFFF   MOV ECX,DWORD PTR SS:[EBP-17D0]   //保存call调用表首地址

00E9B628 在这里查看表格首地址
00DE5553    833C81 00       CMP DWORD PTR DS:[ECX+EAX*4],0    //取表中1项
00DE5557    0F84 90000000   JE 00DE55ED
00DE555D    8B85 E4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F1C]
00DE5563    8B8D 30E8FFFF   MOV ECX,DWORD PTR SS:[EBP-17D0]
00DE5569    8B95 18E7FFFF   MOV EDX,DWORD PTR SS:[EBP-18E8]
00DE556F    031481          ADD EDX,DWORD PTR DS:[ECX+EAX*4]
00DE5572    8995 D4D0FFFF   MOV DWORD PTR SS:[EBP-2F2C],EDX
00DE5578    8B85 D4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F2C]
00DE557E    8B00            MOV EAX,DWORD PTR DS:[EAX]
00DE5580    8985 D0D0FFFF   MOV DWORD PTR SS:[EBP-2F30],EAX
00DE5586    81BD D0D0FFFF 9>CMP DWORD PTR SS:[EBP-2F30],90909090
00DE5590    74 56           JE SHORT 00DE55E8
00DE5592    8B85 D0D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F30]
00DE5598    2B85 E0D0FFFF   SUB EAX,DWORD PTR SS:[EBP-2F20]
00DE559E    8985 D0D0FFFF   MOV DWORD PTR SS:[EBP-2F30],EAX
00DE55A4    FFB5 D0D0FFFF   PUSH DWORD PTR SS:[EBP-2F30]
00DE55AA    8B85 E4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F1C]
00DE55B0    33D2            XOR EDX,EDX
00DE55B2    6A 10           PUSH 10
00DE55B4    59              POP ECX
00DE55B5    F7F1            DIV ECX
00DE55B7    FF1495 48B7DE00 CALL DWORD PTR DS:[EDX*4+DEB748]    //计算该api在IAT中的索引
00DE55BE    59              POP ECX
00DE55BF    8985 D0D0FFFF   MOV DWORD PTR SS:[EBP-2F30],EAX
00DE55C5    8B85 D0D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F30]
00DE55CB    8B8D F0E6FFFF   MOV ECX,DWORD PTR SS:[EBP-1910]
00DE55D1    8D0481          LEA EAX,DWORD PTR DS:[ECX+EAX*4]   //得到该api在IAT中地址
00DE55D4    8985 D0D0FFFF   MOV DWORD PTR SS:[EBP-2F30],EAX
00DE55DA    8B85 D4D0FFFF   MOV EAX,DWORD PTR SS:[EBP-2F2C]
00DE55E0    8B8D D0D0FFFF   MOV ECX,DWORD PTR SS:[EBP-2F30]
00DE55E6    8908            MOV DWORD PTR DS:[EAX],ECX         //写入call [XXX] 的调用地


00DE55E8  ^ E9 4DFFFFFF     JMP 00DE553A  //断在这里

走到这里,看看[EBP-17D0]所指向的内存
00DE554D    8B8D 30E8FFFF   MOV ECX,DWORD PTR SS:[EBP-17D0]   //00E9B628 保存call调用表首

地址

00E9B628  4B 10 00 00 92 10 00 00 A7 10 00 00 B8 10 00 00  K..?..?..?..
00E9B638  EA 10 00 00 14 11 00 00 64 11 00 00 75 11 00 00  ?....d..u..
00E9B648  88 11 00 00 AB 11 00 00 0C 12 00 00 30 12 00 00  ?..?.....0..
00E9B658  B8 12 00 00 CB 12 00 00 E8 12 00 00 37 13 00 00  ?..?..?..7..
00E9B668  AC 13 00 00 B8 14 00 00 C0 14 00 00 D6 14 00 00  ?..?..?..?..
......
00EA2B88  9B 77 1B 00 A8 77 1B 00 06 78 1B 00 79 78 1B 00  ?.?.x.yx.
00EA2B98  EB 78 1B 00 E0 79 1B 00 20 7A 1B 00 7F 7A 1B 00  滕.帙. z.z.
00EA2BA8  00 00 00 00                                      ....
^_^,call调用所在地址表,这正是我们需要的,call所在的RAV地址,这样就可以用这张表来修复

call[XXX]的地址值了,使之直接指向我们的整理后的IAT,不需要原先的IAT做跳板。

拷贝该表格到WinHex中,待会好再粘贴回来,运行脚本

现在再次来到运行前面的脚本到达OEP之处,
然后运行Ricardo的脚本,整理打乱的IAT,然后随便找个空地将刚才得到的call调用地址表binary

paste,
比如我粘贴到00E92000开始的内存里
然后再运行一个小脚本
//脚本3,修改代码段call [XXX],到整理后的IAT
var pCallTable  //存放call调用所在之处的RVA地址表
var calladdr
var base
var iataddr
var goodiat

//设置Call RVA 地址表所在位置
mov pCallTable ,0E92000

//获取当前模块基地址
gmi eip, MODULEBASE 
log $RESULT
mov base, $RESULT

NEXT:
mov calladdr, [pCallTable]
cmp calladdr, 0
je FIN
add calladdr, base              //RVA+base=VA
mov iataddr, [calladdr]         //得到原始IAT表中地址(间接指针,指向整理后得IAT中的地址)
log calladdr
mov goodiat, [iataddr]          //得到整理后得IAT中该api地址
mov [calladdr], goodiat         //修改原始代码中call XXXX中XXXX的地址,指向整理后的IAT
add pCallTable,4
JMP NEXT

FIN:
MSG "Success!"
ret


OK,再看看刚才的那个api调用已经直接指向那个整理后的IAT中了
004E8873    8965 E8         MOV DWORD PTR SS:[EBP-18],ESP
004E8876    FF15 68B05C00   CALL DWORD PTR DS:[5CB068]               ;

kernel32.GetVersion

4. dump&fix

现在用LordPE dump下来,然后用ImportRec修复,填入OEP,RVA及RVASIZE
OEP=00E8850 IATRVA=1CADD0 大小0D90,将Invalid的全部cut。
修复以后运行一下看看,ok了,累 :)

感谢Ricardo,Eggi的教程。已上传至http://bbs.pediy.com/showthread.php?s=&threadid=5962

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞7
打赏
分享
最新回复 (18)
雪    币: 896
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
fly 85 2004-10-25 18:56
2
0
GOOD   辛苦  :D
雪    币: 205
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flyfox 2004-10-25 19:25
3
0
好文。
雪    币: 124
活跃值: (107)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
狗剩 1 2004-10-25 19:31
4
0
顶。
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
stephenteh 2004-10-25 19:59
5
0
nice tut...
keep up good work..:)
雪    币: 383
活跃值: (786)
能力值: ( LV12,RANK:730 )
在线值:
发帖
回帖
粉丝
askformore 18 2004-10-25 20:30
6
0
Yeah, 期代你对付 CC :D
雪    币: 223
活跃值: (106)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
temerata 1 2004-10-25 20:42
7
0
老大很久不上,一上来就是好文呀!:D
雪    币: 282
活跃值: (233)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
wangli_com 5 2004-10-25 20:45
8
0
谢谢,无私的奉献
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
softworm 30 2004-10-25 20:46
9
0
强!
雪    币: 250
活跃值: (105)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
baby 2004-10-26 02:10
10
0
佩服,收下。 arm新版是越来越烦。
雪    币: 282
活跃值: (233)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
wangli_com 5 2004-10-26 10:28
11
0
老大什么时候能看看双进程的,比如Arm375a1.exe,我用kernel32.VirtualAlloc函数什么有用的东西也没拦到,而且它把代码段用异或加密了,而且改变magicjump跳转后,一部分代码也丢失了,我脱出来了,也修复了cc,但是一压缩文件就出错,如下图:
老大能帮忙看看吗?
雪    币: 323
活跃值: (579)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
springkang[DFCG 11 2004-10-26 11:35
12
0
呵呵,很久没能见到你的大作啦,强烈支持一下!
雪    币: 251
活跃值: (260)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
yesky1 5 2004-10-26 20:03
13
0
最初由 wangli_com 发布
老大什么时候能看看双进程的,比如Arm375a1.exe,我用kernel32.VirtualAlloc函数什么有用的东西也没拦到,而且它把代码段用异或加密了,而且改变magicjump跳转后,一部分代码也丢失了,我脱出来了,也修复了cc,但是一压缩文件就出错,如下图:
老大能帮忙看看吗?

这个对我还太难了,:(
这位xDREAM发布了arm3.75a的破解,也许你可以和他联系讨论一下 :)
http://www.exetools.com/forum/showthread.php?t=5681
雪    币: 241
活跃值: (160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiluoyou 2004-10-26 21:43
14
0
顶一下,慢慢看
雪    币: 220
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
XCyber 2 2004-10-27 10:15
15
0
收藏阿!谢谢yesky1大哥
雪    币: 236
活跃值: (54)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ijia 2004-10-27 18:24
16
0
最初由 yesky1 发布

这个对我还太难了,:(
这位xDREAM发布了arm3.75a的破解,也许你可以和他联系讨论一下 :)
http://www.exetools.com/forum/showthread.php?t=5681


能贴一份过来吗?
雪    币: 220
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
XCyber 2 2004-10-27 18:49
17
0
多谢yesky1大哥的指导和Ricardo的教程,Ricardo的教程确实写得很透彻,从中学到了不少分析方法,但是在看他的乱序iat修复方法时,觉得很费解(其实是没看懂,哈哈)。觉得既然我们可以得到正确的iat表和call/jmp地址表,那么为什么不直接修复iat呢?尝试写了个修复脚本,跟yesky1大哥一样都是用要用到call/jmp地址表,具体方是:在修改magic jmp,arma把iat的所有api地址还原后,并且在arma把iat混乱前(这个位置可以取magic jmp后有一个往前跳的大jmp的下一条指令),把正确的iat拷下来,放到一个无用空间,然后call/jmp地址表也一样处理,运行到oep处,这时jmp dword ptr[xxxxxxx]的xxxxxxx是乱序iat中的一个地址,我们读取该api地址值,然后在正确的iat表里面找,找到后就把xxxxxxxx替换成该api地址在正确iat表里的地址。脚本如下:

======================================================================
/*
在oep运行该脚本。
运行前必须先得到一张正确的iat表和远地址jmp/call地址表
*/

var imagebase
var iat_table
var jmp_table
var piat
var pjmp
var viat
var vjmp
var temp
var oldpiat

gmi eip,MODULEBASE     //获得基地址
mov imagebase,$RESULT
log imagebase

ask "new iat table:"
cmp $RESULT,0
je error
mov iat_table,$RESULT  //iat_table:正确iat的地址.修改magic jmp后,并且被乱序之前得到的iat
log iat_table

ask "new jmp table:"
cmp $RESULT,0
je error
mov jmp_table,$RESULT //复制的call调用表的地址,在文中是00E92000
log jmp_table

mov pjmp,jmp_table   //取jmp table的首地址
jmp loop1

loop0:
add pjmp,4          //下一个jmp的地址

loop1:
mov vjmp,[pjmp]     //取jmp table的一个值,就是一个jmp的地址索引
cmp vjmp,0          //如果0,结束
je finish
add vjmp,imagebase  //加上基地址就是该jmp的VA
mov piat,iat_table  //取得新的iat首地址
jmp loop2

loop21:
add piat,4          //下一个api地址指针

loop2:
mov viat,[piat]     //得到api地址
cmp viat,ffffffff   //如果ffffffff结束。注意,该脚本是通过iat中api指针为ffffffff,
                    //判断是否结束,所以要保证iat结束处是ffffffff,并且iat中间不能有ffffffff
je loop0
mov temp,[vjmp]    //得到乱序iat中队应api地址的指针
mov oldpiat,temp   
mov temp,[temp]    //得到api地址
cmp temp,viat      //上面的到api地址与正确的iat表的每一个api地址进行比较,
jne loop21
mov [vjmp],piat   //如果相等就修改。这样就可以对每一个远地址jmp和call进行修复
log oldpiat       //修复前的api地址指针(在乱序的iat表内)
log piat          //修复后的api地址指针(在新的iat表内)
jmp loop0

finish:
msg "finish"
jmp end

error:
msg "error"

end:
ret
==========================================================================
这样会省点功夫,不过运行脚本会挺耗时,耐心等等。

小弟刚接触armadillo不久,当时是为了破解一个叫prtg v4.0.7.139软件,拜读了无数篇破文,在搞定了
debug-blocker,code splicing和import table elimination后,用ollydby装入,发现还加了CC:

0069F13E     E8 7163D6FF         call dumped_.004054B4
0069F143     CC                  int3
0069F144     7A 8D               jpe short dumped_.0069F0D3
0069F146     45                  inc ebp
0069F147     F8                  clc
0069F148     BA 04F36900         mov edx,dumped_.0069F304                  ; ASCII " (Site License)"
0069F14D     E8 EE5FD6FF         call dumped_.00405140

看了fxyang的《UltraEdit-32 10.20版脱壳记》还是不理解,各位大哥可否再指点一下啊?先谢了

雪    币: 217
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
骨灰C 2004-11-4 08:37
18
0
可以自己在oep前模拟这段混乱代码
雪    币: 78
活跃值: (115)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
采臣·宁 1 2004-11-4 13:34
19
0
有没有脱壳机啊?
游客
登录 | 注册 方可回帖
返回