function BTMemoryLoadLibary(fp_data: Pointer;
const f_size: int64): PBTMemoryModule;
var
lp_result: PBTMemoryModule;
l_dos_header: TImageDosHeader;
l_old_header: TImageNtHeaders;
l_code, l_headers: Pointer;
l_locationdelta: Cardinal;
lp_DllEntry: PDllEntryProc;
l_successfull: boolean;
begin
lp_result :=
nil;
Result :=
nil;
try
CopyMemory(@l_dos_header, fp_data, SizeOf(_IMAGE_DOS_HEADER));
if (l_dos_header.e_magic <> IMAGE_DOS_SIGNATURE)
then
begin
lastErrStr := '
BTMemoryLoadLibary: dll dos header is not valid';
exit;
end;
CopyMemory(@l_old_header, IncF(fp_data, l_dos_header._lfanew),
SizeOf(_IMAGE_NT_HEADERS));
if l_old_header.Signature <> IMAGE_NT_SIGNATURE
then
begin
lastErrStr := '
BTMemoryLoadLibary: IMAGE_NT_SIGNATURE is not valid';
exit;
end;
// reserve memory for image of library
l_code := VirtualAlloc(Pointer(l_old_header.OptionalHeader.ImageBase),
l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if l_code =
nil then
// try to allocate memory at arbitrary position
l_code := VirtualAlloc(
nil, l_old_header.OptionalHeader.SizeOfImage,
MEM_RESERVE, PAGE_READWRITE);
if l_code =
nil then
begin
lastErrStr := '
BTMemoryLoadLibary: VirtualAlloc failed';
exit;
end;
// alloc space for the result record
lp_result := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0,
SizeOf(TBTMemoryModule)));
lp_result^.codeBase := l_code;
lp_result^.numModules := 0;
lp_result^.modules :=
nil;
lp_result^.initialized := false;
// xy: is it correct to commit the complete memory region at once?
// calling DllEntry raises an exception if we don't...
VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfImage, MEM_COMMIT,
PAGE_READWRITE);
// commit memory for headers
l_headers := VirtualAlloc(l_code,
l_old_header.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
// copy PE header to code
CopyMemory(l_headers, fp_data,
(UInt64(l_dos_header._lfanew)
+ l_old_header.OptionalHeader.SizeOfHeaders));
lp_result^.headers := PImageNtHeaders
(UInt64(l_headers) + l_dos_header._lfanew);
// update position
lp_result^.headers^.OptionalHeader.ImageBase := UInt64(l_code);
// copy sections from DLL file block to new memory location
CopySections(fp_data, l_old_header, lp_result);
// adjust base address of imported data
l_locationdelta := Cardinal
(UInt64(l_code) - l_old_header.OptionalHeader.ImageBase);
if l_locationdelta <> 0
then
PerformBaseRelocation(lp_result, l_locationdelta);
// load required dlls and adjust function table of imports
if not BuildImportTable(lp_result)
then
begin
lastErrStr := lastErrStr + '
BTMemoryLoadLibary: BuildImportTable failed';
Abort;
end;
// mark memory pages depending on section headers and release
// sections that are marked as "discardable"
FinalizeSections(lp_result);
// get entry point of loaded library
if (lp_result^.headers^.OptionalHeader.AddressOfEntryPoint) <> 0
then
begin
lp_DllEntry := Pointer
(UInt64(l_code)
+ lp_result^.headers^.OptionalHeader.AddressOfEntryPoint);
if lp_DllEntry =
nil then
begin
lastErrStr := '
BTMemoryLoadLibary: Get DLLEntyPoint failed';
Abort;
end;
l_successfull := TDllEntryProc(lp_DllEntry)(UInt64(l_code),
DLL_PROCESS_ATTACH,
nil);
if not l_successfull
then
begin
lastErrStr := '
BTMemoryLoadLibary: Can''
t attach library';
Abort;
end;
lp_result^.initialized := true;
end;
except
BTMemoryFreeLibrary(lp_result);
exit;
end;
Result := lp_result;
end;
function BTMemoryGetProcAddress(fp_module: PBTMemoryModule;
const fp_name: PChar): Pointer;
var
l_idx: Integer;
l_i: DWORD;
l_nameRef: PDWORD;
l_ordinal: PWord;
l_exports: PImageExportDirectory;
l_directory: PImageDataDirectory;
begin
Result :=
nil;
l_idx := -1;
l_directory := GetHeaderDictionary(fp_module, IMAGE_DIRECTORY_ENTRY_EXPORT);
if l_directory^.Size = 0
then
begin
lastErrStr := '
BTMemoryGetProcAddress: no export table found';
exit;
end;
l_exports := IncF(fp_module^.codeBase, l_directory^.VirtualAddress);
if ((l_exports^.NumberOfNames = 0)
or (l_exports^.NumberOfFunctions = 0))
then
begin
lastErrStr := '
BTMemoryGetProcAddress: DLL doesn''
t export anything';
exit;
end;
// search function name in list of exported names
l_nameRef := IncF(fp_module^.codeBase, l_exports^.AddressOfNames);
l_ordinal := IncF(fp_module^.codeBase, l_exports^.ADDressOfNameOrdinals);
for l_i := 0
to l_exports^.NumberOfNames - 1
do
begin
if StrComp(fp_name, PAnsiCharToPChar(IncF(fp_module^.codeBase, l_nameRef^))
) = 0
then
begin
l_idx := l_ordinal^;
break;
end;
Inc(l_nameRef);
Inc(l_ordinal);
end;
if (l_idx = -1)
then
begin
lastErrStr := '
BTMemoryGetProcAddress: exported symbol not found';
exit;
end;
if (UInt64(l_idx) > l_exports^.NumberOfFunctions - 1)
then
begin
lastErrStr :=
'
BTMemoryGetProcAddress: name <-> ordinal number don''
t match';
exit;
end;
// AddressOfFunctions contains the RVAs to the "real" functions
Result := IncF(fp_module^.codeBase,
PUInt64(IncF(fp_module^.codeBase, IncF(l_exports^.AddressOfFunctions,
l_idx * 4)))^);
end;