您的位置:首页 > 其它

Windows 平台下 Api的拦截(hook)

2007-12-18 06:55 417 查看
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;
}
//------------------------------------------------------------------//
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: