史上最全最完整,最详细,软件保护技术-程序脱壳篇-逆向工程学习记录(二)

简介: 史上最全最完整,最详细,软件保护技术-程序脱壳篇-逆向工程学习记录(二)

史上最全最完整,最详细,软件保护技术-程序脱壳篇-逆向工程学习记录(一)

https://developer.aliyun.com/article/1618653



三· 重建IAT输入表(Import Address Table)

1 . 啥是输入表?

在各种不同版本的Windows系统中,DLL的版本各不相同,同一函数在不同版本DLL中的位置也可能不同;另外一个原因在于DLL的重定位,DLL文件的ImageBase值一般为10000000,但当两个DLL尝试装载到同一个地址时会发生冲突,因此有一个DLL得寻找另一个地址装载,这就是所谓的DLL重定位。

因此当我们要调用某个DLL中的函数时,需要借助IAT(Import Address Table,导入地址表)作为中间桥梁。PE文件在装载时由PE装载器将导入函数的真实地址写入到IAT时,函数调用时则需要从IAT中获取函数的真实地址。

对于每一个引入的可执行文件(例如dll),有一个镜像引入描述符(IMAGE_IMPORT_DESCRIPTOR)。
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
     union {
          DWORD Characteristics;         // 0 for terminating null import descriptor
          DWORD OriginalFirstThunk;   // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
     };
     DWORD TimeDateStamp;           // 0 if not bound,
                                                                // -1 if bound, and real date\time stamp
                                                                // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                                                // O.W. date/time stamp of DLL bound to (Old BIND)
      DWORD ForwarderChain;           // -1 if no forwarders
      DWORD Name;                             // RVA,指向字符串,是这个可执行文件的名字。例如"ACE.dll"
      DWORD FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
IAT是一个IMAGE_THUNK_DATA类型的数组。有多少个函数被导入,这个数组就有多少个成员。该数组以0结尾。
typedef struct _IMAGE_THUNK_DATA32 {
     union {
           DWORD ForwarderString;          // 一个RVA地址,指向forwarder string 
           DWORD Function;                       // PDWORD,被导入的函数的入口地址
           DWORD Ordinal;                         // 该函数的序数
           DWORD AddressOfData;           // 一个RVA地址,指向IMAGE_IMPORT_BY_NAME
      } u1;
} IMAGE_THUNK_DATA32;
PIMAGE_IMPORT_BY_NAME是一个非常简单的结构,就两个成员。
typedef struct _IMAGE_IMPORT_BY_NAME {
     WORD Hint;            // 该函数的导出序数
     BYTE Name[1];      // 该函数的名字
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

2 . OD跟踪输入表

例程序:

这是个简单的MessgeBoxA对话框程序,用OD打开:

虽然OD注释可以识别到这是MessgeBox,但点开这条指令是call 004011EA,那为什么它知道内存地址0x004011EA地址是一个MessgeBoxA的API函数呢?

那我们就在这行按下回车Enter键:

可以看到这是个跳转,其实周围还很多都是跳转,查看下面按是跳转到哪里:

上面显示的是取[00402048]内存地址里面的值=77D507EA跳转,为了验证一下,我们在内存窗口Ctrl+G输入00402048,就来到了这个地址:

根据小端存储,从右往左读,发现正是77D507EA!

所以我们可以知道在这整个程序无论到在个位置调用MessgeBoxA,它都相当于call 004011EA,在这里集中跳转到MessgeBoxA的动态链接库!

可以看到上面这些都是OD分析给我的,但是OD为什么会知道呢,其实就是根据IAT得出的!

接下来我们继续跟踪输入表,Alt+M到内存双击PE文件头,也就是00400000区块:

然后我们就可以看到标准PE头文件格式: 标志: Image Base:

偏移地址,这是输入表的地址Import Table address:

回到内存窗口,其实输入表所在地差不多就在这个位置:

接下来我们在代码窗口Ctrl+G搜索00402050,我们就来到了这里,但是发现没办法分析,因为它认为我们这不是在代码段:

所以我们要像之前一样安装一个新的插件:

安装好插件后重新打开,就可以点击Analyze This!

可见左边黑色数据是小端存储,右边绿色是OD简化成了我们方便阅读的字节形式,都是相对400000

的偏移地址,可见总共有两个IMAGE_IMPORT_DESCRIPTOR,最后一个全是0是作为结束的标识。我们先尝试Ctrl+G搜第一个参数OriginalFilrstThunk地址00402098:

然后就走到了INT的第一个参数IMACE_THUNK_DATA又是一个偏移地址00402122,继续搜:

可见我们就来到了IMAGE_IMPORT_BY_NAME内,可找到函数的名字(都是由ASCII码转换翻译的)!

然后看到IMAGE_IMPORT_DESCRIPTOR第五个参数FirstThunk,这才是真正指向IAT的偏移地址:

搜索到:

可见其实这就是IAT输入表!

3 . HOOK-API

壳为了防止输入表被还原,强化壳自身的保护功能,会在IAT大量加密。

例如:源程序要调用一个函数的时候需要找IAT,然后却进到了壳程序进行监控般的跳转才能最终回到IAT!


四· FSG压缩壳和ImportREC的使用

程序可以正常运行:

查看壳:

可见这是用Delphi7.0写的程序,API比较多,所以IAT修复比较麻烦!

安装壳程序,点击install.exe,或者自行解压fsg.rar:

给程序FishC加壳,拖拽即可!这是一个压缩壳,压缩44% 加壳后程序也可正常运行!

现在查看壳就可看到壳了:

把加FSG壳后的程序用OD打开:

此时用老方法较为复杂,目前使用一种新方法,步骤如上图1234,选项/调试选项/SFX/字节方式跟踪真正入口处/重新运行!

在这之后,还是回到了原来的地方,然后再带点击选项/调试选项/SFX/停在自解压器的入口/重新运行/,就可以看见左下角在疯狂的运行,这是在模拟程序的运行,自解压:

然后就来到了OEP,接下来就是右键/分析/从模块中删除分析:

接下来就可以dump操作了。由于SFG壳破坏了IAT,所以不要勾选重建输入表,因为勾选了也没用!我们接下来还要借助ImpREC.exe神奇工具修复IAT!

如图,要确保要修改的程序被OD打开中或者与运行中,ImpREC才能检测到,然后根据我们刚才跟踪到了SFX代码真正入口点的地址,提取偏移地址,修改上面红色框起来的OEP,然后点击IAT AutoSearch就弹出一个提示框:

ImportREC会自动搜索所有的IAT!

翻译:好像找到了一些东西,但也有可能不不正确,如果不正确,建议把RAV改成:00001000 Size改成:00094000

接下俩我们就来验证一下,在内存搜索RAV地址,看它是不是IAT的入口点:

就看到这里:

继续往下滑就可以看见熟悉的API函数:

可见00461BEC上面还包含一些数据其实也是,所以我们还要是要把RVA改成:0046B12C,把这些数据包含进去,这才能确保我们的IAT修复的是完整的,才能正常打开程序!

可见IAT最后到了这里:

所以Size也要修改,范围大了可以,范围小了就不可以,只要把全部IAT包含到了就可以!我们修改成大概10000吧

然后我们就可以点击Get Imports按钮了!

加载一会儿,可以看到很多的valid:NO这些就都是不合法的,总共有6642条都是不合法:

所以我们点击Show Invalid按钮把不合法的都展示出来,可见这些不合法的数据穿插在各个IAT里面,只要程序加载到这里的时候,加载不到,就会报错!所以我们右键/Cut thunk(s),把这些不合法的东西全部都给砍掉!

{AF36F00E-F579-4A0C-9764-32251CE916C7}.png

然后就可见我们见到的都是valid:YES的了,然后我们就点击Fix Dump按钮,选择覆盖刚才OD的dump文件:

{9317CEB9-AAAD-42D2-B3B7-C60ACEBC0661}.png

然后它就帮我们多生成了一个文件dump_可以正常运行!

然后再用PEiD查看壳,如果有时候查看不出来 image.png

可以选择选项/深度扫描: image.png

就出来了!也可以观察到,脱壳后的文件变大了!


五 . UPX和WinUpacx压缩壳

UPX官网

UPX壳是目前最流行的,最稳定的壳,更新也较块!

1 . upx309w命令行加\脱壳

image.png

win+R打开控制台,cd到壳程序目录下,upx.exe加壳,后面的才参数是我们待加壳地程序,加壳后可以看到,压缩到了原来的51.93%,大小从582656变成了302592字节!

其实也可以不用命令行,直接拖拽到upx.exe加壳!

然后我们就能查到壳: image.png

然后查阅文档可知,命令加上-d参数,即可脱壳: image.png

如下:

image.png

2 . Free UPX

image.png

点击Add files按钮选择程序,COMPRESS是加壳,DECOMPRESS脱壳,下面的Backup file可以选择create可以创建一个副本,备份原程序!

3 . OD脱UPX壳

OD打开加UPX壳后的fishc程序: image.png

通过堆栈平衡原理寻找OEP过程中,硬件断点来到这里: image.png

由于这是3.09的版本壳,在之前的版本有可能是jmp,但这里jmp在下面,所以我们先取消硬件断点,然后在下面的jmp加断点/运行至此/去掉断点/F8/分析/分析代码,就来到了OEP: image.png image.png

然后dump操作,注意不要勾选重建输入表,接下来我们要用ImportRE恢复!

5 . 使用ImportREC修复IAT

image.png

  1. 先点击小三角选择用OD正在运行的原程序文件
  2. 更具OD找到的OEP,修改ImportREC的OEP里面的偏移地址
  3. 点击IAT AutoSearch按钮确定
  4. 根据给出的RAV偏移地址去OD内存搜索验证,保证输入表没被修改,如果被修改了,就要把RAV的偏移地址调整过来,把IAT包含进去!这里可见上滑上面没有了,是可以的准确的,下面的Size也把IAT包含了,OK image.png
  5. 点击Get Imports按钮,点击Show Invalid按钮,可见没有错误的IAT image.png
  6. 就可以直接Fix Dump选择刚才OD的dumpupx文件了!

6 . WinUpacx壳

该壳压缩效率更高,但已不更新!

image.png

界面中文,比较友好!建议勾选3.清除导出表/4.清除重定位表

然后压缩之后会出现一个文件: image.png 这个文件去掉.bak后缀之后就是我们的原程序备份!

然后OD打开: image.png

入过一开始不是这里,那也可以Alt+M,双击fishc在数据窗口找到偏移地址,即可搜索: image.png

接下来就是根据堆栈平衡寻找OEP: image.png

就可进行dump操作,由于输入表已被破坏所以记得不用勾选重建,重建也是错误的!

然后其实和上一个程序一样操作ImportREC,不多赘述!

然后如果还不满意可以再进行LordPE操作: image.png

最后这就就完美啦!恭喜结业!!!芜湖!!!

相关文章
|
11月前
|
开发框架 小程序 前端开发
带你了解小程序的框架之谜
带你了解小程序的框架之谜
|
1天前
|
安全 API 数据安全/隐私保护
史上最全最完整,最详细,软件保护技术-程序脱壳篇-逆向工程学习记录(一)
史上最全最完整,最详细,软件保护技术-程序脱壳篇-逆向工程学习记(一)
10 0
|
2月前
|
NoSQL 前端开发 程序员
【震撼揭秘!】程序员绝不会告诉你的秘密:掌握汇编语言调试,轻松从软件故障中全身而退——透视代码底层,成为Bug猎人!
【8月更文挑战第31天】《调试的艺术:如何利用汇编语言追踪和解决软件问题》探讨了使用汇编语言进行高效调试的方法。无论是初学者还是资深开发者,面对棘手的 bug 时,高级语言的信息往往不足。文章通过具体示例展示如何通过汇编代码定位问题,如 C 语言中数组求和函数的崩溃问题。借助 `gcc -S` 生成的汇编代码和 GDB 调试器,可以深入理解程序行为,从而更准确地解决问题。掌握这一技能,将使你在复杂问题面前更加从容。
31 2
|
2月前
|
JSON 数据格式
【Axure高手秘籍】掌握这招,让你的原型设计效率飙升!——元件库导入与使用教程及主流资源下载全解析
【8月更文挑战第20天】Axure RP是界面设计与交互原型制作的强大工具。掌握元件库能显著提升设计效率。元件库包含预设UI元素如按钮、表单等,可直接拖放构建布局。在Axure RP中,通过“元件”选项下的“库”可访问并导入新元件库。导入后,轻松拖放元件至画布调整,甚至自定义样式和交互。利用脚本还能模拟真实交互效果,如按钮点击反馈。推荐资源包括Axure Marketplace、UIZilla等,助力高效设计。
49 0
|
5月前
|
安全 API 数据安全/隐私保护
免杀开发基础(1)
本文是关于Windows恶意软件开发的技术介绍,主要包括动态函数加载和执行、Shellcode执行技术以及注入技术。动态函数加载避免了静态链接到特定库,增加了分析难度。Shellcode执行涉及通过指针、内存分配和回调函数等方式。注入技术如APC注入,包括枚举进程线程、分配内存、写入有效负载等步骤。此外,文章还提到了使用异或加密来隐藏Shellcode,以规避静态特征检测。总的来说,文章探讨了免杀技术的基础知识,强调了在恶意软件开发中灵活性和创意的重要性。
|
5月前
|
移动开发 安全 前端开发
代码混淆不再愁:一篇掌握核心技巧
代码混淆不再愁:一篇掌握核心技巧
68 5
|
存储 JSON Kubernetes
证书管理工具 cfssl 浅尝
证书管理工具 cfssl 浅尝
313 0
|
5月前
|
存储 安全 算法
Android安全性: 如何防止Android应用的逆向工程?
Android安全性: 如何防止Android应用的逆向工程?
162 1
|
JavaScript 前端开发 测试技术
6款程序员实用工具,老少皆宜,你一定用得上!
6款程序员实用工具,老少皆宜,你一定用得上!
124 0
|
SQL 敏捷开发 监控
好文赏析:一文读懂运行时应用程序自我保护(RASP)
RASP作为一种新型的、有效的、实时的应用保护手段,正被越来越多的企业使用,本文用浅显易懂的文字讲解了RASP技术、RASP与WAF的关系,并提供了应用解决方案,快来阅读吧~
366 0