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, commonTypeDefs; resourcestring rsMMLNotAValidFile = 'not a valid file'; rsMMLNotAValidHeader = 'Not a valid header'; rsMMLTriedLoadingA64BitModuleOnA32BitSystem = 'Tried loading a 64-bit module on a 32-bit system'; rsMMLAllocationError = 'Allocation error'; rsMMLFailedFindingAddressOf = 'failed finding address of '; 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(rsMMLNotAValidFile); tempmap:=tmemorystream.Create; try ImageNtHeader:=peinfo_getImageNtHeaders(filemap.Memory, filemap.Size); if ImageNtHeader=nil then raise exception.create(rsMMLNotAValidHeader); if ImageNTHeader^.FileHeader.Machine=$8664 then begin is64bit:=true; if not Is64bitOS then raise exception.create(rsMMLTriedLoadingA64BitModuleOnA32BitSystem); 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(rsMMLAllocationError); 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(rsMMLFailedFindingAddressOf+pwidechar(@importfunctionnamews[1])); end else begin funcaddress:=symhandler.getAddressFromName(importmodulename+'!'+importfunctionname, true, haserror); if haserror then raise exception.create(rsMMLFailedFindingAddressOf+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(rsMMLFailedFindingAddressOf+pwidechar(@importfunctionnamews[1])); end else begin funcaddress:=symhandler.getAddressFromName(importmodulename+'!'+importfunctionname, true, haserror); if haserror then raise exception.create(rsMMLFailedFindingAddressOf+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)