概念
- 远程线程:另一个进程中的线程。
- 注入:别的进程中执行自己的代码
- 远程线程注入:指一个进程在另一个进程中创建线程的技术
设计思路
在DLL的dllmain里写自己的代码,利用系统共享库(系统dll是所有进程共享)的函数动态加载自己的DLL,来运行自己的代码,系统dll里面的LoadLiabrary函数地址在不同进程中的地址是相同的,把这个地址当做远程线程的函数回调,那线程执行的就是这个api,在给这个api传入自己的dll地址,那加载的就是自己的dll了,自然而然的就可以执行自己的代码
- DLL加载
- 获取LoadLiabrary的地址
- 在目标进程申请内存,写入dll的路径,
- 创建远程线程
DLL代码就是想要执行的代码,我的代码就是替换计算器的窗口处理函数
LONG g_oldProc = NULL;
LRESULT CALLBACK MyPro(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_COMMAND)
{
//如果键盘输入的是7就弹框
if (LOWORD(wParam) == 0x83)
{
MessageBox(hWnd, TEXT("按键hook"), TEXT("提示"), MB_OK);
}
}
return CallWindowProc((WNDPROC)g_oldProc, hWnd, Msg, wParam, lParam);
}
void AddMyWinPro()
{
//查找窗口句柄
HWND hWnd = FindWindow(TEXT("SciCalc"), NULL);
//替换消息窗口函数
g_oldProc = SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyPro);
}
void OldWinPro()
{
//查找窗口句柄
HWND hWnd = FindWindow(TEXT("SciCalc"), NULL);
//还原处理
if (g_oldProc != NULL)
{
g_oldProc = SetWindowLong(hWnd, GWL_WNDPROC, (LONG)g_oldProc);
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AddMyWinPro();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
OldWinPro();
break;
}
return TRUE;
}
//注入计算器
//1. 查找窗口
HWND hWnd = ::FindWindow(NULL, _T("计算器"));//通过窗口名获取该窗口的句柄
if (hWnd == NULL)
{
AfxMessageBox(_T("计算器没有运行"));
return;
}
//获取目标进程ID,
DWORD dwProcessId;
::GetWindowThreadProcessId(hWnd, &dwProcessId);
//获取目标进程ID
//UINT dwProcId = GetDlgItemInt(IDC_PROCID);
HANDLE hProces = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwProcessId);
//1获取loadliabrary的地址
//两个进程在kernel32.dll中的loadliabraryA地址映射是一样的,所以在自己进程中获取地址是一样获取到目标进程的loadliabraryA地址
HMODULE hModKer32 = GetModuleHandle(_T("kernel32"));
LPVOID pLoadLibrary = GetProcAddress(hModKer32, "LoadLibraryA");
if (pLoadLibrary == NULL)
{
AfxMessageBox(_T("获取LoadLibraryA地址失败"));
return;
}
// 2) 在目标进程申请内存,写入dll的路径,
//因为两个进程是独立地址空间,如果你传的参数是本进程的地址,目标进程运行时找的地址肯定是错误的
LPVOID pDllPathOfDstProc =
VirtualAllocEx(
hProces,
NULL, //系统自动分配地址
0x1000, //申请内存大小
MEM_COMMIT, //物理映射
PAGE_READWRITE //可读可写
);
if (pDllPathOfDstProc == NULL)
{
AfxMessageBox(_T("申请内存失败"));
return;
}
char szBuff[] = { "D:\\vs2013Code\\远程线程注入\\Debug\\dll.dll" };
DWORD dwBytestToWrite = 0;
BOOL bRet = WriteProcessMemory(
hProces,
pDllPathOfDstProc,//写入内存的首地址
szBuff,
sizeof(szBuff),
&dwBytestToWrite);
if (!bRet)
{
AfxMessageBox(_T("写入路径失败"));
return;
}
// 3) 创建远程线程,目标进程创建了一个线程,执行目标线程的线程回调函数
m_hRemoteThread = CreateRemoteThread(
hProces,
NULL,
0,
(LPTHREAD_START_ROUTINE)pLoadLibrary, //在目标进程中的回调函数的地址
pDllPathOfDstProc,//此时内存存放的是dll,这时候调用pLoadLibrary线程回调函数就会把dll当做参数传进去,就把dll加载进去了,
0,
NULL);
if (m_hRemoteThread == NULL)
{
AfxMessageBox(_T("远程线程创建失败"));
}
else
{
AfxMessageBox(_T("远程线程创建成功"));
}
- DLL卸载
- 获取模块句柄
- 获取freelibrary的地址
- 创建远程线程
// 1) 获取模块句柄
HANDLE hRemoteDll = NULL;
GetExitCodeThread(m_hRemoteThread, (DWORD*)&hRemoteDll);//LoadLibraryA的退出码就是加载的DLL模块句柄
// 2) 获取freelibrary的地址
HMODULE hModKer32 = GetModuleHandle("kernel32");
LPVOID pfnFreeLibrary = GetProcAddress(hModKer32, "FreeLibrary");
if (pfnFreeLibrary == NULL)
{
AfxMessageBox("获取LoadLibraryA地址失败");
return;
}
// 3) 创建远程线程
UINT dwProcId = GetDlgItemInt(EDT_PROCID);
HANDLE hProces = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwProcId);
m_hRemoteThread = CreateRemoteThread(
hProces,
NULL,
0,
(LPTHREAD_START_ROUTINE)pfnFreeLibrary, //在目标进程中的回调函数的地址
hRemoteDll,
0,
NULL);
if (m_hRemoteThread == NULL)
{
AfxMessageBox("远程线程创建失败");
}
else
{
AfxMessageBox("远程线程创建成功");
}