概述
所谓动态库注入是指,将自己编写的动态库,通过自己的程序来注入到别的进程中去,然后运行。
原理:
在目标进程,开辟一段内存,然后写入要注入的动态库.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直接创建出来
动态库的核心代码
// 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)。
运行效果
我们可以使用工具查看一下,是否成功注入到植物大战僵尸进程中
已经成功注入到,植物大战僵尸进程中了。
接下来就是测试下,动态库效果。
可以看到,阳关的数量,和金币的数量已经修改了,植物的冷却已已经完毕,是没有问题的。
接下来测试,樱花炸弹 全屏轰炸效果
没有问题。
文章时间2019年12月20日15:41:54
最后
以上就是文静白云为你收集整理的WIN动态库注入(远线程注入)的全部内容,希望文章能够帮你解决WIN动态库注入(远线程注入)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复