CreateRemoteThread函数多参数传入使用方法

注意事项:

1.Debug版本编译的时候使用增量编译,导致每个函数都是用一个Thunk, 所以请使用Release版本。

2.目标进程非本进程时不能调用本进程内的函数或使用本进程内的变量,有时在隐式使用时可能会引起该

问题,容易引起进程崩溃。(例如WriteProcessMemory写入的函数中调用了本进程的全局变量)

3.多参数使用时请在目标进程中为函数参数分配相应的内存空间,因为CreateRemoteThread第5个参数是LPVOID型,

这意味着它只能放一个指针值,而该指针值应该指向分配的相应内存空间。

使用实例:

假设我们调用的目标进程的主窗口标题为“ImageCall”, 并假设在偏移该进程首地址0x000163D0有一个用于加血的游戏函数。

于是我们可以如下所示来使用CreateRemoteThread多参数调用来在目标进程中调用该加血函数。

(以下使用默认在MFC中,CImageBloodDlg为一个基本对话框类,

AddBlood_Inject()为对话框上某一按钮按下时的触发函数。)

//首先定义全局标题和偏移地址

LPCTSTR gameCaption = _T("ImageCall");
const int ADD_BLOOD_CALL = 0x000163D0;

//之后是上一篇博客中写道的获取进程首地址的函数

//获取目标进程首地址
BOOL CImageBloodDlg::getProcessAddr(DWORD dwPID, DWORD& baseAddr)
{
	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
	MODULEENTRY32 me32;

	// 在目标进程中获取所有进程的snapshot
	hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
	if (hModuleSnap == INVALID_HANDLE_VALUE)
	{
		AfxMessageBox(_T("CreateToolhelp32Snapshot (of modules) fail"));
		return(FALSE);
	}

	// 设置MODULEENTRY32数据结构大小字段
	me32.dwSize = sizeof(MODULEENTRY32);

	//检索第一个模块的信息,不成功则返回
	if (!Module32First(hModuleSnap, &me32))
	{
		AfxMessageBox(_T("Module32First fail")); // 显示调用失败
		CloseHandle(hModuleSnap);    // 清除句柄对象
		return(FALSE);
	}

	// 从me32中得到基址
	baseAddr = (DWORD)me32.modBaseAddr;

	// 别忘了最后清除模块句柄对象
	CloseHandle(hModuleSnap);
	return(TRUE);
}

//然后我们定义一个获取目标地址空间真实地址的结构体

typedef struct tagTrueAddr
{
	DWORD baseAddr;
	DWORD Offset;

}TrueAddr, *PTrueAddr;

//这是我们想在目标进程中进行调用的函数(使用了内联汇编)

void __stdcall addBloodCall(TrueAddr* addr)
{
	DWORD baseAddr = addr->baseAddr;
	DWORD baseOffset = addr->Offset;
	_asm
	{
		mov eax, baseAddr
		add eax, baseOffset
		call eax
	}
}

//最后我们通过远程注入来进行CreateRemoteThread的多参数调用,按下相应按钮时触发该函数

void CImageBloodDlg::AddBlood_Inject()
{
	// TODO:  在此添加控件通知处理程序代码
	//得到窗口句柄
	HWND hwnd = ::FindWindow(NULL, gameCaption);
	//得到进程ID
	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	//获取进程访问权限
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);

	//目标进程分配函数参数空间
	LPVOID paramsCall = VirtualAllocEx(hProcess, NULL, sizeof(TrueAddr), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (paramsCall == NULL)
	{
		AfxMessageBox(_T("get paramsCall failed"));
		return;
	}
	//目标进程分配函数本体空间
	LPVOID baseCall = VirtualAllocEx(hProcess, NULL, 1000, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (baseCall == NULL)
	{
		AfxMessageBox(_T("get baseCall failed"));
		return;
	}

	//在函数本体空间中写入addBloodCall函数本体
	if (!WriteProcessMemory(hProcess, baseCall, addBloodCall, 1000, NULL))
	{
		AfxMessageBox(_T("writeProcessMemory fail"));
		return;
	}

	//得到目标进程首地址
	DWORD baseAddr;
	getProcessAddr(pid, baseAddr);

	//设置真实地址(baseAddr首地址, Offset偏移地址量)
	TrueAddr trueAddr;
	trueAddr.baseAddr = baseAddr;
	trueAddr.Offset = ADD_BLOOD_CALL;
	if (!WriteProcessMemory(hProcess, paramsCall, (LPCVOID)&trueAddr, sizeof(TrueAddr), NULL))
	{
		AfxMessageBox(_T("Write trueAddress failed"));
		return;
	}

	//传入函数参数并创建远程线程函数
	PTrueAddr ptAddr = (PTrueAddr)paramsCall;
	HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)baseCall, (LPVOID)ptAddr, 0,NULL);
	if (!hRemoteThread)
	{
		AfxMessageBox(_T("CreateRemoteThread failed"));
		return;
	}
}

先定义一个结构体的数据结构类型,并在该结构中包括所有的函数入口参数,

然后为想写入的函数提供唯一的一个结构体指针的参数,最后在CreateRemoteThread中

提供该唯一的函数参数,并为该函数参数指针所指的结构体在目标进程中开辟相应的内存空间,

并使该指针指向它,通过这种方法我们便可以成功使用多参数函数传入的CreateRemoteThread调用了。

时间: 2024-10-24 04:37:49

CreateRemoteThread函数多参数传入使用方法的相关文章

把一个函数作为参数传入到函数中

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script> function f1(func){ //func函数作为参数传入f1函数 console.log('1'); //首先进入f1函数 setTimeout(function(){ console.log('2'); //继续进入setTimeout方法

Python中将函数作为另一个函数的参数传入并调用

在Python中,函数本身也是对象,所以可以将函数作为参数传入另一函数并进行调用 在旧版本中,可以使用apply(function, *args, **kwargs)进行调用,但是在新版本中已经移除,以function(*args, **kwargs)进行替代,所以也不应该再使用apply方法 示例代码: def func_a(func, *args, **kwargs): print(func(*args, **kwargs)) def func_b(*args): return args i

Python函数式编程(把函数作为参数传入)

map:接受两个参数(函数,Iterable),map将传入的函数依次作用于Iterable的每个元素,并且返回新的Iterable def f(x): return x*x r = map(f,[1,2,3,4]) #此时的r为惰性求值--可用next()和for...in取值 #通过list()返回全部 print(list(r)) #[1, 4, 9, 16] reduce:接受两个参数(函数,序列),reduce把一个函数作用于序列上,返回的结果继续和序列的下一个元素做累积计算,其效果为

声明数组变量/// 计算所有元素的总和/打印所有元素总和/输出/foreach循环/数组作为函数的参数/调用printArray方法打印

实例 下面是这两种语法的代码示例: double[] myList; // 首选的方法 或 double myList[]; // 效果相同,但不是首选方法 创建数组 Java语言使用new操作符来创建数组,语法如下: arrayRefVar = new dataType[arraySize]; 上面的语法语句做了两件事: 一.使用dataType[arraySize]创建了一个数组. 二.把新创建的数组的引用赋值给变量 arrayRefVar. 数组变量的声明,和创建数组可以用一条语句完成,如

block 参数传入到方法中

def do_n_times(n){ i = 1 while( i<=n ) yield i end } do_n_times( 3 ){ |x| puts "--->#{x}" } # --->1 # --->2 # --->3 上面是使用关键字 yeild 来调用代码块,而下面的例子,在方法定义的时候定义了一个Proc 参数( 索引到传入的块),然后在方法里调用 call 方法,来调用Proc 块. 注意这种使用方式和之前的方式,调用方法是一样的. d

OracleSpatial 处理超过1000个点的几何对象时,报错Ora-00939: 函数的参数过多解决方法

oracle空间字段mdsys.sdo_geometry存储多边形,报错ora-00939:to many arguments for function sql语句  update d_area set coordinate=mdsys.sdo_geometry(2003,8307,null,mdsys.sdo_elem_info_array(1,1003,1), mdsys.sdo_ordinate_array( 119.65415,29.14556,119.64824,....)) wher

Python函数的定义、参数传入与函数的调用

作为计算机代码的一种抽象方式,函数在Python中扮演了极为重要的角色.今天给大家介绍Python函数的定义.参数的传入以及调用方式.其中函数参数的传入方式为本节重点内容.Python函数的参数形式包括必选参数.默认参数.可变参数.命名关键字参数以及关键字参数.五类参数可单独传入也可组合传入. >>>> Python 函数的定义 Python中使用def语句来定义函数,然后依次写出函数名.括号.括号内的参数以及最后不能忘记的冒号,函数体需另起一行在缩进块中编写,最后返回值用retu

python之列表作为函数的参数

函数参数为 列表或者字典 传递一个列表,例如 [1, 2, 3] 将此传给函数get_sum() 求出 各个元素之和 传递一个字典,打印出key/value的对应关系表: #!/usr/bin/env python def get_sum(*args): res = 0 for i in args: res += i print(res) lista = [1, 2, 3] get_sum(*lista) print('-' * 40) def get_vk(**kwargs): for k,

菠菜网站函数参数传入和菠菜平台重复调用函数的搭建使用方法

原创摘要:菠菜网站函数参数传入和菠菜平台重复调用函数的搭建使用详细方法菠菜网站函数参数BCfrom sys import argv#利用sys.argv传入参数,argv是一个BC网参数列表listscript,file_name,input_encoding,errors = argv def main(language_file,encoding,errors):#主函数参数print(">>>>main",repr(language_file),encod