这个技术点真是让我煞费苦心
终于有所突破
没写完Mark
MyDll.cpp
// MyDll.cpp : 定义 DLL 的初始化例程。
//
#include "stdafx.h"
#include "MyDll.h"
#include "D3dx9tex.h"
HRESULT MyD3DXSaveSurfaceToFile(
_In_ LPCTSTR pDestFile,
_In_ D3DXIMAGE_FILEFORMAT DestFormat,
_In_ LPDIRECT3DSURFACE9 pSrcSurface,
_In_ const PALETTEENTRY *pSrcPalette,
_In_ const RECT *pSrcRect
);
typedef HRESULT(WINAPI* DXSave)(
_In_ LPCTSTR pDestFile,
_In_ D3DXIMAGE_FILEFORMAT DestFormat,
_In_ LPDIRECT3DSURFACE9 pSrcSurface,
_In_ const PALETTEENTRY *pSrcPalette,
_In_ const RECT *pSrcRect
);
DXSave OldMsgBoxW = NULL;//指向原函数的指针
FARPROC pfOldMsgBoxW; //指向函数的远指针
BYTE OldCode[5]; //原系统API入口代码
BYTE NewCode[5]; //原系统API新的入口代码 (jmp xxxxxxxx)
HANDLE hProcess = NULL;//本程序进程句柄
HINSTANCE hInst = NULL;//API所在的dll文件句柄
void HookOn();
void HookOff();
void GetApiEntrance();
void OnBnClickedBtnStartHook();
void OnBnClickedBtnCallMsgBox();
void OnBnClickedBtnStopHook();
void capture();
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//
//TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的,
// 则从此 DLL 导出的任何调入
// MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
// 该函数的最前面。
//
// 例如:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // 此处为普通函数体
// }
//
// 此宏先于任何 MFC 调用
// 出现在每个函数中十分重要。 这意味着
// 它必须作为函数中的第一个语句
// 出现,甚至先于所有对象变量声明,
// 这是因为它们的构造函数可能生成 MFC
// DLL 调用。
//
// 有关其他详细信息,
// 请参阅 MFC 技术说明 33 和 58。
//
// CMyDllApp
BEGIN_MESSAGE_MAP(CMyDllApp, CWinApp)
END_MESSAGE_MAP()
// CMyDllApp 构造
CMyDllApp theApp;
// CMyDllApp 初始化
BOOL CMyDllApp::InitInstance()
{
CWinApp::InitInstance();
return TRUE;
}
CMyDllApp::CMyDllApp()
{
capture();
}
void capture(){
DWORD dwPid = ::GetCurrentProcessId();
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);
GetApiEntrance();
}
void GetApiEntrance()
{
HMODULE hmod = ::LoadLibrary(_T("d3d9.dll"));
OldMsgBoxW = (DXSave)::GetProcAddress(hmod, "D3DXSaveSurfaceToFile");
pfOldMsgBoxW = (FARPROC)OldMsgBoxW;
if (pfOldMsgBoxW == NULL)
{
MessageBox(NULL, _T("获取原API入口地址出错"), _T("error!"), 0);
return;
}
_asm
{
lea edi, OldCode //获取OldCode数组的地址,放到edi
mov esi, pfOldMsgBoxW //获取原API入口地址,放到esi
cld //方向标志位,为以下两条指令做准备
movsd //复制原API入口前4个字节到OldCode数组
movsb //复制原API入口第5个字节到OldCode数组
}
NewCode[0] = 0xe9;//实际上0xe9就相当于jmp指令
_asm
{
lea eax, MyD3DXSaveSurfaceToFile //获取我们的MyMessageBoxW函数地址
mov ebx, pfOldMsgBoxW //原系统API函数地址
sub eax, ebx //int nAddr= UserFunAddr – SysFunAddr
sub eax, 5 //nAddr=nAddr-5
mov dword ptr[NewCode + 1], eax //将算出的地址nAddr保存到NewCode后面4个字节
//注:一个函数地址占4个字节
}
HookOn();
}
//开启钩子的函数
void HookOn()
{
ASSERT(hProcess != NULL);
DWORD dwTemp = 0;
DWORD dwOldProtect;
//修改API函数入口前5个字节为jmp xxxxxx
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, NewCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}
//关闭钩子的函数
void HookOff()
{
ASSERT(hProcess != NULL);
DWORD dwTemp = 0;
DWORD dwOldProtect;
//恢复API函数入口前5个字节
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, 5, 0);
VirtualProtectEx(hProcess, pfOldMsgBoxW, 5, dwOldProtect, &dwTemp);
}
HRESULT MyD3DXSaveSurfaceToFile(
_In_ LPCTSTR pDestFile,
_In_ D3DXIMAGE_FILEFORMAT DestFormat,
_In_ LPDIRECT3DSURFACE9 pSrcSurface,
_In_ const PALETTEENTRY *pSrcPalette,
_In_ const RECT *pSrcRect
)
{
HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的
//如果不恢复HOOK,就调用原函数,会造成死循环
::MessageBoxW(NULL,L"123",L"123",0);
//毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。
HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到。
return 0;
}
inject.cpp
#include "stdafx.h"
#include "Remote injection.h"
#include "tlhelp32.h"
using namespace std;
extern DWORD ListProcess(CString Name);
extern int EnableDebugPriv(const WCHAR *);
int _tmain(int argc, TCHAR *argv[], TCHAR *env[])
{
//为了成功使用CreateRemoteThread()函数,必须:
//1.利用OpenProcess()获得远程进程的句柄
//2.利用VirtualAllocEx(),WriteProcessMemory()写入DLL路径字符串
//3.获得远程进程中LoadLibrary()的确切地址
//输入进程ID获得进程句柄
DWORD dwRemoteProcessId;
if (argc == 2)
{
dwRemoteProcessId = ListProcess(argv[1]);
}
else{
printf("参数缺少要注入的进程名!\n");
return 0;
}
//如果输入“”表示向自身进程注入
if (dwRemoteProcessId == 0)
dwRemoteProcessId = GetCurrentProcessId();
//获得调试权限
if (EnableDebugPriv(SE_DEBUG_NAME))
{
printf("Add Privilege error\n");
return -1;
}
//调用OpenProcess()获得句柄
HANDLE hRemoteProcess;
if ((hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId)) == NULL)
{
printf("OpenProcess error\n");
printf("Error Code:%d\n", GetLastError());
system("pause");
return -2;
}
//在远程进程中分配内存,准备拷入DLL路径字符串
//取得当前DLL路径
char DllPath[260]; //Windows路径最大为
GetCurrentDirectoryA(260, DllPath); //获取当前进程执行目录
printf("Proces***e Directory is %s\n", DllPath);
strcat(DllPath, "\\..\\Debug\\MyDLL.dll"); //链接到DLL路径
LPVOID pRemoteDllPath = VirtualAllocEx(hRemoteProcess, NULL, strlen(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteDllPath == NULL)
{
printf("VirtualAllocEx error\n");
return -3;
}
//向远程进程空间中写入DLL路径字符串
printf("DllPath is %s\n", DllPath);
SIZE_T Size;
if (WriteProcessMemory(hRemoteProcess, pRemoteDllPath, DllPath, strlen(DllPath) + 1, &Size) == NULL)
{
printf("WriteProcessMemory error\n");
return -4;
}
printf("WriteRrmoyrProcess Size is %d\n\n", Size);
//获得远程进程中LoadLibrary()的地址
HMODULE hModule = GetModuleHandle(TEXT("kernel32.dll"));
printf("kernel32 Address : 0x%x\n\n", hModule);
LPTHREAD_START_ROUTINE pLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
if (pLoadLibrary == NULL)
{
printf("GetProcAddress error\n");
return -5;
}
else
{
printf("LoadLibrary's Address is 0x%x\n\n", pLoadLibrary);
}
//启动远程线程
DWORD dwThreadId;
HANDLE hThread;
hThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pLoadLibrary, pRemoteDllPath, 0, &dwThreadId);
if (hThread == NULL)
{
printf("CreateRemoteThread error\n");
return -6;
}
else
{
WaitForSingleObject(hThread, INFINITE);
printf("dwThreadId is %d\n\n", dwThreadId);
printf("Inject is done\n");
}
//释放分配内存
if (VirtualFreeEx(hRemoteProcess, pRemoteDllPath, 0, MEM_RELEASE) == 0)
{
printf("VitualFreeEx error\n");
return -8;
}
//释放句柄
if (hThread != NULL) CloseHandle(hThread);
if (hRemoteProcess != NULL) CloseHandle(hRemoteProcess);
system("pause");
return 0;
}
DWORD ListProcess(CString Name)
{
//获取系统快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //不要写错CreateToolhelp32Snapshot()
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
printf("CreateToolHelp32Snapshot error!\n");
return -1;
}
//创建单个进程快照结构体,初始化大小
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32); //务必提前初始化,否则默认的大小不一定满足要求
//初始化缓冲区
WCHAR buff[1024] = { 0 }; //PROCESSENTRY32中的szExeFile为WCHAR类型数组,此处应一致,使用Unicode码
//枚举系统快照链表中的第一个进程项目
BOOL bProcess = Process32First(hProcessSnap, &pe32);
while (bProcess)
{
//格式化进程名和进程ID,这里要使用printf的宽字符版
//格式字符串“”都需要用L转换为宽字符形式
if (pe32.szExeFile == Name){
wsprintf(buff, L"FileName:%-30sID:%-6d\r\n", pe32.szExeFile, pe32.th32ProcessID);
wprintf(L"%s\n", buff);
return pe32.th32ProcessID;
}
//缓冲区复位
memset(buff, 0, sizeof(buff));
//继续枚举下一个进程
bProcess = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return 0;
}
int EnableDebugPriv(const WCHAR *name)
{
HANDLE hToken; //进程令牌句柄
TOKEN_PRIVILEGES tp; //TOKEN_PRIVILEGES结构体,其中包含一个【类型+操作】的权限数组
LUID luid; //上述结构体中的类型值
//打开进程令牌环
//GetCurrentProcess()获取当前进程的伪句柄,只会指向当前进程或者线程句柄,随时变化
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
printf("OpenProcessToken error\n");
return -8;
}
//获得本地进程name所代表的权限类型的局部唯一ID
if (!LookupPrivilegeValue(NULL, name, &luid))
{
printf("LookupPrivilegeValue error\n");
}
tp.PrivilegeCount = 1; //权限数组中只有一个“元素”
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //权限操作
tp.Privileges[0].Luid = luid; //权限类型
//调整进程权限
if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
printf("AdjustTokenPrivileges error!\n");
return -9;
}
return 0;
}