大家好!我是风动鸣 教程分析原理 难免会有纰漏 请大家多多指教 多多包涵
今天给大家带来的教程是 自写脚本脱Themida_v2.3.5.10
脱壳环境是:学破解论坛VM XP虚拟机
http://www./thread-9253-1-1.html
做教程之前学习了sure 以下这篇教程 非常感谢sure分享
http://www./thread-13373-1-1.html
本教程的课件跟他的一致
脚本是代替人工操作,节省时间,提高效率。
我们是怎么操作的,脚本就怎么操作。
代码逻辑加入了各种判断,以限制脚本按照我们的操作流程走,解放我们的双手。
脚本展示:
每个脚本写了实现原理,和适当的代码注释。
只要你懂原理,知道操作流程,你也一样能写出自己的脚本!
详细的代码赏析 回复可见
本帖隐藏的内容- // OEP找法 //
- // 下断点bp ZwFreeVirtualMemory //
- // F9 N次 直到edi反复的出现一个值。 //
- // 断在ZwFreeVirtualMemory,删除断点。 //
- // 在代码段(.code)下内存访问断点 //
- // F9运行-到达OEP 记录下eip //
- ///////////////////////////////////////////
- // www. //
- // //
- // by 风动鸣 //
- // //
- // 2015年11月17日 //
- // //
- //---------------定义变量----------------//
- var temp
- //用来保存edi的值
- var CODE
- //代码段首地址
- var SIZE
- //代码段大小
- var OEP
- //OEP地址
- //-----------清除所有断点--------------- //
- bc
- //清除所有断点
- bpmc
- //清除内存断点
- bphwcall
- //清除硬断点
- //-------------初始化断点-------------//
- bp 7C92D38E
- // xp下 bp ZwFreeVirtualMemory
- jmp going
- // 跳到going 执行
- going:
- //初始化次数
- esto
- //Shift+F9 忽略所有异常运行 代替F9
- cmp edi,0
- //相等
- je going
- //否则
- mov temp,edi
- //保存edi的值
- esto
- //再运一次
- cmp temp,edi
- //如果变化了 就跳
- jnz going
- //否则 edi到了关键地址
- msg "edi反复不变 到了关键地址了"
- bc
- //清除所有断点
- //---------根据实际情况 替换 代码段首地址和大小-------------//
- mov CODE,00401000
- //代码段首地址
- mov SIZE,F7000
- //代码段大小
- bprm CODE,SIZE
- //代码段下内存写入断点
- esto
- mov OEP,eip
- bpmc
- //清除内存断点
- msg OEP
- ret
复制代码- // AB特征找法 //
- // 重载 代码段下内存写入断点 //
- // F9 F7 F8 //
- // F9 直到AB出现 记录下EIP地址 //
- // //
- // API赋值代码地址找法 //
- // 我已经定位好特特征码了 //
- // 12D200FB4140FF31 //
- ///////////////////////////////////////////
- // www. //
- // //
- // by 风动鸣 //
- // //
- // 2015年11月17日 //
- // //
- ///////////////////////////////////////////
- //---------------定义变量----------------//
- var CODE
- //代码段首地址
- var SIZE
- //代码段大小
- var ONLYONEAB
- //AB特征地址
- VAR API
- //赋值真实API的代码地址
- //-----------清除所有断点-------------//
- bc
- //清除所有断点
- bpmc
- //清除内存断点
- bphwcall
- //清除硬断点
- //---------根据实际情况 替换 代码段首地址和大小-------------//
- mov CODE,00401000
- //代码段首地址
- mov SIZE,F7000
- //代码段大小
- //-------------初始化断点-------------//
- bpwm CODE,SIZE
- //代码段下内存写入断点
- esto
- //Shift+F9 忽略所有异常运行 代替F9
- sti
- //F7 单步步入
- sto
- //F8 单步步过
- findAB:
- cmp [eip],#AB#,1
- //当前将要执行的代码地址 的开头一个字节 是否为 AB
- je goOk
- esto
- jmp findAB
- //跳到findAB开头继续向入执行
- goOk:
- mov ONLYONEAB,eip
- bpmc
- //清除内存断点
- msg ONLYONEAB
- find eip,#12D200FB4140FF31# //搜索上面那段代码
- mov API,$RESULT //将搜索的eip地址给aa,也就是图上的771f9处
- sub API,12
- bp API
- //赋值的代码地址 处 下断
- esto
- bc
- //清除所有断点
- msg API
- ret
复制代码- // 原理: //
- // 壳把真实的API函数代码写入到自己申请的 //
- // 地址 再在代码段里自己来调用 //
- // 所以我们要做的就是: //
- // 在壳在代码段里写入调用自己函数调用后 //
- // 替换回真实的调用地址 //
- // 替换后的两种情况: //
- // call dword ptr ds:[IAT表函数地址] //
- // jmp dword ptr ds:[IAT表函数地址] //
- // //
- // www. //
- // //
- // by 风动鸣 //
- // //
- // 2015年11月17日 //
- // //
- //---------------定义变量----------------//
- var REALAPI
- //真实的API函数地址
- var IATAPI
- //IAT表函数地址
- var REPLACE
- //替换代码的地址
- var RECALL
- //替换成 call dword ptr ds:[地址] 的特征码
- var REJMP
- //修改成 jmp dword ptr ds:[地址] 的特征码
- var API
- //赋值API的代码地址
- var CODE
- //代码段首地址
- var SIZE
- //代码段大小
- var ONLYONEAB
- //AB特征地址
- var OEP
- //OEP地址
- //-----------清除所有断点-------------//
- bc
- //清除所有断点
- bpmc
- //清除内存断点
- bphwcall
- //清除硬断点
- //------------替换实际的地址-------------//
- mov API,00709E7C
- //赋值API的代码地址
- mov CODE,00401000
- //代码段首地址
- mov SIZE,F7000
- //代码段大小
- mov ONLYONEAB,00709C55
- //独一无二AB特征地址
- mov OEP,00466C98
- //OEP地址
- //-------替换的特征码-------------//
- mov RECALL,15FF
- mov REJMP,25FF
- //-------------初始化断点-------------//
- bphws API,"x"
- //赋值api真实地址下硬件断点
- bphws OEP,"x"
- //程序入口OEP下硬件断点
- bpwm CODE,SIZE
- //代码段下内存写入断点
- //-------------开始修复----------------//
- esto
- //Shift+F9 忽略所有异常运行
- //异常界面设置好 可以用 run F9 运行 代替】
- sti
- //F7 单步步入
- sto
- //F8 单步步过
- esto
- strat:
- mov [IATAPI],REALAPI
- //把 真实的API地址 写入 IAT表函数地址
- jmp strat2
- strat2:
- mov REALAPI,eax
- //记录下一个 真实的API地址
- esto
- cmp eip,API
- //当前要执行的代码地址 与 将要赋值API的代码地址 做比较
- je strat2
- //相等就跳
- mov IATAPI,edx
- //IAT表函数地址
- esto
- mov [IATAPI],REALAPI
- //在 IAT表函数地址 里 填充 真实的API地址
- cmp eip,API
- je strat
- cmp [eip],AA,1
- je foriat
- cmp eip,OEP
- je end
- jmp foriat
- //循环修复IAT
- foriat:
- cmp [eip],#880B#,2
- je foriat2
- cmp eip,OEP
- je end
- cmp al,e9
- je foriate9
- cmp al,e8
- je foriate8
- mov REPLACE,edi
- //下一个 替换代码的地址 = edi
- esto
- cmp al,e8
- //修复FF15标签
- je foriate8x
- //修复FF25标签
- jmp foriate9x
- foriat2:
- mov REPLACE,ebx
- cmp al,e8
- je iat1
- cmp al,e9
- je iat2
- cmp cl,e8
- je iat1
- jmp iat2
- //修复FF15
- iat1:
- esto
- //运行之后 填充了 E8
- esto
- //运行之后 填充了 call的地址
- //综合效果是 壳生成了自己的函数代码后 在代码段来调用
- //下面就到我们来修复了
- mov [REPLACE],RECALL
- //往 替换代码的地址(目标地址) 替换两字节 为 FF15
- add REPLACE,2
- //向后移两位
- mov [REPLACE],IATAPI
- //替换为 IAT函数表的地址
- //修改完后的效果为:call dword ptr ds:[0x487600]
- cmp eip,API
- je strat
- cmp eip,OEP
- je end
- jmp foriat
- //同修复FF25
- iat2:
- esto
- esto
- mov [REPLACE],REJMP
- add REPLACE,2
- mov [REPLACE],IATAPI
- cmp eip,API
- je strat
- cmp eip,OEP
- je end
- jmp foriat
- foriate8:
- mov REPLACE,edi
- esto
- esto
- mov [REPLACE],RECALL
- //替换成 FF 15
- //等价于call dword ptr ds:[IAT表函数地址]
- add REPLACE,2
- //替换代码的地址加2(就是向后移两位)
- mov [REPLACE],IATAPI
- //替换为IAT表函数的地址
- cmp eip,API
- je strat
- jmp foriat
- //循环修复FF15标签 修改完后的效果为:call dword ptr ds:[0x487600]
- foriate8x:
- esto
- //运行之后 壳已经把 E8 写入代码段指定地址 如:【E8 90909090】
- esto
- //运行之后 壳已经把 真实的API地址 填充到代码段指定地址
- //如:【E8 BB087076】 就是 call 76B2A4EE = call winmm.midiStreamOut
- //下面就到我们来修复了
- mov [REPLACE],RECALL
- //往 替换代码的地址(目标地址) 替换两字节 为 FF15
- add REPLACE,2
- //向后移两位
- mov [REPLACE],IATAPI
- //替换为 IAT函数表的地址
- //修改完后的效果为:call dword ptr ds:[0x487600]
- cmp eip,API
- je strat
- jmp foriat
- foriate9:
- mov REPLACE,edi
- esto
- jmp doiate9
- doiate9:
- esto
- cmp eip,ONLYONEAB
- jnz doiate9
- esto
- mov [REPLACE],REJMP
- add REPLACE,2
- mov [REPLACE],IATAPI
- jmp strat
- //循环修复FF25标签
- foriate9x:
- esto
- //运行之后 壳已经把 E9 写入代码段指定地址 如:【E9 90909090】
- esto
- //运行之后 壳已经把 真实的API地址 填充到代码段指定地址
- //如:【E9 A7915F71】 就是 jmp 71A23FED
- //下面就到我们来修复了
- mov [REPLACE],REJMP
- //往 替换代码的地址(目标地址) 替换两字节 为 FF25
- add REPLACE,2
- //向后移两位
- mov [REPLACE],IATAPI
- //替换为 IAT函数表的地址
- //修改完后的效果为:jmp dword ptr ds:[0x487660]
- cmp eip,API
- je strat
- cmp [eip],AA,1
- je foriat
- cmp eip,OEP
- je end
- jmp strat
- end:
- bc
- bpmc
- bphwcall
- MSG "到达OEP IAT修复完毕"
- ret
复制代码
具体脱壳流程:
总结:学脱壳,先学写脚本——这是我的见解
许多大牛都分享了各种脱壳脚本,脚本是脱壳全过程的体现,浓缩了作者的脱壳思路,对壳的实现原理的理解。
所以要重视脚本,别把大牛分享的脚本只当成脱壳工具。
脚本适用范围小,而读懂脚本原理 你就能脱它不能脱的壳,你才是脚本的创作者!
脚本代码我是一步一步跟的,通过耐心跟踪 观察各种数据,总结经验。
希望对大家有所启发。
不怎么会表达 请大家见谅。
课件工具和脚本分享:
|