cheat-engine/Cheat Engine/ManualModuleLoader.pas
cheatengine@gmail.com 0f35a52416 move the processid and handle from cefuncproc to processhandlerunit
move the processlist function from cefuncproc to it's own unit
start work on the jni library for java
2014-09-08 12:00:14 +00:00

331 lines
13 KiB
ObjectPascal

unit ManualModuleLoader;
{$MODE Delphi}
{
This routine will examine a module and then load it into memory, taking care of the sections and IAT addresses
}
interface
uses windows, LCLIntf, classes, sysutils, imagehlp, dialogs, PEInfoFunctions,CEFuncProc,
NewKernelHandler, symbolhandler, dbk32functions, vmxfunctions;
type TModuleLoader=class
private
filename: string;
FLoaded: boolean;
FEntrypoint: ptruint;
public
Exporttable: TStringlist;
constructor create(filename: string);
property loaded: boolean read FLoaded;
property EntryPoint: ptruint read FEntryPoint;
end;
implementation
uses ProcessHandlerUnit;
constructor TModuleLoader.create(filename: string);
var
i,j,k: integer;
filemap: TMemorystream;
tempmap: tmemorystream;
ImageNTHeader: PImageNtHeaders;
ImageBaseRelocation: PIMAGE_BASE_RELOCATION;
ImageSectionHeader: PImageSectionHeader;
ImageExportDirectory: PImageExportDirectory;
ImageImportDirectory: PImageImportDirectory;
importmodulename: string;
importaddress: ptruint;
importfunctionname: string;
importfunctionnamews: widestring;
is64bit, isDriver: boolean;
numberofrva: integer;
maxaddress: ptrUint;
destinationBase: uint64;
basedifference: dword;
basedifference64: uint64;
x: PtrUInt;
funcaddress: uint64;
haserror: boolean;
processhandle: thandle;
pid: dword;
begin
inherited create;
self.filename:=filename;
exporttable:=tstringlist.create;
pid:=processid;
if pid=0 then
pid:=GetCurrentProcessId;
processhandle:=dbk32functions.OP(PROCESS_ALL_ACCESS, true, pid);
filemap:=tmemorystream.Create;
try
//showmessage('Loading '+filename);
filemap.LoadFromFile(filename);
if PImageDosHeader(filemap.Memory)^.e_magic<>IMAGE_DOS_SIGNATURE then
raise exception.create('not a valid file');
tempmap:=tmemorystream.Create;
try
ImageNtHeader:=peinfo_getImageNtHeaders(filemap.Memory, filemap.Size);
if ImageNtHeader=nil then
raise exception.create('Not a valid header');
if ImageNTHeader^.FileHeader.Machine=$8664 then
begin
is64bit:=true;
if not Is64bitOS then
raise exception.create('Tried loading a 64-bit module on a 32-bit system');
numberofrva:=PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.NumberOfRvaAndSizes;
end else
begin
is64bit:=false;
numberofrva:=ImageNTHeader^.OptionalHeader.NumberOfRvaAndSizes;
end;
ImageSectionHeader:=PImageSectionHeader(ptrUint(@ImageNTHeader^.OptionalHeader)+ImageNTHeader^.FileHeader.SizeOfOptionalHeader);
maxaddress:=0;
for i:=0 to ImageNTHeader^.FileHeader.NumberOfSections-1 do
begin
if maxaddress<(ImageSectionHeader.VirtualAddress+ImageSectionHeader.SizeOfRawData) then
maxaddress:=ImageSectionHeader.VirtualAddress+ImageSectionHeader.SizeOfRawData;
inc(ImageSectionHeader);
end;
//maxaddress is now known
ImageSectionHeader:=PImageSectionHeader(ptrUint(@ImageNTHeader^.OptionalHeader)+ImageNTHeader^.FileHeader.SizeOfOptionalHeader);
tempmap.Size:=maxaddress;
ZeroMemory(tempmap.memory, tempmap.size);
//place the sections at the appropriate locations
for i:=0 to ImageNTHeader^.FileHeader.NumberOfSections-1 do
begin
CopyMemory(@pbytearray(tempmap.memory)[ImageSectionHeader.VirtualAddress], @pbytearray(filemap.memory)[ImageSectionHeader.PointerToRawData], ImageSectionHeader.SizeOfRawData);
inc(ImageSectionHeader);
end;
if uppercase(ExtractFileExt(filename))='.SYS' then
begin
//kernel memory location
//LoadDBK32;
isdriver:=true;
destinationBase:=KernelAlloc64(maxaddress);
end
else
begin
//normal memory location
isdriver:=false;
destinationBase:=ptrUint(VirtualAllocEx(processhandle, nil,maxaddress, MEM_COMMIT, PAGE_EXECUTE_READWRITE));
end;
if destinationBase=0 then raise exception.create('Allocation error');
FEntryPoint:=destinationBase+ImageNTHeader^.OptionalHeader.AddressOfEntryPoint;
//copy the header and get the base difference (needed for relocs)
if is64bit then
begin
CopyMemory(tempmap.memory, filemap.memory, PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.SizeOfHeaders);
basedifference:=dword(destinationBase)-PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.ImageBase;
basedifference64:=destinationBase-PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.ImageBase;
end
else
begin
CopyMemory(tempmap.memory, filemap.memory, ImageNTHeader^.OptionalHeader.SizeOfHeaders);
basedifference:=dword(destinationBase)-ImageNTHeader^.OptionalHeader.ImageBase;
basedifference64:=0;
end;
for i:=0 to numberofrva-1 do
begin
if (is64bit and (PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].VirtualAddress=0)) or
((not is64bit) and (ImageNTHeader^.OptionalHeader.DataDirectory[i].VirtualAddress=0)) then
continue; //don't look into it (virtual address=0) bug...
case i of
0: //exports
begin
if is64bit then
ImageExportDirectory:=PImageExportDirectory(ptrUint(tempmap.memory)+PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].VirtualAddress)
else
ImageExportDirectory:=PImageExportDirectory(ptrUint(tempmap.memory)+ImageNTHeader^.OptionalHeader.DataDirectory[i].VirtualAddress);
if ImageExportDirectory.NumberOfFunctions=ImageExportDirectory.NumberOfNames then
begin //consistent
for j:=0 to ImageExportDirectory.NumberOfFunctions-1 do
begin
k:=pwordarray(ptrUint(tempmap.memory)+ImageExportDirectory.AddressOfNameOrdinals)[j];
exporttable.AddObject(format('%s - %s',[inttohex(destinationBase+pdwordarray(ptrUint(tempmap.memory)+ImageExportDirectory.AddressOfFunctions)[k],1), pchar(ptrUint(tempmap.memory)+pdwordarray(ptrUint(tempmap.memory)+ImageExportDirectory.AddressOfNames)[j])]), pointer(destinationBase+pdwordarray(ptrUint(tempmap.memory)+ImageExportDirectory.AddressOfFunctions)[k]));
end;
end;
end;
1: //imports
begin
j:=0;
if is64bit then
ImageImportDirectory:=PImageImportDirectory(ptrUint(tempmap.memory)+PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].VirtualAddress)
else
ImageImportDirectory:=PImageImportDirectory(ptrUint(tempmap.memory)+ImageNTHeader^.OptionalHeader.DataDirectory[i].VirtualAddress);
while (j<45) do
begin
if ImageImportDirectory.name=0 then break;
if ImageImportDirectory.ForwarderChain<>$ffffffff then
begin
importmodulename:=pchar(ptrUint(tempmap.memory)+ImageImportDirectory.name);
if not isdriver then
InjectDll(importmodulename);
importmodulename:=ChangeFileExt(importmodulename, '');
//--
k:=0;
if is64bit then
begin
while PUINT64(ptrUint(tempmap.memory)+ImageImportDirectory.FirstThunk+8*k)^<>0 do
begin
importaddress:=ptrUint(tempmap.memory)+ImageImportDirectory.FirstThunk+8*k;
importfunctionname:=pchar(ptrUint(tempmap.memory)+pdword(importaddress)^+2);
if isDriver then
begin
importfunctionnamews:=importfunctionname;
funcaddress:=GetKProcAddress64(@importfunctionnamews[1]);
if funcaddress=0 then
raise exception.create('failed finding address of '+pwidechar(@importfunctionnamews[1]));
end
else
begin
funcaddress:=symhandler.getAddressFromName(importmodulename+'!'+importfunctionname, true, haserror);
if haserror then
raise exception.create('failed finding address of '+importmodulename+'!'+importfunctionname);
end;
PQWORD(importaddress)^:=funcaddress;
inc(k);
end;
end
else
begin
while PDWORD(ptrUint(tempmap.memory)+ImageImportDirectory.FirstThunk+4*k)^<>0 do
begin
importaddress:=ptrUint(@pdwordarray(ptrUint(tempmap.memory)+ImageImportDirectory.FirstThunk)[k]);
importfunctionname:=pchar(ptrUint(tempmap.memory)+pdwordarray(ptrUint(tempmap.memory)+ImageImportDirectory.FirstThunk)[k]+2);
if isDriver then
begin
importfunctionnamews:=importfunctionname;
funcaddress:=GetKProcAddress64(@importfunctionnamews[1]);
if funcaddress=0 then
raise exception.create('failed finding address of '+pwidechar(@importfunctionnamews[1]));
end
else
begin
funcaddress:=symhandler.getAddressFromName(importmodulename+'!'+importfunctionname, true, haserror);
if haserror then
raise exception.create('failed finding address of '+importmodulename+'!'+importfunctionname);
end;
pdword(importaddress)^:=funcaddress;
inc(k);
end;
end;
//--
end;
inc(j);
ImageImportDirectory:=PImageImportDirectory(ptrUint(ImageImportDirectory)+sizeof(TImageImportDirectory));
end;
end;
5: //relocation table
begin
if is64bit then
begin
ImageBaseRelocation:=PIMAGE_BASE_RELOCATION(ptrUint(tempmap.memory)+PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].VirtualAddress);
maxaddress:=ptrUint(tempmap.memory)+PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].VirtualAddress+PImageOptionalHeader64(@ImageNTHeader^.OptionalHeader)^.DataDirectory[i].Size;
end
else
begin
ImageBaseRelocation:=PIMAGE_BASE_RELOCATION(ptrUint(tempmap.memory)+ImageNTHeader^.OptionalHeader.DataDirectory[i].VirtualAddress);
maxaddress:=ptrUint(tempmap.memory)+ImageNTHeader^.OptionalHeader.DataDirectory[i].VirtualAddress+ImageNTHeader^.OptionalHeader.DataDirectory[i].Size;
end;
while ptrUint(ImageBaseRelocation)<maxaddress do
begin
if ImageBaseRelocation.SizeOfBlock=0 then break;
for j:=0 to ((ImageBaseRelocation.SizeOfBlock-8) div 2)-1 do
begin
if (ImageBaseRelocation.rel[j] shr 12)=3 then //replace the address at this address with a relocated one (dword)
pdword(ptrUint(tempmap.memory)+ImageBaseRelocation.virtualaddress+(ImageBaseRelocation.rel[j] and $fff))^:=pdword(ptrUint(tempmap.memory)+ImageBaseRelocation.virtualaddress+(ImageBaseRelocation.rel[j] and $fff))^+basedifference;
if (ImageBaseRelocation.rel[j] shr 12)=10 then //replace the address at this address with a relocated one (dword)
PUINT64(ptrUint(tempmap.memory)+ImageBaseRelocation.virtualaddress+(ImageBaseRelocation.rel[j] and $fff))^:=PUINT64(ptrUint(tempmap.memory)+ImageBaseRelocation.virtualaddress+(ImageBaseRelocation.rel[j] and $fff))^+basedifference64;
end;
ImageBaseRelocation:=PIMAGE_BASE_RELOCATION(ptrUint(ImageBaseRelocation)+ImageBaseRelocation.SizeOfBlock);
end;
end;
end;
end;
//ShowMessage(format('I would have written this code. From %x to %x (%d bytes)',[qword(tempmap.memory), qword(destinationbase), tempmap.size]));
WriteProcessMemory64(processhandle, destinationbase, tempmap.memory, tempmap.size, x);
floaded:=true;
//at the end, copy the tempmap contexts to the actual allocated memory using WriteProcessMemory(64)
finally
tempmap.free;
end;
finally
filemap.free;
end;
end;
end.