前言
PE文件即Windos操作系统下的可执行文件的文件结构名称,其中包含但不限于.dll .exe .sys .ocx等等。内存加载PE顾名思义就是通过内存,而非文件。这里的内存指代的是直接加载源。
这个技术其实很早之前就有了,网上也有很多开源可参考的代码,但是仅做一个伸手党那是绝对不行的,首先这些历史悠久的代码存在或多或少的bug,或莫名的崩溃咯,或32和64不兼容咯,各种问题皆是。当然,这些前辈先贤的代码一定是具有非常大的参考和开拓意义的。
技术用途
所谓的内存加载其实就是在加载过程中不适用系统提供的方法,而自行实现这些方法。宏观一点来讲,加载这个操作也包括调度和资源分配。这里调度自然是加载代码。但是资源其实这里仅仅涉及线程和内存的分配。这两项只能使用系统的,但是整个调度过程由我们自己实现。
因此由于加载过程除掉内存和线程资源,其他在映射过程产生的记录信息等通通都不会存在。就是说除了线程和内存,模块的地址、名称、文件等正常加载记录的所有信息几乎都不存在。这样的一个包含可执行代码和资源的模块在非内存的层面几乎是隐身的。
看到上面的用途很多人又开始想为所欲为了,但其实除开灰色的用途意外,该技术完全可以使用在正常的编程中,这可以很大限度上提升破解的难度。将编译型的语言一下子提升到解释语言类似的层次,我们对于内存资源的管控也可以随时让我们更新代码,实现热更新等功能。并且在很多需要授权验证等程序上也可以加大程序的保密性,将软件的破解难度大大提升。
实现要点
PE映射主要分为3部分
1、区段文件复制,将区段文件进行内存对齐复制到预定偏移位置
2、重定位修复,将代码中涉及到重新定位的地方按照将要加载到的位置进行设置
3、函数导入设置,被加载模块所用到的其他模块的函数进行导入操作,保证函数可用
小技巧
关于兼容性我们完全可以在源码中进行一些简单的判断,对其分别进行设置,毕竟在64位PE文件加载中只有少数字段扩展到了64位。
并且可以进行一定的封装,将固定不动的部分进行隐匿封装,而将会不同的部分以接口的方式让其可以进行之后的覆盖实现。在这样简单的实现就可以在应用层和驱动层都愉快地玩耍了。
当然在驱动层玩耍的话,代码要稍微严谨一些。
我的实现
应用层实现(内存加载kernelbase获取导出调用测试):
内核实现(正常加载驱动A使用内存加载代码加载驱动B,b线程循环输出):
子类化覆盖接口实现:
后记
总共就1800行代码,其中将内存分配,获取地址的方法导出,可以让我们自行覆盖,这样的好处是可以在本进程也可以进行跨进程加载。
整个代码写完后对PE文件的加载过程有了更清晰的认识,大概比以前清晰100倍把。
并且其中对空的运用也是十分的巧啊,直呼学到了学到了。
代码路途漫漫,我辈上下求索。