delphi 从内存中加载并启动一个exe


本文整理自网络,侵删。

 windows似乎只提供了一种启动进程的方法:即必须从一个可执行文件中加载并启动。
而下面这段代码就是提供一种可以直接从内存中启动一个exe的变通办法。

用途嘛, 也许可以用来保护你的exe,你可以对要保护的 exe 进行任意切分、加密、存储,只要运行时能将exe的内容正确拼接到一块内存中,就可以直接从内存中启动,而不必不安全地去生成一个临时文件再从临时文件启动进程。另外这段代码也提供了一种自己写exe外壳的简单途径,如果能配合其它各种外壳技术就更好地保护你的exe文件。

原理很简单:就是“借尸还魂”,启动一个僵尸进程(NT下可以是自身程序启动的另一个进程),然后在它运行前将其整个替换成内存中的exe内容,待正式运行后执行的就是你的目标代码了。

不过代码中还有一些不尽人意的地方,比如在98下运行会留一个僵尸程序的壳在硬盘上(其实那个僵尸程序本身就是一个完整的可执行程序,直接运行的话只显示一条错误信息然后就退出了)。另外由于客观条件限制,代码没有经过充分测试,只在XP下进行了一些初步测试:普通exe都能正常运行,upx压缩过的exe绝大多数情况下都能运行,只有在不能卸载僵尸外壳时才有问题(upx压缩过的exe没有重定向表,无法加载到其它地址运行)。

如果有bug望告之,如果有更好的方法特别是能解决98下的遗留尾巴的话希望不吝赐教。

{ ******************************************************* }
{ * 从内存中加载并运行exe * }
{ ******************************************************* }
{ * 参数: }
{ * Buffer: 内存中的exe地址 }
{ * Len: 内存中exe占用长度 }
{ * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)}
{ * ProcessId: 返回的进程Id }
{ * 返回值: 如果成功则返回进程的Handle(ProcessHandle), }
{ 如果失败则返回INVALID_HANDLE_VALUE }
{ ******************************************************* }

unit PEUnit;

interface

uses windows;

function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal;

implementation

{$R ExeShell.res} // 外壳程序模板(98下使用)

type
TImageSectionHeaders = array [0..0] of TImageSectionHeader;
PImageSectionHeaders = ^TImageSectionHeaders;

{ 计算对齐后的大小 }
function GetAlignedSize(Origin, Alignment: Cardinal): Cardinal;
begin
result := (Origin + Alignment - 1) div Alignment * Alignment;
end;

{ 计算加载pe并对齐需要占用多少内存,未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0 }
function CalcTotalImageSize(MzH: PImageDosHeader; FileLen: Cardinal; peH: PImageNtHeaders;
peSecH: PImageSectionHeaders): Cardinal;
var
i: Integer;
begin
{计算pe头的大小}
result := GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders, PeH.OptionalHeader.SectionAlignment);

{计算所有节的大小}
for i := 0 to peH.FileHeader.NumberOfSections - 1 do
if peSecH[i].PointerToRawData + peSecH[i].SizeOfRawData > FileLen then // 超出文件范围
begin
result := 0;
exit;
end
else if peSecH[i].VirtualAddress <> 0 then //计算对齐后某节的大小
if peSecH[i].Misc.VirtualSize <> 0 then
result := GetAlignedSize(peSecH[i].VirtualAddress + peSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment)
else
result := GetAlignedSize(peSecH[i].VirtualAddress + peSecH[i].SizeOfRawData, PeH.OptionalHeader.SectionAlignment)
else if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then
result := result + GetAlignedSize(peSecH[i].SizeOfRawData, peH.OptionalHeader.SectionAlignment)
else
result := result + GetAlignedSize(peSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment);

end;

相关阅读 >>

Delphi的流操作的语法

Delphi实现拖动无标题窗口的5种方法

Delphi gmt时间与tdatetime转换

Delphi 删除或清空一个目录(包含多级)

Delphi隐藏桌面图片和显示桌面图标

Delphi 调用cmd命令行并取得返回结果

Delphi webservices base64编码

Delphi 获取unixtime

delph hash类

Delphi获取系统默认的useragent的方法

更多相关阅读请进入《Delphi》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...