首先,不,我不是黑客游戏,这是一个软件的简单IP重定向器。
我发现了一个DLL注入器,它也可以从库中调用导出,这正是我需要的。在我的机器中,它工作得很好(Win 7 x64),然而,在某些机器中,当它注入程序时只是说“停止工作”或卡住了。这是为什么?这是代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.IO;
using Syringe.Win32;
namespace Syringe
{
public class Injector : IDisposable
{
/// <summary>
/// Internal class to represent an Injected Module within Injector's target process.
/// Simply manages finding export addresses for functions, and caches these addresses for
/// potential future use.
/// </summary>
private class InjectedModule
{
private Dictionary<string, IntPtr> exports;
public ProcessModule Module { get; private set; }
public IntPtr BaseAddress { get { return Module.BaseAddress; } }
public InjectedModule(ProcessModule module)
{
Module = module;
exports = new Dictionary<string, IntPtr>();
}
/// <summary>
/// Get the address of a given function exported in the Module.
/// If the function can't be found, this will throw <see cref="Win32Exception"/>
/// </summary>
/// <param name="func">Name of function to search for</param>
/// <returns><see cref="IntPtr"/> representing the address of this function in the target process</returns>
/// <exception cref="Win32Exception">Thrown if unable to find function address in module</exception>
public IntPtr this[string func]
{
get
{
if (!exports.ContainsKey(func))
exports[func] = FindExport(func);
return exports[func];
}
}
/**
* Actual function to find export - loosely modelled off Cypher's idea/code for loading module into this
* process to find address. Loads module as data, finds RVA of function and uses to find address in target
* process
*/
private IntPtr FindExport(string func)
{
IntPtr hModule = IntPtr.Zero;
try
{
// Load module into local process address space
hModule = Imports.LoadLibraryEx(Module.FileName, IntPtr.Zero, LoadLibraryExFlags.DontResolveDllReferences);
if (hModule == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Call GetProcAddress to get the address of the function in the module locally
IntPtr pFunc = Imports.GetProcAddress(hModule, func);
if (pFunc == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Get RVA of export and add to base address of injected module
// hack at the moment to deal with x64
bool x64 = IntPtr.Size == 8;
IntPtr pExportAddr;
if (x64)
pExportAddr = new IntPtr(Module.BaseAddress.ToInt64() + (pFunc.ToInt64() - hModule.ToInt64()));
else
pExportAddr = new IntPtr(Module.BaseAddress.ToInt32() + (pFunc.ToInt32() - hModule.ToInt32()));
return pExportAddr;
}
finally
{
try
{
Imports.CloseHandle(hModule);
}
catch
{
}
}
}
}
private Process _process;
private IntPtr _handle;
private Dictionary<string, InjectedModule> injectedModules;
public Injector(Process process) : this(process, true) { }
public Injector(Process process, bool ejectOnDispose)
{
if (process == null)
throw new ArgumentNullException("process");
if (process.Id == Process.GetCurrentProcess().Id)
throw new InvalidOperationException("Cannot create an injector for the current process");
Process.EnterDebugMode();
_handle = Imports.OpenProcess(
ProcessAccessFlags.QueryInformation | ProcessAccessFlags.CreateThread |
ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMWrite |
ProcessAccessFlags.VMRead, false, process.Id);
if (_handle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
_process = process;
EjectOnDispose = ejectOnDispose;
injectedModules = new Dictionary<string, InjectedModule>();
}
public bool EjectOnDispose { get; set; }
/// <summary>
/// Injects a library into this Injector's process. <paramref name="libPath"/> can be
/// relative or absolute; either way, the injected module will be referred to by module name only.
/// I.e. "c:\some\directory\library.dll", "library.dll" and "..\library.dll" will all be referred to
/// as "library.dll"
/// </summary>
/// <param name="libPath">Relative or absolute path to the dll to be injected</param>
public void InjectLibrary(string libPath)
{
// (in?)sanity check, pretty sure this is never possible as the constructor will error - left over from how it previously was developed
if (_process == null)
throw new InvalidOperationException("This injector has no associated process and thus cannot inject a library");
if (_handle == IntPtr.Zero)
throw new InvalidOperationException("This injector does not have a valid handle to the associated process and thus cannot inject a library");
if (!File.Exists(libPath))
throw new FileNotFoundException(string.Format("Unable to find library {0} to inject into process {1}", libPath, _process.ProcessName), libPath);
// convenience variables
string fullPath = Path.GetFullPath(libPath);
string libName = Path.GetFileName(fullPath);
// declare resources that need to be freed in finally
IntPtr pLibRemote = IntPtr.Zero; // pointer to allocated memory of lib path string
IntPtr hThread = IntPtr.Zero; // handle to thread from CreateRemoteThread
IntPtr pLibFullPathUnmanaged = Marshal.StringToHGlobalUni(fullPath); // unmanaged C-String pointer
try
{
uint sizeUni = (uint)Encoding.Unicode.GetByteCount(fullPath);
// Get Handle to Kernel32.dll and pointer to LoadLibraryW
IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32");
if (hKernel32 == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
IntPtr hLoadLib = Imports.GetProcAddress(hKernel32, "LoadLibraryW");
if (hLoadLib == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// allocate memory to the local process for libFullPath
pLibRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, sizeUni, AllocationType.Commit, MemoryProtection.ReadWrite);
if (pLibRemote == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// write libFullPath to pLibPath
int bytesWritten;
if (!Imports.WriteProcessMemory(_handle, pLibRemote, pLibFullPathUnmanaged, sizeUni, out bytesWritten) || bytesWritten != (int)sizeUni)
throw new Win32Exception(Marshal.GetLastWin32Error());
// load dll via call to LoadLibrary using CreateRemoteThread
hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hLoadLib, pLibRemote, 0, IntPtr.Zero);
if (hThread == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0)
throw new Win32Exception(Marshal.GetLastWin32Error());
// get address of loaded module - this doesn't work in x64, so just iterate module list to find injected module
IntPtr hLibModule;// = IntPtr.Zero;
if (!Imports.GetExitCodeThread(hThread, out hLibModule))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (hLibModule == IntPtr.Zero)
throw new Exception("Code executed properly, but unable to get an appropriate module handle, possible Win32Exception", new Win32Exception(Marshal.GetLastWin32Error()));
// iterate modules in target process to find our newly injected module
ProcessModule modFound = null;
foreach (ProcessModule mod in _process.Modules)
{
if (mod.ModuleName == libName)
{
modFound = mod;
break;
}
}
if (modFound == null)
throw new Exception("Injected module could not be found within the target process!");
injectedModules.Add(libName, new InjectedModule(modFound));
}
finally
{
Marshal.FreeHGlobal(pLibFullPathUnmanaged); // free unmanaged string
Imports.CloseHandle(hThread); // close thread from CreateRemoteThread
Imports.VirtualFreeEx(_process.Handle, pLibRemote, 0, AllocationType.Release); // Free memory allocated
}
}
/// <summary>
/// Ejects a library that this Injector has previously injected into the target process. <paramref name="libName"/> is the name of the module to
/// eject, as per the name stored in <see cref="Injector.InjectLibrary"/>. Passing the same value as passed to InjectLibrary should always work unless a
/// relative path was used and the program's working directory has changed.
/// </summary>
/// <param name="libName">The name of the module to eject</param>
public void EjectLibrary(string libName)
{
string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName;
if (!injectedModules.ContainsKey(libSearchName))
throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected");
// resources that need to be freed
IntPtr hThread = IntPtr.Zero;
try
{
// get handle to kernel32 and FreeLibrary
IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32");
if (hKernel32 == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
IntPtr hFreeLib = Imports.GetProcAddress(hKernel32, "FreeLibrary");
if (hFreeLib == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, hFreeLib, injectedModules[libSearchName].BaseAddress, 0, IntPtr.Zero);
if (hThread == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
if (Imports.WaitForSingleObject(hThread, (uint)ThreadWaitValue.Infinite) != (uint)ThreadWaitValue.Object0)
throw new Win32Exception(Marshal.GetLastWin32Error());
// get exit code of FreeLibrary
IntPtr pFreeLibRet;// = IntPtr.Zero;
if (!Imports.GetExitCodeThread(hThread, out pFreeLibRet))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (pFreeLibRet == IntPtr.Zero)
throw new Exception("FreeLibrary failed in remote process");
}
finally
{
Imports.CloseHandle(hThread);
}
}
/// <summary>
/// Call an export with no parameter in the target process (i.e. SomeFunc( void );). This function will only
/// return once the remote thread in the target process has returned.
/// </summary>
/// <param name="libName">Name of the injected module in which the function should be found</param>
/// <param name="funcName">Name of the exported function to call</param>
/// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
public IntPtr CallExport(string libName, string funcName)
{
return CallExport((uint)ThreadWaitValue.Infinite, libName, funcName);
}
/// <summary>
/// Call an export with no parameter in the target process (i.e. SomeFunc( void );). This function returns after
/// <paramref name="timeout"/> ms have elapsed, or the remote function finishes (whichever comes first).
/// </summary>
/// <param name="timeout">Number of miliseconds to wait for the remote function to return</param>
/// <param name="libName">Name of the injected module in which the function should be found</param>
/// <param name="funcName">Name of the exported function to call</param>
/// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
public IntPtr CallExport(uint timeout, string libName, string funcName) // param location to avoid possible overload / generic confusion
{
return CallExportInternal(timeout, libName, funcName, IntPtr.Zero, null, 0);
}
/// <summary>
/// Call an export with type <typeparamref name="T"/> data parameter. <typeparamref name="T"/> must be a struct (i.e. a
/// value type or user-defined struct). User-defined structs must have the <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/> set to
/// <see cref="System.Runtime.InteropServices.LayoutKind.Sequential"/> or <see cref="System.Runtime.InteropServices.LayoutKind.Explicit"/>. User-defined
/// structs containing variable length C-style strings should adorn strings with <see cref="CustomMarshalAsAttribute"/> and set the value to the appropriate
/// <see cref="CustomUnmanagedType"/> value.
/// This function will wait until the remote function finishes.
/// </summary>
/// <typeparam name="T">Type of data remote function expects. Value type or struct only.</typeparam>
/// <param name="libName">Name of the injected module in which the function should be found</param>
/// <param name="funcName">Name of the exported function to call</param>
/// <param name="data">Data of type <typeparamref name="T"/> to be sent as argument to remote function</param>
/// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
public IntPtr CallExport<T>(string libName, string funcName, T data) where T : struct
{
return CallExport<T>((uint)ThreadWaitValue.Infinite, libName, funcName, data);
}
/// <summary>
/// Call an export with type <typeparamref name="T"/> data parameter. <typeparamref name="T"/> must be a struct (i.e. a
/// value type or user-defined struct). User-defined structs must have the <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/> set to
/// <see cref="System.Runtime.InteropServices.LayoutKind.Sequential"/> or <see cref="System.Runtime.InteropServices.LayoutKind.Explicit"/>. User-defined
/// structs containing variable length C-style strings should adorn strings with <see cref="CustomMarshalAsAttribute"/> and set the value to the appropriate
/// <see cref="CustomUnmanagedType"/> value.
/// This function will wait for <paramref name="timeout"/> miliseconds or until the remote function finishes (whichever comes first).
/// </summary>
/// <typeparam name="T">Type of data remote function expects. Value type or struct only.</typeparam>
/// <param name="timeout">Number of miliseconds to wait for the remote function to return</param>
/// <param name="libName">Name of the injected module in which the function should be found</param>
/// <param name="funcName">Name of the exported function to call</param>
/// <param name="data">Data of type <typeparamref name="T"/> to be sent as argument to remote function</param>
/// <returns><see cref="IntPtr"/> representing the return value of function <paramref name="funcName"/> in module <paramref name="libName"/></returns>
public IntPtr CallExport<T>(uint timeout, string libName, string funcName, T data) where T : struct
{
IntPtr pData = IntPtr.Zero;
try
{
int dataSize = CustomMarshal.SizeOf(data);
pData = Marshal.AllocHGlobal(dataSize);
CustomMarshal.StructureToPtr(data, pData, true);
return CallExportInternal(timeout, libName, funcName, pData, typeof(T), (uint)dataSize);
}
finally
{
Marshal.FreeHGlobal(pData);
}
}
private IntPtr CallExportInternal(uint timeout, string libName, string funcName, IntPtr data, Type dataType, uint dataSize)
{
string libSearchName = File.Exists(libName) ? Path.GetFileName(Path.GetFullPath(libName)) : libName;
if (!injectedModules.ContainsKey(libSearchName))
throw new InvalidOperationException("That module has not been injected into the process and thus cannot be ejected");
IntPtr pFunc = injectedModules[libSearchName][funcName];
// resources that need to be cleaned
IntPtr pDataRemote = IntPtr.Zero;
IntPtr hThread = IntPtr.Zero;
try
{
// check if we have all required parameters to pass a data parameter
// if we don't, assume we aren't passing any data
if (!(data == IntPtr.Zero || dataSize == 0 || dataType == null))
{
// allocate memory in remote process for parameter
pDataRemote = Imports.VirtualAllocEx(_handle, IntPtr.Zero, dataSize, AllocationType.Commit, MemoryProtection.ReadWrite);
if (pDataRemote == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// rebase the data so that pointers point to valid memory locations for the target process
// this renders the unmanaged structure useless in this process - should be able to re-rebase back to
// this target process by calling CustomMarshal.RebaseUnmanagedStructure(data, data, dataType); but not tested
CustomMarshal.RebaseUnmanagedStructure(data, pDataRemote, dataType);
int bytesWritten;
if (!Imports.WriteProcessMemory(_handle, pDataRemote, data, dataSize, out bytesWritten))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
hThread = Imports.CreateRemoteThread(_handle, IntPtr.Zero, 0, pFunc, pDataRemote, 0, IntPtr.Zero);
if (hThread == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
uint singleObject = Imports.WaitForSingleObject(hThread, timeout);
if (!(singleObject == (uint)ThreadWaitValue.Object0 || singleObject == (uint)ThreadWaitValue.Timeout))
throw new Win32Exception(Marshal.GetLastWin32Error());
IntPtr pRet;
if (!Imports.GetExitCodeThread(hThread, out pRet))
throw new Win32Exception(Marshal.GetLastWin32Error());
return pRet;
}
finally
{
Imports.VirtualFreeEx(_process.Handle, pDataRemote, 0, AllocationType.Release);
Imports.CloseHandle(hThread);
}
}
#region IDisposable Members
public void Dispose()
{
if (EjectOnDispose)
{
foreach (string key in injectedModules.Keys)
{
EjectLibrary(key);
}
}
if (_handle != IntPtr.Zero)
Imports.CloseHandle(_handle);
_handle = IntPtr.Zero;
Process.LeaveDebugMode();
}
#endregion
}
}
现在我想你们中的一些人不会全部阅读..但我不明白为什么它在某些机器上失败了。他们正在使用win 7 x64,就像我一样。我像这样注射:
using (Process process = Process.Start(Path + @"\MyProgram.exe", "Argument1"))
{
while (process.MainWindowHandle == IntPtr.Zero && !process.HasExited)
Thread.Sleep(waitWindowSleep);
if (process.HasExited)
return;
for (int i = 0; i < maxTryCount; i++)
{
using (Injector injector = new Injector(process))
{
try
{
injector.EjectOnDispose = false;
injector.InjectLibrary(dll);
if ("127.0.0.1" != IPAddress.Loopback.ToString())
injector.CallExport<IPInfo>(dll, "SetIP", new IPInfo("127.0.0.1"));
return;
}
catch
{
Thread.Sleep(failInjectSleep);
}
}
}
}
那为什么它会在某些机器上崩溃?感谢。
编辑:调试程序.. http://puu.sh/4Hvcf.png - 我收到的错误。进程和应用程序都以管理员身份运行。
答案 0 :(得分:1)
即使这是一个老问题,我觉得有必要回答它。
您收到的异常消息总结得非常好。 会发生以下情况:您正在使用的库需要调用另一个进程的OpenProcess和CreateRemoteThread。库需要启用SE_DEBUG_PRIVILEGE,因此调用“EnterDebugMode()”,它设置应用程序权限常量SE_DEBUG_NAME。要使此操作成功,用户帐户必须具有调试权限(请参阅下文)。只有管理员(和本地机器)才有这个权利。
解决方案:以管理员身份运行具有所需权限的应用程序。确保在应用程序的清单文件中设置“requireAdministrator”可能会有所帮助。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx http://msdn.microsoft.com/en-US/library/system.diagnostics.process.enterdebugmode(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx http://technet.microsoft.com/en-us/library/cc787339(v=ws.10).aspx