手写PE文件(helloworld)

⼿写PE⽂件(helloworld)
⼿写PE⽂件(hello world)
⽂章⽬录
⼯具
winhex
平台
win10
注意事项
**1、**⽂件读取中以字节读取⽂件,但是存储是以各种类型来使⽤变量
**例如:**word型为两个字节,读取时时先读取低位后读取⾼位,0x1234在读取时显⽰为34 12 **2、**磁盘中以200H为⼀个单位
**例如:**PE⽂件的headers部分为100H,但在磁盘上占200H
**3、**内存以1000H为⼀个单位
**例如:**PE⽂件的sections部分为500H,但在内存上占1000H
PE结构
⼿写PE⽂件⾸先要了解PE⽂件的结构,⼤体结构如下:
goagent iosDOS头
复旦黄山门
PE标志
PE⽂件头
PE可选头
段头
各个段
过程
我们使⽤winhex写⼀个经典的hello world(32位),按照PE⽂件的⼤体结构依次写:甲壳素壳聚糖
DOS头(共0x40个字节)
在DOS头中有⽤的基本就两个,e_magic和e_lfanew
e_magic:WORD型,⼀般为0x4D5A(MZ),PE⽂件必须都是’MZ’开头。
e_lfanew:LONG型,⽤来表⽰DOS头之后的NT头相对⽂件起始地址的偏移。
e_magic:固定为4D 5A
e_lfanew:DOS头的40个字节+DOS程序中的⼤⼩(因为尽可能简单点所以直接省略,0个字节)=40个字节,即为0x00000040,应填写40 00 00 00
DOS程序(⽆固定字节长度)
DOS程序⼀般情况下在⾮DOS系统下将会略过,⼀般情况下将会有汇编编译器⾃动⽣成即“This program cannot run in DOS mode”,但是需要保留⼀定⼤⼩,保留70H即可
PE标志(共4个字节)
固定的标志“PE”,即0x00004550,填⼊“50 45 00 00”
PE⽂件头(共0x14个字节)
IMAGE_FILE_HEADER结构,共4个成员,其中在需要注意的共4个,第⼀个成员Machine(WORD型)、第⼆个成员NumberOfSections(WORD型)、第六个成员SizeOfOptionalHeader(WORD型)和第七个成员Characteristics(WORD型),其余的置0即可
分数阶傅立叶变换
Machine:表⽰运⾏的CPU,因为CPU为intel,写的是32位程序,所以值是0x014C,即填⼊“4C 01”
NumberOfSections:表⽰段的数量,本⽂中只需要3个段,即.text、.rdata、.data,即值为0x0003,填⼊“03 00”SizeOfOptionalHeader:表⽰PE可选头的⼤⼩,0x00E0,填⼊“E0 00”
Characteristics:表⽰PE⽂件的属性,共2个字节,16个⼆进制字节,根据⼆进制各位来确定属性,各⼆进制位意义如下:
Bit 0 :表⽰重定位信息已从⽂件中删除。该⽂件必须以其⾸选的基地址加载。如果基址不可⽤,则加载程序报告错误。
Bit 1 :表⽰该⽂件是可执⾏⽂件,是合法的。
Bit 2 ;COFF⾏号已从⽂件中删除。
Bit 3 :COFF符号条⽬已从⽂件中删除。
Bit 4 :保留
Bit 5 :表⽰应⽤程序可以处理⼤于2GB的地址
Bit 6-7 :保留
Bit 8 :表⽰机器基于32位体系结构。
Bit 9 :表⽰没有调试信息
Bit 10:表⽰该程序不能运⾏于可移动介质中(如软驱或CD-ROM)。
Bit 11:表⽰程序不能在⽹络介质运⾏。
Bit 12:表⽰⽂件是⼀个系统⽂件例如驱动程序。
Bit 13:表⽰⽂件是⼀个动态链接库(DLL)。
Bit 14:表⽰⽂件只能在单处理机器上运⾏。
Bit 15:保留
注:bit代表权值,bit0为最低位,bit15为最⾼位
根据如上信息来确定各⼆进制位为只需将Bit 1位置1即可,值为0000000000000010,即为0x0002,填⼊“02 00”
PE可选头(共0xE0个字节)
IMAGE_OPTIONAL_HEADER32结构,PE可选头需要注意的成员较多,共11个:
第⼀个成员 Magic(WORD型):表⽰可选头的类型,因为写的是32位,即值为0x010B,填⼊“0B 01”
第七个成员AddressOfEntryPoint(DWORD型):表⽰程序⼊⼝的RVA,即headers之后的偏移,因为内存中1000H为⼀个单位,即使headers⼩于1000H,也要偏移1000H,即值为0x00001000,填⼊“00 10 00 00”
第⼗个成员ImageBase(DWORD型):表⽰程序默认载⼊基址,通常为0x00400000,因此填⼊“00 00 40 00”
第⼗⼀个成员SectionAlignment(DWORD型):表⽰程序在内存的对齐⼤⼩,通常为0x1000,因此填⼊”00 10 00 00“
第⼗⼆个成员FileAlignment(DWORD型):表⽰程序在磁盘上的对齐⼤⼩,通常是0x0200,因此填⼊“00 02 00 00"
第⼗七个成员MajorSubsystemVersion(WORD型):表⽰⼦系统的主要版本号,即win32⼦系统,值为0x0004,因此填⼊”04
00“
第⼆⼗个成员SizeOfImage(DWORD型):表⽰程序加载进内存的⼤⼩,因为headers占1000H,三个段各占1000H,即值为
0x4000,填⼊”00 40 00 00“
第⼆⼗⼀个成员SizeOfHeaders(DWORD型):表⽰⽂件headers的⼤⼩,headers⼩于0x400,但占磁盘400H,因此填⼊”00 04 00 00“
第⼆⼗三个成员Subsystem(WORD型):表⽰程序可以运⾏的系统,即win32,因此值为0x0003,填⼊“03 00”
第三⼗个成员NumberOfRvaAndSizes(DWORD型):指第31成员数组的元素个数,即值为0x10,因此填⼊”10 00 00 00“
第三⼗⼀个成员DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES](IMAGE_DATA_DIRECTORY结构),是⼀个
IMAGE_DATA_DIRECTORY类型数组(每个成员占8个字节),共有16个成员,占128个字节,其中我们要填写的是第⼆个成员,其指向导⼊表,在这⾥我们准备把导⼊表写在.rdata段,先不填
段头(共0x28个字节)
注:每个段都需要单独写⼀个段头,我们需要3个段,因此需要写3个段头
IMAGE_SECTION_HEADER结构,需要注意的共6个成员:
第⼀个成员Name[IMAGE_SIZEOF_SHORT_NAME],⾃定义长度,但只取⼋个字节,值为段名
第⼆个成员VirtualSize(DWORD型):表⽰段在内存的⼤⼩,三个段头都⼩于1000H,三个都取1000H,填⼊“00 10 00 00”
第三个成员VirtualAddress(DWORD型):表⽰段在内存的RVA,三个段头的值依次为1000H、2000H、3000H,填⼊”00 10 00 00“、”00 20 00 00“、”00 30 00 00“
第四个成员SizeOfRawData(DWORD型):表⽰段在⽂件的⼤⼩,三个段头都⼩于200H,都取200H,填⼊”00 02 00 00“
心理月刊电子版第五个成员PointerToRawData(DWORD型):表⽰段在⽂件的位置,三个段头的值依次400H、600H、800H,填⼊”00 04 00
00“、”00 04 00 00“、”00 04 00 00“
第⼗个成员DWORD Characteristics(DWORD型):表⽰段的属性,也是按位表⽰,各⼆进制位表⽰的意义如下:
Bit 0-4 :保留
Bit 5 :表⽰包含可执⾏代码。
Bit 6 :表⽰包含初始化数据
Bit 7 :表⽰包含未初始化数据,即程序执⾏前初始化未0。
Bit 8 :保留
Bit 9 :表⽰包含注释或其他信息。这仅对⽬标⽂件有效。
Bit 10 :保留
Bit 11 :表⽰该节在可执⾏⽂件链接后,作为⽂件⼀部分的数据被清除。
Bit 12 :表⽰包含公共块数据,这仅对⽬标⽂件有效。
Bit 13 :保留
Bit 14 :重置本部分TLB条⽬中的推测性异常处理位。
Bit 15 :表⽰本节包含全局指针引⽤的数据,需要在执⾏前侵⼊。
Bit 16-19 :保留
Bits 20-23 :指定对齐。⼀般是库⽂件的对象对齐。
Bit 24 :表⽰节包含扩展的重定位。
Bit 25 :表⽰该节可以根据需要丢弃。
Bit 26 :表⽰节的数据不得缓存。
Bit 27 :表⽰节的数据不得交换出去。
波斯顿矩阵Bit 28 :表⽰节的数据在所有映象例程内共享
Bit 29 :表⽰进程得到“执⾏”访问节内存。
Bit 30 :表⽰进程得到“读出”访问节内存。
Bit 31 :表⽰进程得到“写⼊”访问节内存。
三个段依上述描述依次确认,可以确定三个段头的值依次为“00100000000000000000000001100000”、“01000000000000000000000001000000”、“11000000000000000000000001000000”,即“0x20000060”、“0x40000040”、“0xC0000040”,填⼊“60 00 00 20”、“40 00 00 40 ”、“40 00 00 C
0”
text段
hello world的代码如下:
push 0;
push 0x00403000;
push 0x00403007;
push 0;
call 0x0040101A;
push 0
call 0x00401020;
jmp dword ptr [0x00402080]
jmp dword ptr [0x00402088]
直接将上述代码翻译成机器码:
6A00680030400068073040006A00E8070000006A00E806000000FF2580204000FF2588204000
rdata段
rdata段存储导⼊表,导⼊表⼀般分为导⼊表的⽬录和导⼊表的内容,导⼊⽬录是⼀个IMAGE_IMPORT_DESCRIPTOR结构数组(⼀个元素共20个字节),数组⼤⼩=导⼊的DLL库的数量+结尾的空元素
IMAGE_IMPORT_DESCRIPTOR共5个成员
第⼀个成员OriginalFirstThunk(DWORD型),表⽰name trunk的RVA,指向导⼊名称表
第四个成员Name(DWORD型),表⽰库名的RVA,指向库名所在的地址
第五个成员FirstThunk(DFWORD型),表⽰函数地址的RVA,指向函数地址,但是由于函数的加载地址未知,是由PE加载器填充的,AddressTrunk以全零的DWORD值作为结束标记。所以只要随便填⼊⼀个⾮0的DWROD型值即可
然后将导⼊表的内容填⼊即可,即
MessageBoxA user32.dll  ExitProcess kernel32.dll
注意:函数的序号需要预留出来⼀个word型的位置,即填⼊
0x0000,字符串需要以0x00结尾
data段
data段通常⽤来存储只读数据,只需要填充两个数据,MessageBox所需的参数,消息框的标题和内容,“LSKDSG”、“Hello, World !”
参考:

本文发布于:2024-09-23 19:25:11,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/231533.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:需要   数据   程序
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议