在这里将写一个简单的MFC程序,此MFC将把一个dll插入到一个目标进程(也叫靶子)中。
原理很简单,就是通过目标(靶子)窗口的类名,找到这个目标的进程,再动态地将dll插入其中。
要实现此效果也并不复杂,就算是刚接触vc的也可以完成此程序。(比较复杂的是插入代码的原理)
一、主程序
1、新建一个MFC项目,类型选择基于对话框
2、写一个简单的窗体
点击启动事件
MessageBox(L"调用Dll到程序中成功。");
二、要调用的Dll
1、新建一个win32dll
这个wiin32就是要被插入(注入)的dll。
选择dll、勾选导出符号
1、生成Dll项目
此时会在主程序Main的debug文件夹中生成了Dll.dll和Dll.lib文件
三、配置主程序Main的属性
1、选择链接器——输入——附加依赖项:Dll.lib
1、选择连接器——输入——常规——附加库目录:..\Debug
1、包含头文件。
选择属性——C/C++——附加包含目录:..\..\Dll
然后在主程序的MainDlg.cpp类中加入包含Dll的头文件#include "Dll.h"
再在启动按钮点击时调用一下Dll中的一个函数fnDll
fnDll();
启动程序点击启动
使用PCHunter64.exe查看进程
看到Dll.dll已经在此程序中被调用了。
PCHunterFree下载地址:http://download.csdn.net/detail/u014175572/9500637
以上所做的一切只是为了示范如何用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的进程中。
spy下载地址:http://download.csdn.net/detail/qq_34771394/9500751
1、根据路径再调节一下C/C++包含目录,路径是一个很麻烦的问题,我这里的开发环境需要改一下路径,不同的环境配置的路径都可能会有所不同,这里需要酌情调整。
再启动程序查看靶子进程,Dll.dll已经加入到了目标的进程中
这样,自定义的dll就成功地插入到了靶子(QQ)中。