UPX手动脱壳

UPX手动脱壳脱壳入门,不喜勿喷,欢迎指正。参考《加密与解密(第四版)》0x01壳&脱壳首先了解一下什么是壳,壳实质上是一个子程序,它在程序运行时首先取得控制权并对程序进行压缩。同时隐藏程序真正的OEP。而脱壳的过程总体分为三个步骤:查找真正的程序入口点抓取内存镜像文件重建PE文件关于壳的类型有以下几种:解压->运行解压->运行->解压.->运行解压decoder|encodedcode->decode->excRunth.

大家好,欢迎来到IT知识分享网。

脱壳入门,不喜勿喷,欢迎指正。
参考 “逆向界圣经” 《加密与解密(第四版)》

0x01 壳&脱壳

首先了解一下什么是壳,

壳实质上是一个子程序,它在程序运行时首先取得控制权并对程序进行压缩。同时隐藏程序真正的OEP。

而脱壳的过程总体分为三个步骤:

  • 查找真正的程序入口点
  • 抓取内存镜像文件
  • 重建PE文件

关于壳的类型有以下几种:

  • 解压->运行
  • 解压->运行->解压.->运行
  • 解压 decoder|encoded code->decode ->exc
  • Run the virtual machine

0x02 Dump

一般找到程序入口点(OEP)后我们需要Dump出脱壳之后的文件。
那么,什么是dump?

定义:

dump(抓取内存镜像,“转存”),就是读出指定地址的映像文件并以文件方式保存。一般在OEP处(因为此时一些项目已经完成了初始化)dump

原理:

一些dump工具(如LoardPE、PETools等)利用Module32Next函数,函数声明如下:

BOOL  Module32Next(HANDLE hSnapshot,LPMODULEENTRY32 lpme)

LPMODULEENTRY32其实是一个结构体指针,结构体类型是MODULEENTRY32,这个结构体有两个字段modBaseSize,modBaseAddr,分别代表了一个进程的映像大小与基址。
这类工具先根据这俩个字段获取了一个进程的映像大小与基址;然后用ReadProcessMemory函数读取进程数据同时检测DOS文件头和PE文件头的字段完整性,最终决定是直接用进程文件头还是换用原始文件头(LordPE工具是直接获取原始文件头)

0x03 ESP定律(栈平衡原理)

先给出esp寄存器的功能:

存放栈顶的偏移地址

有关汇编代码中call指令实质上是

push ip                 ;把下一条指令的地址(存放在ip寄存器中)入栈
jmp near ptr 地址        ;跳转到该函数的地址处

还有ret和retf(一个函数结束的标志):

pop ip      ;(ret)返回到call指令的下一条指令
pop IP      ;(retf)返回到call指令的下一条指令
pop CS

在编写加壳软件时,我们必须要保证外壳初始化的现场环境(即各个寄存器的值)与源程序的现场环境是相同的,所以,在程序自解密或者自解压过程中,对于多数壳,它们会先将当前寄存器状态压栈,如使用pushad/pushfd。
而在解压结束后, 会将之前的寄存器值出栈,如使用popad/popfd,一般标志寄存器不是很重要,一般不做处理。
所以编写加壳软件必须遵守的是栈平衡原理。

因此在寄存器出栈时, 往往程序代码被恢复, 此时硬件断点触发(pop IP),这就是我们要下硬件断点的原因,然后在程序当前位置,只需要一些单步操作,就会到达正确的OEP位置。

也就是说,我们可以这么认为,如果载入程序后只有esp寄存器(eip除外)内容发生变化,那么这个程序多半可以用ESP定律。

0x04 实例

加壳程序:re_sign.exe
使用工具:OllyDbg

导入od看到如下提示,点击“否”
在这里插入图片描述
单步调试前先看寄存器窗口的值,此时程序停在了pushad。
在这里插入图片描述
F8执行完pushad,再看寄存器窗口,除了EIP指令,只有ESP寄存器变红。(表明当前指令只用到了esp寄存器)
在这里插入图片描述
再看堆栈面板(把未执行pushad指令时的各个寄存器状态跟现在的堆栈面板的数据进行了比对),发现各个寄存器的值都入栈,表面开始进入壳代码。
在这里插入图片描述

我们接下来就可以下硬件断点了,查看esp寄存器里的值是19FF54,od命令行输入“hr 19FF54”下硬件读断点。
在这里插入图片描述
按F9,看到程序停在了popad指令的下一条指令,说明程序处理完了外壳代码,在调用popad指令恢复现场环境时访问这些栈,此时触发中断。我们比对也可以发现那些寄存器里的初始值恢复了,离我们的OEP不远了。
在这里插入图片描述
F8单步执行下去(中途有个循环可以下断点跳出去),然后jmp指令跳转(跳回程序的OEP),看到了几个push语句如下:
在这里插入图片描述
其中前几个是

push ebp          ;入口点OEP,大多数程序的第一句指令都是push压栈。
mov ebp,esp
push -1

我们便可以判断我们已经找到OEP了,此时右键(利用OD的Ollydump工具)把程序dump出来即可得到脱壳后的程序。
在这里插入图片描述
拖到ida里面看看效果,现在已经可以正常静态分析了。
在这里插入图片描述
其实也有另一种思路。
既然很多OEP的第一句都是push ebp,而壳程序运行前会把ebp寄存器的值入栈,等到运行完壳代码再出栈,接着就是push ebp对ebp进行写入操作。我们不妨对ebp设置硬件写断点,那不就直接F9断在了OEP处了。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/24122.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信