信息来源:邪恶八进制信息安全团队
翻译作者: Regkiller
文中用到的工具下载地址:
TibiaBotNG3.6
http://forums.tibiabot.com/setup-3.6.exe
tibia76
http://download.tibia.com/tibia76.exe
UnpackingArmadillo3.xxDLL
Whiterat//ICUToolsNeeded需要工具
OllyDBG
LordPE
Imprec
ReloXTarget
TargetTibiaBotNG3.4
Homepagehttp://www.TibiaBot.com
PEiDArmadillo2.51-3.xxDLLStub->SiliconRealmsToolworks
目标
目标TibiaBotNG3.4
主页http://www.TibiaBot.com
PEiDArmadillo2.51-3.xxDLLStub->SiliconRealmsToolworks
Introduction
InthistutorialwearegoingtohaveagoatunpackinganArmadillo3.xxDLL.
Usuallythisisquiteaneasytask,butthisprogramseemstomessuptherelocationtable...
SOLETSFIXIT
介绍
在这篇教程中我们将要着手于一个Armadillo3.xxDLL.
通常这是十分简单的任务,但是这个程序似乎陷入了重定位表的困境中...
所以让我们来修复她Start
开始
FireupOllyDBG,andyoushouldlandsomewherelikethis:
打开OD,然后你向这样停在某处:

NowmakesurethatIsDebuggerPresenthasbeenhiddenandthatallexceptionsareignored.
NowletssetabreakpointonVirtualProtect:
现在确定IsDebuggerPresent已经隐藏同时忽略所有异常.
我们设置一个VirtualProtect断点:

ThenpressShift+F9torununtilitbreaks.
Itwillbreak5or6timesandwilllooklikethis:
然后按Shift+F9直到程序中断
她将中断5或6次然后看到堆栈如下提示:

WearelookingforacalltoVirtualProtectfromaDynamiclyAllocatedarea,thisiscalledfrom00A2C892
Whichisin.textsothisisnttheonewewant.
AfterwehavepassedalltheVirtualProtect'swedontwantyouwillseetheArmadilloNAGScreen:
我们寻找一个来自动态分配区的VirtualProtect调用,这个call调用来自于00A2C892
这是哪的?.text段的,所以这不是我们想要的.
在我们通过了所有的VirtualProtect我们不想你看到ArmadilloNAG窗口

AfterpressingOKweshouldbreakonanotherVirtualProtect:
当按下OK后我们会中断在另一个VirtualProtect:

NoticethisiscalledfromaDynamicArea?SoThisisthecallwewerelookingfor!
PressCtrl+F9(NOTSHIFT)thenShift+F7tostepoutofthecallbackintothecode.
Thengotothetopofthesectionandsearchfor"Push100",searchuntilyoufindthis:
注意这个调用是否来自一个动态区?所以这就是我们要找的call!
按Ctrl+F9(不是SHIFT)然后Shift+F7步出回调到代码。
然后来到段顶并查找Push100直到找到这些:

InorderfortheIATtobecleananduseableyoumustchangethePUSHEBPintoRETN
NowremovetheBreakpointonVirtualProtectandplaceoneonCreateThread
Whenitbreaksopenthememorymap(Alt+M)andplaceBreak-On-AccessforCODEsection:
你必须修改PUSHEBP为RETN来跳过ARM加密IAT
现在清除VirtualProtect断点,然后下另一个CreateThread断点
当中断后Alt+M打开内存映射窗口,然后在代码段下"在访问上设置中断":

NowremovethebreakpointonCreateThreadandthenpressShift+F9
YouwillnowbreakontheOEP:
现在清除CreateThread然后按Shift+F9
你将中断在OEP:

NowwehavetoDumpwithLordPE,selectLoadDLLthenrightclick"Hook.dll"andselectFullDump
现在我们用LoadPE转存,选择LoadDLL然后右键单击Hook.dll选择“完整转存”

AfterDumpingfireupImprec,selectLoadDLLagainthenclickPickDLLandchooseHook.dll
转存后打开ImportREC再次选择LoadDLL然后”选取DLL“并选择Hook.dll

TheOEPis009E1D7CandtheImagebaseis00870000
DuetothelimitationsofImprecwehavetofiddlethispart...
Subtract00400000NOT00870000fromtheOEPandwegettheOEPImprecneeds.(005E1D7C)
(DoNotPressGetimportsyet)
OEP是009E1D7C镜象基址是00870000
由于ImportREC有局限性,我们必须欺骗这部分...
从OEP处减去00400000而不是00870000然后就得到了ImportREC需要的OEP(005E1D7C)
(还没按下Getimports)
NowweneedtheRVAandSizeoftheIAT,todothisleaveImprecopenthenreturntoollydbgandgotothetopofthesection(PressHome)thenpressCtrl+BandenterthehexFF25andsearch,Youshouldlandonthisline:
00871250-FF2570D29E00JMPDWORDPTRDS:[9ED270];kernel32.CloseHandle
NowRightClick>FollowInDump>MemoryAddress
TomakeiteasiertoviewRightclickinthedumpandselectLong>Address.
NowscrollupuntilyoucanseewhatlookstobethestartoftheIAT:
现在我们需要IAT的RVA和Size,保留ImportREC为打开状态,然后返回到OD(按Home键)来到段顶Ctrl+B输入十六进制FF25并搜索。你会来到这行:
00871250-FF2570D29E00JMPDWORDPTRDS:[9ED270];kernel32.CloseHandle
右键单击>数据窗口中跟随>内存地址
为了更方便地查看,在转存窗口右键单击选择长型>地址
向上滚动你将看到IAT的起始地址

(Notedowntheaddressnexttothepointer(009ED1B0forus)asweneeditlater)
NowScrolltheoppositewayuntilyoufindwhatlooksliketheendoftheIAT:
记下009ED1B0,一会我们会用到
现在向相反方向滚动直到找到IAT的结束地址:

(Notedowntheaddressnexttothepointer(009EDA44forus)asweneeditlater)
SotheRVAfortheIATis009ED1B8minus00400000=005ED1B8
TheSizeoftheIATis009ED1B8-009EDA44=884
NowenterthisinformationintoImprecandclickGetImports(NotIATAutoSearch):
记下009EDA44,一会我们会用到
所以IAT的RVA是009ED1B8减去00400000=005ED1B8
IAT的Size是009ED1B8-009EDA44=884
现在把这些信息输入到ImportREC然后点"获取输入表"(不是自动搜索IAT):

ClickShowInvalid,thenrightclickandInvalidpointerandchooseCutThunks
点显示"无效函数",然后在无效指针上点右键选择”剪切指针“

NOWWAIT!BeforeyougoclickingFixDumpwehaveavitaltaskleft.
WeneedtherealRVAfortheOEPandIATStart
SotherealOEPRVAis009E1D7Cminus00870000=00171D7C
TherealRVAfortheIATis009ED1B8minus00870000=0017D1B8
SoplacethosevaluesintoImprec:
在修复抓取文件之前等一下,我们还有一个重要的任务
我们需要真正的OEP的RVA和IAT的起始
所以真正的OEPRVA是009E1D7C-00870000=00171D7C
真正的IATRVA是009ED1B8-00870000=0017D1B8
所以在ImportREC中输入这些值

NowclickFixDumpandselectthefileyoudumpedwithLordPEearlier.
NowletsjusttidyuptheDLLbyloadingthePEEditorinLordPE
ChangetheImagebaseto00870000andtheBaseOfCodeto1000thensaveit
现在点"修复抓取文件"并且用LordPE载入你前面转存的文件.
现在我们用LordPE的PEEditor来整理这个DLL
修改镜像基址为00870000代码基址为1000然后保存
Usuallythiswouldbetheendofunpackingthefile(besidesremovingtheunusedsections).
Butthisapphassometrickswhichdamage/invalidatetheRelocationTableinsomeway.
Usuallyyousimplychangetheaddress+sizeoftheRelocationTableinDirectoryInformationfrom.reloc1tomatch.reloc
ThisdoesntworkforthisappsowemustrebuildtheRelocationtable.
通常脱壳到这将要结束了(除删除一些无用的区段外)
但是这个程序的重定位表的某些方面有一些损坏的/无效的tricks
通常你可以简单的修改"目录"信息中的重定位表从reloc1去匹配reloc的地址和大小
但这样不能使这个程序运行,所以我们必须重建重定位表
NowplacethisDLLsomewheresafe
现在把这个DLL放到一个安全的地方
Wenowneedtohave2almostidenticaldumps(SameOEP,Header,GoodIAT)butwithdifferentimagebasesatthetimeofdumping.
Wealreadyhaveonefromabove,butthatwasmadeusingLoadDLL.
Weneedadumpfromtheactualtargetprogramaswell,inthiscaseTibiaBotusesaloadertoinjecthook.dllintotheactiveprocessTibia.exe(TheGamethiswasdesignedfor).
SowemuchloadTibia.exeintoOllyDBGandrunit,thengotoDebuggingOptionsandSelectBreakonNewModule
现在我们需要2个几乎一模一样的Dump文件(同样的OEP,Header,正确的IAT),但是转存的时候不能是相同的基址。
我们已经从上面得到了一个,但是她是用LoadDLL生成的.
我们需要一个最好从现行目标程序的dump,在这个案例中TibiaBot使用一个loader来注入hook.dll到一个激活的进程中Tibia.exe(这是特意为这个游戏的).
所以我们必须载入Tibia.exe到OD并执行她,然后到调试设置>事件>中断于新模块(DLL)
OncethisisdonerunLoader.exe(TheprogramthatinjectstheDLLintotheprocess)andnowOllyDBGshouldbreakshowingtheDLLbeingloaded.
NexttoitthereisacolumncalledEntry,thisshowstheentrypointoftheDLL>Gotoit
OncethereplaceabreakpointonitandthenremoveBreakonnewmodules.
Onceithasbrokenattheentrypointofthedllthenyoumustfollowallthestepsfromthebeginningagainuntilyouhavethe2workingdumps.
Remembertochangetheimagebaseonthe2nddumpeddlltowhatitwasinmemory.
当这些完成后执行Loader.exe(程序会把DLL注入到进程)现在OD应该中断并显示DLL载入后的开始处
这有一列调用表,这些显示DLL的入口点>到那去
然后在那设置一个断点并且删除"中断于新模块(DLL)"
当中断在DLL的入口点后你必须再次重复前面所有的步骤直到你有了2个运行中的dumps.
记住要修改两个Dump出的DLL文件的镜像基址为当时的内存基址
PLEASENOTEthatArmadillocanignorebreakpointsonsometargetsiftheoptionwasenabled,ifthisisthecasethenPressCtrl+GandtypetheAPIname(i.eVirtualProtect)andplaceanormalbreakpointontheretnofthatfunctioninsteadofBPFUNCTION_NAME
请注意如果选项是钩选的Armadillo可以在一些目标上忽略断点,
如果发生这种情况可以按Ctrl+G并输入API名(如:VirtualProtect),并在函数的retn处下一个普通的断点来代替BP函数名这种方式.
Onceyouhaveyour2dll'sthenweneedtouseawonderfultoolcalledReloXbyMackt.
LoadbothDll'sintotheprogram:
当你有了2个DLL后,我们需要一个非常好的Mackt写的工具叫ReloX
载入2个DLL到程序中

ClickSelectsectionsandremovetheticksfromanysectionsthatarentusedforcodeorarepartofArmadillo.
Ionlyticked:
CODE
DATA
.idata
.text
点Selectsections并从所有的段中去掉不是代码所使用钩选或者是属于Armadillo的部分
我只钩选了:
CODE
DATA
.idata
.text
OncethatisdoneclickCompare:
完成后点击Compare:

NowyoucanclickFixPEModuleandchoosethesamedllyouopenedfirstinReloX
(AtthetopofthescreenakaOriginal).
现在你可以单击FixPEModule并选择你用ReloX先打开的相同的DLL
NowTest...
现在测试

Lookslikeitsworkingfine!
看起来运行的还不错!
Lastthingjustforneatnessyoushouldremovealltheunusedsectionsfromyourfile.
Ihaveonlythesesectionsleft:
最后一件事就是整理,你应该从你的文件中删除所有未使用的段
我仅剩下这些段:
CODE
DATA
.idata
.rsrc
.mackt
.reloc
WellDone!
YouhavesuccessfullyunpackedanArmadilloDLL!Greets
TeamICU,TSRh,SnD,FFF,SEC-8,MP2K,ARTeam,AHTeam,Revenge,{RES}andallotherTeams!Writtenby:Whiterat//ICU
8thMarch2006