首页
社区
课程
招聘
[旧帖] [原创]161bytes的PE文件是如何炼成的 0.00雪花
发表于: 2013-11-3 00:30 1655

[旧帖] [原创]161bytes的PE文件是如何炼成的 0.00雪花

2013-11-3 00:30
1655
本文视你对PE文件的熟悉程度,初学者,大概会花掉你两个小时左右的时间完全理解。

最近在网上看到有大神做了个161bytes的hello world,正巧毕业前忧郁闲着,就花几个小时的时间把这个程序结构厘清了一遍,算是重新更深入地学习一次PE文件,写下本文和大家交流。

预备工具:一个xp系统,win7下它跑不动。Winhex,记得弄个破解版。其它的一些你习惯的PE查看工具(我试了几个都不能很好解析这个PE,其实PE解析工具就是在模仿windows解析PE文件,如果程序员本身都对PE文件没有一个深入的理解,写出来的工具模仿windows加载器不够像,就不足够应付畸形的却能够正常运行的PE)

下面先附上十六进制。
4D5A0000504500004C010100E97700000000007869616F00280002000B0148656C6C6F20576F726C642100000C0000005553455233320000000040000400000004000000300000009D000000040000000C000000300000000C00000000000000020000000000000000000000000000000000000000000000020000000000000000000000380000006A006813004000681E0040006A00FF159D004000C3DD010080

Copy到winhex里,粘贴选择ASCII Hex,保存即可。

正式进入正题:
缩小PE,一个惯用手段就是把各种PE结构重叠到一起,这样的PE看起来很晦涩,一个数据项往往扮演着多个数据结构的角色。
---------------------------------------------------------------
1、重叠NT文件头到MZ-DOS头。


如图,把原MZ-DOS头的最后一个数据offset to new exe header设为04,就把NT文件头移到了第四个字节,NT头的数据把MZ DOS头完全覆盖。
此时MZ-DOS的offset to new header同时是NT头的可选头中,section alignment,节对齐,好在4是2的幂次,是可以使用的数值。
这样就省下了不少字节。
---------------------------------------------------------------
2、重叠引入表和可选头。
这里先回顾一下引入表。由于EXE中需要引入别的DLL中的函数,所以在PE中就要有所说明,即引入表,其中要说明包含引入的DLL信息和引入的函数的信息。
具体说来,可选头尾部的数据目录项的第二项(data directory)-->IMAGE_IMPORT_DESCRIPTOR(引入的DLL的信息)-->IAT(引入函数的信息,这里仅讨论IAT,关于INT和IAT不作解释)
由于引入的DLL可以有很多个,引入的函数也可以有很多个,所以上面所说的IMAGE_IMPORT_DESCRIPTOR其实会有许多个,是一串数组。IAT也是个数组。
OK,预热完毕,还不懂的自行百度有许多资料。

附上
数据目录项结构:
IMAGE_DATA_DIRECTORY STRUCT 
  VirtualAddress dd ? 
  isize dd ? 
IMAGE_DATA_DIRECTORY ENDS
DLL描述符结构:
IMAGE_IMPORT_DESCRIPTOR STRUCT 
  union 
    Characteristics dd ? 
    OriginalFirstThunk dd ? 
  ends 
  TimeDateStamp dd ? 
  ForwarderChain dd ? 
  Name1 dd ? 
  FirstThunk dd ? 
IMAGE_IMPORT_DESCRIPTOR ENDS


可选头末尾指出有两个数据目录项,第一个全为0,第二个即是框住的,引入表。引入表指向的DLL描述符,“30”处指向的即是“user32”的ASCII码。
紧随其后的“9D”即指向IAT表,看到图中9D的偏移,“DD 01”即1DD,即是MessageBoxA在user32.dll导出表中的序号。
附IAT项的结构
IMAGE_IMPORT_BY_NAME STRUCT 
  Hint dw ? 
  Name1 db ? 
IMAGE_IMPORT_BY_NAME ENDS
---------------------------------------------------------------
3、重叠节表到可选头
这里需要指出的是NT头中的SizeOfOptionalHeader项中的值,并不是指可选头的大小,更准确来说,应该是,节表开始的位置,相对可选头开始的位置的偏移。
简单地说,其实这个东西标识的是节表的开始,在这个例子里,作者给它写上了0x28,也就是说节表在0x44处。



第二个框是可选头开始的幻数“0B01”,下面那一大串框起来的就是节表中的第一个节的信息。
附上节表结构
struct  IMAGE_SECTION_HEADER
{
BYTE Name[8];
union
{
DWORD PhysicalAddress;//物理地址
DWORD VirtualSize;//真实长度,这两个值是一个联合结构,可以使用其中的任何一个,
//一般是节的数据大小
} Misc;
DWORD VirtualAddress;//RVA
DWORD SizeOfRawData;//物理长度
DWORD PointerToRawData;//节基于文件的偏移量
DWORD PointerToRelocations;//重定位的偏移
DWORD PointerToLinenumbers;//行号表的偏移
WORD NumberOfRelocations;//重定位项数目
WORD NumberOfLinenumbers;//行号表的数目
DWORD Characteristics;//节属性 如可读,可写,可执行等
};

可以看出,真正有用的信息从0x4c开始,意思就是说这个节实际只有4个字节大小,文件中的地址是0xC,对齐后真正需要装到内存的有0x34个字节,装入后的RVA还是0xC。

这里插个问题,为什么对齐后真正需要装到内存的是0x34个字节?(其实0x2d个字节就可以)
这个我也不是特别肯定,我觉得应该是与引入表需要的字符串资源有关,如果小于0x2d,按照对齐只能是0x29,则没有完全包括“user32”这个字串。会导致windows想要加载相应模块时出错。

---------------------------------------------------------------
4、重叠汇编代码和data directory。
如你们所见,在引入表处,作者就已经近不及待地在不影响程序正常运行的引入表的大小处直接插入了代码,随后汇编代码覆盖的是其余的data directory项,并不会造成什么别的影响。
---------------------------------------------------------------
最后说一下程序运行起来的过程。
首先windows就像我们之前分析的那样,把所有东西准备好,把IAT表指向的位置换成MessageBoxA的真实地址(0x9d)。
随后windows到可选头中查找程序入口地址,0xC,然后跳到0xC处开始执行。0xC处是一个跳转语句直接跳到下面的正常代码。
这个插个问题,为什么要这么拐弯抹角跳一次,直接指向功能代码不行吗?
因为之前节表限制了,这个节大小只能有4个字节,这个“4”,即是节表的大小,还是MajorSubsystemVersion,这个值必需得是4。4个字节能做什么?能放下一个跳转,跳到任何地方,做任何事情(长跳也可以,分两次跳),于是就有了一个跳转。
---------------------------------------------------------------
总结:
黑客精神就是这样,投机取巧,无孔不入,在剑尖上带着脚镣跳舞,最终完成一个个奇迹。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 238
活跃值: (55)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
很好,很长
2013-11-3 11:27
0
雪    币: 48
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
图片挂了
2013-11-4 12:00
0
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
。。複製圖片地址再貼到地址欄,湊合著看吧
2013-11-4 12:30
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
还是没懂为什么要跳转。
直接把入口弄到88为什么不行。。
节的大小为4是说只执行完4个字节的指令比如88处的push 0就不往下执行了吗?只有jmp才能继续下去?
2013-11-4 16:53
0
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
指令是可以在任意地方执行的,只要在内存里并且没开DEP。这个不是不能执行,你注意看弹出的提示应该是直接就说PE文件有问题,是因为你要加载“user32”这个DLL,而“user32”这个字串没有包含在你的节里。
你看到节表,节的实际长度是4字节,但实际加载到内存里的是对齐后的0x30个字节,这样就把“user32"包含进去了,你改成0x2d也是可以的,但再小4字节就不行了
2013-11-4 22:02
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
刚才把user32写在了11h-16h,再将节表的dllname指针指向11h,结果那里还是只能最小填2dh,填小一点的话不是也已经把user32覆盖了么?
2013-11-5 13:30
0
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
嗯……我覺得你說得有道理,我按著你的做法做了一遍發覺確實不是我想的那樣。我利用另一個172bytes的PE做了一遍,附上4D5A4D79504500004C0101004D657373616765426F78410078000F010B0155736572333200680C004000EB0448000000FF34246A0090EB54000040000400000004000000040000006A00EBD90400000000000000950000009400000000000000020000000000100000100000000010000A000000000000000200000000000000000000008800000014000000FF157000400090C31E000000700000002E0000001E0000006B0000001E000000

我目前看到的唯一一個相同點,就是節對齊後必需要覆蓋過,導入描述符的第一個字節,即0x39,順便說一句,這個東西不一定要是4的倍數。那個172字節的PE,最小的對齊後節大小是0x6B,當然,你得先把前面的文件中的節大小改小(我改成了2E),它的節表就在PE文件的最末尾。

由於161的那個PE中,我們所改的數據即是sizeofimage,同時也是節的對齊大小,我並不確定是哪個數據出了問題。看到網上有人說sizeofimage必需大於節在內存中的地址範圍。
http://www.pediy.com/kssd/pediy09/pediy09-462.htm
此PE足以說明這是不正確的。

但我覺得我的結論不是一個清晰的結論,還會繼續研究,同時希望能看到你的成果
2013-11-5 15:41
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
172程序
节表
rva与代码开始的值
小于0c(代码开始位置) 错误0x07b
大于0c(代码开始位置) 0x05

161程序
节表
rva与程序入口地址的值

大于48(代码开始位置) 错误0x05
rva最大48

size值   rva值

2b(当rva=1e时最小值)  -1e y
2a(当rva=1f时最小值)  -1f y

如果当rva<1e不成功请注意一下那个6b(size of raw data,的确要把那个包进去)..

size+rva>48(代码开始位置)  也就是说节开始位置必须小于<=代码开始位置,但是
加上size之后要大于代码开始位置,也就是说代码第一个字节必须在节表里面

另外就是在文件中节的大小(virtual)一定要小于等于在内存中大小(size of raw data)
,不然报错不是win32程序

在172程序中size+rva(0c)=10>0c,也无法验证 因为size被固定成4,rva也无法取更小
(fileheader的第一项Magic开始是在0c,因此无法取更小,貌似要从fileheader开始,已经在172程序
中验证过,当取比0c更小的值即使size+rva>48也报0x07b错误)

我想了一下,将161的代码开始从0d开始写,为eb 790000(短跳转到88),结果发现
50处的size也可以改成0c(0c+4>0d&&0c<0d)和0d(0d<=0d)
应该也能一定程度证明一下我的猜想吗?????

晚上头有点晕。。可能有些不对请大神指教。。
2013-11-6 01:25
0
雪    币: 704
活跃值: (657)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
程序之美~
2013-11-9 21:02
0
雪    币: 114
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
有点深奥,在学习下
2013-11-9 23:31
0
游客
登录 | 注册 方可回帖
返回
//