在c#中使用CreateRemoteThread传递多个参数

本文关键字:参数 CreateRemoteThread | 更新日期: 2023-09-27 18:18:37

我的目标是在c#中使用p/Invoke调用远程进程中的函数(CreateRemoteThread)。问题是这个函数有多个参数。是否有一种方法来传递多个参数的函数?

在c#中使用CreateRemoteThread传递多个参数

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
[Flags]
public enum AllocationType
{
    Commit = 0x1000,
    Reserve = 0x2000,
    Decommit = 0x4000,
    Release = 0x8000,
    Reset = 0x80000,
    Physical = 0x400000,
    TopDown = 0x100000,
    WriteWatch = 0x200000,
    LargePages = 0x20000000
}
[Flags]
public enum MemoryProtection
{
    Execute = 0x10,
    ExecuteRead = 0x20,
    ExecuteReadWrite = 0x40,
    ExecuteWriteCopy = 0x80,
    NoAccess = 0x01,
    ReadOnly = 0x02,
    ReadWrite = 0x04,
    WriteCopy = 0x08,
    GuardModifierflag = 0x100,
    NoCacheModifierflag = 0x200,
    WriteCombineModifierflag = 0x400
}
[StructLayout(LayoutKind.Sequential, Pack=1]
public struct RemoteThreadParams
{
    [MarshalAs(UnmanagedType.U1)]
    public byte Param1;
    [MarshalAs(UnmanagedType.I4)]
    public int Param2;
    ...
}
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(        
  IntPtr hProcess,
  IntPtr lpThreadAttributes,
  uint dwStackSize,
  IntPtr lpStartAddress,
  IntPtr lpParameter,
  uint dwCreationFlags,
  out uint lpThreadId
);
RemoteThreadParams params = new RemoteThreadParams();
parms.Param1 = 10;
parms.Param2 = 200;
// Allocate some native heap memory in your process big enough to store the
// parameter data
IntPtr iptrtoparams = Marshal.AllocHGlobal(Marshal.SizeOf(RemoteThreadParams));
// Copies the data in your structure into the native heap memory just allocated
Marshal.StructureToPtr(params, iptrtoparams, false);
// Use to get a handle to the process you intend to create a thread in.
OpenProcess(...,...,...);
// Use to alloc "committed" memory that is addressable by other process
IntPtr iptrremoteallocatedmemory = VirtualAllocEx()...
// Copy from your process memory to the memory the remoteprocess will be accessing
WriteProcessMemory(...,iptrremoteallocatedmemory,iptrtoparams,...,...);
Marshal.FreeHGlobal(iptrtoparams); // safe to free, as you have done the copy
CreateRemoteThread(...,...,...,...,iptrremoteallocatedmemory,...,...);
// Free the memory that was allocated for the other process...but be
// careful of its lifetime.
//
// Only free when the thread will no longer be accessing the allocated native
// memory i.e. when it's finished.
VirtualFreeEx(...,...,...,...);

在你的C/c++代码中有:

#pragma pack(push,1)
struct tagRemoteThreadParams
{
    BYTE Param1;
    int Param2;
} RemoteThreadParams, *PRemoteThreadParams;
#pragma pack(pop)

将线程函数接收到的LPVOID强制转换为PRemoteThreadParams(即*RemoteThreadParams)。

如果你有一些"字符串",你想作为你的参数之一,那么你将不得不做更多的工作来封送它们。有关更多帮助,请参阅:

  • http://www.developerfusion.com/article/84519/mastering-structs-in-c/

其他参考文献:

  • Dll注入。使用参数
  • 执行CreateRemoteThread
  • http://social.msdn.microsoft.com/Forums/vstudio/en-US/e044a6ff-c463-4b9b-8c82-f791c35dbaa1/virtualallocexwriteprocessmemory-and-writing-c-char-arrays?forum=csharpgeneral

如果函数有多个参数,则不可能在不使用shellcode的情况下将它们传递给CreateRemoteThread()调用的函数。

将指针传递给结构体或实参数组将不起作用。

第一个参数将被正确传递,其他参数也将存在于你编写它们的内存中,但它们不会被放入寄存器或堆栈中,因为调用约定需要它们来正确访问它们。

如果函数有2个参数,你传递一个指向结构的指针(正如我在其他答案中看到的那样),第一个参数将被正确地放置在堆栈或寄存器中,但是当函数试图访问后续参数时,它将只是拉出堆栈上或寄存器内的任何数据。

本质上,它将把这些垃圾数据视为参数。

正确获取参数的唯一方法是在对目标函数执行调用或jmp之前,将shellcode写入进程,该进程将参数加载到适当的寄存器和堆栈中。

您可以通过尝试使用CreateRemoteThread:

执行其中任何一个来轻松地测试这一点。
MessageBoxA(0,0,0,0);
Beep(500, 500);

您可以自己跟踪程序集并很容易地发现问题,程序集在任何时候都不会尝试接触第一个参数后面的地址。相反,它只是在参数应该所在的位置(在堆栈和寄存器中,而不是在您写入内存的结构中)触摸数据。

如果你的函数接受一个指向结构体的指针,那么其他答案中提供的方法可以工作