Guest User

Untitled

a guest
Nov 15th, 2015
446
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 22.72 KB | None | 0 0
  1.  
  2.  
  3. Injector.cs
  4.  
  5.     using System;
  6.     using System.Collections.Generic;
  7.     using System.Linq;
  8.     using System.Text;
  9.     using System.Diagnostics;
  10.     using System.ComponentModel;
  11.     using System.Runtime.InteropServices;
  12.     using System.IO;
  13.      
  14.     using Syringe.Win32;
  15.      
  16.      
  17.     namespace Syringe
  18.     {
  19.         public class Injector : IDisposable
  20.         {
  21.             /// <summary>
  22.             /// Internal class to represent an Injected Module within Injector's target process.
  23.             /// Simply manages finding export addresses for functions, and caches these addresses for
  24.             /// potential future use.
  25.             /// </summary>
  26.             private class InjectedModule
  27.             {
  28.                 private Dictionary<string, IntPtr> exports;
  29.      
  30.                 public ProcessModule Module { get; private set; }
  31.                 public IntPtr BaseAddress { get { return Module.BaseAddress; } }
  32.      
  33.                 public InjectedModule(ProcessModule module)
  34.                 {
  35.                     Module = module;
  36.                     exports = new Dictionary<string, IntPtr>();
  37.                 }
  38.      
  39.                 /// <summary>
  40.                 /// Get the address of a given function exported in the Module.
  41.                 /// If the function can't be found, this will throw <see cref="Win32Exception"/>
  42.                 /// </summary>
  43.                 /// <param name="func">Name of function to search for</param>
  44.                 /// <returns><see cref="IntPtr"/> representing the address of this function in the target process</returns>
  45.                 /// <exception cref="Win32Exception">Thrown if unable to find function address in module</exception>
  46.                 public IntPtr this[string func]
  47.                 {
  48.                     get
  49.                     {
  50.                         if (!exports.ContainsKey(func))
  51.                             exports[func] = FindExport(func);
  52.                         return exports[func];
  53.                     }
  54.                 }
  55.      
  56.                 /**
  57.                  * Actual function to find export - loosely modelled off Cypher's idea/code for loading module into this
  58.                  * process to find address. Loads module as data, finds RVA of function and uses to find address in target
  59.                  * process
  60.                  */
  61.                 private IntPtr FindExport(string func)
  62.                 {
  63.                     IntPtr hModule = IntPtr.Zero;
  64.                     try
  65.                     {
  66.                         // Load module into local process address space
  67.                         hModule = Imports.LoadLibraryEx(Module.FileName, IntPtr.Zero, LoadLibraryExFlags.DontResolveDllReferences);
  68.                         if (hModule == IntPtr.Zero)
  69.                             throw new Win32Exception(Marshal.GetLastWin32Error());
  70.      
  71.                         // Call GetProcAddress to get the address of the function in the module locally
  72.                         IntPtr pFunc = Imports.GetProcAddress(hModule, func);
  73.                         if (pFunc == IntPtr.Zero)
  74.                             throw new Win32Exception(Marshal.GetLastWin32Error());
  75.      
  76.                         // Get RVA of export and add to base address of injected module
  77.                         // hack at the moment to deal with x64
  78.                         bool x64 = IntPtr.Size == 8;
  79.                         IntPtr pExportAddr;
  80.                         if (x64)
  81.                             pExportAddr = new IntPtr(Module.BaseAddress.ToInt64() + (pFunc.ToInt64() - hModule.ToInt64()));
  82.                         else
  83.                             pExportAddr = new IntPtr(Module.BaseAddress.ToInt32() + (pFunc.ToInt32() - hModule.ToInt32()));
  84.      
  85.                         return pExportAddr;
  86.                     }
  87.                     finally
  88.                     {
  89.                         try
  90.                         {
  91.                             Imports.CloseHandle(hModule);
  92.                         }
  93.                         catch
  94.                         {
  95.                         }
  96.                     }
  97.                 }
  98.             }
  99.      
  100.             private Process _process;
  101.             private IntPtr _handle;
  102.             private Dictionary<string, InjectedModule> injectedModules;
  103.      
  104.             public Injector(Process process) : this(process, true) { }
  105.             public Injector(Process process, bool ejectOnDispose)
  106.             {
  107.                 if (process == null)
  108.                     throw new ArgumentNullException("process");
  109.                 if (process.Id == Process.GetCurrentProcess().Id)
  110.                     throw new InvalidOperationException("Cannot create an injector for the current process");
  111.      
  112.                 Process.EnterDebugMode();
  113.      
  114.                 _handle = Imports.OpenProcess(
  115.                     ProcessAccessFlags.QueryInformation | ProcessAccessFlags.CreateThread |
  116.                     ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMWrite |
  117.                     ProcessAccessFlags.VMRead, false, process.Id);
  118.      
  119.                 if (_handle == IntPtr.Zero)
  120.                     throw new Win32Exception(Marshal.GetLastWin32Error());
  121.      
  122.                 _process = process;
  123.                 EjectOnDispose = ejectOnDispose;
  124.                 injectedModules = new Dictionary<string, InjectedModule>();
  125.             }
  126.      
  127.             public bool EjectOnDispose { get; set; }
  128.      
  129.             /// <summary>
  130.             /// Injects a library into this Injector's process. <paramref name="libPath"/> can be
  131.             /// relative or absolute; either way, the injected module will be referred to by module name only.
  132.             /// I.e. "c:\some\directory\library.dll", "library.dll" and "..\library.dll" will all be referred to
  133.             /// as "library.dll"
  134.             /// </summary>
  135.             /// <param name="libPath">Relative or absolute path to the dll to be injected</param>
  136.             public void InjectLibrary(string libPath)
  137.             {
  138.                 // (in?)sanity check, pretty sure this is never possible as the constructor will error - left over from how it previously was developed
  139.                 if (_process == null)
  140.                     throw new InvalidOperationException("This injector has no associated process and thus cannot inject a library");
  141.                 if (_handle == IntPtr.Zero)
  142.                     throw new InvalidOperationException("This injector does not have a valid handle to the associated process and thus cannot inject a library");
  143.      
  144.                 if (!File.Exists(libPath))
  145.                     throw new FileNotFoundException(string.Format("Unable to find library {0} to inject into process {1}", libPath, _process.ProcessName), libPath);
  146.      
  147.                 // convenience variables
  148.                 string fullPath = Path.GetFullPath(libPath);
  149.                 string libName = Path.GetFileName(fullPath);
  150.      
  151.                 // declare resources that need to be freed in finally
  152.                 IntPtr pLibRemote = IntPtr.Zero; // pointer to allocated memory of lib path string
  153.                 IntPtr hThread = IntPtr.Zero; // handle to thread from CreateRemoteThread
  154.                 IntPtr pLibFullPathUnmanaged = Marshal.StringToHGlobalUni(fullPath); // unmanaged C-String pointer
  155.      
  156.                 try
  157.                 {
  158.                     uint sizeUni = (uint)Encoding.Unicode.GetByteCount(fullPath);
  159.      
  160.                     // Get Handle to Kernel32.dll and pointer to LoadLibraryW
  161.                     IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32");
  162.                     if (hKernel32 == IntPtr.Zero)
  163.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  164.                     IntPtr hLoadLib = Imports.GetProcAddress(hKernel32, "LoadLibraryW");
  165.                     if (hLoadLib == IntPtr.Zero)
  166.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  167.      
  168.                     // allocate memory to the local process for libFullPath
  169.                     pLibRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, sizeUni, AllocationType.Commit, MemoryProtection.ReadWrite);
  170.                     if (pLibRemote == IntPtr.Zero)
  171.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  172.      
  173.                     // write libFullPath to pLibPath
  174.                     int bytesWritten;
  175.                     if (!Imports.WriteProcessMemory(_handle, pLibRemote, pLibFullPathUnmanaged, sizeUni, out bytesWritten) || bytesWritten != (int)sizeUni)
  176.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  177.      
  178.                     // load dll via call to LoadLibrary using CreateRemoteThread
  179.                     hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hLoadLib, pLibRemote, 0, IntPtr.Zero);
  180.                     if (hThread == IntPtr.Zero)
  181.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  182.                     if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0)
  183.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  184.                     // get address of loaded module - this doesn't work in x64, so just iterate module list to find injected module
  185.                     IntPtr hLibModule;// = IntPtr.Zero;
  186.                     if (!Imports.GetExitCodeThread(hThread, out hLibModule))
  187.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  188.                     if (hLibModule == IntPtr.Zero)
  189.                         throw new Exception("Code executed properly, but unable to get an appropriate module handle, possible Win32Exception", new Win32Exception(Marshal.GetLastWin32Error()));
  190.      
  191.                     // iterate modules in target process to find our newly injected module
  192.                     ProcessModule modFound = null;
  193.                     foreach (ProcessModule mod in _process.Modules)
  194.                     {
  195.                         if (mod.ModuleName == libName)
  196.                         {
  197.                             modFound = mod;
  198.                             break;
  199.                         }
  200.                     }
  201.                     if (modFound == null)
  202.                         throw new Exception("Injected module could not be found within the target process!");
  203.      
  204.                     injectedModules.Add(libName, new InjectedModule(modFound));
  205.                 }
  206.                 finally
  207.                 {
  208.                     Marshal.FreeHGlobal(pLibFullPathUnmanaged); // free unmanaged string
  209.                     Imports.CloseHandle(hThread); // close thread from CreateRemoteThread
  210.                     Imports.VirtualFreeEx(_process.Handle, pLibRemote, 0, AllocationType.Release); // Free memory allocated
  211.                 }
  212.             }
  213.      
  214.             /// <summary>
  215.             /// Ejects a library that this Injector has previously injected into the target process. <paramref name="libName"/> is the name of the module to
  216.             /// eject, as per the name stored in <see cref="Injector.InjectLibrary"/>. Passing the same value as passed to InjectLibrary should always work unless a
  217.             /// relative path was used and the program's working directory has changed.
  218.             /// </summary>
  219.             /// <param name="libName">The name of the module to eject</param>
  220.             public void EjectLibrary(string libName)
  221.             {
  222.                 string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName;
  223.      
  224.                 if (!injectedModules.ContainsKey(libSearchName))
  225.                     throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected");
  226.      
  227.                 // resources that need to be freed
  228.                 IntPtr hThread = IntPtr.Zero;
  229.      
  230.                 try
  231.                 {
  232.                     // get handle to kernel32 and FreeLibrary
  233.                     IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32");
  234.                     if (hKernel32 == IntPtr.Zero)
  235.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  236.                     IntPtr hFreeLib = Imports.GetProcAddress(hKernel32, "FreeLibrary");
  237.                     if (hFreeLib == IntPtr.Zero)
  238.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  239.      
  240.                     hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hFreeLib, injectedModules[libSearchName].BaseAddress, 0, IntPtr.Zero);
  241.                     if (hThread == IntPtr.Zero)
  242.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  243.                     if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0)
  244.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  245.      
  246.                     // get exit code of FreeLibrary
  247.                     IntPtr pFreeLibRet;// = IntPtr.Zero;
  248.                     if (!Imports.GetExitCodeThread(hThread, out pFreeLibRet))
  249.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  250.      
  251.                     if (pFreeLibRet == IntPtr.Zero)
  252.                         throw new Exception("FreeLibrary failed in remote process");
  253.                 }
  254.                 finally
  255.                 {
  256.                     Imports.CloseHandle(hThread);
  257.                 }
  258.             }
  259.      
  260.             /// <summary>
  261.             /// Call an export with no parameter in the target process (i.e. SomeFunc( void );). This function will only
  262.             /// return once the remote thread in the target process has returned.
  263.             /// </summary>
  264.             /// <param name="libName">Name of the injected module in which the function should be found</param>
  265.             /// <param name="funcName">Name of the exported function to call</param>
  266.             /// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
  267.             public IntPtr CallExport(string libName, string funcName)
  268.             {
  269.                 return CallExport((uint)ThreadWaitValue.Infinite, libName, funcName);
  270.             }
  271.      
  272.             /// <summary>
  273.             /// Call an export with no parameter in the target process (i.e. SomeFunc( void );). This function returns after
  274.             /// <paramref name="timeout"/> ms have elapsed, or the remote function finishes (whichever comes first).
  275.             /// </summary>
  276.             /// <param name="timeout">Number of miliseconds to wait for the remote function to return</param>
  277.             /// <param name="libName">Name of the injected module in which the function should be found</param>
  278.             /// <param name="funcName">Name of the exported function to call</param>
  279.             /// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
  280.             public IntPtr CallExport(uint timeout, string libName, string funcName) // param location to avoid possible overload / generic confusion
  281.             {
  282.                 return CallExportInternal(timeout, libName, funcName, IntPtr.Zero, null, 0);
  283.             }
  284.      
  285.             /// <summary>
  286.             /// Call an export with type <typeparamref name="T"/> data parameter. <typeparamref name="T"/> must be a struct (i.e. a
  287.             /// value type or user-defined struct). User-defined structs must have the <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/> set to
  288.             /// <see cref="System.Runtime.InteropServices.LayoutKind.Sequential"/> or <see cref="System.Runtime.InteropServices.LayoutKind.Explicit"/>. User-defined
  289.             /// structs containing variable length C-style strings should adorn strings with <see cref="CustomMarshalAsAttribute"/> and set the value to the appropriate
  290.             /// <see cref="CustomUnmanagedType"/> value.
  291.             /// This function will wait until the remote function finishes.
  292.             /// </summary>
  293.             /// <typeparam name="T">Type of data remote function expects. Value type or struct only.</typeparam>
  294.             /// <param name="libName">Name of the injected module in which the function should be found</param>
  295.             /// <param name="funcName">Name of the exported function to call</param>
  296.             /// <param name="data">Data of type <typeparamref name="T"/> to be sent as argument to remote function</param>
  297.             /// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
  298.             public IntPtr CallExport<T>(string libName, string funcName, T data) where T : struct
  299.             {
  300.                 return CallExport<T>((uint)ThreadWaitValue.Infinite, libName, funcName, data);
  301.             }
  302.      
  303.             /// <summary>
  304.             /// Call an export with type <typeparamref name="T"/> data parameter. <typeparamref name="T"/> must be a struct (i.e. a
  305.             /// value type or user-defined struct). User-defined structs must have the <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/> set to
  306.             /// <see cref="System.Runtime.InteropServices.LayoutKind.Sequential"/> or <see cref="System.Runtime.InteropServices.LayoutKind.Explicit"/>. User-defined
  307.             /// structs containing variable length C-style strings should adorn strings with <see cref="CustomMarshalAsAttribute"/> and set the value to the appropriate
  308.             /// <see cref="CustomUnmanagedType"/> value.
  309.             /// This function will wait for <paramref name="timeout"/> miliseconds or until the remote function finishes (whichever comes first).
  310.             /// </summary>
  311.             /// <typeparam name="T">Type of data remote function expects. Value type or struct only.</typeparam>
  312.             /// <param name="timeout">Number of miliseconds to wait for the remote function to return</param>
  313.             /// <param name="libName">Name of the injected module in which the function should be found</param>
  314.             /// <param name="funcName">Name of the exported function to call</param>
  315.             /// <param name="data">Data of type <typeparamref name="T"/> to be sent as argument to remote function</param>
  316.             /// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
  317.             public IntPtr CallExport<T>(uint timeout, string libName, string funcName, T data) where T : struct
  318.             {
  319.                 IntPtr pData = IntPtr.Zero;
  320.                 try
  321.                 {
  322.                     int dataSize = CustomMarshal.SizeOf(data);
  323.                     pData = Marshal.AllocHGlobal(dataSize);
  324.                     CustomMarshal.StructureToPtr(data, pData, true);
  325.                     return CallExportInternal(timeout, libName, funcName, pData, typeof(T), (uint)dataSize);
  326.                 }
  327.                 finally
  328.                 {
  329.                     Marshal.FreeHGlobal(pData);
  330.                 }
  331.             }
  332.      
  333.             private IntPtr CallExportInternal(uint timeout, string libName, string funcName, IntPtr data, Type dataType, uint dataSize)
  334.             {
  335.                 string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName;
  336.      
  337.                 if (!injectedModules.ContainsKey(libSearchName))
  338.                     throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected");
  339.      
  340.                 IntPtr pFunc = injectedModules[libSearchName][funcName];
  341.                 // resources that need to be cleaned
  342.                 IntPtr pDataRemote = IntPtr.Zero;
  343.                 IntPtr hThread = IntPtr.Zero;
  344.      
  345.                 try
  346.                 {
  347.                     // check if we have all required parameters to pass a data parameter
  348.                     // if we don't, assume we aren't passing any data
  349.                     if (!(data == IntPtr.Zero || dataSize == 0 || dataType == null))
  350.                     {
  351.                         // allocate memory in remote process for parameter
  352.                         pDataRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, dataSize, AllocationType.Commit, MemoryProtection.ReadWrite);
  353.                         if (pDataRemote == IntPtr.Zero)
  354.                             throw new Win32Exception(Marshal.GetLastWin32Error());
  355.      
  356.                         // rebase the data so that pointers point to valid memory locations for the target process
  357.                         // this renders the unmanaged structure useless in this process - should be able to re-rebase back to
  358.                         // this target process by calling CustomMarshal.RebaseUnmanagedStructure(data, data, dataType); but not tested
  359.                         CustomMarshal.RebaseUnmanagedStructure(data, pDataRemote, dataType);
  360.      
  361.                         int bytesWritten;
  362.                         if (!Imports.WriteProcessMemory(_handle, pDataRemote, data, dataSize, out bytesWritten))
  363.                             throw new Win32Exception(Marshal.GetLastWin32Error());
  364.                     }
  365.      
  366.                     hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, pFunc, pDataRemote, 0, IntPtr.Zero);
  367.                     if (hThread == IntPtr.Zero)
  368.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  369.      
  370.                     uint singleObject = Imports.WaitForSingleObject(hThread, timeout);
  371.                     if (!(singleObject == (uint)ThreadWaitValue.Object0 || singleObject == (uint)ThreadWaitValue.Timeout))
  372.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  373.      
  374.                     IntPtr pRet;
  375.                     if (!Imports.GetExitCodeThread(hThread, out pRet))
  376.                         throw new Win32Exception(Marshal.GetLastWin32Error());
  377.      
  378.                     return pRet;
  379.                 }
  380.                 finally
  381.                 {
  382.                     Imports.VirtualFreeEx(_process.Handle, pDataRemote, 0, AllocationType.Release);
  383.                     Imports.CloseHandle(hThread);
  384.                 }
  385.      
  386.             }
  387.      
  388.             #region IDisposable Members
  389.      
  390.             public void Dispose()
  391.             {
  392.                 if (EjectOnDispose)
  393.                 {
  394.                     foreach (string key in injectedModules.Keys)
  395.                     {
  396.                         EjectLibrary(key);
  397.                     }
  398.                 }
  399.                 if (_handle != IntPtr.Zero)
  400.                     Imports.CloseHandle(_handle);
  401.                 _handle = IntPtr.Zero;
  402.      
  403.                 Process.LeaveDebugMode();
  404.             }
  405.      
  406.             #endregion
  407.         }
  408.     }
Advertisement
Add Comment
Please, Sign In to add comment