Guest User

manualmapper

a guest
Aug 29th, 2017
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 34.04 KB | None | 0 0
  1. /*
  2.     ManualMap.cs
  3.     Copyright (C) 2012 Jason Larke
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     In addition to the above disclaimers, I am also not responsible for how
  16.     you decide to use software resulting from this library.
  17.  
  18.     For a full specification of the GNU GPL license, see <http://www.gnu.org/copyleft/gpl.html>
  19.  
  20.     This license notice should be left in tact in all future works
  21. */
  22.  
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Text;
  26. using JLibrary.PortableExecutable;
  27. using JLibrary.Win32;
  28. using JLibrary.Tools;
  29. using System.Runtime.InteropServices;
  30. using System.Diagnostics;
  31. using System.IO;
  32.  
  33. namespace InjectionLibrary
  34. {
  35.     internal class ManualMap : InjectionMethod
  36.     {
  37.         #region Path Injection Implementations
  38.         public override IntPtr Inject(string dllPath, IntPtr hProcess)
  39.         {
  40.             ClearErrors();
  41.             try
  42.             {
  43.                 using (PortableExecutable img = new PortableExecutable(dllPath))
  44.                     return Inject(img, hProcess);
  45.             }
  46.             catch (Exception e)
  47.             {
  48.                 SetLastError(e);
  49.                 return IntPtr.Zero;
  50.             }
  51.         }
  52.  
  53.         public override IntPtr[] InjectAll(string[] dllPaths, IntPtr hProcess)
  54.         {
  55.             ClearErrors();
  56.             return Array.ConvertAll(dllPaths, dp => Inject(dp, hProcess));
  57.         }
  58.         #endregion
  59.  
  60.         public override IntPtr Inject(PortableExecutable image, IntPtr hProcess)
  61.         {
  62.             ClearErrors();
  63.             try
  64.             {
  65.                 return MapModule(Utils.DeepClone(image), hProcess, true);
  66.             }
  67.             catch (Exception e)
  68.             {
  69.                 SetLastError(e);
  70.                 return IntPtr.Zero;
  71.             }
  72.         }
  73.  
  74.         public override IntPtr[] InjectAll(PortableExecutable[] images, IntPtr hProcess)
  75.         {
  76.             ClearErrors();
  77.             return Array.ConvertAll(images, pe => Inject(pe, hProcess));
  78.         }
  79.  
  80.         public override bool Unload(IntPtr hModule, IntPtr hProcess)
  81.         {
  82.             // Unloading a manually mapped file is fairly straightforward. There is no need to call FreeLibrary or anything
  83.             // because the file was never actually injected using LoadLibrary and doesn't need to clear any PEB entries etc.
  84.             // basically just call the Entry Point again with DLL_PROCESS_DETACH flag and not-null for the lpReserved parameter
  85.             // and then VirtualFree the remote memory.
  86.             ClearErrors();
  87.  
  88.             if (hModule.IsNull())
  89.                 throw new ArgumentNullException("hModule", "Invalid module handle");
  90.  
  91.             if (hProcess.IsNull() || hProcess.Compare(-1))
  92.                 throw new ArgumentException("Invalid process handle.", "hProcess");
  93.  
  94.             IntPtr pStub = IntPtr.Zero;
  95.             uint nBytes = 0;
  96.             try
  97.             {
  98.                 uint entry = FindEntryPoint(hProcess, hModule);
  99.                 if (entry != 0)
  100.                 {
  101.                     var stub = (byte[])DLLMAIN_STUB.Clone();
  102.                     BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B);
  103.                     BitConverter.GetBytes((uint)0).CopyTo(stub, 0x06);
  104.                     BitConverter.GetBytes((uint)1000).CopyTo(stub, 0x01);
  105.  
  106.                     pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40);
  107.                     if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length))
  108.                         throw new InvalidOperationException("Unable to write stub to the remote process.");
  109.  
  110.                     IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)hModule.Add(entry).ToInt32(), 0, 0);
  111.                     if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L)
  112.                     {
  113.                         WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000);
  114.                         WinAPI.CloseHandle(hStubThread);
  115.                         return WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000);
  116.                     }
  117.                     return false;
  118.                 }
  119.                 else
  120.                 {
  121.                     return WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000);
  122.                 }
  123.             }
  124.             catch (Exception e)
  125.             {
  126.                 SetLastError(e);
  127.                 return false;
  128.             }
  129.         }
  130.  
  131.         public override bool[] UnloadAll(IntPtr[] hModules, IntPtr hProcess)
  132.         {
  133.             // No fancy optimized method here, UnloadAll simply represents a series of direct calls to Unload for each
  134.             // module. Pretty simple stuff.
  135.             ClearErrors();
  136.             if (hModules == null)
  137.                 throw new ArgumentNullException("hModules", "Parameter cannot be null.");
  138.             if (hProcess.IsNull() || hProcess.Compare(-1))
  139.                 throw new ArgumentOutOfRangeException("hProcess", "Invalid process handle specified.");
  140.             try
  141.             {
  142.                 var results = new bool[hModules.Length];
  143.                 for (int i = 0; i < hModules.Length; i++)
  144.                     results[i] = Unload(hModules[i], hProcess);
  145.                 return results;
  146.             }
  147.             catch (Exception e)
  148.             {
  149.                 SetLastError(e);
  150.                 return null;
  151.             }
  152.         }
  153.  
  154.         #region Codebase
  155.         // Most efficient version, this will be the work horse.
  156.         private static IntPtr MapModule(PortableExecutable image, IntPtr hProcess, bool preserveHeaders = false)
  157.         {
  158.             if (hProcess.IsNull() || hProcess.Compare(-1))
  159.                 throw new ArgumentException("Invalid process handle.", "hProcess");
  160.  
  161.             if (image == null)
  162.                 throw new ArgumentException("Cannot map a non-existant PE Image.", "image");
  163.  
  164.             int processId = WinAPI.GetProcessId(hProcess);
  165.  
  166.             if (processId == 0)
  167.                 throw new ArgumentException("Provided handle doesn't have sufficient permissions to inject", "hProcess");
  168.  
  169.             IntPtr hModule = IntPtr.Zero;
  170.             IntPtr pStub = IntPtr.Zero;
  171.             uint nBytes = 0;
  172.  
  173.             try
  174.             {
  175.                 //allocate memory for the image to load into the remote process.
  176.                 hModule = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, image.NTHeader.OptionalHeader.SizeOfImage, 0x1000 | 0x2000, 0x04);  
  177.                 if (hModule.IsNull())
  178.                     throw new InvalidOperationException("Unable to allocate memory in the remote process.");
  179.  
  180.                 PatchRelocations(image, hModule);
  181.                 LoadDependencies(image, hProcess, processId);
  182.                 PatchImports(image, hProcess, processId);
  183.  
  184.                 if (preserveHeaders)
  185.                 {
  186.                     long szHeader = (image.DOSHeader.e_lfanew + Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)) + sizeof(uint) + image.NTHeader.FileHeader.SizeOfOptionalHeader);
  187.                     byte[] header = new byte[szHeader];
  188.                     if (image.Read(0, SeekOrigin.Begin, header))
  189.                         WinAPI.WriteProcessMemory(hProcess, hModule, header, header.Length, out nBytes);
  190.                 }
  191.  
  192.                 MapSections(image, hProcess, hModule);
  193.  
  194.                 // some modules don't have an entry point and are purely libraries, mapping them and keeping the handle is just fine
  195.                 // an unlikely scenario with forced injection, but you never know.
  196.                 if (image.NTHeader.OptionalHeader.AddressOfEntryPoint > 0)
  197.                 {
  198.                     var stub = (byte[])DLLMAIN_STUB.Clone();
  199.                     BitConverter.GetBytes(hModule.ToInt32()).CopyTo(stub, 0x0B);
  200.  
  201.                     pStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)DLLMAIN_STUB.Length, 0x1000 | 0x2000, 0x40);
  202.                     if (pStub.IsNull() || (!WinAPI.WriteProcessMemory(hProcess, pStub, stub, stub.Length, out nBytes) || nBytes != (uint)stub.Length))
  203.                         throw new InvalidOperationException("Unable to write stub to the remote process.");
  204.  
  205.                     IntPtr hStubThread = WinAPI.CreateRemoteThread(hProcess, 0, 0, pStub, (uint)(hModule.Add(image.NTHeader.OptionalHeader.AddressOfEntryPoint).ToInt32()), 0, 0);
  206.                     if (WinAPI.WaitForSingleObject(hStubThread, 5000) == 0x0L)
  207.                     {
  208.                         WinAPI.GetExitCodeThread(hStubThread, out nBytes);
  209.                         if (nBytes == 0)
  210.                         {
  211.                             WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000);
  212.                             throw new Exception("Entry method of module reported a failure " + Marshal.GetLastWin32Error().ToString());
  213.                         }
  214.                         WinAPI.VirtualFreeEx(hProcess, pStub, 0, 0x8000);
  215.                         WinAPI.CloseHandle(hStubThread);
  216.                     }
  217.                 }
  218.             }
  219.             catch (Exception e)
  220.             {
  221.                 if (!hModule.IsNull())
  222.                     WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000);
  223.                 if (!pStub.IsNull())
  224.                     WinAPI.VirtualFreeEx(hProcess, hModule, 0, 0x8000);
  225.  
  226.                 hModule = IntPtr.Zero;
  227.                 throw e;
  228.             }
  229.             return hModule;
  230.         }
  231.  
  232.         /**
  233.          * Find the entry point of a loaded module
  234.          * based on its Base Address. Reverses the PE
  235.          * structure to find the entry point
  236.          */
  237.         private static uint FindEntryPoint(IntPtr hProcess, IntPtr hModule)
  238.         {
  239.             if (hProcess.IsNull() || hProcess.Compare(-1))
  240.                 throw new ArgumentException("Invalid process handle.", "hProcess");
  241.             if (hModule.IsNull())
  242.                 throw new ArgumentException("Invalid module handle.", "hModule");
  243.  
  244.             byte[] bDosHeader = WinAPI.ReadRemoteMemory(hProcess, hModule, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)));
  245.             if (bDosHeader != null)
  246.             {
  247.                 ushort e_magic = BitConverter.ToUInt16(bDosHeader, 0);
  248.                 uint e_lfanew = BitConverter.ToUInt32(bDosHeader, 0x3C);
  249.                 if (e_magic == 23117)
  250.                 {
  251.                     byte[] bNtHeader = WinAPI.ReadRemoteMemory(hProcess, hModule.Add(e_lfanew), (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADER32)));
  252.                     if (bNtHeader != null && BitConverter.ToUInt32(bNtHeader, 0) == 17744)
  253.                     {
  254.                         IMAGE_NT_HEADER32 ntHd = default(IMAGE_NT_HEADER32);
  255.                         using (var buffer = new UnmanagedBuffer(256))
  256.                             if (buffer.Translate<IMAGE_NT_HEADER32>(bNtHeader, out ntHd))
  257.                                 return ntHd.OptionalHeader.AddressOfEntryPoint;
  258.                     }
  259.                 }
  260.             }
  261.             return 0;
  262.         }
  263.  
  264.         private static void MapSections(PortableExecutable image, IntPtr hProcess, IntPtr pModule)
  265.         {
  266.             //very straightforward really. Just iterate through all the sections and map them to their desired virtual addresses in the remote process.
  267.             //I'm not 100% sure about how well masking the section header characteristics and passing them off as memory protection constants goes. But
  268.             //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.
  269.             byte[] databuffer;
  270.             uint n;
  271.  
  272.             foreach (var pSecHd in image.EnumSectionHeaders())
  273.             {
  274.                 databuffer = new byte[pSecHd.SizeOfRawData];
  275.                 if (image.Read(pSecHd.PointerToRawData, SeekOrigin.Begin, databuffer))
  276.                 {
  277.                     if ((pSecHd.Characteristics & 0x02000000) == 0) //can actually ignore this section (usually the reloc section)
  278.                     {
  279.                         WinAPI.WriteProcessMemory(hProcess, pModule.Add(pSecHd.VirtualAddress), databuffer, databuffer.Length, out n);
  280.                         WinAPI.VirtualProtectEx(hProcess, pModule.Add(pSecHd.VirtualAddress), pSecHd.SizeOfRawData, pSecHd.Characteristics & 0x00FFFFFF, out n);
  281.                     }
  282.                 }
  283.                 else
  284.                 {
  285.                     throw image.GetLastError();
  286.                 }
  287.             }
  288.         }
  289.  
  290.         private static void PatchRelocations(PortableExecutable image, IntPtr pAlloc)
  291.         {
  292.             // Base relocations are essentially Microsofts ingenious way of preserving portability in images.
  293.             // for all absolute address calls/jmps/references...etc, an entry is made into the base relocation
  294.             // table telling the loader exactly where an "absolute" address is being used. This allows the loader
  295.             // to iterate through the relocations and patch these absolute values to ensure they are correct when
  296.             // the image is loaded somewhere that isn't its preferred base address.
  297.             IMAGE_DATA_DIRECTORY relocDir = image.NTHeader.OptionalHeader.DataDirectory[(int)DATA_DIRECTORIES.BaseRelocTable];
  298.             if (relocDir.Size > 0) //check if there are in fact any relocations.
  299.             {
  300.                 uint n = 0;
  301.                 uint delta = (uint)(pAlloc.ToInt32() - image.NTHeader.OptionalHeader.ImageBase); //The difference in loaded/preferred addresses.
  302.                 uint pReloc = image.GetPtrFromRVA(relocDir.VirtualAddress);
  303.                 uint szReloc = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION));
  304.                 IMAGE_BASE_RELOCATION reloc;
  305.  
  306.                 while (n < relocDir.Size && image.Read(pReloc, SeekOrigin.Begin, out reloc))
  307.                 {
  308.                     // A relocation block consists of an IMAGE_BASE_RELOCATION, and an array of WORDs.
  309.                     // To calculate the number of relocations (represented by WORDs), just do some simple math.
  310.                     int nrelocs = (int)((reloc.SizeOfBlock - szReloc) / sizeof(ushort));
  311.                     uint pageVa = image.GetPtrFromRVA(reloc.VirtualAddress); //The Page RVA for this set of relocations (usually a 4K boundary).
  312.                     ushort vreloc;
  313.                     uint old;
  314.  
  315.                     for (int i = 0; i < nrelocs; i++)
  316.                     {
  317.                         // There are only 2 types of relocations on Intel machines: ABSOLUTE (padding, nothing needs to be done) and HIGHLOW (0x03)
  318.                         // Highlow means that all 32 bits of the "delta" value need to be added to the relocation value.
  319.                         if (image.Read(pReloc + szReloc + (i << 1), SeekOrigin.Begin, out vreloc) && (vreloc >> 12 & 3) != 0)
  320.                         {
  321.                             uint vp = (uint)(pageVa + (vreloc & 0x0FFF));
  322.                             if (image.Read<uint>(vp, SeekOrigin.Begin, out old))
  323.                                 image.Write<uint>(-4, SeekOrigin.Current, (uint)(old + delta));
  324.                             else
  325.                                 throw image.GetLastError(); //unlikely, but I hate crashing targets because something in the PE was messed up.
  326.                         }
  327.                     }
  328.                     n += reloc.SizeOfBlock;
  329.                     pReloc += reloc.SizeOfBlock;
  330.                 }
  331.             }
  332.         }
  333.  
  334.         private static void PatchImports(PortableExecutable image, IntPtr hProcess, int processId)
  335.         {
  336.             string module = string.Empty;
  337.             string fname = string.Empty;
  338.  
  339.             foreach (var desc in image.EnumImports())
  340.             {
  341.                 if (image.ReadString(image.GetPtrFromRVA(desc.Name), SeekOrigin.Begin, out module))
  342.                 {
  343.                     IntPtr pModule = IntPtr.Zero;
  344.                     IntPtr tModule = IntPtr.Zero;
  345.                     //Thanks to FastLoadDependencies, all dependent modules *should* be loaded into the remote process already.
  346.                     pModule = GetRemoteModuleHandle(module, processId);
  347.  
  348.                     if (pModule.IsNull())
  349.                         throw new FileNotFoundException(string.Format("Unable to load dependent module '{0}'.", module));
  350.  
  351.                     //now have a supposedly valid module handle remote process, all that remains to be done is patch the info.
  352.                     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.
  353.                     uint szThunk = (uint)Marshal.SizeOf(typeof(IMAGE_THUNK_DATA));
  354.                     IMAGE_THUNK_DATA thunk;
  355.  
  356.                     while (image.Read(pThunk, SeekOrigin.Begin, out thunk) && thunk.u1.AddressOfData > 0) //final thunk is signified by a null-filled IMAGE_THUNK_DATA structure.
  357.                     {
  358.                         IntPtr remote = IntPtr.Zero;
  359.                         object procVal = null;
  360.                         if ((thunk.u1.Ordinal & 0x80000000) == 0) //import by name
  361.                         {
  362.                             if (image.ReadString(image.GetPtrFromRVA(thunk.u1.AddressOfData) + 2, SeekOrigin.Begin, out fname)) //get the function name.
  363.                                 procVal = fname;
  364.                             else
  365.                                 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.
  366.                         }
  367.                         else //import by ordinal.
  368.                         {
  369.                             procVal = (ushort)(thunk.u1.Ordinal & 0xFFFF);
  370.                         }
  371.  
  372.                         // the following section of code simply aims to reduce overhead. A check is first performed to see if the current module
  373.                         // is loaded in the current process first, if so it simply uses relative addresses to calculate the function address in the remote
  374.                         // process. If the module isn't found in our process, a call to GetProcAddressEx is used to find the remote address. Of course, you
  375.                         // could simply guarantee the first case by calling LoadLibrary internally, but I find that can have unwanted side effects.
  376.                         if (!(remote = WinAPI.GetModuleHandleA(module)).IsNull())
  377.                         {
  378.                             IntPtr local = procVal.GetType().Equals(typeof(string))
  379.                                             ? WinAPI.GetProcAddress(remote, (string)procVal)
  380.                                             : WinAPI.GetProcAddress(remote, (uint)((ushort)procVal) & 0x0000FFFF);
  381.                             if (!local.IsNull())
  382.                                 remote = pModule.Add(local.Subtract(remote.ToInt32()).ToInt32());
  383.                         }
  384.                         else
  385.                         {
  386.                             remote = WinAPI.GetProcAddressEx(hProcess, pModule, procVal);
  387.                         }
  388.                        
  389.                         if (remote.IsNull()) //alas, couldn't find the function.
  390.                             throw new EntryPointNotFoundException(string.Format("Unable to locate imported function '{0}' from module '{1}' in the remote process.", fname, module));
  391.  
  392.                         image.Write<int>(pThunk, SeekOrigin.Begin, remote.ToInt32()); //overwrite the thunk and continue on our merry way.
  393.                         pThunk += szThunk;
  394.                     }
  395.                 }
  396.             }
  397.         }
  398.  
  399.         /*
  400.          * Handles loading of all dependent modules. Iterates the IAT entries and attempts to load (using LoadLibrary) all
  401.          * of the necessary modules for the main module to function. The manifest is extracted and activation contexts used to
  402.          * ensure correct loading of Side-By-Side dependencies.
  403.          */
  404.         private static bool LoadDependencies(PortableExecutable image, IntPtr hProcess, int processId)
  405.         {
  406.             List<string> neededDependencies = new List<string>();
  407.             string curdep = string.Empty;
  408.             bool success = false;
  409.  
  410.             foreach (var desc in image.EnumImports())
  411.             {
  412.                 if (image.ReadString(image.GetPtrFromRVA(desc.Name), SeekOrigin.Begin, out curdep) && !string.IsNullOrEmpty(curdep))
  413.                 {
  414.                     if (GetRemoteModuleHandle(curdep, processId).IsNull())
  415.                         neededDependencies.Add(curdep);
  416.                 }
  417.             }
  418.  
  419.             if (neededDependencies.Count > 0) //do we actually need to load any new modules?
  420.             {
  421.                 byte[] bManifest = ExtractManifest(image);
  422.                 string pathManifest = string.Empty;
  423.  
  424.                 if (bManifest == null) // no internal manifest, may be an external manifest or none at all?
  425.                 {
  426.                     if (!string.IsNullOrEmpty(image.FileLocation) && File.Exists(Path.Combine(Path.GetDirectoryName(image.FileLocation), Path.GetFileName(image.FileLocation) + ".manifest")))
  427.                     {
  428.                         pathManifest = Path.Combine(Path.GetDirectoryName(image.FileLocation), Path.GetFileName(image.FileLocation) + ".manifest");
  429.                     }
  430.                     else // no internal or external manifest, presume no side-by-side dependencies.
  431.                     {
  432.                         var standard = InjectionMethod.Create(InjectionMethodType.Standard);
  433.                         var results = standard.InjectAll(neededDependencies.ToArray(), hProcess);
  434.  
  435.                         foreach (var result in results)
  436.                             if (result.IsNull())
  437.                                 return false; // failed to inject a dependecy, abort mission.
  438.  
  439.                         return true; // done loading dependencies.
  440.                     }
  441.                 }
  442.                 else
  443.                 {
  444.                     pathManifest = Utils.WriteTempData(bManifest);
  445.                 }
  446.  
  447.                 if (string.IsNullOrEmpty(pathManifest))
  448.                     return false;
  449.  
  450.                 IntPtr pResolverStub = WinAPI.VirtualAllocEx(hProcess, IntPtr.Zero, (uint)RESOLVER_STUB.Length, 0x1000 | 0x2000, 0x40);
  451.                 IntPtr pManifest = WinAPI.CreateRemotePointer(hProcess, Encoding.ASCII.GetBytes(pathManifest + "\0"), 0x04);
  452.                 IntPtr pModules = WinAPI.CreateRemotePointer(hProcess, Encoding.ASCII.GetBytes(string.Join("\0", neededDependencies.ToArray()) + "\0"), 0x04);
  453.  
  454.                 if (!pResolverStub.IsNull())
  455.                 {
  456.                     var resolverStub = (byte[])RESOLVER_STUB.Clone();
  457.                     uint nBytes = 0;
  458.  
  459.                     // Call patching. Patch the empty function addresses with the runtime addresses.
  460.                     BitConverter.GetBytes(FN_CREATEACTCTXA.Subtract(pResolverStub.Add(0x3F)).ToInt32()).CopyTo(resolverStub, 0x3B);
  461.                     BitConverter.GetBytes(FN_ACTIVATEACTCTX.Subtract(pResolverStub.Add(0x58)).ToInt32()).CopyTo(resolverStub, 0x54);
  462.                     BitConverter.GetBytes(FN_GETMODULEHANDLEA.Subtract(pResolverStub.Add(0x84)).ToInt32()).CopyTo(resolverStub, 0x80);
  463.                     BitConverter.GetBytes(FN_LOADLIBRARYA.Subtract(pResolverStub.Add(0x92)).ToInt32()).CopyTo(resolverStub, 0x8E);
  464.                     BitConverter.GetBytes(FN_DEACTIVATEACTCTX.Subtract(pResolverStub.Add(0xC8)).ToInt32()).CopyTo(resolverStub, 0xC4);
  465.                     BitConverter.GetBytes(FN_RELEASEACTCTX.Subtract(pResolverStub.Add(0xD1)).ToInt32()).CopyTo(resolverStub, 0xCD);
  466.  
  467.                     // Parameter patching
  468.                     BitConverter.GetBytes(pManifest.ToInt32()).CopyTo(resolverStub, 0x1F);
  469.                     BitConverter.GetBytes(neededDependencies.Count).CopyTo(resolverStub, 0x28);
  470.                     BitConverter.GetBytes(pModules.ToInt32()).CopyTo(resolverStub, 0x31);
  471.  
  472.                     if (WinAPI.WriteProcessMemory(hProcess, pResolverStub, resolverStub, resolverStub.Length, out nBytes) && nBytes == (uint)resolverStub.Length)
  473.                     {
  474.                         uint result = WinAPI.RunThread(hProcess, pResolverStub, 0, 5000);
  475.                         success = (result != uint.MaxValue && result != 0);
  476.                     }
  477.  
  478.                     // Cleanup
  479.                     WinAPI.VirtualFreeEx(hProcess, pModules, 0, 0x8000);
  480.                     WinAPI.VirtualFreeEx(hProcess, pManifest, 0, 0x8000);
  481.                     WinAPI.VirtualFreeEx(hProcess, pResolverStub, 0, 0x8000);
  482.                 }
  483.             }
  484.  
  485.             return success;
  486.         }
  487.  
  488.         /**
  489.          * Extract an application manifest from
  490.          * an executable file's resources.
  491.          * Returns null if no manifest was found in the executable.
  492.          */
  493.         private static byte[] ExtractManifest(PortableExecutable image)
  494.         {
  495.             byte[] manifest = null;
  496.             ResourceWalker walker = new ResourceWalker(image);
  497.             ResourceWalker.ResourceDirectory manifestDir = null;
  498.             for (int i = 0; i < walker.Root.Directories.Length && manifestDir == null; i++)
  499.                 if (walker.Root.Directories[i].Id == Constants.RT_MANIFEST)
  500.                     manifestDir = walker.Root.Directories[i];
  501.  
  502.             if (manifestDir != null && manifestDir.Directories.Length > 0)
  503.                 if (IsManifestResource(manifestDir.Directories[0].Id) && manifestDir.Directories[0].Files.Length == 1)
  504.                     manifest = manifestDir.Directories[0].Files[0].GetData();
  505.  
  506.             return manifest;
  507.         }
  508.  
  509.         private static bool IsManifestResource(int id)
  510.         {
  511.             switch ((uint)id)
  512.             {
  513.                 case Constants.CREATEPROCESS_MANIFEST_RESOURCE_ID:
  514.                 case Constants.ISOLATIONAWARE_MANIFEST_RESOURCE_ID:
  515.                 case Constants.ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID:
  516.                     return true;
  517.                 default:
  518.                     return false;
  519.             }
  520.         }
  521.  
  522.         private static IntPtr GetRemoteModuleHandle(string module, int processId)
  523.         {
  524.             IntPtr hModule = IntPtr.Zero;
  525.             Process target = Process.GetProcessById(processId);
  526.             for (int i = 0; i < target.Modules.Count && hModule.IsNull(); i++)
  527.                 if (target.Modules[i].ModuleName.ToLower() == module.ToLower())
  528.                     hModule = target.Modules[i].BaseAddress;
  529.             return hModule;
  530.         }
  531.         #endregion
  532.  
  533.         #region Gigantic Assembly Bytecode, do not open for fear of losing eyesight.
  534.         /* patch values */
  535.         private static readonly IntPtr H_KERNEL32 = WinAPI.GetModuleHandleA("KERNEL32.dll");
  536.         private static readonly IntPtr FN_CREATEACTCTXA = WinAPI.GetProcAddress(H_KERNEL32, "CreateActCtxA");
  537.         private static readonly IntPtr FN_ACTIVATEACTCTX = WinAPI.GetProcAddress(H_KERNEL32, "ActivateActCtx");
  538.         private static readonly IntPtr FN_LOADLIBRARYA = WinAPI.GetProcAddress(H_KERNEL32, "LoadLibraryA");
  539.         private static readonly IntPtr FN_GETMODULEHANDLEA = WinAPI.GetProcAddress(H_KERNEL32, "GetModuleHandleA");
  540.         private static readonly IntPtr FN_DEACTIVATEACTCTX = WinAPI.GetProcAddress(H_KERNEL32, "DeactivateActCtx");
  541.         private static readonly IntPtr FN_RELEASEACTCTX = WinAPI.GetProcAddress(H_KERNEL32, "ReleaseActCtx");
  542.  
  543.         // DllMain function call stub.
  544.         private static readonly byte[] DLLMAIN_STUB =
  545.         {
  546.             0x68, 0x00, 0x00, 0x00, 0x00, //push lpReserved
  547.             0x68, 0x01, 0x00, 0x00, 0x00, //push dwReason
  548.             0x68, 0x00, 0x00, 0x00, 0x00, //push hModule
  549.             0xFF, 0x54, 0x24, 0x10, //call [esp + 10h]
  550.             0xC3//2, 0x0C, 0x00
  551.         };
  552.  
  553.         // Resolve a list of dlls.
  554.         private static readonly byte[] RESOLVER_STUB =
  555.         {
  556.             0x55,                              //push ebp
  557.             0x8B, 0xEC,                        //mov ebp, esp
  558.             0x83, 0xEC, 0x3C,                  //sub esp, 3Ch
  559.             0x8B, 0xCC,                        //mov ecx, esp
  560.             0x8B, 0xD1,                        //mov edx, ecx
  561.             0x83, 0xC2, 0x3C,                  //add edx, 3Ch
  562.             0xC7, 0x01, 0x00, 0x00, 0x00, 0x00,//mov [ecx], 0 <--- memset
  563.             0x83, 0xC1, 0x04,                  //add ecx, 4h            ^
  564.             0x3B, 0xCA,                        //cmp ecx, edx           |
  565.             0x7E, 0xF3,                        //jle memset   -----------
  566.             0xC6, 0x04, 0x24, 0x20,            //mov [esp], 20h
  567.             0xB9, 0x00, 0x00, 0x00, 0x00,      //mov ecx, 0x00000000 //manifest char*
  568.             0x89, 0x4C, 0x24, 0x08,            //mov [esp + 8], ecx
  569.             0xB9, 0x00, 0x00, 0x00, 0x00,      //mov ecx, 0x00000000 //nFiles
  570.             0x89, 0x4C, 0x24, 0x28,            //mov [esp + 28h], ecx
  571.             0xB9, 0x00, 0x00, 0x00, 0x00,      //mov ecx, 0x00000000 //files char*
  572.             0x89, 0x4C, 0x24, 0x2C,            //mov [esp + 2Ch], ecx
  573.             0x54,                              //push esp
  574.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call CreateActCtxA
  575.             0x83, 0x38, 0xFF,                  //cmp eax, -1
  576.             0x0F, 0x84, 0x89, 0x00, 0x00, 0x00,//je finish -----------------------------------v
  577.             0x89, 0x44, 0x24, 0x30,            //mov [esp + 30h], eax                         |
  578.             0x8B, 0xCC,                        //mov ecx, esp                                 |
  579.             0x83, 0xC1, 0x20,                  //add ecx, 20h                                 |
  580.             0x51,                              //push ecx                                     |
  581.             0x50,                              //push eax                                     |
  582.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call ActivateActCtxA                         |
  583.             0x83, 0xF8, 0x00,                  //cmp eax, 0                                   |
  584.             0x74, 0x6B,                        //je cleanupfinish -------------------------v  |
  585.             0xC6, 0x44, 0x24, 0x24, 0x01,      //mov [esp + 24h], 1                        |  |
  586.             0x8B, 0x4C, 0x24, 0x28,            //mov ecx, [esp + 28h] <--- loadloop <+     |  |
  587.             0x83, 0xF9, 0x00,                  //cmp ecx, 0                          |     |  |
  588.             0x7E, 0x3E,                        //jle endloop ------------------------|--v  |  |
  589.             0x83, 0xE9, 0x01,                  //sub ecx, 1                          |  |  |  |
  590.             0x89, 0x4C, 0x24, 0x28,            //mov [esp + 28h], ecx                |  |  |  |
  591.             0x8B, 0x4C, 0x24, 0x24,            //mov ecx, [esp + 24h]                |  |  |  |
  592.             0x83, 0xF9, 0x00,                  //cmp ecx, 0                          |  |  |  |
  593.             0x74, 0x2E,                        //je endloop -------------------------|--v  |  |
  594.             0xFF, 0x74, 0x24, 0x2C,            //push [esp + 2Ch]                    |  |  |  |
  595.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call GetModuleHandleA               |  |  |  |
  596.             0x83, 0xF8, 0x00,                  //cmp eax, 0                          |  |  |  |
  597.             0x75, 0x09,                        //jnz initnext -------------------+   |  |  |  |
  598.             0xFF, 0x74, 0x24, 0x2C,            //push [esp + 2Ch]                |   |  |  |  |
  599.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call LoadLibraryA               v   |  |  |  |
  600.             0x89, 0x44, 0x24, 0x24,            //mov [esp + 24h], eax <--- initnext  |  |  |  |
  601.             0x8B, 0x4C, 0x24, 0x2C,            //mov ecx, [esp + 2Ch]                |  |  |  |
  602.             0x8A, 0x01,                        //mov al, [ecx] <--- findnull         |  |  |  |
  603.             0x83, 0xC1, 0x01,                  //add ecx, 1                 ^        |  |  |  |
  604.             0x3C, 0x00,                        //cmp al, 0                  |        |  |  |  |
  605.             0x75, 0xF7,                        //jnz findnull --------------+        |  |  |  |
  606.             0x89, 0x4C, 0x24, 0x2C,            //mov [esp + 2Ch], ecx                |  |  |  |
  607.             0xEB, 0xB9,                        //jmp loadloop -----------------------+  |  |  |
  608.             0x8B, 0x44, 0x24, 0x24,            //mov eax, [esp + 24h]   <---endloop-----+  |  |
  609.             0xB9, 0x01, 0x00, 0x00, 0x00,      //mov ecx, 1                                |  |
  610.             0x23, 0xC1,                        //and eax, ecx                              |  |
  611.             0x89, 0x4C, 0x24, 0x24,            //mov [esp + 24h], ecx                      |  |
  612.             0x83, 0xF9, 0x00,                  //cmp ecx, 0                                |  |
  613.             0x75, 0x14,                        //jne finish -------------------------------|--v
  614.             0xFF, 0x74, 0x24, 0x20,            //push [esp + 20h]                          |  |
  615.             0x6A, 0x00,                        //push 0                                    |  |
  616.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call DeactivateActCtx                     |  |
  617.             0xFF, 0x74, 0x24, 0x30,            //push [esp + 30h] <--- cleanupfinish ------+  |
  618.             0xE8, 0x00, 0x00, 0x00, 0x00,      //call ReleaseActCtx                           |
  619.             0x8B, 0x44, 0x24, 0x24,            //mov eax, [esp + 24h] <--- finish <-----------+
  620.             0x8B, 0xE5,                        //mov esp, ebp
  621.             0x5D,                              //pop ebp
  622.             0xC3                               //ret
  623.         };
  624.         #endregion
  625.     }
  626. }
Add Comment
Please, Sign In to add comment