Jump to content
Tuts 4 You

Load Dll Directly From memory


Departure

Recommended Posts

While I was wondering around on the net a stumbled accross and interesting example, Corvu5 has showen this example in delphi

With this Unit written by me, you can load a Dll directly from a Bytearray, use the Functions of the DLL and free it at last.

Post Bugs if you find some here!

{

[===========================================]

[?]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

Link to comment

Hmm this reminds me of this:

Tutorial: Loading A DLL From Memory Shub-Nigurrath V12.rar

Author: Shub-Nigurrath

Description:

The tutorial aims describing a protection technique which consists loading a Dll for a program, directly from memory, without temporary files. Example and sources included.


/>http://arteam.accessroot.com/tutorials.html?fid=103

Good to have different options for the same issue.

Thanks

Nacho_dj

Link to comment
While I was wondering around on the net a stumbled accross and interesting example, Corvu5 has showen this example in delphi

Hi Departure, interesting and thanks for source. I do not have access to delphi, do you have a compiled example you could let me have.

tia

Link to comment
[ CDW, Cryptocrack ]

[ & Joachim Bauch for his ]

[ GetSectionProtection function ]

Check greetings, J. Bauch also released such a paper some time ago at tuts4you; can't remember right, but I think even Shub's code was based on Bauch's examples?

Link to comment

I'm sure J. Bauch is the origin.. no doubt. Shub credited him with huge letters,

but also added useful stuff, which you won't find on Bauch's site.

Link to comment
  • 4 months later...
  • 2 weeks later...

Ported it to C# with the C++ source, a bit messy but works.

		public unsafe static class MemoryLibrary
{
static ushort Endian(ushort num)
{
return (ushort)((num << 8) | (num >> 8));
}
static void memcpy(byte* dest, byte* src, uint size)
{
for (uint i = 0; i < size; i++)
{
*(dest + i) = *(src + i);
}
}
static void memset(byte* dest, byte c, uint size)
{
for (uint i = 0; i < size; i++)
{
*dest = c;
}
}
#region IMAGE_DOS_HEADER
const ushort IMAGE_DOS_SIGNATURE = 0x4D5A; // MZ
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_DOS_HEADER // DOS .EXE header
{
public ushort e_magic; // Magic number
public ushort e_cblp; // Bytes on last page of file
public ushort e_cp; // Pages in file
public ushort e_crlc; // Relocations
public ushort e_cparhdr; // Size of header in paragraphs
public ushort e_minalloc; // Minimum extra paragraphs needed
public ushort e_maxalloc; // Maximum extra paragraphs needed
public ushort e_ss; // Initial (relative) SS value
public ushort e_sp; // Initial SP value
public ushort e_csum; // Checksum
public ushort e_ip; // Initial IP value
public ushort e_cs; // Initial (relative) CS value
public ushort e_lfarlc; // File address of relocation table
public ushort e_ovno; // Overlay number
public fixed ushort e_res[4]; // Reserved ushorts
public ushort e_oemid; // OEM identifier (for e_oeminfo)
public ushort e_oeminfo; // OEM information; e_oemid specific
public fixed ushort e_res2[10]; // Reserved ushorts
public uint e_lfanew; // File address of new exe header
}
#endregion
#region IMAGE_NT_HEADERS
const byte IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_NT_HEADERS
{
public uint Signature;
public IMAGE_FILE_HEADER FileHeader;
public IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_FILE_HEADER
{
public ushort Machine;
public ushort NumberOfSections;
public uint TimeDateStamp;
public uint PointerToSymbolTable;
public uint NumberOfSymbols;
public ushort SizeOfOptionalHeader;
public ushort Characteristics;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_OPTIONAL_HEADER32
{
//
// Standard fields.
// public ushort Magic;
public byte MajorLinkerVersion;
public byte MinorLinkerVersion;
public uint SizeOfCode;
public uint SizeOfInitializedData;
public uint SizeOfUninitializedData;
public uint AddressOfEntryPoint;
public uint BaseOfCode;
public uint BaseOfData; //
// NT additional fields.
// public uint ImageBase;
public uint SectionAlignment;
public uint FileAlignment;
public ushort MajorOperatingSystemVersion;
public ushort MinorOperatingSystemVersion;
public ushort MajorImageVersion;
public ushort MinorImageVersion;
public ushort MajorSubsystemVersion;
public ushort MinorSubsystemVersion;
public uint Win32VersionValue;
public uint SizeOfImage;
public uint SizeOfHeaders;
public uint CheckSum;
public ushort Subsystem;
public ushort DllCharacteristics;
public uint SizeOfStackReserve;
public uint SizeOfStackCommit;
public uint SizeOfHeapReserve;
public uint SizeOfHeapCommit;
public uint LoaderFlags;
public uint NumberOfRvaAndSizes;
public fixed ulong DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_DATA_DIRECTORY
{
public uint VirtualAddress;
public uint Size;
}
#endregion
#region VirtualAlloc
[DllImport("kernel32.dll")]
private static extern uint VirtualAlloc(uint lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
private static extern int VirtualFree(uint lpAddress, uint dwSize, uint dwFreeType);
[DllImport("kernel32.dll")]
private static extern int VirtualProtect(uint lpAddress, uint dwSize, uint flNewProtect, uint* lpflOldProtect);
const uint PAGE_NOACCESS = 0x01;
const uint PAGE_READONLY = 0x02;
const uint PAGE_READWRITE = 0x04;
const uint PAGE_WRITECOPY = 0x08;
const uint PAGE_EXECUTE = 0x10;
const uint PAGE_EXECUTE_READ = 0x20;
const uint PAGE_EXECUTE_READWRITE = 0x40;
const uint PAGE_EXECUTE_WRITECOPY = 0x80;
const uint PAGE_GUARD = 0x100;
const uint PAGE_NOCACHE = 0x200;
const uint PAGE_WRITECOMBINE = 0x400;
const uint MEM_COMMIT = 0x1000;
const uint MEM_RESERVE = 0x2000;
const uint MEM_DECOMMIT = 0x4000;
const uint MEM_RELEASE = 0x8000;
const uint MEM_FREE = 0x10000;
const uint MEM_PRIVATE = 0x20000;
const uint MEM_MAPPED = 0x40000;
const uint MEM_RESET = 0x80000;
const uint MEM_TOP_DOWN = 0x100000;
const uint MEM_WRITE_WATCH = 0x200000;
const uint MEM_PHYSICAL = 0x400000;
const uint MEM_LARGE_PAGES = 0x20000000;
const uint MEM_4MB_PAGES = 0x80000000;
#endregion
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MEMORYMODULE
{
public IMAGE_NT_HEADERS* headers;
public byte* codeBase;
public uint* modules;
public int numModules;
public int initialized;
}
const uint DLL_PROCESS_ATTACH = 1;
delegate uint DllEntryPointFunc(uint code, uint method, uint flag);
#region IMAGE_SECTION_HEADER
const int IMAGE_SIZEOF_SHORT_NAME = 8;
const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code.
const uint IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040; // Section contains initialized data.
const uint IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080; // Section contains uninitialized data.
const uint IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; // Section contains extended relocations.
const uint IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; // Section can be discarded.
const uint IMAGE_SCN_MEM_NOT_CACHED = 0x04000000; // Section is not cachable.
const uint IMAGE_SCN_MEM_NOT_PAGED = 0x08000000; // Section is not pageable.
const uint IMAGE_SCN_MEM_SHARED = 0x10000000; // Section is shareable.
const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable.
const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable.
const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writeable.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_SECTION_HEADER
{
public fixed byte Name[IMAGE_SIZEOF_SHORT_NAME];
public uint PhysicalAddress;
public uint VirtualAddress;
public uint SizeOfRawData;
public uint PointerToRawData;
public uint PointerToRelocations;
public uint PointerToLinenumbers;
public ushort NumberOfRelocations;
public ushort NumberOfLinenumbers;
public uint Characteristics;
}
static uint[, ,] ProtectionFlags = new uint[2, 2, 2]{
{
// not executable
{PAGE_NOACCESS, PAGE_WRITECOPY},
{PAGE_READONLY, PAGE_READWRITE},
}, {
// executable
{PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
},};
static IMAGE_SECTION_HEADER* IMAGE_FIRST_SECTION(IMAGE_NT_HEADERS* img)
{
return (IMAGE_SECTION_HEADER*)((int)img + 0x18 + img->FileHeader.SizeOfOptionalHeader);
}
static void CopySections(byte* data, IMAGE_NT_HEADERS* old_headers, MEMORYMODULE* module)
{
uint i, size;
byte* codeBase = module->codeBase;
byte* dest;
IMAGE_SECTION_HEADER* section = IMAGE_FIRST_SECTION(module->headers);
for (i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++)
{
if (section->SizeOfRawData == 0)
{
// section doesn't contain data in the dll itself, but may define
// uninitialized data
size = old_headers->OptionalHeader.SectionAlignment;
if (size > 0)
{
dest = (byte*)VirtualAlloc((uint)codeBase + (uint)section->VirtualAddress, size, MEM_COMMIT, PAGE_READWRITE); section->PhysicalAddress = (uint)dest;
memset(dest, 0, size);
} // section is empty
continue;
} // commit memory block and copy data from dll
dest = (byte*)VirtualAlloc((uint)codeBase + section->VirtualAddress,
section->SizeOfRawData,
MEM_COMMIT,
PAGE_READWRITE);
memcpy(dest, (byte*)((uint)data + (uint)section->PointerToRawData), section->SizeOfRawData);
section->PhysicalAddress = (uint)dest;
}
}
static void FinalizeSections(MEMORYMODULE* module)
{
IMAGE_SECTION_HEADER* section = IMAGE_FIRST_SECTION(module->headers);
for (int i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++)
{
uint protect, oldProtect, size;
uint executable = Convert.ToUInt32((section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0);
uint readable = Convert.ToUInt32((section->Characteristics & IMAGE_SCN_MEM_READ) != 0);
uint writeable = Convert.ToUInt32((section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0);
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
{
// section is not needed any more and can safely be freed
VirtualFree(section->PhysicalAddress, section->SizeOfRawData, MEM_DECOMMIT);
continue;
}
protect = ProtectionFlags[executable, readable, writeable];
if ((section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0)
protect |= PAGE_NOCACHE; // determine size of region
size = section->SizeOfRawData;
if (size == 0)
{
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0)
size = module->headers->OptionalHeader.SizeOfInitializedData;
else if ((section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0)
size = module->headers->OptionalHeader.SizeOfUninitializedData;
} if (size > 0)
{
// change memory access flags
VirtualProtect(section->PhysicalAddress, section->SizeOfRawData, protect, &oldProtect);
}
}
}
#endregion
#region BaseRelocation
const uint IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table
static IMAGE_DATA_DIRECTORY* GET_HEADER_DICTIONARY(MEMORYMODULE* module, uint idx)
{
return (IMAGE_DATA_DIRECTORY*)(&module->headers->OptionalHeader.DataDirectory[idx]);
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_BASE_RELOCATION
{
public uint VirtualAddress;
public uint SizeOfBlock;
}
const uint IMAGE_SIZEOF_BASE_RELOCATION = 8;
const uint IMAGE_REL_BASED_ABSOLUTE = 0;
const uint IMAGE_REL_BASED_HIGHLOW = 3;
static void PerformBaseRelocation(MEMORYMODULE* module, uint delta)
{
uint i;
byte* codeBase = module->codeBase; IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
if (directory->Size > 0)
{
IMAGE_BASE_RELOCATION* relocation = (IMAGE_BASE_RELOCATION*)((uint)codeBase + directory->VirtualAddress);
for (; relocation->VirtualAddress > 0; )
{
byte* dest = (byte*)((uint)codeBase + relocation->VirtualAddress);
ushort* relInfo = (ushort*)((byte*)relocation + IMAGE_SIZEOF_BASE_RELOCATION);
for (i = 0; i < ((relocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++)
{
uint* patchAddrHL;
uint type, offset; // the upper 4 bits define the type of relocation
type = (uint)(*relInfo >> 12);
// the lower 12 bits define the offset
offset = (uint)(*relInfo & 0xfff); switch (type)
{
case IMAGE_REL_BASED_ABSOLUTE:
// skip relocation
break; case IMAGE_REL_BASED_HIGHLOW:
// change complete 32 bit address
patchAddrHL = (uint*)((uint)dest + offset);
*patchAddrHL += delta;
break; default:
//printf("Unknown relocation: %d\n", type);
break;
}
} // advance to next relocation block
relocation = (IMAGE_BASE_RELOCATION*)((uint)relocation + relocation->SizeOfBlock);
}
}
}
#endregion
#region BuildImportTable
[DllImport("kernel32.dll", EntryPoint = "LoadLibraryA")]
private static extern uint LoadLibrary(byte* lpLibFileName);
[DllImport("kernel32.dll")]
private static extern uint GetProcAddress(uint hModule, byte* lpProcName);
const uint IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_IMPORT_DESCRIPTOR
{
public uint Characteristics; // 0 for terminating null import descriptor
public uint TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND) public uint ForwarderChain; // -1 if no forwarders
public uint Name;
public uint FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_IMPORT_BY_NAME
{
public ushort Hint;
public fixed byte Name[1];
}
static byte* realloc(byte* bytes, uint newsize, uint oldsize)
{ byte* New = (byte*)Marshal.AllocHGlobal((int)newsize).ToPointer();
if ((int)bytes != 0)
{
memcpy(New, bytes, oldsize);
Marshal.FreeHGlobal(new IntPtr(bytes));
}
return New;
}
static bool BuildImportTable(MEMORYMODULE* module)
{
bool result = true;
byte* codeBase = module->codeBase; IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (directory->Size > 0)
{
IMAGE_IMPORT_DESCRIPTOR* importDesc = (IMAGE_IMPORT_DESCRIPTOR*)((uint)codeBase + directory->VirtualAddress);
for (; importDesc->Name != 0; importDesc++)
{
uint* thunkRef;
uint* funcRef;
uint handle = LoadLibrary((byte*)((uint)codeBase + importDesc->Name));
if (handle == 0)
{
result = false;
break;
} module->modules = (uint*)realloc((byte*)module->modules, (uint)(module->numModules + 1) * 4, (uint)(module->numModules) * 4);
if (module->modules == null)
{
result = false;
break;
} module->modules[module->numModules++] = handle;
if (importDesc->Characteristics != 0)
{
thunkRef = (uint*)((uint)codeBase + importDesc->Characteristics);
funcRef = (uint*)((uint)codeBase + importDesc->FirstThunk);
}
else
{
// no hint table
thunkRef = (uint*)((uint)codeBase + importDesc->FirstThunk);
funcRef = (uint*)((uint)codeBase + importDesc->FirstThunk);
}
for (; *thunkRef != 0; thunkRef++, funcRef++)
{
if ((*thunkRef & 0x80000000) != 0)
*funcRef = GetProcAddress(handle, (byte*)(*thunkRef & 0xffff));
else
{
IMAGE_IMPORT_BY_NAME* thunkData = (IMAGE_IMPORT_BY_NAME*)((uint)codeBase + *thunkRef);
*funcRef = GetProcAddress(handle, (byte*)(int)(thunkData) + 2);
}
if (*funcRef == 0)
{
result = false;
break;
}
} if (!result)
break;
}
} return result;
}
#endregion
const uint IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export Directory
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IMAGE_EXPORT_DIRECTORY
{
public uint Characteristics;
public uint TimeDateStamp;
public ushort MajorVersion;
public ushort MinorVersion;
public uint Name;
public uint Base;
public uint NumberOfFunctions;
public uint NumberOfNames;
public uint AddressOfFunctions; // RVA from base of image
public uint AddressOfNames; // RVA from base of image
public uint AddressOfNameOrdinals; // RVA from base of image
}
static bool stricmp(string str, byte* bytes)
{
int idx = 0;
while (*bytes != 0 && idx < str.Length)
{
if (str[idx] != *(bytes + idx))
{
return false;
}
idx++;
}
return true;
}
const uint DLL_PROCESS_DETACH = 0;
[DllImport("kernel32.dll")]
private static extern int FreeLibrary(uint hLibModule);
public static int MemoryLoadLibrary(byte[] bytes)
{
fixed (byte* b = bytes)
{
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)b;
if (Endian(dos_header->e_magic) != IMAGE_DOS_SIGNATURE)
{
return 0;
}
IMAGE_NT_HEADERS* old_header = (IMAGE_NT_HEADERS*)(b + dos_header->e_lfanew);
uint code = VirtualAlloc(old_header->OptionalHeader.ImageBase, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if (code == 0)
code = VirtualAlloc(0, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if (code == 0)
return 0;
MEMORYMODULE* result = (MEMORYMODULE*)Marshal.AllocHGlobal(sizeof(MEMORYMODULE));
result->codeBase = (byte*)code;
result->numModules = 0;
result->modules = null;
result->initialized = 0;
VirtualAlloc(code, old_header->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
uint headers = VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); // copy PE header to code
memcpy((byte*)headers, (byte*)dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders);
result->headers = (IMAGE_NT_HEADERS*)&((byte*)(headers))[dos_header->e_lfanew]; // update position
result->headers->OptionalHeader.ImageBase = (uint)code; // copy sections from DLL file block to new memory location
CopySections(b, old_header, result); // adjust base address of imported data
uint locationDelta = (uint)(code - old_header->OptionalHeader.ImageBase);
if (locationDelta != 0)
PerformBaseRelocation(result, locationDelta); // load required dlls and adjust function table of imports
if (!BuildImportTable(result))
goto error; // mark memory pages depending on section headers and release
// sections that are marked as "discardable"
FinalizeSections(result); // get entry point of loaded library
if (result->headers->OptionalHeader.AddressOfEntryPoint != 0)
{
uint DllEntry = ((uint)code + result->headers->OptionalHeader.AddressOfEntryPoint);
if (DllEntry == 0)
{
goto error;
} // notify library about attaching to process
DllEntryPointFunc func = (DllEntryPointFunc)Marshal.GetDelegateForFunctionPointer(new IntPtr(DllEntry), typeof(DllEntryPointFunc));
uint successfull = func(code, DLL_PROCESS_ATTACH, 0);
if (successfull == 0)
{
goto error;
}
result->initialized = 1;
} return (int)result; error:
// cleanup
//MemoryFreeLibrary(result);
return 0;
}
}
public static int MemoryGetProcAddress(int module, string name)
{
byte* codeBase = ((MEMORYMODULE*)module)->codeBase;
int idx = -1;
uint i;
uint* nameRef;
ushort* ordinal;
IMAGE_EXPORT_DIRECTORY* exports;
IMAGE_DATA_DIRECTORY* directory = GET_HEADER_DICTIONARY((MEMORYMODULE*)module, IMAGE_DIRECTORY_ENTRY_EXPORT);
if (directory->Size == 0)
// no export table found
return 0; exports = (IMAGE_EXPORT_DIRECTORY*)((uint)codeBase + directory->VirtualAddress);
if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0)
// DLL doesn't export anything
return 0; // search function name in list of exported names
nameRef = (uint*)((uint)codeBase + exports->AddressOfNames);
ordinal = (ushort*)((uint)codeBase + exports->AddressOfNameOrdinals);
for (i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++)
{
if (stricmp(name, (byte*)((uint)codeBase + *nameRef)))
{
idx = *ordinal;
break;
}
} if (idx == -1)
// exported symbol not found
return 0; if ((uint)idx > exports->NumberOfFunctions)
// name <-> ordinal number don't match
return 0; // AddressOfFunctions contains the RVAs to the "real" functions
return (int)((uint)codeBase + *(uint*)((uint)codeBase + exports->AddressOfFunctions + (idx * 4)));
}
public static void MemoryFreeLibrary(int mod)
{
int i;
MEMORYMODULE* module = (MEMORYMODULE*)mod; if (module != null)
{
if (module->initialized != 0)
{
// notify library about detaching from process
uint DllEntry = (uint)((uint)module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint);
// notify library about attaching to process
DllEntryPointFunc func = (DllEntryPointFunc)Marshal.GetDelegateForFunctionPointer(new IntPtr(DllEntry), typeof(DllEntryPointFunc));
uint successfull = func((uint)module->codeBase, DLL_PROCESS_ATTACH, 0);
module->initialized = 0;
} if (module->modules != null)
{
// free previously opened libraries
for (i = 0; i < module->numModules; i++)
if (module->modules[i] != 0)
FreeLibrary(module->modules[i]); Marshal.FreeHGlobal(new IntPtr(module->modules));
} if ((int)module->codeBase != 0)
// release memory of library
VirtualFree((uint)module->codeBase, 0, MEM_RELEASE); Marshal.FreeHGlobal(new IntPtr(module));
}
}
}
Link to comment

Okay well, there is a problem.

Dlls using "MSVCR80.dll" give an error messagebox when LoadLibrary is called on "MSVCR80.dll".

Why is this?

Does MSVCR80.dll need to be loaded specially?

Link to comment
Okay well, there is a problem.

Dlls using "MSVCR80.dll" give an error messagebox when LoadLibrary is called on "MSVCR80.dll".

Why is this?

Does MSVCR80.dll need to be loaded specially?

about LoadLibrary:

"...If the function fails, the return value is NULL. To get extended error information, call GetLastError..."

u could add that in c# like this:

if (Marshal.GetLastWin32Error() != 0) MessageBox.Show((new Win32Exception()).Message);

then look up the error msg.. prolly couldn't find that dll ?

EDIT/

You also need to add "SetLastError=true" :

[DllImport("kernel32.dll", EntryPoint = "LoadLibraryA", SetLastError=true)]

private static extern uint LoadLibrary(byte* lpLibFileName);

Edited by Ufo-Pu55y
Link to comment
Okay well, there is a problem.

Dlls using "MSVCR80.dll" give an error messagebox when LoadLibrary is called on "MSVCR80.dll".

Why is this?

Does MSVCR80.dll need to be loaded specially?

about LoadLibrary:

"...If the function fails, the return value is NULL. To get extended error information, call GetLastError..."

u could add that in c# like this:

if (Marshal.GetLastWin32Error() != 0) MessageBox.Show((new Win32Exception()).Message);

then look up the error msg.. prolly couldn't find that dll ?

EDIT/

You also need to add "SetLastError=true" :

[DllImport("kernel32.dll", EntryPoint = "LoadLibraryA", SetLastError=true)]

private static extern uint LoadLibrary(byte* lpLibFileName);

Well the dll messageboxes when loaded.

I think msvcr80.dll needs to be loaded specially.

Link to comment

just a quick question, is DllMain executed here?

Cause I tried a similar but much shorter solution but I was unable to

execute DllMain and I had some things that was needed to execute there.

Nice coding btw :ph34r:

Edited by atlantisx
Link to comment

Well the c++ code I ported from does

// get entry point of loaded library

if (result->headers->OptionalHeader.AddressOfEntryPoint != 0)

{

uint DllEntry = ((uint)code + result->headers->OptionalHeader.AddressOfEntryPoint);

if (DllEntry == 0)

{

goto error;

}

// notify library about attaching to process

DllEntryPointFunc func = (DllEntryPointFunc)Marshal.GetDelegateForFunctionPointer(new IntPtr(DllEntry), typeof(DllEntryPointFunc));

uint successfull = func(code, DLL_PROCESS_ATTACH, 0);

if (successfull == 0)

{

goto error;

}

result->initialized = 1;

}

Link to comment
  • 1 month later...
Okay well, there is a problem.

Dlls using "MSVCR80.dll" give an error messagebox when LoadLibrary is called on "MSVCR80.dll".

Why is this?

Does MSVCR80.dll need to be loaded specially?

Yes, it's due to manifest stuff.

Link to comment
  • 3 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...