吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 3025|回复: 7

[转载技术] 第五十三章-TPPpack脱壳

[复制链接]
Shark恒 发表于 2015-1-20 17:35 | 显示全部楼层 |阅读模式

                             第五十三章-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_excep
var Newoep
var dir_JMP
var dir_CALL
var oep
var StartScan
var Opcodes
var temp
var temp2
var 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, [dir_CALL]              // 获取待修正的偏移量并保存到变量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 [temp3], Opcodes                // 修正偏移量
jmp LookForCall
final:
ret
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
附脚本的截图:
image002.jpg
image004.jpg
image006.jpg
下面我来给大家详细讲解这个脚本的作用。
Part1:定位OEP并修复stolen bytes(by Ularteck)。
详情:
首先我们需要配置一下反反调试插件。
image008.jpg
image010.jpg
image012.jpg
OD加载目标程序以后直接运行起来,可以看到完美运行。
image014.jpg
下面我们利用最后一次异常法来定位OEP,对于最后一次异常法大家应该很熟练了吧。我们经常会用到它。此法同样适用于ASProtect 2.1 SKE,2.2 SKE,2.3SKE以及带VM的版本。
这里我们先将所有忽略的异常选项都勾选上。
image016.jpg
接着将程序运行起来,然后打开日志窗口,看看最后一次异常发生指令所在的地址是哪里。
image018.jpg
我这里最后一次异常指令所在的地址为0046D36B,下面我们就可以利用脚本来定位OEP。
在使用脚本之前,我先演示一下如何手工定位OEP。
我们重启OD。
接着将忽略的异常选项的对勾都去掉。
image020.jpg
接着直接按F9键运行起来。如果断在了不是0046D36B的异常处的话,就直接按SHIFT+F9忽略掉异常继续执行。
image022.jpg
这里我们就断在了最后一次异常处。接下来按ALT+M打开区段列表窗口。
对代码段设置内存访问断点。
image024.jpg
按SHIFT+F9忽略掉异常运行起来,断在了这里。
image026.jpg
如果我们观察一下堆栈的话就会发现这里并不是真正的OEP,明显存在stolen bytes。
image028.jpg
我们可以看到之前已经执行过stolen bytes了。返回地址为8B0EA4,该地址属于起始地址为8B0000的区段。
image030.jpg
好,下面我们重启OD。
我们现在将脚本修改一下,让其自动定位到最后一次异常处。
将脚本修改成如下:
image032.jpg
好,修改完毕以后。
我们重启OD以后,执行该脚本。
image034.jpg
image036.jpg
这里弹出了一个对话框要求我们输入最后一次异常指令所在的地址,这里我输入46D36B。
单击OK。
image038.jpg
好了,我们可以看到脚本执行完毕了,我们可以看到刚好断在了最后一次异常处。
我们按ALT+M打开区段列表窗口。
image040.jpg
接下来我们并不是跟刚才一样对代码段设置内存访问断点,这次我们对起始地址为8B0000的区段设置内存访问断点。
按SHIFT+F9忽略掉运行起来,断在了stolen bytes处。
image042.jpg
如果我们按减号键可以看到回到了最后一次异常指令处。
image044.jpg
以下脚本是根据Martian先生在他的教程中介绍的定位stolen bytes的思路编写的,定位stolen bytes的思路如下:首先定位到最后一次异常处,接着往下搜索机器码为FFE0的JMP EAX指令,搜到该指令以后,对其设置断点,接着运行起来,断到了JMP EAX处,然后按F7键单步一下,就可以到达stolen bytes处了。
我们在脚本中添加一个变量。
image046.jpg
变量dir_JMP用于保存JMP EAX指令的地址。
接下来在last标签处添加以下内容:
image048.jpg
我们执行该脚本看看效果。
image050.jpg
我们可以看到成功定位到了stolen bytes处。下面我们要做的就是将stolen bytes拷贝到入口点处。
image052.jpg
这里我们从8B0E48开始拷贝,一直到8B0EA4为止,注意是二进制复制。
粘贴到入口点处。
image054.jpg
image056.jpg
这里我们可以看到46B067处的这个CALL是一个间接CALL。
image058.jpg
这里原stolen bytes应该是CALL 004293A0,目标地址是004293A0。
但是由于这是一个间接CALL,所以我们这里直接将其二进制复制到别的地方的话,目标地址就变了。
所以这个CALL被复制到别处的话,首先需要修正偏移量,我们来看看如何修正偏移量,首先我们在数据窗口中定位到该指令。
image060.jpg
image062.jpg
这里我们不用考虑前面的操作码,直接看后面的4个字节的偏移量。
FF B7 84 FC,为了下面列公式方便,这里我们将其命名为OPCODES。
image064.jpg
这里我们将008B0E9F,即这个CALL指令所在的地址命名为DIR_CALL。
我们来算一下目标地址004293A0是如何得到的:
目标地址 = OPCODES + DIR_CALL + 5
目标地址 = FFB784FC + 008B0E9F + 5 = 004293A0
好了,现在我们已经知道004293A0这个目标地址是如何得来的了。下面我们来计算新的OPCODES。
目标地址- CALL指令新的地址 - 5 = 新的OPCODES
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
何谓CALL指令新的地址:即该CALL指令被拷贝到的新的地址。
例如:
image066.jpg
如果我们将Stolen bytes拷贝到入口点处。
image068.jpg
这里我们看到46B067这个地址。这个地址的计算公式如下:
原地址 - Stolen bytes的起始地址 + 入口点
这里原地址为008B0E9F。
image070.jpg
stolen bytes的起始地址 = 008B0E48
image072.jpg
入口点为0046B010。
image074.jpg
8B0E9F - 8B0E48 + 46B010 = 0046B067
所以说新地址为0046B067
好了,现在我们来计算新的OPCODES。
目标地址 - 新地址- 5 = FFFBE334
004293A0 - 0046B067 - 5 = FFFBE334
这里新的OPCODES我们有了。
现在我们来手动编辑它。
我们定位到stolen bytes处。
image076.jpg
我们在数据窗口中定位到这个CALL:
image078.jpg
这里我们跳过E8这个机器码,直接修改后面的4个字节的偏移量:
image080.jpg
image082.jpg
将其替换成新的OPCODES.
image084.jpg
image086.jpg
我们可以看到该CALL的OPCODE已经改变了,现在我们将stolen bytes拷贝到入口点处。
image088.jpg
image090.jpg
我们可以看到46B067处的CALL的目标地址这次正确了。
下面我们给脚本添加一些内容让其自动完成上述操作。
image092.jpg
然后
image094.jpg
image096.jpg
执行该脚本。
image098.jpg
image100.jpg
image102.jpg
image104.jpg
这里我们可以看到执行了该脚本后,下面CALL的偏移量都被修正了。
下面我们要做的就是将stolen bytes二进制复制到入口点处。
image106.jpg
好,现在我们定位到了入口点处,我们将EIP修改到入口点处。
image108.jpg
image110.jpg
我们选择是,下面来进行dump。
image112.jpg
Martian先生的教程中提到了,这个大小也得修改,不然单击Dump按钮,会报错。
image114.jpg
修改为:
image116.jpg
这里我不使用OllyDump来修复IAT,所以我去掉了Rebuild Import的对勾。
然后按dump按钮进行dump。
image118.jpg
好了,这里我们就dump完成了,但是肯定是无法正常运行的,因为IAT还没有修复。
下面我们来修复IAT。
如果我们直接用OD加载dump文件的话,直接就会报错。
image120.jpg
我们尝试用PE编辑工具重建PE看看。
image122.jpg
image124.jpg
好,重建PE完毕了,我们再次用OD加载它。
image126.jpg
这里提一句,HideOD这款插件有时候会出错导致程序正常运行,所以最好将其用HideDebugger和OllyAdvanced代替。
好了,第一个脚本已经给大家介绍完了,接下来给大家介绍第二个脚本。
var base
var dir_VirtualAlloc
var dir_VirtualProtect
var dir_mov
Initiation:
gpa "VirtualAlloc", "kernel32.dll"           //获取VirtualAlloc这个API函数的地址
mov dir_VirtualAlloc, $RESULT
log dir_VirtualAlloc
gpa "VirtualProtect", "kernel32.dll"
mov dir_VirtualProtect, $RESULT
bp dir_VirtualAlloc
run
eob info
info:
mov base, eax
log base
bc dir_VirtualAlloc
bp dir_VirtualProtect
Area:
eob Section
run
Section:
cmp esi, 00460000
je Return
jmp Area
Return:
bc dir_VirtualProtect
mov Reg_esp, [esp]
bp Reg_esp
eob Area_1
run
Area_1:
bc Reg_esp
find base, #897C24188B4424#
mov dir_mov, $RESULT
log dir_mov
jmp Nop
Nop:
bp dir_mov
eob Nop2
run
Nop2:
bc dir_mov
fill dir_mov, 4, 90
final:
msg "NOP完毕,请按F9键运行."
ret
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
附第二个脚本截图:
image128.jpg
image130.jpg
这是修复IAT其中一个比较经典的方法,Martian先生在他的教程中详细介绍过。在到达OEP之前我们可以对IAT中重定向的项设置内存写入断点,断下来的地方就是写入重定向值的地方。但是要对IAT进行写入的话,首先得让IAT所在的内存单元具有写入权限,所以势必会调用VirtualProtect来修改IAT所在内存单元的内存访问属性,赋予其写入权限。所以我们可以先对VirtualProtect这个API函数设置一个断点,等执行完该函数赋予写入权限以后,我们再对IAT中重定向的项设置内存写入断点。
image132.jpg
从Martian先生教程中这张截图我们可以看到断在了VirtualProtect这个API函数的入口处,其想修改IAT所在内存单元的访问属性。我们执行到返回,然后对重定向的IAT项设置内存写入断点,接着运行起来,断在了写入重定向值的地方。
image134.jpg
这里就断在了写入重定向值的地方,仔细观察我们可以知道此时EAX中保存了重定向的值,而EBP指向的是对应的IAT项。
现在我们在前面几行处设置一个断点,跟踪一下,看看是什么情况。
image136.jpg
我们可以看到前面几行会获取正确的IAT值,而接下来会将正确的IAT值覆盖为重定向的值。所以我们要做的就是将写入重定向值的语句NOP掉。
所以脚本要做的事情就是定位到写入重定向值的指令,并将其NOP掉。
首先脚本要做的第一件事情就是查找VirtualAlloc这个API函数的地址,首次断到VirtualAlloc这个API函数时,我们就可以获取需要NOP掉的指令所在内存单元的首地址了,因为在不同的机器上,待NOP掉的指令的地址是会变的,所以我们有必要动态获取它。
var base
var dir_VirtualAlloc
var dir_VirtualProtect
var dir_mov
Initiation:
gpa "VirtualAlloc", "kernel32.dll"           //获取VirtualAlloc这个API函数的地址
mov dir_VirtualAlloc, $RESULT
log dir_VirtualAlloc
这里是获取VirtualAlloc这个API函数的地址,然后将其保存到变量dir_VirtualAlloc中,同理VirtualProtect也是一样。
gpa "VirtualProtect", "kernel32.dll"
mov dir_VirtualProtect, $RESULT
获取VirtualProtect这个API函数的地址,然后将其保存到变量dir_VirtualProtect中。
bp dir_VirtualAlloc
run
eob info
info:
mov base, eax
log base
bc dir_VirtualAlloc
bp dir_VirtualProtect
接着对VirtualAlloc设置断点,运行起来,如果断下来就跳转到info标签处,将该程序刚申请的内存单元的首地址保存到变量base中,下面我们需要NOP掉的指令将位于这块内存单元中。
接下来删除掉VirtualAlloc的断点,然后对VirutalProtect设置断点。
Area:
eob Section
run
Section:
cmp esi, 00460000
je Return
jmp Area
断下来了的话,判断ESI的值是否等于460000(IAT的起始地址),因为该程序会调用VirtualProtect修改IAT所在内存单元的访问属性。如果ESI等于460000的话,就跳转到return标签处。
Return:
bc dir_VirtualProtect
mov Reg_esp, [esp]
bp Reg_esp
删除掉VirtualProtect的断点,将ESP指向的内容(返回地址)保存到变量Reg_esp中,接着对返回地址处设置断点。
Area_1:
bc Reg_esp
find base, #897C24188B4424#
mov dir_mov, $RESULT
log dir_mov
jmp Nop
当VirtualProtect调用返回后,下面就可以在之前申请的内存单元中搜索需要NOP掉的指令了。这里我们利用特征码来搜索。
特征码为:897C24188B4424。
image138.jpg
搜索到了的话就跳转到Nop标签处。
Nop:
bp dir_mov
eob Nop2
run
Nop2:
bc dir_mov
fill dir_mov, 4, 90
final:
msg "NOP完毕,请按F9键运行."
ret
好了,这里第二个脚本也介绍完了。感谢Ularteck童鞋提供的这两个脚本以及Martian先生提供的教程。我从Martian先生的教程中截了一张图片来解释第二个脚本。
本章,大家应该对于如何编写脚本更加了解了吧。
好,本章就到这里。

本系列文章汉化版转载看雪论坛

感谢原作者:RicardoNarvaja(西班牙人)
原作者个人主页:http://www.ricardonarvaja.info/

感谢热心翻译的朋友:
1~3章译者:BGCoder
4~58章译者:安于此生

全集配套程序下载地址:

链接: http://pan.baidu.com/s/1eQzTWfo 密码: vytv




评分

参与人数 12HB +8 THX +8 收起 理由
lies + 1
Jawon + 2
一路走来不容易 + 1
娄胖胖 + 1
冷亦飞 + 1
消逝的过去 + 1
akk1898 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
成丰羽 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
hackysh + 1
hnymsh + 1
wpsys + 1 + 1 教程非常易懂,对新人帮助极大!楼主大爱!
雨季 + 2 + 1 评分=感恩!简单却充满爱!感谢您的作品!!.

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
hackysh 发表于 2022-2-9 17:45 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
头像被屏蔽
别管我了行 发表于 2022-3-3 04:37 | 显示全部楼层

提示: 作者被禁止或删除 内容自动屏蔽
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
zg2600 发表于 2022-6-22 00:06 | 显示全部楼层

[吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
曾经沧海 发表于 2022-10-31 20:11 | 显示全部楼层

看着好麻烦呀~~
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
一生逍遥 发表于 2022-12-5 08:09 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
曾经沧海 发表于 2023-4-7 08:02 | 显示全部楼层

可以啊,老铁666.
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
一生逍遥 发表于 2023-4-22 17:29 | 显示全部楼层

就算荧光棒变成拐杖,你依旧是我信仰
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层
8层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

快速回复 返回顶部 返回列表