使用OllyDbg从零开始Cracking 第五十三章-TPPpack脱壳
第五十三章-TPPpack脱壳上一章中最后留的那个小比赛最后的获胜者是Ularteck童鞋。下面我们就用Ularteck童鞋编写的第一个脚本来定位OEP以及修复stolen bytes。脚本如下:/*################################ CracksLatinoS - 2006 作者: Ulaterck. 描述: 该脚本的功能的定位TPPpack的OEP以及修复其stolen bytes 目标程序: UnPackMe_TPPpack.exe 配置要求: ODBGScript 1.48 , HideDebugger 1.24 , HideOD,停在入口点处,忽略Kernel32的异常,其他异常均不忽略. 因为我们这里要用到最后一次异常法,所以在执行该脚本之前首先要知道最后一次异常的地址,然后再执行该脚 本 以下关于该脚本的详细注释################################*/ var dir_excepvar Newoepvar dir_JMP var dir_CALLvar oepvar StartScanvar Opcodes var tempvar temp2var temp3 Data: mov Newoep, eip // 将入口点保存到变量Newoep中 ask "最后一次异常的地址是多少?" // 弹出一个对话框让用户输入最后一次异常的地址 cmp $RESULT,0 // 判断用户是否输入了地址 je warning // 如果用户没有输入地址则跳转到warning标签处 mov dir_excep, $RESULT // 将用户输入的地址保存到变量dir_excep中 jmp Initiation // 跳转到Initiation标签处 warning: msg "请重新执行该脚本,再次输入一个有效的地址!" jmp final Initiation: run // 运行起来 eoe check // 如果发生异常断了下来,就跳转到check标签处 check: cmp eip,dir_excep // 判断断下来的地方是不是最后一次异常处 je last // 断下来的地方刚好是最后一次异常处,则跳转到last标签处 esto // 忽略掉异常继续执行,相当于在OD中按SHIFT+F9 jmp Initiation: // 跳转Initiation标签处继续定位最后一次异常处 last: findop eip,#FFE0# // 从最后一次异常处开始搜索JMP EAX指令,以便下面定位stolen bytes mov dir_JMP,$RESULT // 将JMP EAX指令的地址保存到变量dir_JMP中 bp dir_JMP // 对JMP EAX指令设置断点 esto // 忽略掉异常继续执行,相当于在OD中按了SHIFT+F9 bc dir_JMP // 删除掉JMP EAX指令处的断点 sti // 单步步入,相当于在OD中按F7,单步以后就到了stolen bytes处 mov oep,eip // 将stolen bytes的起始地址保存到变量oep中 mov StartScan,eip // 将stolen bytes的起始地址保存到变量StartScan中 LookForCall: // 开始搜索Stolen bytes中需要修正偏移量的CALL findop StartScan,#E8# // 搜索以机器码E8开头的CALL指令,即待修正偏移量的CALL指令 cmp $RESULT, 0 // 判断是否搜索到了待修正偏移量的CALL指令 je final // 没有搜索到的话,则跳转到final标签处 mov dir_CALL, $RESULT // 将待修正偏移量CALL的地址保存到变量dir_CALL中 mov StartScan, $RESULT // 将待修正偏移量的CALL指令的地址赋值给变量StartScan add dir_CALL,1 // 指向偏移量 mov Opcodes, // 获取待修正的偏移量并保存到变量Opcodes中 add Opcodes,StartScan // 将偏移量加上CALL指令所在的地址 add Opcodes,5 // 加上CALL指令的长度 // 这样就得到了CALL指令的目标地址 //修正CALL指令的偏移量 mov temp, StartScan // 将CALL指令的地址保存到临时变量temp中 sub temp, oep // 计算CALL指令距离stolen bytes起始地址的长度,并保存到临时变量temp中 mov temp2, Newoep // 将入口点的值保存到临时变量temp2中 add temp,temp2 // 计算CALL指令新的地址,并保存到变量temp中 sub Opcodes, temp // 将目标地址减去CALL指令新的地址 sub Opcodes, 5 // 然后减去5,就得到了CALL指令修正后的偏移量 edit: // 将CALL指令的偏移量修正 mov temp3, StartScan // 将CALL指令所在的地址保存到临时变量temp3中 add temp3,1 // 指向待修正的偏移量 mov , Opcodes // 修正偏移量 jmp LookForCall final:ret----------------------------------------------------------------------------------------------------------------------------------------------------------------------附脚本的截图:下面我来给大家详细讲解这个脚本的作用。Part1:定位OEP并修复stolen bytes(by Ularteck)。详情:首先我们需要配置一下反反调试插件。OD加载目标程序以后直接运行起来,可以看到完美运行。下面我们利用最后一次异常法来定位OEP,对于最后一次异常法大家应该很熟练了吧。我们经常会用到它。此法同样适用于ASProtect 2.1 SKE,2.2 SKE,2.3SKE以及带VM的版本。这里我们先将所有忽略的异常选项都勾选上。接着将程序运行起来,然后打开日志窗口,看看最后一次异常发生指令所在的地址是哪里。我这里最后一次异常指令所在的地址为0046D36B,下面我们就可以利用脚本来定位OEP。在使用脚本之前,我先演示一下如何手工定位OEP。我们重启OD。接着将忽略的异常选项的对勾都去掉。接着直接按F9键运行起来。如果断在了不是0046D36B的异常处的话,就直接按SHIFT+F9忽略掉异常继续执行。这里我们就断在了最后一次异常处。接下来按ALT+M打开区段列表窗口。对代码段设置内存访问断点。按SHIFT+F9忽略掉异常运行起来,断在了这里。如果我们观察一下堆栈的话就会发现这里并不是真正的OEP,明显存在stolen bytes。我们可以看到之前已经执行过stolen bytes了。返回地址为8B0EA4,该地址属于起始地址为8B0000的区段。好,下面我们重启OD。我们现在将脚本修改一下,让其自动定位到最后一次异常处。将脚本修改成如下:好,修改完毕以后。我们重启OD以后,执行该脚本。这里弹出了一个对话框要求我们输入最后一次异常指令所在的地址,这里我输入46D36B。单击OK。好了,我们可以看到脚本执行完毕了,我们可以看到刚好断在了最后一次异常处。我们按ALT+M打开区段列表窗口。接下来我们并不是跟刚才一样对代码段设置内存访问断点,这次我们对起始地址为8B0000的区段设置内存访问断点。按SHIFT+F9忽略掉运行起来,断在了stolen bytes处。如果我们按减号键可以看到回到了最后一次异常指令处。以下脚本是根据Martian先生在他的教程中介绍的定位stolen bytes的思路编写的,定位stolen bytes的思路如下:首先定位到最后一次异常处,接着往下搜索机器码为FFE0的JMP EAX指令,搜到该指令以后,对其设置断点,接着运行起来,断到了JMP EAX处,然后按F7键单步一下,就可以到达stolen bytes处了。我们在脚本中添加一个变量。变量dir_JMP用于保存JMP EAX指令的地址。接下来在last标签处添加以下内容:我们执行该脚本看看效果。我们可以看到成功定位到了stolen bytes处。下面我们要做的就是将stolen bytes拷贝到入口点处。这里我们从8B0E48开始拷贝,一直到8B0EA4为止,注意是二进制复制。粘贴到入口点处。这里我们可以看到46B067处的这个CALL是一个间接CALL。这里原stolen bytes应该是CALL 004293A0,目标地址是004293A0。但是由于这是一个间接CALL,所以我们这里直接将其二进制复制到别的地方的话,目标地址就变了。所以这个CALL被复制到别处的话,首先需要修正偏移量,我们来看看如何修正偏移量,首先我们在数据窗口中定位到该指令。这里我们不用考虑前面的操作码,直接看后面的4个字节的偏移量。FF B7 84 FC,为了下面列公式方便,这里我们将其命名为OPCODES。这里我们将008B0E9F,即这个CALL指令所在的地址命名为DIR_CALL。我们来算一下目标地址004293A0是如何得到的:目标地址 = OPCODES + DIR_CALL + 5目标地址 = FFB784FC + 008B0E9F + 5 = 004293A0好了,现在我们已经知道004293A0这个目标地址是如何得来的了。下面我们来计算新的OPCODES。目标地址- CALL指令新的地址 - 5 = 新的OPCODES----------------------------------------------------------------------------------------------------------------------------------------------------------------------何谓CALL指令新的地址:即该CALL指令被拷贝到的新的地址。例如:如果我们将Stolen bytes拷贝到入口点处。这里我们看到46B067这个地址。这个地址的计算公式如下:原地址 - Stolen bytes的起始地址 + 入口点这里原地址为008B0E9F。stolen bytes的起始地址 = 008B0E48入口点为0046B010。8B0E9F - 8B0E48 + 46B010 = 0046B067所以说新地址为0046B067好了,现在我们来计算新的OPCODES。目标地址 - 新地址- 5 = FFFBE334004293A0 - 0046B067 - 5 = FFFBE334这里新的OPCODES我们有了。现在我们来手动编辑它。我们定位到stolen bytes处。我们在数据窗口中定位到这个CALL:这里我们跳过E8这个机器码,直接修改后面的4个字节的偏移量:将其替换成新的OPCODES.我们可以看到该CALL的OPCODE已经改变了,现在我们将stolen bytes拷贝到入口点处。我们可以看到46B067处的CALL的目标地址这次正确了。下面我们给脚本添加一些内容让其自动完成上述操作。然后执行该脚本。这里我们可以看到执行了该脚本后,下面CALL的偏移量都被修正了。下面我们要做的就是将stolen bytes二进制复制到入口点处。好,现在我们定位到了入口点处,我们将EIP修改到入口点处。我们选择是,下面来进行dump。Martian先生的教程中提到了,这个大小也得修改,不然单击Dump按钮,会报错。修改为:这里我不使用OllyDump来修复IAT,所以我去掉了Rebuild Import的对勾。然后按dump按钮进行dump。 好了,这里我们就dump完成了,但是肯定是无法正常运行的,因为IAT还没有修复。下面我们来修复IAT。如果我们直接用OD加载dump文件的话,直接就会报错。我们尝试用PE编辑工具重建PE看看。好,重建PE完毕了,我们再次用OD加载它。这里提一句,HideOD这款插件有时候会出错导致程序正常运行,所以最好将其用HideDebugger和OllyAdvanced代替。好了,第一个脚本已经给大家介绍完了,接下来给大家介绍第二个脚本。var basevar dir_VirtualAllocvar dir_VirtualProtectvar dir_mov Initiation: gpa "VirtualAlloc", "kernel32.dll" //获取VirtualAlloc这个API函数的地址mov dir_VirtualAlloc, $RESULTlog dir_VirtualAlloc gpa "VirtualProtect", "kernel32.dll"mov dir_VirtualProtect, $RESULT bp dir_VirtualAllocruneob info info: mov base, eaxlog basebc dir_VirtualAllocbp dir_VirtualProtect Area:eob Sectionrun Section:cmp esi, 00460000je Returnjmp Area Return:bc dir_VirtualProtectmov Reg_esp, bp Reg_esp eob Area_1run Area_1:bc Reg_espfind base, #897C24188B4424#mov dir_mov, $RESULTlog dir_movjmp Nop Nop:bp dir_moveob Nop2runNop2:bc dir_movfill dir_mov, 4, 90 final: msg "NOP完毕,请按F9键运行." ret----------------------------------------------------------------------------------------------------------------------------------------------------------------------附第二个脚本截图:这是修复IAT其中一个比较经典的方法,Martian先生在他的教程中详细介绍过。在到达OEP之前我们可以对IAT中重定向的项设置内存写入断点,断下来的地方就是写入重定向值的地方。但是要对IAT进行写入的话,首先得让IAT所在的内存单元具有写入权限,所以势必会调用VirtualProtect来修改IAT所在内存单元的内存访问属性,赋予其写入权限。所以我们可以先对VirtualProtect这个API函数设置一个断点,等执行完该函数赋予写入权限以后,我们再对IAT中重定向的项设置内存写入断点。从Martian先生教程中这张截图我们可以看到断在了VirtualProtect这个API函数的入口处,其想修改IAT所在内存单元的访问属性。我们执行到返回,然后对重定向的IAT项设置内存写入断点,接着运行起来,断在了写入重定向值的地方。这里就断在了写入重定向值的地方,仔细观察我们可以知道此时EAX中保存了重定向的值,而EBP指向的是对应的IAT项。现在我们在前面几行处设置一个断点,跟踪一下,看看是什么情况。我们可以看到前面几行会获取正确的IAT值,而接下来会将正确的IAT值覆盖为重定向的值。所以我们要做的就是将写入重定向值的语句NOP掉。所以脚本要做的事情就是定位到写入重定向值的指令,并将其NOP掉。首先脚本要做的第一件事情就是查找VirtualAlloc这个API函数的地址,首次断到VirtualAlloc这个API函数时,我们就可以获取需要NOP掉的指令所在内存单元的首地址了,因为在不同的机器上,待NOP掉的指令的地址是会变的,所以我们有必要动态获取它。var basevar dir_VirtualAllocvar dir_VirtualProtectvar dir_mov Initiation: gpa "VirtualAlloc", "kernel32.dll" //获取VirtualAlloc这个API函数的地址mov dir_VirtualAlloc, $RESULTlog dir_VirtualAlloc这里是获取VirtualAlloc这个API函数的地址,然后将其保存到变量dir_VirtualAlloc中,同理VirtualProtect也是一样。gpa "VirtualProtect", "kernel32.dll"mov dir_VirtualProtect, $RESULT获取VirtualProtect这个API函数的地址,然后将其保存到变量dir_VirtualProtect中。bp dir_VirtualAllocruneob info info: mov base, eaxlog basebc dir_VirtualAllocbp dir_VirtualProtect接着对VirtualAlloc设置断点,运行起来,如果断下来就跳转到info标签处,将该程序刚申请的内存单元的首地址保存到变量base中,下面我们需要NOP掉的指令将位于这块内存单元中。接下来删除掉VirtualAlloc的断点,然后对VirutalProtect设置断点。Area:eob Sectionrun Section:cmp esi, 00460000je Returnjmp Area断下来了的话,判断ESI的值是否等于460000(IAT的起始地址),因为该程序会调用VirtualProtect修改IAT所在内存单元的访问属性。如果ESI等于460000的话,就跳转到return标签处。Return:bc dir_VirtualProtectmov Reg_esp, bp Reg_esp删除掉VirtualProtect的断点,将ESP指向的内容(返回地址)保存到变量Reg_esp中,接着对返回地址处设置断点。Area_1:bc Reg_espfind base, #897C24188B4424#mov dir_mov, $RESULTlog dir_movjmp Nop当VirtualProtect调用返回后,下面就可以在之前申请的内存单元中搜索需要NOP掉的指令了。这里我们利用特征码来搜索。特征码为:897C24188B4424。搜索到了的话就跳转到Nop标签处。Nop:bp dir_moveob Nop2runNop2:bc dir_movfill dir_mov, 4, 90 final: msg "NOP完毕,请按F9键运行."ret好了,这里第二个脚本也介绍完了。感谢Ularteck童鞋提供的这两个脚本以及Martian先生提供的教程。我从Martian先生的教程中截了一张图片来解释第二个脚本。本章,大家应该对于如何编写脚本更加了解了吧。好,本章就到这里。本系列文章汉化版转载看雪论坛
感谢原作者:RicardoNarvaja(西班牙人) 原作者个人主页:http://www.ricardonarvaja.info/
感谢热心翻译的朋友:1~3章译者:BGCoder4~58章译者:安于此生
全集配套程序下载地址:
链接: http://pan.baidu.com/s/1eQzTWfo 密码: vytv
[快捷回复]-感谢楼主热心分享! [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意! 看着好麻烦呀~~ 活到老,学到老! 可以啊,老铁666. 就算荧光棒变成拐杖,你依旧是我信仰
页:
[1]