学习 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. JS笔记(一)

    第一章: 编写JS流程: 1.  布局:HTML和CSS 2.  样式:修改页面元素样式,div的display样式 3.  事件:确定用户做什么操作,onclick(鼠标点击事件).onmouseo ...

  2. [洛谷P1197/BZOJ1015][JSOI2008]星球大战Starwar - 并查集,离线,联通块

    Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过 ...

  3. python中的多线程

    一个程序可以理解为一个进程,这个进程有其代号,可以依据这个代号将其杀死. 一个进程肯定有且只有一个主线程,他可以有很多子线程. 运行一个任务如果可以有许多子线程同时去做,当然会提高效率. 但是,在py ...

  4. 学习React系列(七)——Fragments、Portals、Error Boundaries与WEB组件

    React.Fragment portals Error Boundaries WEB组件 React.Fragment 想象一个场景,想把td包装为组件添加到table中去,代码如下: class ...

  5. jQuery系列 第七章 jQuery框架DOM操作

    第七章 jQuery框架的选择器 jQuery框架继承和优化了JavaScript访问DOM对象的特性,我们使用jQuery框架提供的api可以更加方便的操作DOM对象. 7.1 创建DOM节点 使用 ...

  6. [LeetCode] Maximum Product of Three Numbers 三个数字的最大乘积

    Given an integer array, find three numbers whose product is maximum and output the maximum product. ...

  7. js常用的字符串方法分析

    ##字符串## 字符串: 由0个或多个字符组成,被成对的英文单引号或双引号包含起来的. 字符编码: 每一个字符在计算机存储的编号. 计算机会保存有一套或几套用于标注编号与字符对应关系的字典.(字符集) ...

  8. Linux 在添加一个新账号后却没有权限怎么办

    当添加一个新账号后,我们可能会发现新账号sudo 时会报告不在sudoers中,使用su -s时输入密码后也会认证失败 上网搜索大部分都要求修改/etc/sudoers中的内容,但修改这个文件必须需要 ...

  9. MYSQL时间盲住

    mysql注释 -- ,-- -,#,--+等 常用的判断语句: ' and if(1=0,1, sleep(10)) # " and if(1=0,1, sleep(10)) --+ ) ...

  10. 各种电脑进入BIOS快捷键

    组装机主板 品牌笔记本 品牌台式机 主板品牌 启动按键 笔记本品牌 启动按键 台式机品牌 启动按键 华硕主板 F8 联想笔记本 F12 联想台式机 F12 技嘉主板 F12 宏基笔记本 F12 惠普台 ...