从内存中加载并运行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;?
{ 加載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; BaseAddr, ImageSize: Cardinal): string;?
var?
??? r, h, sz: Cardinal;?
??? p: Pointer;?
??? fid, l: Integer;?
??? buf: Pointer;?
??? peH: PImageNtHeaders;?
??? peSecH: PImageSectionHeaders;?
begin?
??? if IsNT then?
??? { NT 系統下直接使用自身程序作為外殼進程 }?
????? result := ParamStr(0) + CmdParam?
??? else begin?
??? // 由于98系統下無法重新分配外殼進程占用內存,所以必須保證運行的外殼程序能容納目標進程并且加載地址一致?
??? // 此處使用的方法是從資源中釋放出一個事先建立好的外殼程序,然后通過修改其PE頭使其運行時能加載到指定地址并至少能容納目標進程?
????? r := FindResource(HInstance, 'SHELL_EXE', RT_RCDATA);?
????? h := LoadResource(HInstance, r);?
????? p := LockResource(h);?
????? l := SizeOfResource(HInstance, r);?
????? GetMem(Buf, l);?
????? Move(p^, Buf^, l);???? // 讀到內存?
????? FreeResource(h);?
????? peH := Pointer(Integer(Buf) + PImageDosHeader(Buf)._lfanew);?
????? peSecH := Pointer(Integer(peH) + sizeof(TImageNtHeaders));?
????? peH.OptionalHeader.ImageBase := BaseAddr;????? // 修改PE頭重的加載基址?
????? if peH.OptionalHeader.SizeOfImage < ImageSize then??? // 目標比外殼大,修改外殼程序運行時占用的內存?
????? begin?
??????? sz := Imagesize - peH.OptionalHeader.SizeOfImage;?
??????? Inc(peH.OptionalHeader.SizeOfImage, sz);????? // 調整總占用內存數?
??????? Inc(peSecH[peH.FileHeader.NumberOfSections-1].Misc.VirtualSize, sz);???? // 調整最后一節占用內存數?
????? end;?
????? // 生成外殼程序文件名, 為本程序改后綴名得到的?
????? // 由于不想 uses SysUtils (一旦 use 了程序將增大80K左右), 而且偷懶,所以只支持最多運行11個進程,后綴名為.dat, .da0~.da9?
????? result := ParamStr(0);?
????? result := copy(result, 1, length(result) - 4) + '.dat';?
????? r := 0;?
????? while r < 10 do?
????? begin?
??????? fid := CreateFile(pchar(result), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);?
??????? if fid < 0 then?
??????? begin?
????????? result := copy(result, 1, length(result)-3)+'da'+Char(r+Byte('0'));?
????????? inc(r);?
??????? end?
??????? else begin?
????????? //SetFilePointer(fid, Imagesize, nil, 0);?
????????? //SetEndOfFile(fid);?
????????? //SetFilePointer(fid, 0, nil, 0);?
????????? WriteFile(fid, Buf^, l, h, nil);??? // 寫入文件?
????????? CloseHandle(fid);?
????????? break;?
??????? end;?
????? end;?
????? result := result + CmdParam;??? // 生成命令行?
????? FreeMem(Buf);?
??? end;?
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.?
{?
寫了一個簡單程序測試通過:)?
}?
program Test;?
//{$APPTYPE CONSOLE}?
uses?
????? SysUtils,?
????? Classes,?
????? PEUnit in 'PEUnit.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);?
????????? MemExecute(ABuffer[0], Stream.Size, '', ProcessId);?
????? finally?
????????? Stream.Free;?
????? end;?
end.
{?
?? 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.
轉自:http://blog.csdn.net/aroc_lo/archive/2010/04/03/5448700.aspx
總結
以上是生活随笔為你收集整理的从内存中加载并运行exe(两种方法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 直接将自身代码注入傀儡进程
- 下一篇: 小红伞和NOD32基于源码的免杀经验总结