// Token: 0x06000121 RID: 289 RVA: 0x0000DB90 File Offset: 0x0000BD90 private static void PatchRelocations(PortableExecutable image, IntPtr pAlloc) { IMAGE_DATA_DIRECTORY image_DATA_DIRECTORY = image.NTHeader.OptionalHeader.DataDirectory[5]; if (image_DATA_DIRECTORY.Size > 0u) { uint num = 0u; uint num2 = (uint)((long)pAlloc.ToInt32() - (long)((ulong)image.NTHeader.OptionalHeader.ImageBase)); uint num3 = image.GetPtrFromRVA(image_DATA_DIRECTORY.VirtualAddress); uint num4 = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_BASE_RELOCATION image_BASE_RELOCATION; while (num < image_DATA_DIRECTORY.Size && image.Read <IMAGE_BASE_RELOCATION>((long)((ulong)num3), SeekOrigin.Begin, out image_BASE_RELOCATION)) { int num5 = (int)((image_BASE_RELOCATION.SizeOfBlock - num4) / 2u); uint ptrFromRVA = image.GetPtrFromRVA(image_BASE_RELOCATION.VirtualAddress); for (int i = 0; i < num5; i++) { ushort num6; if (image.Read <ushort>((long)((ulong)(num3 + num4) + (ulong)((long)((long)i << 1))), SeekOrigin.Begin, out num6) && (num6 >> 12 & 3) != 0) { uint num7 = (uint)((ulong)ptrFromRVA + (ulong)((long)(num6 & 4095))); uint num8; if (!image.Read <uint>((long)((ulong)num7), SeekOrigin.Begin, out num8)) { throw image.GetLastError(); } image.Write <uint>(-4L, SeekOrigin.Current, num8 + num2); } } num += image_BASE_RELOCATION.SizeOfBlock; num3 += image_BASE_RELOCATION.SizeOfBlock; } } }
private static void PatchRelocations(PortableExecutable image, IntPtr pAlloc) { // Base relocations are essentially Microsofts ingenious way of preserving portability in images. // for all absolute address calls/jmps/references...etc, an entry is made into the base relocation // table telling the loader exactly where an "absolute" address is being used. This allows the loader // to iterate through the relocations and patch these absolute values to ensure they are correct when // the image is loaded somewhere that isn't its preferred base address. IMAGE_DATA_DIRECTORY relocDir = image.NTHeader.OptionalHeader.DataDirectory[(int)DATA_DIRECTORIES.BaseRelocTable]; if (relocDir.Size > 0) //check if there are in fact any relocations. { uint n = 0; uint delta = (uint)(pAlloc.ToInt32() - image.NTHeader.OptionalHeader.ImageBase); //The difference in loaded/preferred addresses. uint pReloc = image.GetPtrFromRVA(relocDir.VirtualAddress); uint szReloc = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_BASE_RELOCATION reloc; while (n < relocDir.Size && image.Read(pReloc, SeekOrigin.Begin, out reloc)) { // A relocation block consists of an IMAGE_BASE_RELOCATION, and an array of WORDs. // To calculate the number of relocations (represented by WORDs), just do some simple math. int nrelocs = (int)((reloc.SizeOfBlock - szReloc) / sizeof(ushort)); uint pageVa = image.GetPtrFromRVA(reloc.VirtualAddress); //The Page RVA for this set of relocations (usually a 4K boundary). ushort vreloc; uint old; for (int i = 0; i < nrelocs; i++) { // There are only 2 types of relocations on Intel machines: ABSOLUTE (padding, nothing needs to be done) and HIGHLOW (0x03) // Highlow means that all 32 bits of the "delta" value need to be added to the relocation value. if (image.Read(pReloc + szReloc + (i << 1), SeekOrigin.Begin, out vreloc) && (vreloc >> 12 & 3) != 0) { uint vp = (uint)(pageVa + (vreloc & 0x0FFF)); if (image.Read <uint>(vp, SeekOrigin.Begin, out old)) { image.Write <uint>(-4, SeekOrigin.Current, (uint)(old + delta)); } else { throw image.GetLastError(); //unlikely, but I hate crashing targets because something in the PE was messed up. } } } n += reloc.SizeOfBlock; pReloc += reloc.SizeOfBlock; } } }
private static void MapSections(PortableExecutable image, IntPtr hProcess, IntPtr pModule) { //very straightforward really. Just iterate through all the sections and map them to their desired virtual addresses in the remote process. //I'm not 100% sure about how well masking the section header characteristics and passing them off as memory protection constants goes. But //so far I haven't hit any issues. (i.e a section header with characteristics "IMAGE_SCN_TYPE_NO_PAD" will set "PAGE_WRITECOPY" memory protection. byte[] databuffer; uint n; foreach (var pSecHd in image.EnumSectionHeaders()) { databuffer = new byte[pSecHd.SizeOfRawData]; if (image.Read(pSecHd.PointerToRawData, SeekOrigin.Begin, databuffer)) { if ((pSecHd.Characteristics & 0x02000000) == 0) //can actually ignore this section (usually the reloc section) { WinAPI.WriteProcessMemory(hProcess, pModule.Add(pSecHd.VirtualAddress), databuffer, databuffer.Length, out n); WinAPI.VirtualProtectEx(hProcess, pModule.Add(pSecHd.VirtualAddress), pSecHd.SizeOfRawData, pSecHd.Characteristics & 0x00FFFFFF, out n); } } else { throw image.GetLastError(); } } }
private static void PatchImports(PortableExecutable image, IntPtr hProcess, int processId) { string empty = string.Empty; string empty2 = string.Empty; foreach (IMAGE_IMPORT_DESCRIPTOR current in image.EnumImports()) { if (image.ReadString((long)((ulong)image.GetPtrFromRVA(current.Name)), SeekOrigin.Begin, out empty, -1, null)) { IntPtr intPtr = IntPtr.Zero; IntPtr arg_4F_0 = IntPtr.Zero; intPtr = ManualMap.GetRemoteModuleHandle(empty, processId); if (intPtr.IsNull()) { throw new FileNotFoundException(string.Format("Unable to load dependent module '{0}'.", empty)); } uint num = image.GetPtrFromRVA(current.FirstThunkPtr); uint num2 = (uint)Marshal.SizeOf(typeof(IMAGE_THUNK_DATA)); IMAGE_THUNK_DATA iMAGE_THUNK_DATA; while (image.Read <IMAGE_THUNK_DATA>((long)((ulong)num), SeekOrigin.Begin, out iMAGE_THUNK_DATA) && iMAGE_THUNK_DATA.u1.AddressOfData > 0u) { IntPtr intPtr2 = IntPtr.Zero; object obj; if ((iMAGE_THUNK_DATA.u1.Ordinal & 2147483648u) == 0u) { if (!image.ReadString((long)((ulong)(image.GetPtrFromRVA(iMAGE_THUNK_DATA.u1.AddressOfData) + 2u)), SeekOrigin.Begin, out empty2, -1, null)) { throw image.GetLastError(); } obj = empty2; } else { obj = (ushort)(iMAGE_THUNK_DATA.u1.Ordinal & 65535u); } if (!(intPtr2 = WinAPI.GetModuleHandleA(empty)).IsNull()) { IntPtr ptr = obj.GetType().Equals(typeof(string)) ? WinAPI.GetProcAddress(intPtr2, (string)obj) : WinAPI.GetProcAddress(intPtr2, (uint)((ushort)obj & 65535)); if (!ptr.IsNull()) { intPtr2 = intPtr.Add((long)ptr.Subtract((long)intPtr2.ToInt32()).ToInt32()); } } else { intPtr2 = WinAPI.GetProcAddressEx(hProcess, intPtr, obj); } if (intPtr2.IsNull()) { throw new EntryPointNotFoundException(string.Format("Unable to locate imported function '{0}' from module '{1}' in the remote process.", empty2, empty)); } image.Write <int>((long)((ulong)num), SeekOrigin.Begin, intPtr2.ToInt32()); num += num2; } } } }
// Token: 0x06000120 RID: 288 RVA: 0x0000DAC8 File Offset: 0x0000BCC8 private static void MapSections(PortableExecutable image, IntPtr hProcess, IntPtr pModule) { foreach (IMAGE_SECTION_HEADER image_SECTION_HEADER in image.EnumSectionHeaders()) { byte[] array = new byte[image_SECTION_HEADER.SizeOfRawData]; if (!image.Read((long)((ulong)image_SECTION_HEADER.PointerToRawData), SeekOrigin.Begin, array)) { throw image.GetLastError(); } if ((image_SECTION_HEADER.Characteristics & 33554432u) == 0u) { uint num; WinAPI.WriteProcessMemory(hProcess, pModule.Add((long)((ulong)image_SECTION_HEADER.VirtualAddress)), array, array.Length, out num); WinAPI.VirtualProtectEx(hProcess, pModule.Add((long)((ulong)image_SECTION_HEADER.VirtualAddress)), image_SECTION_HEADER.SizeOfRawData, image_SECTION_HEADER.Characteristics & 16777215u, out num); } } }
private static void PatchImports(PortableExecutable image, IntPtr hProcess, int processId) { string module = string.Empty; string fname = string.Empty; foreach (var desc in image.EnumImports()) { if (image.ReadString(image.GetPtrFromRVA(desc.Name), SeekOrigin.Begin, out module)) { IntPtr pModule = IntPtr.Zero; IntPtr tModule = IntPtr.Zero; //Thanks to FastLoadDependencies, all dependent modules *should* be loaded into the remote process already. pModule = GetRemoteModuleHandle(module, processId); if (pModule.IsNull()) { throw new FileNotFoundException(string.Format("Unable to load dependent module '{0}'.", module)); } //now have a supposedly valid module handle remote process, all that remains to be done is patch the info. uint pThunk = image.GetPtrFromRVA(desc.FirstThunkPtr); //despite the fact FirstThunk and OriginalFirstThunk are identical within an unmapped PE, only FirstThunk is looked up after mapping. uint szThunk = (uint)Marshal.SizeOf(typeof(IMAGE_THUNK_DATA)); IMAGE_THUNK_DATA thunk; while (image.Read(pThunk, SeekOrigin.Begin, out thunk) && thunk.u1.AddressOfData > 0) //final thunk is signified by a null-filled IMAGE_THUNK_DATA structure. { IntPtr remote = IntPtr.Zero; object procVal = null; if ((thunk.u1.Ordinal & 0x80000000) == 0) //import by name { if (image.ReadString(image.GetPtrFromRVA(thunk.u1.AddressOfData) + 2, SeekOrigin.Begin, out fname)) //get the function name. { procVal = fname; } else { throw image.GetLastError(); //error occurred during memory iteration, this is only a safeguard and shouldn't really ever occur, but the universe loves proving me wrong. } } else //import by ordinal. { procVal = (ushort)(thunk.u1.Ordinal & 0xFFFF); } // the following section of code simply aims to reduce overhead. A check is first performed to see if the current module // is loaded in the current process first, if so it simply uses relative addresses to calculate the function address in the remote // process. If the module isn't found in our process, a call to GetProcAddressEx is used to find the remote address. Of course, you // could simply guarantee the first case by calling LoadLibrary internally, but I find that can have unwanted side effects. if (!(remote = WinAPI.GetModuleHandleA(module)).IsNull()) { IntPtr local = procVal.GetType().Equals(typeof(string)) ? WinAPI.GetProcAddress(remote, (string)procVal) : WinAPI.GetProcAddress(remote, (uint)((ushort)procVal) & 0x0000FFFF); if (!local.IsNull()) { remote = pModule.Add(local.Subtract(remote.ToInt32()).ToInt32()); } } else { remote = WinAPI.GetProcAddressEx(hProcess, pModule, procVal); } if (remote.IsNull()) //alas, couldn't find the function. { throw new EntryPointNotFoundException(string.Format("Unable to locate imported function '{0}' from module '{1}' in the remote process.", fname, module)); } image.Write <int>(pThunk, SeekOrigin.Begin, remote.ToInt32()); //overwrite the thunk and continue on our merry way. pThunk += szThunk; } } } }
// Most efficient version, this will be the work horse. private static IntPtr MapModule(PortableExecutable image, IntPtr hProcess, bool preserveHeaders = false) { if (hProcess.IsNull() || hProcess.Compare(-1)) { throw new ArgumentException("Invalid process handle.", "hProcess"); } if (image == null) { throw new ArgumentException("Cannot map a non-existant PE Image.", "image"); } int processId = WinAPI.GetProcessId(hProcess); if (processId == 0) { throw new ArgumentException("Provided handle doesn't have sufficient permissions to inject", "hProcess"); } IntPtr hModule = IntPtr.Zero; IntPtr pStub = IntPtr.Zero; uint nBytes = 0; try { //allocate memory for the image to load into the remote process. hModule = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, image.NTHeader.OptionalHeader.SizeOfImage, 0x1000 | 0x2000, 0x04); if (hModule.IsNull()) { throw new InvalidOperationException("Unable to allocate memory in the remote process."); } PatchRelocations(image, hModule); LoadDependencies(image, hProcess, processId); PatchImports(image, hProcess, processId); if (preserveHeaders) { long szHeader = (image.DOSHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + sizeof(uint) + image.NTHeader.FileHeader.SizeOfOptionalHeader); byte[] header = new byte[szHeader]; if (image.Read(0, SeekOrigin.Begin, header)) { WinAPI.WriteProcessMemory(hProcess, hModule, header, header.Length, out nBytes); } } MapSections(image, hProcess, hModule); // some modules don't have an entry point and are purely libraries, mapping them and keeping the handle is just fine // an unlikely scenario with forced injection, but you never know. if (image.NTHeader.OptionalHeader.AddressOfEntryPoint > 0) { var stub = (byte[])DLLMAIN_STUB.Clone(); BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B); pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40); if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length)) { throw new InvalidOperationException("Unable to write stub to the remote process."); } IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)(hModule.Add(image.NTHeader.OptionalHeader.AddressOfEntryPoint).ToInt32()), 0, 0); if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L) { WinAPI.GetExitCodeThread(hStubThread, out nBytes); if (nBytes == 0) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); throw new Exception("Entry method of module reported a failure " + Marshal.GetLastWin32Error().ToString()); } WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000); WinAPI.CloseHandle(hStubThread); } } } catch (Exception e) { if (!hModule.IsNull()) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } if (!pStub.IsNull()) { WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000); } hModule = IntPtr.Zero; throw e; } return(hModule); }
// Token: 0x0600011E RID: 286 RVA: 0x0000D708 File Offset: 0x0000B908 private static IntPtr MapModule(PortableExecutable image, IntPtr hProcess, bool preserveHeaders = false) { if (!hProcess.IsNull() && !hProcess.Compare(-1L)) { if (image == null) { throw new ArgumentException("Cannot map a non-existant PE Image.", "image"); } int processId = WinAPI.GetProcessId(hProcess); if (processId == 0) { throw new ArgumentException("Provided handle doesn't have sufficient permissions to inject", "hProcess"); } IntPtr intPtr = IntPtr.Zero; IntPtr intPtr2 = IntPtr.Zero; uint num = 0u; try { intPtr = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, image.NTHeader.OptionalHeader.SizeOfImage, 12288, 4); if (intPtr.IsNull()) { throw new InvalidOperationException("Unable to allocate memory in the remote process."); } ManualMap.PatchRelocations(image, intPtr); ManualMap.LoadDependencies(image, hProcess, processId); ManualMap.PatchImports(image, hProcess, processId); if (preserveHeaders) { long num2 = (long)((ulong)image.DOSHeader.e_lfanew + (ulong)((long)Marshal.SizeOf(typeof(IMAGE_FILE_HEADER))) + 4UL + (ulong)image.NTHeader.FileHeader.SizeOfOptionalHeader); byte[] array = new byte[num2]; if (image.Read(0L, SeekOrigin.Begin, array)) { WinAPI.WriteProcessMemory(hProcess, intPtr, array, array.Length, out num); } } ManualMap.MapSections(image, hProcess, intPtr); if (image.NTHeader.OptionalHeader.AddressOfEntryPoint > 0u) { byte[] array2 = (byte[])ManualMap.DLLMAIN_STUB.Clone(); BitConverter.GetBytes(intPtr.ToInt32()).CopyTo(array2, 11); intPtr2 = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)ManualMap.DLLMAIN_STUB.Length, 12288, 64); if (!intPtr2.IsNull() && WinAPI.WriteProcessMemory(hProcess, intPtr2, array2, array2.Length, out num)) { if (num == (uint)array2.Length) { IntPtr intPtr3 = WinAPI.CreateRemoteThread(hProcess, 0, 0, intPtr2, (uint)intPtr.Add((long)((ulong)image.NTHeader.OptionalHeader.AddressOfEntryPoint)).ToInt32(), 0, 0); if ((ulong)WinAPI.WaitForSingleObject(intPtr3, 5000) != 0UL) { goto IL_23D; } WinAPI.GetExitCodeThread(intPtr3, out num); if (num == 0u) { WinAPI.VirtualFreeEx(hProcess, intPtr, 0, 32768); throw new Exception("Entry method of module reported a failure " + Marshal.GetLastWin32Error().ToString()); } WinAPI.VirtualFreeEx(hProcess, intPtr2, 0, 32768); WinAPI.CloseHandle(intPtr3); goto IL_23D; } } throw new InvalidOperationException("Unable to write stub to the remote process."); } IL_23D: return(intPtr); } catch (Exception ex) { if (!intPtr.IsNull()) { WinAPI.VirtualFreeEx(hProcess, intPtr, 0, 32768); } if (!intPtr2.IsNull()) { WinAPI.VirtualFreeEx(hProcess, intPtr, 0, 32768); } intPtr = IntPtr.Zero; throw ex; } } throw new ArgumentException("Invalid process handle.", "hProcess"); }