前阵子读到一篇关于《HOOK API入门之Hook自己程序的MessageBoxW》的博客,博客地址:http://blog.csdn.net/friendan/article/details/12222651,感觉写的很好但这篇博客主要讲的是本进程(本程序)的API HOOK那么如何将DLL注入到远程进程并进行API HOOK呢,好了废话不多说直接动手实践。

创建DLL动态库(我是在vs2008上实现的)

新建项目

创建一个名为MyDLL(名字随便)win32项目(我创建的是win32  DLL)点击确定

选择下一步

选择DLL,并点击完成

完成后到这个界面选择源文件中的dllmain.cpp如下图

这样就已经创建好一个DLL了,创建好了应该在里面做点什么吧,那么下面我们就动手实践吧:)。

我们这次HOOK的依然是MessageBoxW这个API。

直接上代码:

 #include "stdafx.h"

 //原函数类型定义
typedef int (WINAPI* MsgBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
MsgBoxW OldMsgBoxW = NULL;//指向原函数的指针
FARPROC pfOldMsgBoxW; //指向函数的远指针
BYTE OldCode[]; //原系统API入口代码
BYTE NewCode[]; //原系统API新的入口代码(jmp xxxxxxxx) HANDLE hProcess = NULL;//本程序进程句柄
HINSTANCE hInst = NULL;//API所在的dll文件句柄 void HookOn();
void HookOff();
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的
//如果不恢复HOOK,就调用原函数,会造成死循环
//毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。 int nRet = ::MessageBoxW(hWnd, L"哈哈,MessageBoxW被HOOK了", lpCaption, uType); HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到。 return nRet;
} //开启钩子的函数
void HookOn()
{
if ( NULL == hProcess)
{
return;
} DWORD dwTemp=;
DWORD dwOldProtect; //修改API函数入口前个字节为jmp xxxxxx
VirtualProtectEx(hProcess,pfOldMsgBoxW,,PAGE_READWRITE,&dwOldProtect);
WriteProcessMemory(hProcess,pfOldMsgBoxW,NewCode,,);
VirtualProtectEx(hProcess,pfOldMsgBoxW,,dwOldProtect,&dwTemp); } //关闭钩子的函数
void HookOff()
{
if ( NULL == hProcess)
{
return;
} DWORD dwTemp=;
DWORD dwOldProtect; //恢复API函数入口前个字节
VirtualProtectEx(hProcess, pfOldMsgBoxW, , PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, pfOldMsgBoxW, OldCode, , );
VirtualProtectEx(hProcess, pfOldMsgBoxW, , dwOldProtect, &dwTemp);
} //获取API函数入口前个字节
//旧入口前个字节保存在前面定义的字节数组BYTE OldCode[5]
//新入口前个字节保存在前面定义的字节数组BYTE NewCode[5]
void GetApiEntrance()
{ //获取原API入口地址
HMODULE hmod = ::LoadLibrary( L"User32.dll" );
OldMsgBoxW = (MsgBoxW)::GetProcAddress(hmod, "MessageBoxW");
pfOldMsgBoxW = (FARPROC)OldMsgBoxW; if (NULL == pfOldMsgBoxW)
{
MessageBox(NULL, L"获取原API入口地址出错", L"error!", );
return;
} // 将原API的入口前个字节代码保存到OldCode[]
_asm
{
lea edi,OldCode //获取OldCode数组的地址,放到edi
mov esi,pfOldMsgBoxW //获取原API入口地址,放到esi
cld //方向标志位,为以下两条指令做准备
movsd //复制原API入口前个字节到OldCode数组
movsb //复制原API入口第个字节到OldCode数组
} NewCode[]=0xe9;//实际上xe9就相当于jmp指令 //获取MyMessageBoxW的相对地址,为Jmp做准备
//int nAddr= UserFunAddr –SysFunAddr - (我们定制的这条指令的大小);
//Jmp nAddr;
//(我们定制的这条指令的大小), 这里是,个字节嘛
_asm
{
lea eax,MyMessageBoxW //获取我们的MyMessageBoxW函数地址
mov ebx,pfOldMsgBoxW //原系统API函数地址
sub eax,ebx //int nAddr= UserFunAddr –SysFunAddr
sub eax, //nAddr=nAddr-5
mov dword ptr [NewCode+],eax //将算出的地址nAddr保存到NewCode后面个字节
//注:一个函数地址占个字节
} //填充完毕,现在NewCode[]里的指令相当于Jmp MyMessageBoxW
//既然已经获取到了Jmp MyMessageBoxW
//现在该是将Jmp MyMessageBoxW写入原API入口前个字节的时候了
//知道为什么是个字节吗?
//Jmp指令相当于xe9,占一个字节的内存空间
//MyMessageBoxW是一个地址,其实是一个整数,占个字节的内存空间
//int n=0x123; n占个字节和MyMessageBoxW占个字节是一样的
//1+4=5,知道为什么是个字节了吧
HookOn();
} BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
DWORD dwPid=::GetCurrentProcessId();
hProcess=OpenProcess(PROCESS_ALL_ACCESS,,dwPid);
GetApiEntrance();
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
HookOff();
break;
}
return TRUE;
}

其中:

DWORD dwPid=::GetCurrentProcessId();

hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

这两行的作用是得到被注入DLL进程的进程句柄。

好了DLL库部分已经解决,那让我看看远程注入DLL到指定进程部分的代码吧。

在开始之前最好将DLL先编译出来,以便在下面的代码中使用。

我创建的win32控制台应用程序来测试。

直接上代码:)。

 // exe.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <time.h> BOOL InjectDllToRemoteProcess(const char* lpDllName, const char* lpPid, const char* lpProcName); int main(int argc, char* argv[])
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
BOOL fRet=CreateProcess(_T("C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\ASD.exe"),NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi);
//创建一个进程,这个进程可以是你自己写的MFC程序。 if (!fRet)
{
//创建进程失败
MessageBoxW(NULL,L"创建进程失败",L"error",MB_OK); } BOOL isInject = InjectDllToRemoteProcess("C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\MyDLL.dll", NULL , "ASD.exe");
// C:\\Users\\Administrator\\Desktop\\远程进程注入与HOOKapi例子\\exe\\MyDLL.dll这个的DLL的路径
// ASD.exe是要注入的进程名,可以写一个MFC对话框程序在上面添加个按钮点击按钮弹出MessageBox看看你的MessageBox是不是被HOOK住了 if (!isInject)
{
//注入远程进程失败
MessageBoxW(NULL,L"注入远程进程失败",L"error",MB_OK);
} while()
{ } return ;
}
//进程快照(枚举各进程)
BOOL GetPidByProcessName(LPCTSTR lpszProcessName , DWORD &dwPid)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, );
if ( INVALID_HANDLE_VALUE == hSnapshot )
{
return FALSE;
} PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if ( !Process32First(hSnapshot, &pe) )
{
::CloseHandle(hSnapshot);
return FALSE;
} while ( Process32Next(hSnapshot, &pe) )
{
if ( !_stricmp(lpszProcessName, pe.szExeFile) )
{
::CloseHandle(hSnapshot);
dwPid = pe.th32ProcessID;
return TRUE;
}
} ::CloseHandle(hSnapshot);
return FALSE;
} /********************************************************************************************************/ //注入DLL到远程进程
BOOL InjectDllToRemoteProcess(const char* lpDllName, const char* lpPid, const char* lpProcName)
{
DWORD dwPid = ;
if (NULL == lpPid || == strlen(lpPid))
{
if (NULL != lpProcName && != strlen(lpProcName))
{
if (!GetPidByProcessName(lpProcName, dwPid))
{
return FALSE;
}
}
else
{
return FALSE;
}
}
else
{
dwPid = atoi(lpPid);
} //根据Pid得到进程句柄(注意必须权限)
HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, dwPid);
if (INVALID_HANDLE_VALUE == hRemoteProcess)
{
return FALSE;
} //计算DLL路径名需要的内存空间
DWORD dwSize = ( + lstrlenA(lpDllName)) * sizeof(char); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区,成功返回分配内存的首地址.
LPVOID lpRemoteBuff = (char *)VirtualAllocEx(hRemoteProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (NULL == lpRemoteBuff)
{
CloseHandle(hRemoteProcess);
return FALSE;
} //使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间,成功返回TRUE.
DWORD dwHasWrite = ;
BOOL bRet = WriteProcessMemory(hRemoteProcess, lpRemoteBuff, lpDllName, dwSize, &dwHasWrite);
if (!bRet || dwHasWrite != dwSize)
{
VirtualFreeEx(hRemoteProcess, lpRemoteBuff, dwSize, MEM_COMMIT);
CloseHandle(hRemoteProcess);
return FALSE;
} //创建一个在其它进程地址空间中运行的线程(也称:创建远程线程),成功返回新线程句柄.
//注意:进程句柄必须具备PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE,和PROCESS_VM_READ访问权限
DWORD dwRemoteThread = ;
//LPTHREAD_START_ROUTINE pfnLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
//HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pfnLoadLibrary, lpRemoteBuff, 0, &dwRemoteThread);
HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, , (LPTHREAD_START_ROUTINE)LoadLibraryA, lpRemoteBuff, , &dwRemoteThread);
if (INVALID_HANDLE_VALUE == hRemoteThread)
{
VirtualFreeEx(hRemoteProcess, lpRemoteBuff, dwSize, MEM_COMMIT);
CloseHandle(hRemoteProcess);
return FALSE;
} //注入成功释放句柄
WaitForSingleObject(hRemoteThread, INFINITE);
CloseHandle(hRemoteThread);
CloseHandle(hRemoteProcess); //补充:卸载过程(有bug)
//准备卸载之前注入的Dll
//DWORD dwHandle, dwID;
//LPVOID pFunc = GetModuleHandleA; //获得在远程线程中被注入的Dll的句柄
//HANDLE hThread = CreateRemoteThread(hRemoteProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpRemoteBuff, 0, &dwID);
//WaitForSingleObject(hThread, INFINITE);
//GetExitCodeThread(hThread, &dwHandle); //线程的结束码即为Dll模块儿的句柄
//CloseHandle(hThread);
//pFunc = FreeLibrary;
//hThread = CreateRemoteThread(hThread, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &dwID); //将FreeLibraryA注入到远程线程中去卸载Dll
//WaitForSingleObject(hThread, INFINITE);
//CloseHandle(hThread);
//CloseHandle(hRemoteProcess); return TRUE;
}

代码的注释还是很清楚的,就不解释了。

最新文章

  1. LeetCode 119 Pascal&#39;s Triangle II
  2. 通俗理解T检验和F检验
  3. struts2学习笔记之四:多配置文件支持和常用配置参数
  4. sizeof操作符-结构体与类大小
  5. spark基本概念
  6. Git &amp; Github 一页简明笔记(转)main
  7. bzoj1417: Pku3156 Interconnect
  8. node &amp; grunt path处理相关
  9. HBase之CF持久化系列(续1)
  10. Spring-AOP 基于注解的实现
  11. Shader 屏幕后期特效 Shake(震屏)&amp;Wave(波纹)
  12. HDU 6336 Matrix from Arrays (杭电多校4E)
  13. H5调用本地摄像头[转]
  14. Postgres通用翻页函数
  15. [PHP] 算法-快速排序的PHP实现
  16. 【Java】 剑指offer(16) 打印1到最大的n位数
  17. day11 - 15(装饰器、生成器、迭代器、内置函数、推导式)
  18. Oracle12c中容错&amp;amp;性能新特性之表空间组
  19. locaton.href传参数
  20. java web 大文件下载

热门文章

  1. CodeForces 132C Logo Turtle (记忆化搜索)
  2. Tree(prime)
  3. 加濾鏡效果GlowTween
  4. 从头开始-07.Foundation框架常用结构体
  5. HTML——CSS样式表&amp;布局页面
  6. SET STATISTICS IO和SET STATISTICS TIME 在SQL Server查询性能优化中的作用
  7. Object-C 重载
  8. 【IOS学习基础】OC类的相关
  9. HDU 2473 - Junk-Mail Filter ,并查集的删点
  10. POJ 3279(Fliptile)题解