学习 PE 可执行文件格式,用 delphi 实现给 EXE 文件增加区段
unit uStudyPE;

interface
uses
Classes, SysUtils, Windows, uPERec; type TImage_Section_headerList = class; TStudyPE = class
private
FFileStream: TFileStream;
FNewStream: TMemoryStream;
FImage_Dos_Header: PImage_DOS_Header;
FImage_NT_Headers: PImage_NT_Headers;
FImage_Section_HeaderList: TImage_Section_headerList;
public
constructor Create;
destructor Destroy; override;
public
procedure LoadPE(AFileName: string);
property Image_Dos_Header: PImage_DOS_Header read FImage_Dos_Header;
property Image_NT_Headers: PImage_NT_Headers read FImage_NT_Headers;
property Image_Section_HeaderList: TImage_Section_headerList read FImage_Section_HeaderList;
end; TImage_Section_headerList = class(TList)
public
procedure FreeAllItems();
destructor Destroy; override;
end; implementation
{ TStudyPE }
const
Image_Dos_Header_len = SizeOf(TImage_dos_header);
Image_NT_Headers_len = SizeOf(TImage_NT_Headers);
Image_Section_Header_len = SizeOf(TImage_Section_Header); constructor TStudyPE.Create;
begin
inherited Create;
New(FImage_Dos_Header);
New(FImage_NT_Headers);
FImage_Section_HeaderList := TImage_Section_headerList.Create;
FNewStream := TMemoryStream.Create;
end; destructor TStudyPE.Destroy;
begin
Dispose(FImage_Dos_Header);
Dispose(FImage_NT_Headers);
FImage_Section_HeaderList.Free;
FNewStream.Free;
inherited;
end; procedure TStudyPE.LoadPE(AFileName: string);
var e_lfanew: DWORD;
pSecHeader: PImage_Section_header;
nNumberOfSections: word;
i: integer;
nDosStubLen: integer;
nSizeOfImage: DWORD;
LImage_Section_header: TImage_Section_Header;
Rva: DWORD;
vaSize: DWORD; SizeOfHeaders: DWORD; // 一般是 $400
NewSectionSize: DWORD; // 新增区段大小 begin if Assigned(FFileStream) then
begin
FFileStream.Free;
end; NewSectionSize := $; FFileStream := TFileStream.Create(AFileName, fmOpenRead);
FFileStream.Read(FImage_Dos_Header^, Image_Dos_Header_len); // 读 DOS 头,64字节 FNewStream.Size := FFileStream.Size + NewSectionSize; // 新文件大小
FNewStream.Write(FImage_Dos_Header^, Image_Dos_Header_len); // 将 DOS 头写入新文件 e_lfanew := FImage_Dos_Header.e_lfanew; // 获取 Image_NT_Headers 的位置
nDosStubLen := e_lfanew - Image_Dos_Header_len; // DOS 汇编代码区域长度 // 将 DOS 汇编代码写入新文件,写完后 FFileStream.Position 正好在 Image_NT_Header 的位置上
FFileStream.Read((Pbyte(FNewStream.Memory) + Image_Dos_Header_len)^, nDosStubLen);
FNewStream.Position := Image_Dos_Header_len + nDosStubLen; FFileStream.Read(FImage_NT_Headers^, Image_NT_Headers_len); // 获取 Image_NT_Headers
SizeOfHeaders := FImage_NT_Headers.Image_Optional_Header32.SizeOfHeaders; nNumberOfSections := FImage_NT_Headers.Image_File_Header.NumberOfSections; // 区段数量
FImage_NT_Headers.Image_File_Header.NumberOfSections := nNumberOfSections + ; // 增加区段数量 nSizeOfImage := FImage_NT_Headers.Image_Optional_Header32.SizeOfImage;
FImage_NT_Headers.Image_Optional_Header32.SizeOfImage := nSizeOfImage + NewSectionSize; // 修改 EXE 所占内存大小
FNewStream.Write(FImage_NT_Headers^, Image_NT_Headers_len); // 将 Image_NT_Headers 写入新文件 FImage_Section_HeaderList.FreeAllItems; for i := to nNumberOfSections - do
begin
New(pSecHeader);
FImage_Section_HeaderList.Add(pSecHeader);
FFileStream.Read(pSecHeader^, Image_Section_Header_len);
FNewStream.Write(pSecHeader^, Image_Section_Header_len); // 将各个 Image_Section_Header 写入新文件
end; LImage_Section_header := pSecHeader^; // 给新区段命名
LImage_Section_header.Name[] := ord('.');
LImage_Section_header.Name[] := ord('N');
LImage_Section_header.Name[] := ord('E');
LImage_Section_header.Name[] := ord('W');
LImage_Section_header.Name[] := ord('T');
LImage_Section_header.Name[] := ord('E');
LImage_Section_header.Name[] := ord('S');
LImage_Section_header.Name[] := ord('T'); // 用最后一个区段作参考计算新增区段的 VirtualAddress,PointerToRawData 的值
// VirtualAddress 是在EXE中虚拟地址
// PointerToRawData 新区段在文件中的位置
Rva := pSecHeader.VirtualAddress;
vaSize := ((pSecHeader.Misc.VirtualSize + $FFF) div $) * $;
LImage_Section_header.VirtualAddress := Rva + vaSize; // 新区段的虚拟地址 Rva := pSecHeader.PointerToRawData;
vaSize := ((pSecHeader.Misc.VirtualSize + $1FF) div $) * $;
LImage_Section_header.PointerToRawData := Rva + vaSize; // 新区段的文件中的位置 LImage_Section_header.Misc.VirtualSize := NewSectionSize;
LImage_Section_header.SizeOfRawData := NewSectionSize;
LImage_Section_header.Characteristics := $; // 区段的属性(读,写,执行) // 要计算位置是否够放新 Section, 未完成,本例所改的 exe 是可以的。 if ((SizeOfHeaders - FFileStream.Position) < Image_Section_Header_len) then
begin
raise Exception.Create('区段位置不够,本Demo无法操作!');
// 为了简单,所以这样操作了。实际上是可以的,只是每个区段都得重新计算虚拟地址与在文件中的地址
end; FNewStream.Write(LImage_Section_header, Image_Section_Header_len); // 将新增 Image_Section_Header 写入新文件 // 将源文件剩下的数据写入新文件
FFileStream.Seek(SizeOfHeaders, soBeginning);
FFileStream.Read((Pbyte(FNewStream.Memory) + SizeOfHeaders)^, FFileStream.Size - SizeOfHeaders);
FNewStream.SaveToFile('new.exe'); end; { TImage_Section_headerList } destructor TImage_Section_headerList.Destroy;
begin
FreeAllItems;
inherited;
end; procedure TImage_Section_headerList.FreeAllItems;
var
p: PImage_Section_header;
begin
for p in self do
Dispose(p);
Clear;
end; end.

uStudyPE.pas

unit uPERec;

interface
uses
Classes, SysUtils, Windows; type
// Windows 单元中有这些结构,而我为了学习,从书上重新操作了一遍 PImage_DOS_Header = ^TImage_DOS_Header;
TImage_DOS_Header = packed record
e_magic: WORD; // DOS signature:4D5A ('MZ')
e_cblp: WORD;
e_cp: WORD;
e_crlc: WORD;
e_cparhdr: WORD;
e_minalloc: WORD;
e_maxalloc: WORD;
e_ss: WORD;
e_sp: WORD;
e_csum: WORD;
e_ip: WORD;
e_cs: WORD;
e_lfarlc: WORD;
e_ovno: WORD;
e_res: array [ .. ] of WORD;
e_oemid: WORD;
e_oeminfo: WORD;
e_res2: array [ .. ] of WORD;
e_lfanew: DWORD; // offset to NT hearder
end; TImage_Optional_Header32 = _Image_Optional_Header32;
TImage_File_Header = _Image_File_Header; PImage_NT_Headers = ^TImage_NT_Headers;
TImage_NT_Headers = packed record
Signature: DWORD; // PE Signature: 50450000 ('PE'00)
Image_File_Header: TImage_File_Header;
Image_Optional_Header32: TImage_Optional_Header32;
end; PImage_File_Header = ^TImage_File_Header;
_Image_File_Header = packed record
Machine: WORD;
NumberOfSections: WORD;
TimeDateStamp: DWORD;
PointerToSymbolTable: DWORD;
NumberOfSymbols: DWORD;
SizeOfOptionalHeader: WORD;
Characteristics: WORD;
end; const
Image_NumberOf_Directory_Entries = ; type TImage_Data_Directory = _Image_Data_Directory; PImage_Optional_Header32 = ^TImage_Optional_Header32;
_Image_Optional_Header32 = packed record
Magic: WORD;
MajorLinkerVersion: BYTE;
MinorLinkerVersion: BYTE;
SizeOfCode: DWORD;
SizeOfInitializedData: DWORD;
SizeOfUninitializedData: DWORD;
AddressOfEntryPoint: DWORD;
BaseOfCode: DWORD;
BaseOfData: DWORD;
ImageBase: DWORD;
SectionAlignment: DWORD;
fileAlignment: DWORD;
MajorOperatingSystemVersion: WORD;
MinorOperatingSystemVersion: WORD;
MajorImageVersion: WORD;
minorImageVersion: WORD;
MajorSubsystemVersion: WORD;
MinorSubsystemVersion: WORD;
Win32VersionValue: DWORD;
SizeOfImage: DWORD;
SizeOfHeaders: DWORD;
checkSum: DWORD;
Subsystem: WORD;
DllCharacteristics: WORD;
SizeOfStackReserve: DWORD;
SizeOfStackCommit: DWORD;
sizeOfHeapReserve: DWORD;
sizeofHeapcommit: DWORD;
LoaderFlags: DWORD;
NumberOfRvaAndSizes: DWORD;
Image_Data_Directory: array [ .. Image_NumberOf_Directory_Entries - ] of TImage_Data_Directory;
end; _Image_Data_Directory = packed record
VirtualAddress: DWORD;
Size: DWORD;
end;
const
Image_SizeOf_Short_Name = ; type TMisc = packed record
case integer of
:(PhysicalAddress: DWORD);
:(VirtualSize: DWORD);
end;
// 此为 C 语言 union 格式 改写而成
//
// union {
// DWORD PhysicalAddress;
// DWORD VirtualSize;
// } Misc;
//
// PImage_Section_Header = ^TImage_Section_Header;
TImage_Section_Header = packed record
Name: array [ .. Image_SizeOf_Short_Name - ] of BYTE;
Misc: TMisc;
VirtualAddress: DWORD;
SizeOfRawData: DWORD;
PointerToRawData: DWORD;
PointerToRelocations: DWORD;
PointerToLineNumbers: DWORD;
NumberOfRelocations: WORD;
NumberofLineNumbers: WORD;
Characteristics: DWORD;
end; implementation
end.

uPERec.pas

delphi 给EXE文件增加区段的更多相关文章

  1. 在delphi的exe文件中嵌入另外一个exe文件

    http://www.cnblogs.com/dabiao/archive/2009/11/28/delphi.html 1.创建rc文件.可以用任意文本编辑器来写.文件格式为:"资源名 资 ...

  2. 如何用DELPHI编程修改外部EXE文件的版本信

    右击里面有修改 点开直接修改就可以了吧. DELPHI 里程序的版本信息怎么是灰色的,无法更改 耐心读以下说明,应该能解决你的问题,如果不能解决,请Hi我~ 如何给自己的dll文件添加版本信息呢? 首 ...

  3. delphi编写提取exe文件的ICO图标

    http://www.duote.com/tech/4/11797.html delphi编写提取exe文件的ICO图标 7.0分 出处:天下网吧 时间:2011-08-05 人气:2390 核心提示 ...

  4. 常用EXE文件反编译工具

    PE Explorer V1.99 R5 绿色汉化特别版_强大的可视化汉化集成工具 功能极为强大的可视化汉化集成工具,可直接浏览.修改软件资源,包括菜单.对话框.字符串表等: 另外,还具备有 W32D ...

  5. 转载:常见EXE文件反编译工具

    PE Explorer V1.99 R5 绿色汉化特别版_强大的可视化汉化集成工具 功能极为强大的可视化汉化集成工具,可直接浏览.修改软件资源,包括菜单.对话框.字符串表等: 另外,还具备有 W32D ...

  6. 减小Delphi的Exe文件大小(11种方法)

    一般来说,由Delphi生成的EXE文件,要比其由它编程语言生成的体积大一些.这主要是由于使用VCL的原因(当然,VCL是有许多优点的!) 以下是减小EXE文件大小的几种途径: 01) 使用加壳工具( ...

  7. WinExec打开exe文件

    1,WinExec():   WinExec主要运行EXE文件,不能运行其他类型的文件.不用引用特别单元.   原型:UINT WinExec(exePath,ShowCmd)   示例,我想要用记事 ...

  8. 常用EXE文件反编译工具【转】

    http://www.cnblogs.com/happyday56/p/3740108.html PE Explorer V1.99 R5 绿色汉化特别版_强大的可视化汉化集成工具 功能极为强大的可视 ...

  9. Delphi 使用CHM文件制作系统帮助文档(上下文感知帮助的制作)

    一.基础知识简介         使用帮助提示窗口或状态栏只能提供简单.单一的帮助,无法对某一模块或应用程序整体提供系统的 帮助,因此运行Windows应用程序,需要帮助时一般都可以通过执行帮助菜单获 ...

随机推荐

  1. __new__ 单例

    a.实例化类 实例化一个类时 1. 创建一个对象,调用__new__方法,如果没有会调用父类的__new__方法 2. 调用__init__方法 3. 返回对象的引用 class Dog(object ...

  2. spark2.1操作json(save/read)

    建筑物配置信息: case class BuildingConfig(buildingid: String, building_height: Long, gridcount: Long, gis_d ...

  3. Struts(十六):通过CURD来学习Struts流程及ModelDriven的用法

    背景: 从一个Member的增删改查,来了解Struts2的运行原理及学习ModelDriven拦截器.Preparable拦截器. 新建项目实现列表的展示及删除功能: web.xml <?xm ...

  4. glut 深度测试无不起作用问题解决

    OpenGL中使用glEnable(GL_DEPTH_TEST)后深度测试没有起作用,发现深度缓冲没有创建.glut库在兼容模式(GL_COMPATIBILITY_PROFILE)下displaymo ...

  5. Linux OpenGL 实践篇-1 OpenGL环境搭建

    本次实践所使用环境为CentOS 7. 参考:http://www.xuebuyuan.com/1472808.html OpenGL开发环境搭建: 1.opengl库安装 opengl库使用mesa ...

  6. leetcode 566 Reshape the Matrix 重塑矩阵

    参考:https://www.cnblogs.com/grandyang/p/6804753.html 注意:复习容器的定义方法?? class Solution { public: vector&l ...

  7. [JSOI2008]最大数

    题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度. 2. 插入操作 ...

  8. bzoj 3745: [Coci2015]Norma

    Description Solution 考虑分治: 我们要统计跨越 \(mid\) 的区间的贡献 分最大值和最小值所在位置进行讨论: 设左边枚举到了 \(i\),左边 \([i,mid]\) 的最大 ...

  9. Codeforces Round #464 F. Cutlet

    Description 题面 有\(2*n\)的时间,去煎一块肉,肉有两面,你需要在特定的时间内翻转,使得每一面都恰好煎了\(n\)分钟,你有\(k\)次翻转的机会,每一次表示为一段时间 \([L_i ...

  10. bzoj 3672: [Noi2014]购票

    Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...