我记得自己写的32位远程线程注入的时候,我就在目标进程中申请一块虚拟内存然后写入自编的汇编代码就能创建远程线程,是不是很简单,但是在64位系统注入64位程序的进程的时候不管你是使用API NtCreateThreadEx 或者使用代理都需要这个地址必须是一个有效的函数起始地址才会成功,否则你随便给个地址是会提示找不到地址的。先看一下代码,创建远程线程的。
[DllImport("ntdll.dll", SetLastError = true)]//创建远程线程, CreateRemoteThread API 是通过调用NtCreateThreadEx 实现的,这里直接获取这个未公开API的地址调用。这里只是声明这个API作参考,只有这个API才能在64位进程中起作用,所以必须用这个API
public static extern int NtCreateThreadEx(out IntPtr hThread, uint DesiredAccess, MyProcAPI64 ObjectAttributes, IntPtr ProcessHandle, Int64 lpStartAddress, Int64 lpParameter, Int64 CreateSuspended, MyProcAPI64 StackZeroBits, MyProcAPI64 SizeOfStackCommit, MyProcAPI64 SizeOfStackReserve,MyProcAPI64 lpBytesBuffer);
//直接调用这个API可能会报一个错,所以必须先用GetProcAddress API 得到这个API的地址后赋值给指针或句柄类型‘IntPtr’参数然后直接将这个参数当作方法使用
//比如说:IntPtr NtCreateThreadEx=null;NtCreateThreadEx=GetProcAddress(uint hModule, string lpProcName);这里取得地址后,直接当作方法使用NtCreateThreadEx();
//hThread 此参数是取得一个创建成功的远程线程句柄,数据原型位:PHANDLE ,64位系统中应位64位
//DesiredAccess 此参数是希望进入的方式,值可以为0x1FFFFF 数据原型为:ACCESS_MASK , 表示访问掩码,先定义为32位
//ObjectAttributes 数据原型为:LPVOID 此参数表示对象的属性,可以是一个结构体,所以说此参数类型也是一个64位的指针类型,可以位空或零
//ProcessHandle 数据原型为:HANDLE ,此参数表示将要创建线程所在的进程句柄,就是说在那个进程里面创建线程。64位系统应为64位
//lpStartAddress 数据原型为:LPTHREAD_START_ROUTINE 此参数表示线程将要开始运行函数的地址,类型是一个指针,这里是64位的,也就是线程要调用的方法的起始地址。比如说LoadLibraryA(lpfilename),还可以目标进程中的方法,不过这个API只能传递一个参数的地址。不过这不重要,我们用这个API主要是为了注入自己的DLL,调用LoadLibraryA加载我们的Dll就达到目的了。
//lpParameter 数据原型为:LPVOID 此参数表示线程将要运行的方法所附带的参数地址,所以说这个参数类型应该是一个64位的指针,这个参数可以是一个数据,也可以是一个保护多个数据的结构体,也可以说传入的是参数的起始地址
//CreateSuspended 数据原型为:ULONG ,也就是CreatThreadFlags 此参数表示创建线程的状态,CREATE_SUSPENDED=0x00000004 线程以挂起方式创建,因此这个参数是一般boll 型32位数据
//StackZeroBits 数据原型为:SIZE_T ,这个类型表示容量最大的类型, 此参数表示线程堆栈零字节数,无符号长整型64位,可以位空或零
//SizeOfStackCommit 数据原型为:SIZE_T ,这个类型表示容量最大的类型此参数表示堆栈命令的的字节数,无符号长整型64位