Api拦截并不是一种新技术,在许多的商业软件中也使用了这一技术。主要使用的方法有
两种:一种就是《windows核心编程》中介绍的修改PE文件的输入节,这种方法很安全,不过
有些麻烦,还有个缺点就是有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到
的情况。第二种方法就是古老而又实用的jmp XXXX技术。
先讲一讲我们使用jmp的思路:
1. 先找到系统代码在进程空间中的起始位置
2. 然后我们写jmp "我们的代码" 的机器指令到系统代码的超始位置
3. 这样系统在调用api之前,就会先执行我们的代码
下来我们给出一些关键代码来具体说明一下:
1. 得到系统代码的位置,保存原始的系统机器码:
BYTE SysCode[5]; //机器指令占1B,32位指针(DWORD)占4B
HMODULE hMod = GetModuleHandle( m_MoudleName );
m_SysApi = (void*)GetProcAddress(hMod , m_SysApiName);
memcpy( SysCode, m_SysApi, sizeof(SysCode) );
2. 构造我们的jmp机器指令:
BYTE JmpCode[5];
/* 计算jmp指令的偏移地址: offset = userfun-sysfun-5 */
JmpCode[0] = 0xE9; //jmp的机器指令
*(DWORD*)(JmpCode+1) = (DWORD)((LONG)m_UserApi-(LONG)m_SysApi-5); //这儿是DWORD
3. 写跳转指令
bRet = WriteProcessMemory( GetCurrentProcess(),
(LPVOID)m_SysApi, (LPVOID)JmpCode, m_CodeLength ,NULL);
4. ok,到这儿,我们就完成了拦截过程,有点要注意的是我们拦截函数的写法:
首先,拦截函数的定义要和目标函数相同,最起码在数据类型上要兼容,主要是指参数的
个数和参数类型的长度要一致!
下面是个例子:
int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags)
{
int ret=0;
if (ah3.isHooked)
{
ah3.HookOff(); //先写回系统的代码,不然就是死循环!!!
ret = recv(s,buf,len,flags);
ah3.SetJumpCode();
WriteBufferToFile("c://hook_recv",buf,len);
return ret;
}
return 0;
}
5. 一点小问题:在win2k里面,系统在装载DLL时是同进程在同一个空间,所以这时的拦截
只是拦截目标进程中的api,不影响系统的api;但在win9x中拦截的却是整个系统的api。
6. ok,我们把我们的拦截函数写成一个DLL,再按照《远程线程技术(一)》中的方法,写一个
挂接程序,把我们的DLL挂接到目标进程中去,就可以了!!
=============================================================================
下面给出完整的源代码(调试环境:VC6+W2k):
//
// ApiHook.h: interface for the CApiHook class.
// by ssssss24cn@hotmail.com 2003.07.24
//
#if !defined(AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_)
#define AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <windows.h>
class CApiHook
{
public:
BOOL HookOff();
BOOL HookOn(const char *szModName, const char *szFunName, void* userfun);
BOOL SetJumpCode();
CApiHook();
virtual ~CApiHook();
public:
BOOL isHooked;
private:
BOOL SaveSysCode();
void InitJmpCode();
private:
int m_CodeLength;
void *m_UserApi; //指向用户函数的指针
void *m_SysApi; //指向系统函数的指针
char m_MoudleName[30]; //目标模块
char m_SysApiName[80]; //目标函数
BYTE SysCode[5]; //存放原来的系统机器码
BYTE JmpCode[5]; //存放跳转指令的机器码
};
#endif // !defined(AFX_APIHOOK_H__F7B7A124_D1EA_407F_B199_8592E86D5FEC__INCLUDED_)
//
// ApiHook.cpp: implementation of the CApiHook class.
// by ssssss24cn@hotmail.com 2003.07.24
//
#include "stdafx.h"
#include "ApiHook.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CApiHook::CApiHook()
{
isHooked = FALSE;
JmpCode[0]=0x00;
SysCode[0]=0x00;
m_CodeLength=sizeof(BYTE)*5;
m_SysApi=NULL;
m_UserApi=NULL;
}
CApiHook::~CApiHook()
{
}
BOOL CApiHook::HookOn(const char *szModName, const char *szFunName, void *userfun)
{
if (!szModName) return FALSE;
if (!szFunName) return FALSE;
/
memcpy(m_MoudleName,szModName,strlen(szModName)+1);
memcpy(m_SysApiName,szFunName,strlen(szFunName)+1);
m_UserApi = userfun;
/
//保存系统原始机器码
if (!SaveSysCode()) return FALSE;
//写跳转指令机器码
InitJmpCode();
//写目标代码
return SetJumpCode();
}
BOOL CApiHook::HookOff()
{
BOOL bRet;
bRet = WriteProcessMemory(GetCurrentProcess(), m_SysApi,
(LPVOID)SysCode, m_CodeLength,NULL);
if(!bRet)
{
return FALSE;
}
isHooked = FALSE;
return TRUE;
}
void CApiHook::InitJmpCode()
{
/* 计算jmp指令的偏移地址: offset = userfun-sysfun-5 */
JmpCode[0] = 0xE9; //jmp的机器指令
*(DWORD*)(JmpCode+1) = (DWORD)((LONG)m_UserApi-(LONG)m_SysApi-5);
}
BOOL CApiHook::SaveSysCode()
{
HMODULE hMod = GetModuleHandle( m_MoudleName );
if ( hMod == NULL )
{
return FALSE;
}
m_SysApi = (void*)GetProcAddress(hMod , m_SysApiName);
if (m_SysApi == NULL )
{
return FALSE;
}
//save
memcpy( SysCode, m_SysApi, sizeof(SysCode) );
return TRUE;
}
BOOL CApiHook::SetJumpCode()
{
//写目标地址
BOOL bRet;
bRet = WriteProcessMemory( GetCurrentProcess(),
(LPVOID)m_SysApi, (LPVOID)JmpCode, m_CodeLength ,NULL);
if(!bRet)
{
return FALSE;
}
isHooked = TRUE;
return TRUE;
}
/
// dll.cpp : Defines the entry point for the DLL application.
// by ssssss24cn@hotmail.com 2003.07.24
/
#include "stdafx.h"
#include <windows.h>
#include <ImageHlp.h>
#include <winsock2.h>
#include "ApiHook.h"
/*========================================================*/
#pragma comment(lib, "ImageHlp")
#pragma comment(lib, "ws2_32")
/*========================================================*/
int FAR PASCAL hook_send(SOCKET s,const char FAR * buf,int len,int flags);
int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags);
/*========================================================*/
void WINAPI HookOn();
int WINAPI WriteBufferToFile(const char *fn, const char *bp, const unsigned long blen);
/*========================================================*/
HANDLE hDllSelf=NULL;
CApiHook ah1,ah2,ah3,ah4;
/*========================================================*/
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
if (ul_reason_for_call==DLL_PROCESS_ATTACH)
{
hDllSelf = hModule;
HookOn();
}
return TRUE;
}
//------------------------------------------------------------------//
void WINAPI HookOn()
{
PROC new_fun=NULL;
//ws2_32.dll
new_fun = (PROC)hook_send;
if (!ah1.HookOn("ws2_32.dll","send",new_fun))
MessageBox(NULL,"hook ws2_32.dll failed.","提示",16);
//wsock32.dll
if (!ah2.HookOn("wsock32.dll","send",new_fun))
MessageBox(NULL,"hook wsock32.dll failed.","提示",16);
//ws2_32.dll
new_fun = (PROC)hook_recv;
if (!ah3.HookOn("ws2_32.dll","recv",new_fun))
MessageBox(NULL,"hook ws2_32.dll failed.","提示",16);
//wsock32.dll
if (!ah4.HookOn("wsock32.dll","recv",new_fun))
MessageBox(NULL,"hook wsock32.dll failed.","提示",16);
}
//------------------------------------------------------------------//
int FAR PASCAL hook_send(SOCKET s,const char FAR * buf,int len,int flags)
{
int ret=0;
if (ah1.isHooked)
{
WriteBufferToFile("c://hook_send",buf,len);
ah1.HookOff();
ret = send(s,buf,len,flags);
ah1.SetJumpCode();
return ret;
}
if (ah2.isHooked)
{
WriteBufferToFile("c://hook_send",buf,len);
ah2.HookOff();
ret = send(s,buf,len,flags);
ah2.SetJumpCode();
return ret;
}
return 0;
}
//------------------------------------------------------------------//
int FAR PASCAL hook_recv(SOCKET s,char FAR * buf,int len,int flags)
{
int ret=0;
if (ah3.isHooked)
{
ah3.HookOff();
ret = recv(s,buf,len,flags);
ah3.SetJumpCode();
WriteBufferToFile("c://hook_recv",buf,len);
return ret;
}
if (ah4.isHooked)
{
ah4.HookOff();
ret = recv(s,buf,len,flags);
ah4.SetJumpCode();
WriteBufferToFile("c://hook_recv",buf,len);
return ret;
}
return 0;
}
//------------------------------------------------------------------//
int WINAPI WriteBufferToFile(const char *fn, const char *bp, const unsigned long blen)
{
FILE *fp;
int wlen=-1;
fp = fopen(fn,"wb+");
if (fp)
{
fseek(fp,0L,SEEK_END);
wlen = fwrite(bp,sizeof(char),blen,fp);
fclose(fp);
}
return wlen;
}
//------------------------------------------------------------------//