/// <summary> /// Loads libraries into the main executable and patches them as needed /// </summary> /// <param name="processInformation">The <see cref="ProcessInformation"/> corresponding to the main executable</param> /// <param name="patchDocument">The <see cref="XElement"/> containing the data to use</param> private static void PatchLibraries(ProcessInformation processInformation, XElement patchDocument) { foreach (var patchLibrary in patchDocument.Elements(PatchLibraryTag)) { var libraryNameAttr = patchLibrary.Attribute(LibraryNameAttribute); if (libraryNameAttr == null) { throw new InvalidOperationException("The library name attribute is not found"); } var offsetAttr = patchLibrary.Attribute(OffsetAttribute); if (offsetAttr == null) { throw new InvalidOperationException("The offset attribute is not found"); } var dataAttr = patchLibrary.Attribute(DataAttribute); if (dataAttr == null) { throw new InvalidOperationException("The data attribute is not found"); } var offset = ParseAddress(offsetAttr.Value); var data = ParseData(dataAttr.Value); var libraryHandle = GetLibraryAddress(libraryNameAttr.Value, (int) processInformation.dwProcessId); MemoryProtection oldProtect; var result = Kernel32.VirtualProtectEx( processInformation.hProcess, libraryHandle + (int) offset, (uint) data.Length, MemoryProtection.ExcecuteReadWrite, out oldProtect); ValidateResult(result); using (var alloc = new CoTaskMemoryAllocator(data.Length)) { alloc.Write(data); uint mumberOfBytesWritten; result = Kernel32.WriteProcessMemory( processInformation.hProcess, libraryHandle + (int) offset, alloc.BufferAddress, (uint) alloc.BufferLength, out mumberOfBytesWritten); ValidateResult(result); } result = Kernel32.VirtualProtectEx( processInformation.hProcess, libraryHandle + (int) offset, (uint) data.Length, oldProtect, out oldProtect); ValidateResult(result); } }
/// <summary> /// Populates the list of loaded modules within the specified process /// </summary> /// <param name="hProcess">The handle of the process to populate the list of modules</param> private static void EnumModules(IntPtr hProcess) { using (var alloc = new CoTaskMemoryAllocator(0x10000)) { int needed; var result = Kernel32.EnumProcessModulesExPsapi( hProcess, alloc, alloc.BufferLength, out needed, ListModulesFlag.LIST_MODULES_ALL); ValidateResult(result); for (var i = 0; i < needed/IntPtr.Size; i++) { var hModule = Marshal.ReadIntPtr(alloc.BufferAddress, i*IntPtr.Size); var baseName = new StringBuilder(260); result = Kernel32.GetModuleFileNameExWPsapi(hProcess, hModule, baseName, baseName.Capacity); ValidateResult(result); LoadedLibraries.Add(Path.GetFileName(baseName.ToString()).ToLower(), hModule); } } }
/// <summary> /// Patches the main executable /// </summary> /// <param name="processInformation">The <see cref="ProcessInformation"/> corresponding to the main executable</param> /// <param name="patchDocument">The <see cref="XElement"/> containing the data to use</param> private static void PatchExecutable(ProcessInformation processInformation, XElement patchDocument) { foreach (var patch in patchDocument.Elements(PatchTag)) { var offsetAttr = patch.Attribute(OffsetAttribute); if (offsetAttr == null) { throw new InvalidOperationException("The offset attribute is not found"); } var dataAttr = patch.Attribute(DataAttribute); if (dataAttr == null) { throw new InvalidOperationException("The data attribute is not found"); } var offset = ParseAddress(offsetAttr.Value); var baseAddress = GetExecutableBaseAddress(processInformation); if (baseAddress == IntPtr.Zero) { throw new InvalidOperationException("The base address of the main executable is not found"); } var address = new IntPtr(baseAddress.ToInt64() + offset.ToInt64()); var data = ParseData(dataAttr.Value); MemoryProtection oldProtect; var result = Kernel32.VirtualProtectEx( processInformation.hProcess, address, (uint) data.Length, MemoryProtection.ExcecuteReadWrite, out oldProtect); ValidateResult(result); using (var alloc = new CoTaskMemoryAllocator(data.Length)) { alloc.Write(data); uint mumberOfBytesWritten; result = Kernel32.WriteProcessMemory( processInformation.hProcess, address, alloc.BufferAddress, (uint) alloc.BufferLength, out mumberOfBytesWritten); ValidateResult(result); } result = Kernel32.VirtualProtectEx( processInformation.hProcess, address, (uint) data.Length, oldProtect, out oldProtect); ValidateResult(result); } }