MFC動態呼叫dll到指定的程序中(win7系統vs2013環境下)
在這裡將寫一個簡單的MFC程式,此MFC將把一個dll插入到一個目標程序(也叫靶子)中。
原理很簡單,就是通過目標(靶子)視窗的類名,找到這個目標的程序,再動態地將dll插入其中。
要實現此效果也並不複雜,就算是剛接觸vc的也可以完成此程式。(比較複雜的是插入程式碼的原理)
一、主程式
1、新建一個MFC專案,型別選擇基於對話方塊
2、寫一個簡單的窗體
點選啟動事件
MessageBox(L"呼叫Dll到程式中成功。");
二、要呼叫的Dll
1、新建一個win32dll
這個wiin32就是要被插入(注入)的dll。
選擇dll、勾選匯出符號
1、生成Dll專案
此時會在主程式Main的
三、配置主程式Main的屬性
1、選擇連結器——輸入——附加依賴項:Dll.lib
1、選擇聯結器——輸入——常規——附加庫目錄:..\Debug
1、包含標頭檔案。
選擇屬性——C/C++——附加包含目錄:..\..\Dll
然後在主程式的MainDlg.cpp類中加入包含Dll的標頭檔案#include "Dll.h"
再在啟動按鈕點選時呼叫一下Dll中的一個函式fnDll
fnDll();
啟動程式點選啟動
使用PCHunter64.exe檢視程序
看到Dll.dll已經在此程式中被呼叫了。
以上所做的一切只是為了示範如何用MFC呼叫dll(高手請無視上面的內容)。
接下來才是重點。下面將“找到目標程序”、“插入dll到目標程序中”在MFC程式啟動按鈕的點選事件中完成。
四、動態呼叫dll
1、先將屬性的連結器——輸入——附加依賴項刪除
把專案中剛呼叫的引用標頭檔案以及函式都遮蔽
1、引入注入的工具程式碼Injection.h到主程式的標頭檔案資料夾中以及Injection.cpp到原始檔夾中。
Injection.h內容如下:
#pragma once
HANDLE InjectProcess(DWORD dwProcessId, const WCHAR* szModuleName);
void UpdataToken();
Injection.cpp內容如下:
#include "stdafx.h"
#include "Injection.h"
HANDLE hAimProcess=NULL;
DWORD dAimProcessId=0;
HMODULE hKernel32=NULL;
HANDLE hInjectionThread=NULL;
PTHREAD_START_ROUTINE lpLoadLibraryAddress=NULL;
LPVOID lpParameter=NULL;
WCHAR wFilePath[MAX_PATH]={0};
size_t nPathLength=0;
HMODULE hInst=NULL;
HMODULE StartInjectionThread()
{
hInjectionThread=::CreateRemoteThread(hAimProcess,NULL,0,lpLoadLibraryAddress,lpParameter,0,NULL);
DWORD h = 0;
if(hInjectionThread){
::WaitForSingleObject(hInjectionThread,INFINITE);
::GetExitCodeThread(hInjectionThread,&h);
}
return (HMODULE)h;
}
void FreeSpace()
{
if(hInjectionThread!=NULL){
DWORD h=0;
::TerminateThread(hInjectionThread,h);
::CloseHandle(hInjectionThread);
::VirtualFreeEx(hAimProcess,lpParameter,nPathLength,MEM_DECOMMIT);
::CloseHandle(hAimProcess);
hInjectionThread=NULL;
}
}
void InitInjectionAddress()
{
nPathLength = (1 + wcslen(wFilePath)) * sizeof(WCHAR);
hKernel32 = GetModuleHandle(L"Kernel32.dll");
lpLoadLibraryAddress=(PTHREAD_START_ROUTINE)GetProcAddress(hKernel32,"LoadLibraryW");
}
BOOL AllocateMemToAimProcess()
{
lpParameter = VirtualAllocEx(hAimProcess,0,nPathLength,MEM_COMMIT,PAGE_READWRITE);
return WriteProcessMemory(hAimProcess,lpParameter,wFilePath,nPathLength,NULL);
}
void InitInjectionModulePath(const WCHAR* szModuleName)
{
GetModuleFileName(hInst,wFilePath,MAX_PATH);
int nLen = wcslen(wFilePath);
for(int i=nLen-1;i>-1;i--)
{
if(wFilePath[i]==L'\\')
{
for(int j=i+1;j<nLen;j++)
{
wFilePath[j]=0;
}
wcscat(wFilePath,szModuleName);
break;
}
}
}
HANDLE InjectProcess(DWORD dwProcessId, const WCHAR* szModuleName)
{
dAimProcessId = dwProcessId;
hAimProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);
InitInjectionModulePath(szModuleName);
InitInjectionAddress();
if(!AllocateMemToAimProcess())
{
return FALSE;
}
StartInjectionThread();
FreeSpace();
return hAimProcess;
}
void UpdataToken()
{
HANDLE hToken;
LUID DebugNameValue;
TOKEN_PRIVILEGES Privileges;
DWORD dwRet;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, L"SeDebugPrivilege", &DebugNameValue);
Privileges.PrivilegeCount=1;
Privileges.Privileges[0].Luid=DebugNameValue;
Privileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE,&Privileges, sizeof(Privileges), NULL, &dwRet);
CloseHandle(hToken);
}
此時編譯會出現一個錯誤警告
error C4996: 'wcscat': This function or variable may be unsafe. Consider using wcscat_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
只需要在在專案->屬性->C/C++->前處理器->前處理器定中新增_CRT_SECURE_NO_WARNINGS這個預定義。
1、加入呼叫Injection的函式
#include "Injection.h"
WCHAR czClassName[] = L"TXGuiFoundation";
WCHAR czWinName[] = L"陸周泉";
void CMainDlg::OnBnClickedOk()
{
// TODO: 在此新增控制元件通知處理程式程式碼
//CDialogEx::OnOK();
//fnDll();
MessageBox(L"程式啟動成功。");
DWORD procid = 0;
CWnd *pWnd = FindWindow(czClassName, NULL);
if (pWnd){
MessageBox(L"找到視窗");
GetWindowThreadProcessId(pWnd->m_hWnd, &procid);
if (procid){
//MessageBox(L"找到程序id");
UpdataToken();
if (InjectProcess(procid, L"Dll.dll"))
{
MessageBox(L"注入成功");
}
}
}
//MessageBox(L"呼叫Dll成功。");
}
void CMainDlg::OnBnClickedOk()就是MFC窗體中啟動按鈕的點選事件。
其中WCHAR czClassName[] = L"TXGuiFoundation";為類名,可以使用Spy4Win.exe軟體獲取
WCHAR czClassName[] 的值就是要插入的那個程序的類名,這個類名必須要知道。為何不用記憶體地址指標呢?記憶體地址是會改變,但視窗的類名很少變動。
這個類名你們可以根據需求自己獲取(獲取類名的工具有很多,這裡用的是spy),這裡我用QQ作為靶子程式,即把Dll插入到QQ的程序中。
1、根據路徑再調節一下C/C++包含目錄,路徑是一個很麻煩的問題,我這裡的開發環境需要改一下路徑,不同的環境配置的路徑都可能會有所不同,這裡需要酌情調整。
再啟動程式檢視靶子程序,Dll.dll已經加入到了目標的程序中
這樣,自定義的dll就成功地插入到了靶子(QQ)中。