逆向基础-脱壳

这篇具有很好参考价值的文章主要介绍了逆向基础-脱壳。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

脱壳

脱壳的步骤:
1.程序运行先从壳代码运行,壳代码执行完以后会跳转到真正的OEP,也就是我们第一步要做的事情就是找到真正的OEP。
如何查找原始的OEP?或者说如何判断壳代码已经执行完毕了?
大部分情况壳代码都会在一个单独的区段里面,壳代码最后执行完一定会跳转到原始的.text段。
然后我们就可以dump出来了,但是dump出来以后我们还需要进行iat表的修复。
因为dump出来以后已经是内存的状态,是函数的地址,不是函数的名称了。那么操作系统就不会帮我们进行修复了。

根据OEP的特征来判断是否是原始的OEP。
不同程序,不同的版本编译器编译出来的程序的OEP各不相同,大致有以下的特点:
vc6的OEP处第1个API调用的是GetVersion
VS2013是GetSystemTimeAsFileTime
Delphi是GetModuleHandle

2.dump内存文件
3.修复导入表

FF15
E8
两个不同的call:
  -E8直接就是call 立即数
    -调用的是我们自己写的call
  -FF15里面call 的是一个内存单元,这个内存单元中保存的才是真正的地址
    -然后通过观察,我们发现FF15就是调用IAT表的一种call
  
总结:
  -E8 call 调用的是我们自己定call
  -FF15 call 调用的导入表IAT表的一种call


程序脱壳,逆向,c++,windows,microsoft

给程序进行脱壳要做的第一步,查看程序的壳信息。

然后我们就知道这是一个UPX的壳,然后是VC6编译的。

然后我们发现区段那些的确都消失了。

UPX壳就是把我们区段进行了合并,然后压缩。

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft

通过给esp添加硬件断点。

然后我们观察内存,最后一个jmp的确跳的很远。
直接跳回去了第一个区段,我们知道进行加壳之前我们的第一个区段就是我们的代码段。
那么就是说他跳回去代码段了。

很可能就是我们的OEP。
然后我们发现调用的第一个API是GetVersion,那么就确定的确是我们的入口OEP了。

程序脱壳,逆向,c++,windows,microsoft

然后我们手工dump我们的文件。【其实就是PE文件的逆操作,把PE文件从内存加载到硬盘,唯一不同的是这个时候我们dump出来的是按照内存对齐的了,不是文件对齐的了】

我们一块一块自己粘出来。
  -1.先dump PE头
  -2.然后dump剩下的区段
就是把pe文件dump出来
【dos头,pe头,区段头,区段...】

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft

然后dump出来以后我们要对exe进行修复。
通过010 Editor
  -1.修复区段头信息【区段的大小 偏移等信息】修改跟内存一样就好了,因为现在我们是内存状态dump出来的
  -2.通过ImportREC.exe这个工具修复IAT表
    -它就是依据我们上面说的FF15是调用IAT表的函数,它往上和往下进行查找然后把函数名和函数地址那些找到
    -修复的原理就是重新开一个区段然后根据原本我们dump出来的函数地址进行修复。

然后我们就发现IAT表被成功修复了。

然后发现程序就可以正常被执行了

重点:我们dump出来是以内存状态的,这个时候IAT表已经被修复为地址了,所以我们再启动因为不是名字,所以操作系统不会帮我们进行修复。
所以我们要修复为地址先

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft

脱壳练习

发现这是一个VC6.0编译的壳,所以OEP的特点也是GetVersion
然后壳的版本是ASPack

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft

然后发现第二个程序也是VC6.0编译的,
然后壳的版本是yoda's cryptor 1.2

程序脱壳,逆向,c++,windows,microsoft

然后我们发现它不是直接存储IAT的函数的
而是存了一个地址
那些地址是一条jmp指令
跳转过去才是真正的IAT函数

所以我们就要检测内存中什么时候被修改的,就是什么时候IAT表被替换为一个jmp的函数地址

然后通过观察我们还发现它的代码是动态解密出来的,有一条mov指令是关键指令会把IAT表替换为jmp的地址。

所以我们在它把代码动态解密出来之后,把那条关键的替换IAT表为jmp的地址指令NOP掉,NOP掉之后它就替换不了了,只能正常的进行解密。

然后我们发现我们nop掉,然后正常解密之后想dump出来,却发现程序不能正常执行。

然后通过观察我们发现在修复iat代码解密之后,还有解密下一段代码。
但是因为我们nop掉了,在某个地方它有判断,发现被操作了,所以它就没有继续解密了。
程序就无法进行了。

偷懒的方法:在解密完之后,我们就直接jmp真正的OEP了,其他代码我们也不让他执行了。
发现壳的版本是VC.6.0的,那么入口就是GetVersion

然后我们使用esp定律,但是我们发现程序没有断下来,直接执行了。

然后我们我们下面有一个pushad
我们让pushad执行完毕以后再下断点,然后发现这次停下来了。
也jmp到真正的OEP了,但是我们发现它又对IAT做了手脚。

程序脱壳,逆向,c++,windows,microsoft

程序脱壳,逆向,c++,windows,microsoft文章来源地址https://www.toymoban.com/news/detail-560803.html

脱壳的思路:
  -1.找OEP
  -2.dump内存
    -2.1.先把真实的IAT还原回去
  -3.修复IAT表

004E0895    8902            mov dword ptr ds:[edx],eax
我们发现EAX的值已经有了,就是它填进去的中转的函数地址
我们要查看EAX值的来源。

call xxxx
  -esp - 4
lea esp,dword ptr ss:[esp+0x4]
  -esp + 4
==== jmp 
刚开始call,会把下一条指令的地址push 进入 然后esp - 4
然后接着我取esp + 4的地址给esp,就相当于把call抵消了
所以相当于一条jmp指令

Shellcode api调用:
我们对API函数名称进行了hash运算,拿着hash值进行比较,去遍历dll的导出表,然后对每一个api函数名称也进行hash运算,然后进行比较。

005C1C81    AC              lods byte ptr ds:[esi]
005C1C82    E8 13000000     call 005C1C9A
005C1C87    8D6424 04       lea esort 005C1CA8
005C1C8E  ^ EB F1           jmp p,dword ptr ss:[esp+0x4]
005C1C8B    5A              pop edx
005C1C8C    EB 1A           jmp shshort 005C1C81
005C1C90    EB 39           jmp short 005C1CCB
从esi中取一个字节,丢到al中,加密的地方

005B0474    8BD0           mov edx,eax     ; kernel32.GetVersionExA
005B0476    E8 86080000     call 005B0D01
005B047B    8D6424 04       lea esp,dword ptr ss:[esp+0x4]
005B047F    0345 C8         add eax,dword ptr ss:[ebp-0x38]

把eax的值给edx
            8D6424 04
005B14DC    895401 FC       mov dword ptr ds:[ecx+eax-0x4],edx          ; kernel32.GetVersionExA
把API地址保存到了[ecx+eax-0x4]

005B0D73    8D6424 04       lea esp,dword ptr ss:[esp+0x4]
005B0D77    8B57 04         mov edx,dword ptr ds:[edi+0x4]
edx值被毁掉了

我们在edx被毁掉之前,把api的真实地址保存到了ebx中

005B0890  ^\E9 D7FCFFFF     jmp 005B056C
005B0895    8902            mov dword ptr ds:[edx],eax  ; 填充iat
005B0897    E8 39000000     call 005B08D5
填充IAT
然后在这里我们就可以通过ebx进行填充iat

我们就是要在覆盖之前,把它的API地址保存起来,保存到一个我们可以拿到的地方。
然后再用我们保存起来的真实的api地址来填充IAT表,这样IAT表保存的就是真实的API地址。

OD脚本编写:
  -1.查找了调用VirtualAlloc之后的地址,下了断点
  -2.查找获取API地址处,并转存我们API地址到ebx
  -3.找到了填充IAT的地址,使用ebx正确的api地址进行填充回去
  -4.执行到OEP并断下来
  
// 1.先定义变量
VAR VallocAddr
VAR getApiAddr
VAR setIatAddr
VAR oepPoint
VAR realApiAddr // 可以用变量 何必使用寄存器转存

// 2.初始化变量
MOV VallocAddr,0x47A37F
MOV oepPoint,0x47148B
// 这就是转存iat表的地址
MOV getApiAddr,0x14D8 // 距离申请出来的空间的偏移,我们到时候加上基址就好
// 这就是填充iat表的地址指令的下一条
// 我们等他填充了,然后再覆盖它填充的地址为真实地址
MOV setIatAddr,0x0897 // 距离申请出来的空间的偏移,我们到时候加上基址就好

// 3.清除断点信息
BPHWC // 清除硬件断点
BC // 清除断点

// 4.设置我们字节的断点
BPHWS VallocAddr,"x" // 硬件执行断点
BPHWS oepPoint,"x" // 硬件执行断点

RUN // 让程序运行起来 然后到我们的VallocAddr断点停下来
CMP VallocAddr,eip 
JNZ error // 那么就是出错了
// 它停下来以后就意味着它申请的内存空间已经申请好了
ADD getApiAddr,eax // 那么我们就可以添加基址了
ADD setIatAddr,eax // 那么我们就可以添加基址了
BPHWS getApiAddr,"x" // 硬件执行断点
BPHWS setIatAddr,"x" // 硬件执行断点

RUN // 让程序运行到转存IAT的位置
CMP getApiAddr,eip 
JNZ error // 那么就是出错了
MOV realApiAddr,edx // 保存edx的函数API地址

RUN // 让程序运行到修复完IAT表的下一行地址,即这个时候已经被填充加密之后的了
CMP setIatAddr,eip 
JNZ error // 那么就是出错了
MOV [edx],realApiAddr // 然后把正确的地址覆盖下去

RUN // 现在就到OEP了
CMP oepPoint,eip 
JNE error
JMP end

error:
MSG "脚本执行错误"

end:
MSG "脚本执行完毕"

到了这里,关于逆向基础-脱壳的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows逆向安全(一)之基础知识(十)

    之前的文章学习过了四种基本类型:char short int long的汇编表示形式 因为它们的数据宽度都小于等于32位,所以都可以只用一个通用寄存器来存储 接下来的数组显然就无法只用一个通用寄存器就可以存储了 在学习数组之前,再学习一个数据类型:long long(__int64),因为它也无

    2024年02月16日
    浏览(31)
  • Windows逆向安全(一)之基础知识(一)

    前言 逆向是一种新型的思维模式也是软件开发领域中极为重要的技术,涵盖各种维度去深挖软件架构的本质和操作系统原理,学习逆向后可以在各领域中发挥至关重要的作用,其中包括黑灰色,安全开发,客户端安全,物联网,车联网,游戏安全,红队免杀等行业中绘制出更

    2024年02月07日
    浏览(29)
  • Windows逆向安全(一)之基础知识(八)

    这次来研究if else嵌套在汇编中的表现形式,本次以获取三个数中最大的数这个函数为例子,分析if else的汇编形式 首先贴上代码: 先验证执行的结果是正确的: 确认可以函数是可以取出三个数的最大值的,于是开始分析该函数 为方便观看,将多余的验证删去,直接改为 然后

    2024年02月12日
    浏览(34)
  • Windows逆向安全(一)之基础知识(十四)

    一般关于指针的解释都离不开地址。这里先暂且忘记这个概念 指针其实也是一种数据类型,和先前学习的int float等数据类型没有实质上的区别,只不过这个数据类型是在先前学习的所有数据类型后面加上若干个*号,如char *,int *等等,这种数据类型被称为指针 任意类型后面

    2024年02月13日
    浏览(28)
  • Windows逆向安全(一)之基础知识(十六)

    通过先前指针的学习,了解了指针和地址以及数据的关系,现在结合先前的知识继续学习巩固 有了先前的基础,再来看看如何用指针遍历数组 代码 代码说明 稍微说明的一下代码部分 主要是声明了一个数组,然后用两种方法取得数组的首地址,一种是arr[0],另一种则直接是

    2024年02月05日
    浏览(32)
  • Windows逆向安全(一)之基础知识(十三)

    先前讲了分支结构的if else形式,除此之外还有一种分支结构:switch 此次就来以反汇编的角度研究switch语句,并与if else进行比较 有关Switch语句在vc++6.0中生成的反汇编可分为4种情况,这4种情况的区分在于case的不同 代码 switch(表达式)中,表达式应该为整数类型:char short in

    2024年02月01日
    浏览(28)
  • 【Web实战】零基础微信小程序逆向(非常详细)从零基础入门到精通,看完这一篇就够了

    本文以微信小程序为例,从实战入手,讲解有关于小程序这种新型攻击面的渗透,对于了解小程序的安全性和防范措施有一定的帮助。 作为中国特有的一种程序形态,小程序在我们的日常生活中已经无处不在。腾讯、百度、阿里巴巴、字节跳动、京东等各家互联网大厂都有各

    2024年02月04日
    浏览(48)
  • 使用 Codemagic 将 Flutter Windows 应用程序发布到 Microsoft 合作伙伴中心

    https://medium.com/flutter-community/publishing-flutter-windows-apps-to-microsoft-partner-center-with-codemagic-b1962575510c 这篇文章最初发表在 Codemagic 博客上,由 Souvik Biswas 撰写 Flutter 允许您使用单个代码库为移动设备、网络、桌面和嵌入式设备构建应用程序。2.0 的引入使得试用桌面应用程序变得更

    2024年02月04日
    浏览(65)
  • Windows server 2012 安装VMware Tools出现 安装程序无法继续 Microsoft Runtime DLL 安装程序未能完成安装

    1、Windows server 2012 安装VMware Tools出现 安装程序无法继续 Microsoft Runtime DLL 安装程序未能完成安装 2、先不点确定,“win+r”打开运行,输入“%temp%”,打开vmware tool预安装文件夹路径,进入第一个“{一串数字}”的文件夹,发现有vcredist x64.exe、vcredist x86.exe和vmwareTool.msi文件。

    2024年02月11日
    浏览(48)
  • “Windows Server 2012 R2安装VMwareTools提示“安装程序无法验证是否已安装所需的Microsoft更新KB2919355”的解决办法

    Windows Server 2012 R2安装VMwareTools提示“安装程序无法验证是否已安装所需的Microsoft更新KB2919355 网上查询资料说是Windows Server 2012 R2缺少补丁KB2919355 安装KB2919355更新:Download Windows Server 2012 R2 更新 (KB2919355) from Official Microsoft Download Center  或者直接点击安装包下载: 补丁安装包 若

    2024年02月08日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包