WIN动态库注入(远线程注入)

所谓动态库注入是指,将自己编写的动态库,通过自己的程序来注入到别的进程中去,然后运行。

原理:
在目标进程,开辟一段内存,然后写入要注入的动态库.dll 。然后让目标运行加载动态库函数,将该动态库载入到到进程中,然后运行指定函数,通常在进程创建一个线程,然后运行指定的代码。

涉及到的函数如下如果需要更详细的解释,请前往MSDN查阅:

/*
\ brief		检索顶级窗口的句柄,该窗口的类名和窗口名与指定的字符串匹配。
\ param		lpClassName  窗口或控件类名称
\ param		lpWindowName 窗口名称(窗口标题)
\ return	返回窗口的句柄,失败返回NULL
*/
HWND FindWindowW(
  LPCSTR lpClassName,
  LPCSTR lpWindowName
);

/*
\ brief		检索指定窗口的线程标识符(ID)与进程标识符(ID)
\ param		hWnd	窗口的句柄
\ param		lpdwProcessId 接收进程标识符的指针
\ return	线程标识符
*/
DWORD GetWindowThreadProcessId(
  HWND    hWnd,
  LPDWORD lpdwProcessId
);

/*
\ brief		打开一个现有的本地过程对象
\ param		dwDesiredAccess		进程访问权限
\ param		bInheritHandle		进程是否继承句柄
\ param		dwProcessId			进程标识符
\ return	进程的打开句柄,失败返回NULL
*/
HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);

/*
\ brief		指定进程分配虚拟内存,提交或更改内存区域状态,并初始化为NULL
\ param		hProcess	进程的句柄
\ param		lpAddress	分配的页面区域指定所需的起始地址,NULL则由系统默认
\ param		dwSize		要分配的内存区域的大小,以字节为单位,NULL则由系统默认认					
\ param		flAllocationType 内存分配的类型
\ param		flProtect	内存保护常量
\ return	页面分配的基地址(起始地址),失败返回NULL
*/
LPVOID VirtualAllocEx(
  HANDLE hProcess,		
  LPVOID lpAddress,		
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

/*
\ brief		在指定的进程中将数据写入内存区域
\ param		hProcess		进程句柄,必须具有PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问权限
\ param		lpBaseAddress	指向要写入数据的指定进程中的基地址的指针
\ param		lpBuffer		要写入数据的缓冲区的指针
\ param		nSize			缓冲区大小
\ param		lpNumberOfBytesWritten	该变量接收传输到指定进程中的字节数
\ return	失败返回,fALSE
*/
BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);

/*
\ brief		创建一个在另一个进程中运行的线程
\ param		hProcess	创建线程的进程的句柄
\ param		lpThreadAttributes	该结构为新线程指定安全描述符,NULL为系统默认
\ param		dwStackSize	 	堆栈的初始大小,以字节为单位,0 则使用系统默认大小
\ param		lpStartAddress	类型为LPTHREAD_START_ROUTINE函数的指针
\ param		lpParameter		函数的参数指针
\ param		dwCreationFlags	控制线程创建的标志
\ param		lpThreadId		指向接收线程标识符的变量的指针,NULL则不返回
\ return	新线程句柄,失败返回NULL
*/
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);

/*
\ brief		关闭打开的句柄
\ param		句柄
\ return	失败返回FALSE
*/
BOOL CloseHandle(
  HANDLE hObject
);

准备好要注入的,动态库。
我个人是喜欢将动态库,直接放置早要注入的程序目录下。

动态库注入

注入程序的代码,项目的字符集使用的Unicode字符

#include<iostream>
#include<Windows.h>			// 引入Windows库
using namespace std;

int main(int argc, char* argv[])
{
	// 获取窗口句柄 , 结尾是 W 表示宽字节, A 表示多字节
	HWND hwnd = ::FindWindowW(NULL, TEXT("植物大战僵尸中文版"));
	if (hwnd == NULL) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 定义一个变量接收 进程标识符
	DWORD pId;
	// 获取进程与线程 标识符
	DWORD tId = GetWindowThreadProcessId(hwnd, &pId);
	// 获取进程句柄
	HANDLE pHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
	if (pHandle == NULL) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 定义宽字节数组,接收宽字节字符串
	TCHAR buf[] = TEXT("StaticMfcDll.dll");
	// 在目标进程分配一块内存区域,使用 baseAddress变量接收,内存地址
	LPVOID baseAddress = ::VirtualAllocEx(pHandle, 
											NULL,
											sizeof(buf),
											MEM_COMMIT, 
											PAGE_EXECUTE_READWRITE);
	// 在目标进程写入buf数组,也就是 StaticMfcDll.dll  这一串字符串,注意这是宽字节
	if (!::WriteProcessMemory(pHandle, 
								baseAddress,
								buf, 
								sizeof(buf),
								NULL)) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 在目标进程调用 LoadLibrary()函数加载动态库函数,参数是 baseAddress 地址的字符串。
	if (!::CreateRemoteThread(pHandle,
								NULL,
								0,
								(LPTHREAD_START_ROUTINE)LoadLibrary,
								baseAddress,
								0,
								NULL)) {
		cout << __FILE__ << "   " << __LINE__ << endl;
		system("pause");
		return 0;
	}
	// 关闭句柄
	::CloseHandle(pHandle);

}

这个动态库是 MFC库,重点配置是,可以用vs直接创建出来
MFC配置

动态库的核心代码

// CStaticMfcDllApp 初始化
// .h  头文件定义的一个  线程指针
private:
	std::unique_ptr<std::thread> tPtr;

/*
\ breif		线程运行的函数
*/
void CStaticMfcDllApp::ThreadFunciton()
{
	// 定义 植物变量
	Plant p;	
	// 模态显示 植物对话框
	p.DoModal();
}

/*
\brief	当加载该库的时候,会调用到这个重载函数。
*/
BOOL CStaticMfcDllApp::InitInstance()
{
	CWinApp::InitInstance();
	// 开启一个线程,运行 成员函数
	tPtr = std::make_unique<std::thread>(&CStaticMfcDllApp::ThreadFunciton, this);
	return TRUE;
}

/*
\ brief		析构函数
*/
CStaticMfcDllApp::~CStaticMfcDllApp()
{
// 销毁时,阻塞等待线程退出
	tPtr->join();
}

/*
\ brief		这个是修改阳光
*/
void Plant::OnBnClickedBtnSum()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	int sum = _wtoi(editSum.GetBuffer());
	// 阳光基址 [[006A9EC0]+768]+5560
	size_t * pointer = (size_t*)((*(size_t*)((*(size_t*)0x006A9EC0) + 0x768)) + 0x5560);
	*pointer = sum;
}

/*
\ brief		这个是修改金币
*/
void Plant::OnBnClickedBtnMenory()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);
	int menory = _wtoi(editMenory.GetBuffer());
	// 金币基址 [[006A9EC0] + 82C] + 28
	size_t* pointer = (size_t*)((*(size_t*)((*(size_t*)0x006A9EC0) + 0x82C)) + 0x28);
	*pointer = menory;
}

/*
\ brief		这个是修改植物的CD冷却逻辑代码,直接修改程序运行代码
*/
void Plant::OnBnClickedPlant()
{
	// TODO: 在此添加控件通知处理程序代码
	// 将00487296 | 7E 14  | jle plantsvszombies.4872AC  处代码 修改成 9090
	UpdateData(TRUE);
	UCHAR buf[2] = {};
	if (plantCD) {
		buf[0] = 0x90;
		buf[1] = 0x90;
	}
	else {
		buf[0] = 0x7E;
		buf[1] = 0x14;
	}
	// 只能使用这个 函数来进行代码段的修改,直接 使用指针会使程序崩溃,哪怕是在同一个进程
	::WriteProcessMemory(::GetCurrentProcess(), 
							 LPVOID(0x00487296),
							 buf, 
							 sizeof(buf),
							 NULL);
}


/*
\ brief		这个是修改大嘴花的吞噬冷却逻辑
*/
void Plant::OnBnClickedFlower()
{
	// TODO: 在此添加控件通知处理程序代码
	//  将 0046324C 处代码 0046324C | 83C0 FF | add eax,FFFFFFFF  
	//  修改成 0046324C | 33C0 90 | 		 xor eax,eax  nop	
	UpdateData(TRUE);
	UCHAR buf[3] = {};
	if (flowerCd) {
		buf[0] = 0x33;
		buf[1] = 0xC0;
		buf[2] = 0x90;
	}
	else {
		buf[0] = 0x83;
		buf[1] = 0xC0;
		buf[2] = 0xFF;
	}
	// 只能使用这个 函数来进行代码段的修改,直接 使用指针会使程序崩溃,哪怕是在同一个进程
	::WriteProcessMemory(::GetCurrentProcess(), 
							 LPVOID(0x0046324C),
							 buf, 
							 sizeof(buf),
							 NULL);
}

/*
\ brief		按放樱花炸弹
\ param		x 轴坐标 0-8
\ param		y 轴坐标 0-8
*/
void Plant::Bom(int x, int y)
{
// 这个是汇编代码,调用 游戏的植物按放call
	_asm
	{
		pushad	
		push 0xFFFFFFFF
		push 2
		mov eax, y
		push x
		mov ebx, ds: [0x6A9EC0]
		mov ebx, ds : [ebx + 0x768]
		push ebx
		mov edx, 0x40D120;
		call edx	
		popad
	}
}
/*
\ brief		满屏樱花炸弹
*/
void Plant::OnBnClickedBtnBom()
{
	// TODO: 在此添加控件通知处理程序代码
	for (int i = 0; i < 9; ++i) {
		for (int j = 0; j < 9; ++j) {
			Bom(i, j);
		}
	}
}


看一下实际运行测试:

先启动,植物大战僵尸游戏程序(PlantsVsZombies.exe),然后启动注入程序(Grammar.exe)。
运行效果
运行效果
我们可以使用工具查看一下,是否成功注入到植物大战僵尸进程中
pe
已经成功注入到,植物大战僵尸进程中了。

接下来就是测试下,动态库效果。

测试
可以看到,阳关的数量,和金币的数量已经修改了,植物的冷却已已经完毕,是没有问题的。

接下来测试,樱花炸弹 全屏轰炸效果
樱花炸弹

没有问题。
文章时间2019年12月20日15:41:54

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值