C++ dll注入
2022-07-02
编译环境:Unicode字符集
编译代码:
#include <windows.h>
#include <iostream>
#include <Tlhelp32.h>
#include <string>
#include <string.h>
#include <stdio.h>
using namespace std;
/// <summary>
/// 根据进程名称获取进程信息
/// </summary>
/// <param name="info"></param>
/// <param name="processName"></param>
/// <returns></returns>
BOOL getProcess32Info(PROCESSENTRY32* info, const TCHAR processName[])
{
HANDLE handle; //定义CreateToolhelp32Snapshot系统快照句柄
handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);//获得系统快照句柄
//PROCESSENTRY32 结构的 dwSize 成员设置成 sizeof(PROCESSENTRY32)
info->dwSize = sizeof(PROCESSENTRY32);
//调用一次 Process32First 函数,从快照中获取进程列表
Process32First(handle, info);
//重复调用 Process32Next,直到函数返回 FALSE 为止
while (Process32Next(handle, info) != FALSE)
{
if (wcscmp(processName, info->szExeFile) == 0)
{
return TRUE;
}
}
return FALSE;
}
/// <summary>
/// 注入DLL文件
/// </summary>
/// <param name="DllFullPath">DLL文件的全路径</param>
/// <param name="dwRemoteProcessId">要注入的程序的PID</param>
/// <returns></returns>
BOOL InjectDLL(const wchar_t* DllFullPath, const DWORD dwRemoteProcessId)
{
// 计算路径的字节数
int pathSize = (wcslen(DllFullPath) + 1) * sizeof(wchar_t);
// 获取句柄后,可以完全控制进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId);
if (hProcess == NULL) {
cout << "获取句柄失败" << endl;
return FALSE;
}
// TerminateProcess(hProcess, 0);//关闭句柄对象
// 实现注入
// 1.首先要提升权限,打开进程的访问令牌
// 【参数1】当前程序
// 【参数2】权限,可添加的权限|可查询的权限
HANDLE hToken;
if (FALSE == OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY, &hToken)) {
// 权限修改失败
cout << "权限修改失败" << endl;
return FALSE;
}
//2.查看与进程相关的特权信息
LUID luid;
if (FALSE == LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
// 特权信息查询失败
cout << "特权信息查询失败" << endl;
return FALSE;
};
//3.调节进程的访问令牌的特权属性
// 这几行代码固定不变
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 打开特权
// 【参数1】访问令牌
// 【参数2】是否禁用特权
// 【参数3】新特权所占的字节数
// 【参数4】原来的特权是否需要保存
// 【参数5】原特权的长度
if (FALSE == AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
{
// 提升特权失败
cout << "提升特权失败" << endl;
return FALSE;
};
//在远程进程中申请内存空间
// 【参数1】程序的句柄对象
// 【参数2】申请的内存地址,由系统分配,所以为NULL
// 【参数3】申请的内存长度
// 【参数4】调用物理存储器
// 【参数5】这块内存可读可写,可执行
// 【返回】申请到的地址
LPVOID lpAddr = VirtualAllocEx(hProcess, NULL, pathSize, MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (lpAddr == NULL) {
// 在远程进程中申请内存失败
cout << "在远程进程中申请内存失败" << endl;
return FALSE;
}
// 把DLL路径写入到远程进程中
// 强行修改程序的内存
// 【参数1】程序的句柄
// 【参数2】申请到的内存首地址
// 【参数3】写入的内容
// 【参数4】要写入的字节数
// 【参数5】
if (FALSE == WriteProcessMemory(hProcess, lpAddr, DllFullPath,
pathSize, NULL)) {
// 在远程进程中写入数据失败
cout << "在远程进程中写入数据失败" << endl;
return FALSE;
};
// 调用Kernel32.dll中的LoadLibraryW方法用以加载DLL文件
PTHREAD_START_ROUTINE pfnStartAssr =
(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32.dll"),
"LoadLibraryW");
// 在远程进程中开辟线程
// 【参数1】远程线程的句柄
// 【参数2】线程属性。NULL表示使用默认属性
// 【参数3】堆栈大小。0代表默认
// 【参数4】加载DLL文件的对象
// 【参数5】加载文件的路径
// 【参数6】延迟时间。0代表立即启动
// 【参数7】线程ID。为NULL就行了
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAssr, lpAddr, 0,
NULL);
if (hRemoteThread == NULL) {
// 创建远程线程失败
cout << "创建远程线程失败" << endl;
// 释放内存
VirtualFreeEx(hProcess, lpAddr, 0, MEM_FREE);
return FALSE;
}
cout << "注入成功" << endl;
// 等待线程结束
WaitForSingleObject(hRemoteThread, -1);
// 关闭线程
CloseHandle(hRemoteThread);
// 释放内存
VirtualFreeEx(hProcess, lpAddr, 0, MEM_FREE);
}
/*Char*转TCHAR*/
LPWSTR ConvertCharToLPWSTR(const char* szString)
{
int dwLen = strlen(szString) + 1;
int nwLen = MultiByteToWideChar(CP_ACP, 0, szString, dwLen, NULL, 0);//算出合适的长度
LPWSTR lpszPath = new WCHAR[dwLen];
MultiByteToWideChar(CP_ACP, 0, szString, dwLen, lpszPath, nwLen);
return lpszPath;
}
int main()
{
cout << "请输入窗口标题:";
string title;
cin >> title;
cout << "请输入DLL路径:";
string path;
cin >> path;
HWND hWnd;
LPCWSTR newititle = ConvertCharToLPWSTR(title.c_str());
hWnd = FindWindow(NULL, newititle);//根据窗口标题获取窗口句柄
DWORD PID;
GetWindowThreadProcessId(hWnd, &PID);//存入PID
LPCWSTR newipath = ConvertCharToLPWSTR(path.c_str());
InjectDLL(newipath, PID);//这个dll你所要注入的dll文件,这个"数字"是你想注入的进程的PID号
while (true);
}
发表评论: