打造XP下可运行的微型PE文件
前几天和朋友交流技术,提到手工打造微型PE文件,他说现在网上流传的大部分版本在XP SP3下都不能运行,于是心血来潮,拍着胸脯说:“你放心,忙完了帮你做一个。”
后来花了半天时间,终于打造出一个XP下可运行的微型PE,弹出一个对话框,292字节,当然这离极限也许还差得远,不过自己做了一次,还是有些心得,贴出来和大家分享一下。本文介绍的这个MiniPE可以在下载:http://download.csdn.net/source/774041
第一步 准备PE文件
先创建一个PE文件,为了尽可能地小,我们用汇编语言来编写。代码如下:
.386
.model flat,stdcall
option casemap:none
.data
byData db 90h
.code
start:
end
代码什么也没做,运行就报错(因为PE文件的EntryPoint实际上指向了不存在的区域),代码我们到后面再来填充它,这个PE
文件只包含一个数据节。在Windows XP下,PE文件必须包含至少一个节,否则无法运行,这正是我们为什么要定义byData这个数据的原因。
为了让生成出的PE文件尽可能小,在链接的时候,我们使用/align:4这个选项,指定文件和节为4字节对齐(高版本的Microsoft增量链接器可能不支持4字节对齐,比如我测试的8.0版本,要求至少16字节对齐。所以使用这个选项,应该用低版本的链接器,我用的是MASM32V9自带的链接器,版本是5.12。)
这样生成出来的PE文件只有460字节,这是一个很好的开始,因为大部分极其简单的汇编程序生成出来都会在1.5K左右,如果是高级语言编写的,将会更高。文件的内容如下:
00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?........ ..
00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 A8 00 00 00 ; ............?..
00000040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ; ..?.???L?Th
00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno
00000060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 ; t be run in DOS
00000070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 ; mode....$.......
00000080h: 5D 17 1D DB 19 76 73 88 19 76 73 88 19 76 73 88 ; ]..?vs?vs?vs?
00000090h: E5 56 61 88 18 76 73 88 52 69 63 68 19 76 73 88 ; 錠a?vs圧ich.vs?
000000a0h: 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 01 00 ; ........PE..L...
000000b0h: 77 B8 1A 49 00 00 00 00 00 00 00 00 E0 00 0F 01 ; w?I........?..
000000c0h: 0B 01 05 0C 00 00 00 00 04 00 00 00 00 00 00 00 ; ................
000000d0h: C8 01 00 00 C8 01 00 00 C8 01 00 00 00 00 40 00 ; ?..?..?....@.
000000e0h: 04 00 00 00 04 00 00 00 04 00 00 00 00 00 00 00 ; ................
000000f0h: 04 00 00 00 00 00 00 00 CC 01 00 00 C8 01 00 00 ; ........?..?..
00000100h: 00 00 00 00 02 00 00 00 00 00 10 00 00 10 00 00 ; ................
00000110h: 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 ; ................
00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000140h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000160h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000001a0h: 2E 64 61 74 61 00 00 00 01 00 00 00 C8 01 00 00 ; .data.......?..
000001b0h: 04 00 00 00 C8 01 00 00 00 00 00 00 00 00 00 00 ; ....?..........
000001c0h: 00 00 00 00 40 00 00 C0 90 00 00 00 ; ....@..缾...
第二步 去掉数据节内容
看到文件的最后4字节,90 00 00
00,这正是我们定义的byData(链接器使用4字节对起,后面3字节填0),这当然不是我们需要的东西,我们定义byData,只是为了让链接器生成
PE文件时能至少有一个节。所以我们先把它拿掉,在UltraEdit中直接删除最后4个字节,把000001a8处Section的VirtualSize改为0,这样,文件又少了4个字节。
第三步 去掉DOS Stub
我们的目标是在Windows XP下运行,DOS
Stub自然是多余的,可是链接器并没有选项来去掉DOS
Stub,只好手工来做这个工作,文件偏移0x3C处(IMAGE_DOS_HEADER的e_lfanew)指定了PE文件头位置,这里是
0x000000A8,直接将文件偏移0x3C到0xA8间的数据删除,把后面的数据往前移,再将一些数据适当修正,比如e_lfanew修正为
0x40。这里DOS Stub的大小为0xA8-0x40=0x68,拿掉它,我们的文件又小了104字节,内容如下:
00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?........ ..
00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 ; ............@...
00000040h: 50 45 00 00 4C 01 01 00 77 B8 1A 49 00 00 00 00 ; PE..L...w?I....
00000050h: 00 00 00 00 E0 00 0F 01 0B 01 05 0C 00 00 00 00 ; ....?..........
00000060h: 09 00 00 00 00 00 00 00 60 01 00 00 60 01 00 00 ; ........`...`...
00000070h: 60 01 00 00 00 00 40 00 04 00 00 00 04 00 00 00 ; `.....@.........
00000080h: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ; ................
00000090h: 64 01 00 00 60 01 00 00 00 00 00 00 02 00 00 00 ; d...`...........
000000a0h: 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ; ................
000000b0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000130h: 00 00 00 00 00 00 00 00 2E 64 61 74 61 00 00 00 ; .........data...
00000140h: 00 00 00 00 60 01 00 00 00 00 00 00 60 01 00 00 ; ....`.......`...
00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 C0 ; ............@..
第四步 重叠DOS文件头和PE文件头
在Windows下,PE装载器只关心DOS文件头的e_magic和e_lfanew,有这么多无用的项目,何不把PE文件头往前挪挪,大家挤一挤,再誊点空间出来。当然,PE文件头的长度超过了DOS文件头,往前移动,肯定是会覆盖到
e_lfanew的。e_lfanew是不能随便乱填的,怎么办?我们把PE文件头移动到文件偏移0x04的位置,再把e_lfanew修改为0x04,
现在PE装载器可以正确从e_lfanew找到PE文件头的位置了,我们在来看看PE文件头,在PE文件头偏移0x3C-0x4=0x38的位置,刚好是
IMAGE_OPETION_HEADER的SectionAlignment――节对齐值,刚刚好,我们的节对齐也是4,讲到这里,如果你链接PE文件
时,用的对齐值不是4那么就得修改为4咯。
这一步也很简单,直接把刚才文件偏移0x40的数据拷贝到0x04处,这时候,我们的PE文件总大小为292字节:sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)+4。文件内容如下:
00000000h: 4D 5A 90 00 50 45 00 00 4C 01 01 00 77 B8 1A 49 ; MZ?PE..L...w?I
00000010h: 00 00 00 00 00 00 00 00 E0 00 0F 01 0B 01 05 0C ; ........?......
00000020h: 00 00 00 00 09 00 00 00 00 00 00 00 60 01 00 00 ; ............`...
00000030h: 60 01 00 00 60 01 00 00 00 00 40 00 04 00 00 00 ; `...`.....@.....
00000040h: 04 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 ; ................
00000050h: 00 00 00 00 64 01 00 00 60 01 00 00 00 00 00 00 ; ....d...`.......
00000060h: 02 00 00 00 00 00 10 00 00 10 00 00 00 00 10 00 ; ................
00000070h: 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ; ................
00000080h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000090h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ..............
打造XP下可运行的微型PE文件的更多相关文章
- msvsmon.exe xp下不能运行
远程调试 xp 下不能执行 vs2013 远程调试器 xp下不能运行 vs2010 远程调试器 xp下可以运行
- VOL.1 利用vmware ThinApp 制作非XP下可以运行的IE6 【无插件版】(windows vista/7/8 x86/x64 )
作为一名前端开发工程师,不免要考虑IE6的兼容性,但是大部分挑剔的同行们估计都不会用XP,所以基本上IE6的兼容性测试,都是使用IE Tester或者虚拟机. IE Tester的话,很多地方模拟的还 ...
- Mac下怎么运行python3的py文件
我的Mac现在是10.14.6系统,默认自带的python版本是2.7.(怎么查看版本?打开终端,输入python即可看到版本号) 由于现在需要运行python3写的py文件,需要将自带的python ...
- 如何让VS2013编写的程序在xp下运行
总体分c++程序和c#程序 1.c++程序 这个用C++编写的程序可以经过设置后在XP下运行,主要的“平台工具集”里修改就可以. 额外说明:(1)程序必须为Dotnet 4.0及以下版本.(XP只支持 ...
- C++PE文件格式解析类(轻松制作自己的PE文件解析器)
PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣 ...
- 如何让VS2012编写的程序在XP下运行
Win32主程序需要以下设置 第一步:在工程属性General设置 第二步:在C/C++ Code Generation 设置 第三步:SubSystem 和 Minimum Required Ve ...
- (转载)用VS2012或VS2013在win7下编写的程序在XP下运行就出现“不是有效的win32应用程序“
原文地址:http://www.vcerror.com/?p=1483 问题描述: 用VC2013编译了一个程序,在Windows 8.Windows 7(64位.32位)下都能正常运行.但在Win ...
- VS2012 生成可以在XP下运行的exe文件
1. 在已安装VS2012条件下,安装update,作者已经安装了update3; 2. 相关设置: 设置"平台工具集":在项目右击-属性-常规-在"平台工具集" ...
- 在XP下基于VHD版XP 2003 win7制作的RAMOS心得
在XP下基于VHD版win7制作的RAMOS心得1.用DiskGenius创建1.85G的VHD固定磁盘文件,以win7prosen.vhd为例,然后进行分区格式化,格式化时启用NTFS压缩.2.为了 ...
随机推荐
- 如何查找STM32开发资料
Ⅰ.概述 该文写给那些处于初学ST芯片开发.英文不好而又想偷懒的人. 该文主要的目的是提醒大家:学习一门技术是需要舍得花功夫,捷径是你在起点与终点之间不断的探索,最终总结出来的一条适合自己的路. 下面 ...
- 线程操作API
线程操作API 1.currentThread 2.getId() .getName().getPriority().getStart.isAlive().isDaemon().isInterrupt ...
- C语言 将产生的随机数存入数组,数据不能相同
1.定义一个一维数,数组大小为24. 2.产生0~23的随机数. 3.将产生的随机数存入i数组,要求数组中的每个数据不能相同. 4.补充说明,这个子程序要求每次调用后,这个数组里面就 存放了0~23这 ...
- java中对象的序列化和反序列化
[对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...
- Oracle表结构转换SqlSERVER表结构 脚本
在审计工作中,有时需要将Oracle的表结构修改后再SqlSERVER中创建表结构,然后将数据导入到SqlSERVER中,在修改表结构的过程中方法狠多.手工修改,最蠢的方法,或者用工具UE批量修改,还 ...
- [Letcode] 1. Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...
- http://www.linuxso.com/linuxpeixun/10332.html
http://blog.chinaunix.net/uid-134240-id-62371.html http://blog.chinaunix.net/uid-26495963-id-3279216 ...
- 深入浅出TCP/IP簇
TCP/IP是“transmission Control Protocol/Internet Protocol”的简写,中文译名为传输控制协议/互联网络协议.TCP/IP不是一个协议,而是一个协议簇的 ...
- Python实现NN(神经网络)
Python实现NN(神经网络) 参考自Github开源代码:https://github.com/dennybritz/nn-from-scratch 运行环境 Pyhton3 numpy(科学计算 ...
- P1912: [Apio2010]patrol 巡逻
这道题讨论了好久,一直想不明白,如果按传统的随便某一个点出发找最长链,再回头,K=2 的时候赋了-1就没法用这种方法找最长链了,于是乎,更强的找最长链的方法就来了..类似于DP的东西吧.先上代码: ; ...