uDllFromMem - Load a DLL from Memory

Post date: Aug 25, 2010 1:48:21 PM

{
[===========================================]
[?]uDllFromMem - Loading a DLL from Memory[?]
[v]              Version 1.0              [v]
[c]          Hamtaro aka CorVu5           [c]
[@]     hamtaro.6x.to OR corvu5.6x.to     [@]
[================Description================]
[With this Code, you can load a DLL in your ]
[application directly from Memory, the file ]
[doesnt have to be present on your Harddrive]
[===================Note====================]
[   This example doesnt work with Bound     ]
[       Import Tables at this time          ]
[==================thx to===================]
[              CDW, Cryptocrack             ]
[           & Joachim Bauch for his         ]
[      GetSectionProtection function        ]
[===========================================]
[  there must be 50 ways to learn to hover  ]
[===========================================]
}
unit uDllfromMem;
interface
uses windows;
type
PImageBaseRelocation = ^TImageBaseRelocation;
  _IMAGE_BASE_RELOCATION = packed record
    VirtualAddress: DWORD;
    SizeOfBlock: DWORD;
end;
{$EXTERNALSYM _IMAGE_BASE_RELOCATION}
  TImageBaseRelocation = _IMAGE_BASE_RELOCATION;
  IMAGE_BASE_RELOCATION = _IMAGE_BASE_RELOCATION;
{$EXTERNALSYM IMAGE_BASE_RELOCATION}
type
PImageImportDescriptor = ^TImageImportDescriptor;
  TImageImportDescriptor = packed record
    OriginalFirstThunk: dword;
    TimeDateStamp: dword;
    ForwarderChain: dword;
    Name: dword;
    FirstThunk: dword;
end;
type
PImageImportByName = ^TImageImportByName;
  TImageImportByName = packed record
    Hint : WORD;
    Name : array[0..255] of Char;
end;
type
PImageThunkData = ^TImageThunkData;
  TImageThunkData = packed record
    case integer of
      0 : (ForwarderString: PBYTE);
      1 : (FunctionPtr    : PDWORD);
      2 : (Ordinal        : DWORD);
      3 : (AddressOfData  : PImageImportByName);
end;
type
  TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall;
function memLoadLibrary(FileBase : Pointer) : Pointer;
function memGetProcAddress(Physbase : Pointer; NameOfFunction : String) : Pointer;
function memFreeLibrary(physbase : Pointer) : Boolean;
const
IMAGE_REL_BASED_HIGHLOW = 3;
IMAGE_ORDINAL_FLAG32 = DWORD($80000000);
var DllentryProc : TDLLEntryProc;
implementation
//strComp Function from SysUtils
function StrComp(const Str1, Str2: PChar): Integer; assembler;
asm
        PUSH    EDI
        PUSH    ESI
        MOV     EDI,EDX
        MOV     ESI,EAX
        MOV     ECX,0FFFFFFFFH
        XOR     EAX,EAX
        REPNE   SCASB
        NOT     ECX
        MOV     EDI,EDX
        XOR     EDX,EDX
        REPE    CMPSB
        MOV     AL,[ESI-1]
        MOV     DL,[EDI-1]
        SUB     EAX,EDX
        POP     ESI
        POP     EDI
end;
function GetSectionProtection(ImageScn: cardinal): cardinal;
  begin
    Result := 0;
    if (ImageScn and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
    begin
    Result := Result or PAGE_NOCACHE;
    end;
    if (ImageScn and IMAGE_SCN_MEM_EXECUTE) <> 0 then
    begin
      if (ImageScn and IMAGE_SCN_MEM_READ)<> 0 then
      begin
        if (ImageScn and IMAGE_SCN_MEM_WRITE)<> 0 then
        begin
          Result := Result or PAGE_EXECUTE_READWRITE
        end
        else
        begin
          Result := Result or PAGE_EXECUTE_READ
        end;
      end
      else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
      begin
        Result := Result or PAGE_EXECUTE_WRITECOPY
      end
      else
      begin
        Result := Result or PAGE_EXECUTE
      end;
    end
    else if (ImageScn and IMAGE_SCN_MEM_READ)<> 0 then
    begin
      if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
      begin
        Result := Result or PAGE_READWRITE
      end
      else
      begin
        Result := Result or PAGE_READONLY
      end
    end
    else if (ImageScn and IMAGE_SCN_MEM_WRITE) <> 0 then
    begin
      Result := Result or PAGE_WRITECOPY
    end
    else
    begin
      Result := Result or PAGE_NOACCESS;
    end;
  end;
function memLoadLibrary(FileBase : Pointer) : Pointer;
var
pfilentheader : PIMAGENTHEADERS;
pfiledosheader: PIMAGEDOSHEADER;
pphysntheader : PIMAGENTHEADERS;
pphysdosheader: PIMAGEDOSHEADER;
physbase  : Pointer;
pphyssectionheader : PIMAGESECTIONHEADER;
i : Integer;
importsDir : PImageDataDirectory;
importsBase: Pointer;
importDesc :  PImageImportDescriptor;
importThunk: PImageThunkData;
dll_handle : Cardinal;
importbyname : pimageimportbyname;
relocbase : Pointer;
relocdata : PIMAGeBaseRElocation;
relocitem : PWORD;
reloccount : Integer;
dllproc : TDLLEntryProc;
begin
result := 0;
pfiledosheader := filebase;
pfilentheader  := Pointer(Cardinal(filebase) + pfiledosheader^._lfanew);
////////////////////////
/////////////allozieren/
physbase := VirtualAlloc(Pointer(pfilentheader^.OptionalHeader.ImageBase),pfilentheader^.OptionalHeader.SizeOfImage,MEM_RESERVE,PAGE_READWRITE);
if Cardinal(physbase) = 0 Then begin
physbase := VirtualAlloc(0,pfilentheader^.OptionalHeader.SizeOfImage,MEM_RESERVE Or Mem_COMMIT,PAGE_READWRITE);
end;
/////////////////////////////
/////////////header kopieren/
CopyMemory(physbase,filebase,pfilentheader^.OptionalHeader.SizeOfHeaders);
//header im memory finden & anpassen
pphysdosheader := physbase;
pphysntheader := Pointer(Cardinal(physbase) + pphysdosheader^._lfanew);
pphysntheader^.OptionalHeader.ImageBase := Cardinal(physbase);
///////////////////////////////
/////////////sections kopieren/
pphyssectionheader := Pointer(Cardinal(pphysntheader) + SizeOf(TIMAGENTHEADERS));
for i := 0 To (pphysntheader^.FileHeader.NumberOfSections - 1) do begin
  if pphyssectionheader^.SizeOfRawData = 0 Then begin
    //keine raw data
    ZeroMemory(Pointer(Cardinal(physbase) + pphyssectionheader^.VirtualAddress),pphyssectionheader^.Misc.VirtualSize);
  end else begin
    //raw data vorhanden
    CopyMemory(Pointer(Cardinal(physbase) + pphyssectionheader^.VirtualAddress),Pointer(Cardinal(filebase) + pphyssectionheader^.PointerToRawData),pphyssectionheader^.SizeOfRawData);
  end;
  pphyssectionheader^.Misc.PhysicalAddress :=  Cardinal(physbase) + pphyssectionheader^.VirtualAddress;
  //next one please
  pphyssectionheader :=  Pointer(Cardinal(pphyssectionheader) + SizeOf(TIMAGESECTIONHEADER));
end;
//////////////////////
/////////////imports/
importsBase := Pointer(Cardinal(physbase) + pphysntheader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
importDesc := importsBase;
while (importDesc.Name) <> 0 Do begin
  dll_handle := LoadLibrary(pchar(Cardinal(physbase) + importdesc.Name));
  importDesc.ForwarderChain := dll_handle;
  importThunk := Pointer(Cardinal(physbase) +  importDesc.FirstThunk);
  while importThunk.Ordinal <> 0 Do begin
    importbyname := Pointer(Cardinal(physbase) + importThunk.Ordinal);
    //Später noch überprüfen ob OriginalFirstThunk = 0
    if (importThunk.Ordinal and IMAGE_ORDINAL_FLAG32) <> 0 Then
    begin //ordinal
      importThunk.FunctionPtr := GetProcaddress(dll_handle,pchar(importThunk.Ordinal and $ffff))
    end else begin //normal
      importThunk.FunctionPtr := GetProcAddress(dll_handle,importByname.name);
    end;
  //next one, please
  importThunk := Pointer(Cardinal(importThunk) + SizeOf(TIMAGETHUNKDATA));
  end;
//next one, please
importDesc := Pointer(Cardinal(importDesc) + sizeOf(TIMAGEIMPORTDESCRIPTOR));
end;
/////////////////////
/////////////relocs/
relocbase := Pointer(Cardinal(physbase) + pphysntheader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
relocData := RElocbase;
while (Cardinal(relocdata) -  Cardinal(relocbase)) < pphysntheader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size do begin
  reloccount := trunc((relocdata.SizeOfBlock - 8) / 2);
  relocitem  := Pointer(Cardinal(relocdata) + 8);
  For i := 0 To (reloccount - 1) do begin
    if (relocitem^ shr 12) = IMAGE_REL_BASED_HIGHLOW Then begin
      Inc(PDWord(Cardinal(physbase) + relocdata.VirtualAddress + (relocitem^ and $FFF))^,(Cardinal(physbase) - pfilentheader.OptionalHeader.ImageBase));
    end;
    relocitem := Pointer(Cardinal(relocitem) + SizeOf(WORD));
  end;
  //next one please
  relocdata := Pointer(Cardinal(relocdata) + relocdata.SizeOfBlock);
end;
/////////////////////////////////
////////Section protection & so/
pphyssectionheader := Pointer(Cardinal(pphysntheader) + SizeOf(TIMAGENTHEADERS));
For i := 0 To (pphysntheader^.FileHeader.NumberOfSections - 1) do begin
  VirtualProtect(Pointer(Cardinal(physbase) + pphyssectionheader^.VirtualAddress),pphyssectionheader^.Misc.VirtualSize,GetSectionProtection(pphyssectionheader.Characteristics),nil);
  pphyssectionheader := Pointer(Cardinal(pphyssectionheader) + SizeOf(TIMAGESECTIONHEADER));
end;
////////////////////////////////
////////////////Dll entry proc/
dllEntryproc := Pointer(Cardinal(physbase) + pphysntheader.OptionalHeader.AddressOfEntryPoint);
dllEntryproc(cardinal(physbase),DLL_PROCESS_ATTACH,nil);
result := physbase;
end;
function memGetProcAddress(Physbase : Pointer; NameOfFunction : String) : Pointer;
var
pdosheader: PIMAGEDOSHEADER;
pntheader : PIMAGENTHEADERS;
pexportdir: PImageExportDirectory;
i : Integer;
pexportname : PDWORD;
pexportordinal : PWORD;
pexportFunction : PDWORD;
begin
result := 0;
pdosheader := physbase;
pntheader := Pointer(Cardinal(physbase) + pdosheader._lfanew);
pexportdir := Pointer(Cardinal(physbase) + pntheader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if pexportdir.NumberOfFunctions Or pexportdir.NumberOfNames  = 0 Then exit;
pexportName    := Pointer(Cardinal(physbase) + Cardinal(pexportDir.AddressOfNames));
pexportordinal := Pointer(Cardinal(physbase) + Cardinal(pexportDir.AddressOfNameOrdinals));
pexportFunction:= Pointer(Cardinal(physbase) + Cardinal(pexportDir.AddressOfFunctions));
For i := 0 To (pexportdir.NumberOfNames - 1) Do begin
  if StrComp(pchar(Pointer(Cardinal(physbase) + pexportName^)),pchar(NameOfFunction)) = 0 Then begin
    result := pchar(Pointer(Cardinal(physbase) + pexportFunction^));
    break;
  end;
  //next one, please
  Inc(pexportFunction);
  Inc(pexportName);
  Inc(pexportOrdinal);
end;
end;
function memFreeLibrary(physbase : Pointer) : Boolean;
begin
try begin
  //Keine Ahnung ob die DLL ihre Imports wieder "Free't" wenn man DLL_PROCESS_DETACH aufruft
  result := true;
  dllEntryProc(Cardinal(physbase),DLL_PROCESS_DETACH,0);
  VirtualFree(physbase,0,MEM_RELEASE);
end except
  result := false;
end;
end;
end.