学习 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. python爬虫requests json与字典对象互相转换

    import requests import json ''' json.loads(json_str) json字符串转换成字典 json.dumps(dict) 字典转换成json字符串 ''' ...

  2. leetcode算法:Next Greater Element I

    You are given two arrays (without duplicates) nums1 and nums2 where nums1's elements are subset of n ...

  3. SSM登陆注册

    package com.coingod.controller; import java.io.IOException;import java.io.PrintWriter;import java.ut ...

  4. 2018 php的flush和ob_flush不起作用 整理解决

    2018 php的flush和ob_flush不起作用 整理解决成功解决. 要点 : 使用函数 str_repeat2处配置:检查php.ini.Nginx 中有下面两个设置使用方式:echo str ...

  5. SpringMVC的流程分析(二)—— HandlerMapping组件

    1.HandlerMapping的类结构 如上图所示,HandlerMapping接口有一个叫做:getHandler()的方法,这个方法是用来回去HandlerMapping对应的处理器的,由此也就 ...

  6. AutoFac+MVC+WebApi源码----我踩过的坑

    发现网上关于AutoFac的Demo源码比较少,综合MVC和WepApi的更少.所以贴出源码 WebApi项目(MVC4不需要引用,历史遗留问题,人懒没删) 建项目 新建类库IAutoFacDal(接 ...

  7. Xshell5下利用sftp上传下载传输文件

    sftp是Secure File Transfer Protocol的缩写,安全文件传送协议.可以为传输文件提供一种安全的加密方法.sftp 与 ftp 有着几乎一样的语法和功能.SFTP 为 SSH ...

  8. 一篇文章说透Nginx的rewrite模块

    rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块.rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配 ...

  9. 运用正则+replace+substring将一段英语的字母大写 angurlar运用自定义指令filter完成首字母大写

    复习下js基础并运用正则+replace+substring将一段英语的字母大写 <!DOCTYPE html><html> <head> <meta cha ...

  10. [LeetCode] Cracking the Safe 破解密码

    There is a box protected by a password. The password is n digits, where each letter can be one of th ...