/// <summary> /// Gets the total amount of modules within an assembly. /// </summary> public int GetModuleCount() { int count = 0; IntPtr codeBase = module.codeBase; IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[1]; if (directory.Size > 0) { var importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress); while (importDesc.Name > 0) { var str = codeBase + (int)importDesc.Name; string tmp = Marshal.PtrToStringAnsi(str); int handle = Win32Imports.LoadLibrary(tmp); if (handle == -1) { break; } count++; importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, (uint)(directory.VirtualAddress + (Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * (count)))); } } return(count); }
/// <summary> /// Obtains the memory address of an assembly. /// </summary> /// <param name="name">The name of the assembly to find the address of.</param> public uint GetProcAddress(string name) { unsafe { IntPtr codeBase = module.codeBase; int idx = -1; uint i; IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return(0); } var exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); var nameRef = (uint *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); var ordinal = (ushort *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); for (i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { var str = codeBase + (int)(*nameRef); string tmp = Marshal.PtrToStringAnsi(str); if (tmp == name) { idx = *ordinal; break; } } var tmpaa = (uint *)(codeBase.ToInt32() + (exports.AddressOfFunctions + (idx * 4))); var addr = (uint)((codeBase.ToInt32()) + (*tmpaa)); return(addr); } }
public void CopySections(Byte[] data, IMAGE_NT_HEADERS oldHeaders, IntPtr headers, IMAGE_DOS_HEADER dosHeader) { Int32 i; IntPtr codebase = _module.codeBase; IMAGE_SECTION_HEADER section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (UInt32)(24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader)); for (i = 0; i < _module.headers.FileHeader.NumberOfSections; i++) { IntPtr dest; if (section.SizeOfRawData == 0) { UInt32 size = oldHeaders.OptionalHeader.SectionAlignment; if (size > 0) { dest = new IntPtr((Win32Imports.VirtualAlloc((UInt32)(codebase.ToInt32() + (Int32)section.VirtualAddress), size, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE))); section.PhysicalAddress = (UInt32)dest; IntPtr write = new IntPtr(headers.ToInt32() + (32 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i))); Marshal.WriteInt32(write, (Int32)dest); Byte[] datazz = new Byte[size + 1]; Marshal.Copy(datazz, 0, dest, (Int32)size); } section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (UInt32)((24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i + 1)))); continue; } dest = new IntPtr((Win32Imports.VirtualAlloc((UInt32)(codebase.ToInt32() + (Int32)section.VirtualAddress), section.SizeOfRawData, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE))); Marshal.Copy(data, (Int32)section.PointerToRawData, dest, (Int32)section.SizeOfRawData); section.PhysicalAddress = (UInt32)dest; IntPtr write2 = new IntPtr(headers.ToInt32() + (32 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i))); Marshal.WriteInt32(write2, (Int32)dest); section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (UInt32)((24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i + 1)))); } }
public String[] GetProcedures() { unsafe { IntPtr codeBase = this._module.codeBase; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return new String[] { } } ; IMAGE_EXPORT_DIRECTORY exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); UInt32 *nameRef = (UInt32 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); UInt16 *ordinal = (UInt16 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); String[] result = new String[exports.NumberOfNames]; for (UInt32 i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { IntPtr str = new IntPtr(codeBase.ToInt32() + (Int32)(*nameRef)); result[i] = Marshal.PtrToStringAnsi(str); } return(result); } }
public Int32 GetModuleCount() { Int32 count = 0; IntPtr codeBase = this._module.codeBase; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[1]; if (directory.Size > 0) { IMAGE_IMPORT_DESCRIPTOR importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress); while (importDesc.Name > 0) { Int32 str = codeBase.ToInt32() + (Int32)importDesc.Name; String tmp = Marshal.PtrToStringAnsi(new IntPtr(str)); Int32 handle = Win32Imports.LoadLibrary(tmp); if (handle == -1) { break; } count++; importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, (UInt32)(directory.VirtualAddress + (Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * (count)))); } } return(count); }
internal unsafe Boolean LoadLibrary(Byte[] data) { //fnDllEntry dllEntry; IMAGE_DOS_HEADER dosHeader = PointerHelpers.ToStruct <IMAGE_DOS_HEADER>(data); IMAGE_NT_HEADERS oldHeader = PointerHelpers.ToStruct <IMAGE_NT_HEADERS>(data, (UInt32)dosHeader.e_lfanew); IntPtr code = (IntPtr)(Win32Imports.VirtualAlloc(oldHeader.OptionalHeader.ImageBase, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_RESERVE, Win32Constants.PAGE_READWRITE)); if (code == IntPtr.Zero) { code = (IntPtr)(Win32Imports.VirtualAlloc((UInt32)code, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_RESERVE, Win32Constants.PAGE_READWRITE)); } _module = new MEMORYMODULE { codeBase = code, numModules = 0, modules = new IntPtr(0), initialized = 0 }; Win32Imports.VirtualAlloc((UInt32)code, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE); IntPtr headers = (IntPtr)(Win32Imports.VirtualAlloc((UInt32)code, oldHeader.OptionalHeader.SizeOfHeaders, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE)); Marshal.Copy(data, 0, headers, (Int32)(dosHeader.e_lfanew + oldHeader.OptionalHeader.SizeOfHeaders)); _module.headers = PointerHelpers.ToStruct <IMAGE_NT_HEADERS>(headers, (UInt32)dosHeader.e_lfanew); _module.headers.OptionalHeader.ImageBase = (UInt32)code; this.CopySections(data, oldHeader, headers, dosHeader); UInt32 locationDelta = (UInt32)(code.ToInt32() - oldHeader.OptionalHeader.ImageBase); if (locationDelta != 0) { this.PerformBaseRelocation(locationDelta); } this.BuildImportTable(); this.FinalizeSections(headers, dosHeader, oldHeader); Boolean success = false; try { fnDllEntry dllEntry = (fnDllEntry)Marshal.GetDelegateForFunctionPointer( new IntPtr(_module.codeBase.ToInt32() + (Int32)_module.headers.OptionalHeader.AddressOfEntryPoint), typeof(fnDllEntry)); success = dllEntry(code.ToInt32(), 1, (void *)0); } catch (Exception exc) { System.Diagnostics.Trace.WriteLine(exc.Message); return(false); } return(success); }
/// <summary> /// Loads a native assembly into memory from bytes. /// </summary> /// <param name="data">The assembly data to inject.</param> public unsafe bool LoadAssembly(byte[] data) { var dosHeader = PointerHelpers.ToStruct <IMAGE_DOS_HEADER>(data); var oldHeader = PointerHelpers.ToStruct <IMAGE_NT_HEADERS>(data, (uint)dosHeader.e_lfanew); var code = (IntPtr)(Win32Imports.VirtualAlloc(oldHeader.OptionalHeader.ImageBase, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_RESERVE, Win32Constants.PAGE_READWRITE)); if (code.ToInt32() == 0) { code = (IntPtr)(Win32Imports.VirtualAlloc((uint)code, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_RESERVE, Win32Constants.PAGE_READWRITE)); } module = new MEMORYMODULE { codeBase = code, numModules = 0, modules = new IntPtr(0), initialized = 0 }; Win32Imports.VirtualAlloc((uint)code, oldHeader.OptionalHeader.SizeOfImage, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE); var headers = (IntPtr)(Win32Imports.VirtualAlloc((uint)code, oldHeader.OptionalHeader.SizeOfHeaders, Win32Constants.MEM_COMMIT, Win32Constants.PAGE_READWRITE)); Marshal.Copy(data, 0, headers, (int)(dosHeader.e_lfanew + oldHeader.OptionalHeader.SizeOfHeaders)); module.headers = PointerHelpers.ToStruct <IMAGE_NT_HEADERS>(headers, (uint)dosHeader.e_lfanew); module.headers.OptionalHeader.ImageBase = (uint)code; CopySections(data, oldHeader, headers, dosHeader); var locationDelta = (uint)(code - (int)oldHeader.OptionalHeader.ImageBase); if (locationDelta != 0) { PerformBaseRelocation(locationDelta); } BuildImportTable(); FinalizeSections(headers, dosHeader, oldHeader); bool success = false; try { fnDllEntry dllEntry = (fnDllEntry) Marshal.GetDelegateForFunctionPointer( new IntPtr(module.codeBase.ToInt32() + (int)module.headers.OptionalHeader.AddressOfEntryPoint), typeof(fnDllEntry)); success = dllEntry(code.ToInt32(), 1, (void *)0); } catch (Exception ex) { throw ex; } return(success); }
public void PerformBaseRelocation(uint delta) { IntPtr codeBase = module.codeBase; int sizeOfBase = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[5]; int cnt = 0; if (directory.Size > 0) { var relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, directory.VirtualAddress); while (relocation.VirtualAddress > 0) { unsafe { var dest = (IntPtr)(codeBase.ToInt32() + (int)relocation.VirtualAddress); var relInfo = (ushort *)(codeBase.ToInt32() + (int)directory.VirtualAddress + sizeOfBase); uint i; for (i = 0; i < ((relocation.SizeOfBlock - Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION))) / 2); i++, relInfo++) { int type = *relInfo >> 12; int offset = (*relInfo & 0xfff); switch (type) { case 0x00: break; case 0x03: var patchAddrHl = (uint *)((dest) + (offset)); * patchAddrHl += delta; break; } } } cnt += (int)relocation.SizeOfBlock; relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, (uint)(directory.VirtualAddress + cnt)); } } }
public void PerformBaseRelocation(UInt32 delta) { IntPtr codeBase = _module.codeBase; Int32 sizeOfBase = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY directory = _module.headers.OptionalHeader.DataDirectory[5]; Int32 cnt = 0; if (directory.Size > 0) { IMAGE_BASE_RELOCATION relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, directory.VirtualAddress); while (relocation.VirtualAddress > 0) { unsafe { IntPtr dest = (IntPtr)(codeBase.ToInt32() + (int)relocation.VirtualAddress); UInt16 *relInfo = (UInt16 *)(codeBase.ToInt32() + (int)directory.VirtualAddress + sizeOfBase); UInt16 i; for (i = 0; i < ((relocation.SizeOfBlock - Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION))) / 2); i++, relInfo++) { Int32 type = *relInfo >> 12; Int32 offset = (*relInfo & 0xfff); switch (type) { case 0x00: break; case 0x03: UInt32 *patchAddrHl = (UInt32 *)((dest.ToInt32()) + (offset)); * patchAddrHl += delta; break; } } } cnt += (Int32)relocation.SizeOfBlock; relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, (UInt32)(directory.VirtualAddress + cnt)); } } }
public UInt32?GetProcAddress(String name) { unsafe { IntPtr codeBase = this._module.codeBase; Int32? idx = null; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return(null); } IMAGE_EXPORT_DIRECTORY exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); UInt32 *nameRef = (UInt32 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); UInt16 *ordinal = (UInt16 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); for (UInt32 i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { IntPtr str = new IntPtr(codeBase.ToInt32() + (Int32)(*nameRef)); String tmp = Marshal.PtrToStringAnsi(str); if (tmp == name) { idx = *ordinal; break; } } if (idx.HasValue) { UInt32 *tmpaa = (UInt32 *)(codeBase.ToInt32() + (exports.AddressOfFunctions + (idx.Value * 4))); UInt32 addr = (UInt32)((codeBase.ToInt32()) + (*tmpaa)); return(addr); } else { return(null); } } }
/// <summary> /// Allocates memory pages and sets header permissions. /// </summary> /// <param name="headers">The headers to write to each section of the PE.</param> /// <param name="dosHeader">The current header of the PE.</param> /// <param name="oldHeaders">The old headers of the PE that have been overwritten.</param> public void FinalizeSections(IntPtr headers, IMAGE_DOS_HEADER dosHeader, IMAGE_NT_HEADERS oldHeaders) { ProtectionFlags[0] = new int[2][]; ProtectionFlags[1] = new int[2][]; ProtectionFlags[0][0] = new int[2]; ProtectionFlags[0][1] = new int[2]; ProtectionFlags[1][0] = new int[2]; ProtectionFlags[1][1] = new int[2]; ProtectionFlags[0][0][0] = 0x01; ProtectionFlags[0][0][1] = 0x08; ProtectionFlags[0][1][0] = 0x02; ProtectionFlags[0][1][1] = 0x04; ProtectionFlags[1][0][0] = 0x10; ProtectionFlags[1][0][1] = 0x80; ProtectionFlags[1][1][0] = 0x20; ProtectionFlags[1][1][1] = 0x40; var section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (uint)(24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader)); for (int i = 0; i < module.headers.FileHeader.NumberOfSections; i++) { int executable = (section.Characteristics & 0x20000000) != 0 ? 1 : 0; int readable = (section.Characteristics & 0x40000000) != 0 ? 1 : 0; int writeable = (section.Characteristics & 0x80000000) != 0 ? 1 : 0; if ((section.Characteristics & 0x02000000) > 0) { bool aa = Win32Imports.VirtualFree(new IntPtr(section.PhysicalAddress), (UIntPtr)section.SizeOfRawData, 0x4000); continue; } var protect = (uint)ProtectionFlags[executable][readable][writeable]; if ((section.Characteristics & 0x04000000) > 0) { protect |= 0x200; } var size = (int)section.SizeOfRawData; if (size == 0) { if ((section.Characteristics & 0x00000040) > 0) { size = (int)module.headers.OptionalHeader.SizeOfInitializedData; } else if ((section.Characteristics & 0x00000080) > 0) { size = (int)module.headers.OptionalHeader.SizeOfUninitializedData; } } if (size > 0) { uint oldProtect; if (!Win32Imports.VirtualProtect(new IntPtr(section.PhysicalAddress), section.SizeOfRawData, protect, out oldProtect)) { } } section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (uint)((24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i + 1)))); } }
/// <summary> /// Rebuilds the PE import table after address relocations. /// </summary> public int BuildImportTable() { int ucount = GetModuleCount(); module.modules = Marshal.AllocHGlobal((ucount) * sizeof(int)); int pcount = 0; int result = 1; IntPtr codeBase = module.codeBase; IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[1]; if (directory.Size > 0) { var importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress); while (importDesc.Name > 0) { var str = codeBase + (int)importDesc.Name; string tmp = Marshal.PtrToStringAnsi(str); unsafe { uint *thunkRef; uint *funcRef; int handle = Win32Imports.LoadLibrary(tmp); if (handle == -1) { result = 0; break; } if (importDesc.CharacteristicsOrOriginalFirstThunk > 0) { IntPtr thunkRefAddr = codeBase + (int)importDesc.CharacteristicsOrOriginalFirstThunk; thunkRef = (uint *)thunkRefAddr; funcRef = (uint *)(codeBase + (int)importDesc.FirstThunk); } else { thunkRef = (uint *)(codeBase + (int)importDesc.FirstThunk); funcRef = (uint *)(codeBase + (int)importDesc.FirstThunk); } for (; *thunkRef > 0; thunkRef++, funcRef++) { if ((*thunkRef & 0x80000000) != 0) { *funcRef = (uint)Win32Imports.GetProcAddress(new IntPtr(handle), new IntPtr(*thunkRef & 0xffff)); } else { var str2 = codeBase + (int)(*thunkRef) + 2; var tmpaa = Marshal.PtrToStringAnsi(str2); * funcRef = Win32Imports.GetProcAddress(new IntPtr(handle), tmpaa); } if (*funcRef == 0) { result = 0; break; } } pcount++; importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress + (uint)(Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * pcount)); } } } return(result); }
public void FinalizeSections(IntPtr headers, IMAGE_DOS_HEADER dosHeader, IMAGE_NT_HEADERS oldHeaders) { ProtectionFlags[0] = new Int32[2][]; ProtectionFlags[1] = new Int32[2][]; ProtectionFlags[0][0] = new Int32[2]; ProtectionFlags[0][1] = new Int32[2]; ProtectionFlags[1][0] = new Int32[2]; ProtectionFlags[1][1] = new Int32[2]; ProtectionFlags[0][0][0] = 0x01; ProtectionFlags[0][0][1] = 0x08; ProtectionFlags[0][1][0] = 0x02; ProtectionFlags[0][1][1] = 0x04; ProtectionFlags[1][0][0] = 0x10; ProtectionFlags[1][0][1] = 0x80; ProtectionFlags[1][1][0] = 0x20; ProtectionFlags[1][1][1] = 0x40; IMAGE_SECTION_HEADER section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (UInt32)(24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader)); for (Int32 i = 0; i < _module.headers.FileHeader.NumberOfSections; i++) { //Console.WriteLine("Finalizing " + Encoding.UTF8.GetString(section.Name)); Int32 executable = (section.Characteristics & 0x20000000) != 0 ? 1 : 0; Int32 readable = (section.Characteristics & 0x40000000) != 0 ? 1 : 0; Int32 writeable = (section.Characteristics & 0x80000000) != 0 ? 1 : 0; if ((section.Characteristics & 0x02000000) > 0) { Boolean aa = Win32Imports.VirtualFree(new IntPtr(section.PhysicalAddress), (UIntPtr)section.SizeOfRawData, 0x4000); continue; } UInt32 protect = (UInt32)ProtectionFlags[executable][readable][writeable]; if ((section.Characteristics & 0x04000000) > 0) { protect |= 0x200; } Int32 size = (Int32)section.SizeOfRawData; if (size == 0) { if ((section.Characteristics & 0x00000040) > 0) { size = (Int32)_module.headers.OptionalHeader.SizeOfInitializedData; } else if ((section.Characteristics & 0x00000080) > 0) { size = (Int32)_module.headers.OptionalHeader.SizeOfUninitializedData; } } if (size > 0) { UInt32 oldProtect; if (!Win32Imports.VirtualProtect(new IntPtr(section.PhysicalAddress), section.SizeOfRawData, protect, out oldProtect)) { } } section = PointerHelpers.ToStruct <IMAGE_SECTION_HEADER>(headers, (UInt32)((24 + dosHeader.e_lfanew + oldHeaders.FileHeader.SizeOfOptionalHeader) + (Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)) * (i + 1)))); } }