网上确实有关于DLL注入的过程,但是很多写的都不全,或者内容有点老旧。
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "windows.h"
#include
#include
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
// 当DLL被进程 <<第一次>> 调用时,导致DllMain函数被调用,
// 同时ul_reason_for_call的值为DLL_PROCESS_ATTACH,
// 如果同一个进程后来再次调用此DLL时,操作系统只会增加DLL的使用次数,
// 不会再用DLL_PROCESS_ATTACH调用DLL的DllMain函数。
// 获取窗口对象
HWND hwnd = GetActiveWindow();
MessageBox(hwnd, L"DLL已进入目标进程。", L"信息", MB_ICONINFORMATION);
}
}
return TRUE;
}
这里就很好办了
创建MFC 应用,注意,如果没有的话,点击【工具】-【获取工具和功能】
MFC 应用程序的使用方法这里不详细说明了。
建立好MFC应用程序后,打开资源文件
在注入之前,你需要获得被注入程序的相关信息。通过SPY++获取(VS的内置工具)
拖拽【查找程序窗口工具】到记事本窗口窗顶
自动显示相关的内容
以下是注入程序的内容(写在与Button绑定的事件函数中)
// m_StrDLLPath 为DLL文件的绝对路径,例如CString m_StrDLLPath(L"D:\\桌面\\testDLL.DLL")
if (m_StrDLLPath.IsEmpty()) {
MessageBox(_T("请选择DLL模块"));
return;
}
// :: 代表全局查找,后面的内容可以通过SPY++获取
// 【参数1】类
// 【参数2】标题
HWND hwnd = ::FindWindow(L"Notepad++", L"D:\\桌面\\新建文本文档 (2).txt - Notepad++");
if (hwnd == NULL) {
MessageBox(L"没有找到");
return;
}
// 获取窗口所在的PID
DWORD dwPID = 0;
GetWindowThreadProcessId(hwnd, &dwPID);
if (dwPID == 0) {
MessageBox(L"获取PID失败");
return;
}
// 通过PID获取进程的句柄
// 获取句柄后,可以完全控制进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
if (hProcess == NULL) {
MessageBox(L"进程的句柄获取失败");
return;
}
// TerminateProcess(hProcess, 0);//关闭句柄对象
// 实现注入
// 1.首先要提升权限,打开进程的访问令牌
// 【参数1】当前程序
// 【参数2】权限,可添加的权限|可查询的权限
HANDLE hToken;
if (FALSE == OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
// 权限修改失败
MessageBox(L"权限修改失败");
return;
}
//2.查看与进程相关的特权信息
LUID luid;
if (FALSE == LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
// 特权信息查询失败
MessageBox(L"特权信息查询失败");
return;
};
//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)) {
// 提升特权失败
MessageBox(L"提升特权失败");
return;
};
//在远程进程中申请内存空间
// 【参数1】程序的句柄对象
// 【参数2】申请的内存地址,由系统分配,所以为NULL
// 【参数3】申请的内存长度
// 【参数4】调用物理存储器
// 【参数5】这块内存可读可写,可执行
// 【返回】申请到的地址
LPVOID lpAddr = VirtualAllocEx(hProcess, NULL, m_StrDLLPath.GetLength() * 2+2,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (lpAddr == NULL) {
// 在远程进程中申请内存失败
MessageBox(L"在远程进程中申请内存失败");
return;
}
// 把DLL路径写入到远程进程中
// 强行修改程序的内存
// 【参数1】程序的句柄
// 【参数2】申请到的内存首地址
// 【参数3】写入的内容
// 【参数4】要写入的字节数
// 【参数5】
if (FALSE == WriteProcessMemory(hProcess, lpAddr, m_StrDLLPath, m_StrDLLPath.GetLength() * 2, NULL)) {
// 在远程进程中写入数据失败
MessageBox(L"在远程进程中写入数据失败");
return;
};
// 调用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 hThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAssr, lpAddr, 0, NULL);
if (hThread == NULL) {
// 创建远程线程失败
MessageBox(L"创建远程线程失败");
return;
}
MessageBox(L"注入成功");
#include
#include
#include
#include
using namespace std;
///
/// 根据进程名称获取进程信息
///
///
///
///
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;
}
///
/// 注入DLL文件
///
/// DLL文件的全路径
/// 要注入的程序的PID
///
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);
}
int main()
{
PROCESSENTRY32 info;
if (getProcess32Info(&info, L"EditPlus.exe"))
{
// 24
InjectDLL(L"F:\\Dll1.dll", info.th32ProcessID);//这个dll你所要注入的dll文件,这个"数字"是你想注入的进程的PID号
}
else {
cout << "查找失败" << endl;
}
return 0;
}
#include
#include
#include
#include
using namespace std;
///
/// 根据进程名称获取进程信息
///
///
///
///
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;
}
BOOL ZwCreateThreadExInjectDll(DWORD dwProcessId, const wchar_t* pszDllFileName)
{
int pathSize = (wcslen(pszDllFileName) + 1) * sizeof(wchar_t);
// 1.打开目标进程
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS, // 打开权限
FALSE, // 是否继承
dwProcessId); // 进程PID
if (NULL == hProcess)
{
cout << L"打开目标进程失败!" << endl;
return FALSE;
}
// 2.在目标进程中申请空间
LPVOID lpPathAddr = VirtualAllocEx(
hProcess, // 目标进程句柄
0, // 指定申请地址
pathSize, // 申请空间大小
MEM_RESERVE | MEM_COMMIT, // 内存的状态
PAGE_READWRITE); // 内存属性
if (NULL == lpPathAddr)
{
cout << L"在目标进程中申请空间失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
// 3.在目标进程中写入Dll路径
if (FALSE == WriteProcessMemory(
hProcess, // 目标进程句柄
lpPathAddr, // 目标进程地址
pszDllFileName, // 写入的缓冲区
pathSize, // 缓冲区大小
NULL)) // 实际写入大小
{
cout << L"目标进程中写入Dll路径失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
//4.加载ntdll.dll
HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
if (NULL == hNtdll)
{
cout << L"加载ntdll.dll失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
//5.获取LoadLibraryA的函数地址
//FARPROC可以自适应32位与64位
FARPROC pFuncProcAddr = GetProcAddress(GetModuleHandle(L"Kernel32.dll"),
"LoadLibraryW");
if (NULL == pFuncProcAddr)
{
cout << L"获取LoadLibrary函数地址失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
//6.获取ZwCreateThreadEx函数地址,该函数在32位与64位下原型不同
//_WIN64用来判断编译环境 ,_WIN32用来判断是否是Windows系统
#ifdef _WIN64
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnkown
);
#else
typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD dw1,
DWORD dw2,
LPVOID pUnkown
);
#endif
typedef_ZwCreateThreadEx ZwCreateThreadEx =
(typedef_ZwCreateThreadEx)GetProcAddress(hNtdll, "ZwCreateThreadEx");
if (NULL == ZwCreateThreadEx)
{
cout << L"获取ZwCreateThreadEx函数地址失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
//7.在目标进程中创建远线程
HANDLE hRemoteThread = NULL;
DWORD dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL,
hProcess,
(LPTHREAD_START_ROUTINE)pFuncProcAddr, lpPathAddr, 0, 0, 0, 0, NULL);
if (NULL == hRemoteThread)
{
cout << L"目标进程中创建线程失败!" << endl;
CloseHandle(hProcess);
return FALSE;
}
// 8.等待线程结束
WaitForSingleObject(hRemoteThread, -1);
// 9.清理环境
VirtualFreeEx(hProcess, lpPathAddr, 0, MEM_RELEASE);
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
FreeLibrary(hNtdll);
return TRUE;
}
const wchar_t dllPath[] = L"F:\\Dll1.dll";
int main()
{
PROCESSENTRY32 info;
// 查找指定进程名的PID
if (getProcess32Info(&info, L"EditPlus.exe"))
{
// 进程标识符PID。
ZwCreateThreadExInjectDll(info.th32ProcessID, dllPath);
cout << "注入成功" << endl;
}
else {
cout << "注入失败" << endl;
}
}