API HOOK的基本问题,做过的进来

jone7319 2012-07-25 10:15:36
  想做个gdi32.dll里的TextOutA的Hook.有个基本的问题没弄清,Hook的时候,自己用于替换API的那个新函数必须放在DLL里还是也可以在当前的project里面自定义?
...全文
166 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
fxworld 2012-07-27
  • 打赏
  • 举报
回复
如果这样写挂接函数,在挂接函数里价一个 Form1->Invalidate(); 就进入死循环了,这是需要注意的地方。

//自定义的处理函数
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{

static INT64 qwi = 0;
qwi++;
Form1->Memo1->Lines->Add( String(lpszString, cbString ) +IntToStr( qwi ) ) ;
Form1->Invalidate();

}
//-------------------------------------------------------------------------------------
fxworld 2012-07-27
  • 打赏
  • 举报
回复

我说的是这样的死循环没有发生:

Form1->OnPaint->挂接函数->Memo1输出(如果输出时Memo1调用了TextOut,则又会反过来调用挂接函数,这时就会进入死循环。 这个死循环实际上没有发生,所以判断Memo没有调用TextOut, DrawText也是同样的。 )

fxworld 2012-07-27
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]

呵呵,是循环的啊,你移动一下那个ShowMessage对话框试一下就知道了
[/Quote]

这个不是死循环,移动ShowMessage会引起Form1调用Invalidate()然后在Paint()方法里调用OnPaint事件,这时挂接函数发生作用,这是正常的循环,挂接函数不正是要挂接TextOutA呀,不是死循环,呵呵。

你把ShowMessage窗口移动到Form1的窗口之外,Memo1的输出就停止了,如果是死循环的话,Memo1应该会不停的输出。

jone7319 2012-07-26
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]
另外,更正一下我在14楼的解释,免得有的网友看到了不敢用TMemo.

今天早上测试了一下TMemo组件,发觉它内部并没有调用TextOut和DrawText,有可能是它直接调用了ntdll.dll中NtDrawText,所以TMemo不会引起死循环。
[/Quote]
呵呵,是循环的啊,你移动一下那个ShowMessage对话框试一下就知道了
fxworld 2012-07-26
  • 打赏
  • 举报
回复

另外,更正一下我在14楼的解释,免得有的网友看到了不敢用TMemo.

今天早上测试了一下TMemo组件,发觉它内部并没有调用TextOut和DrawText,有可能是它直接调用了ntdll.dll中NtDrawText,所以TMemo不会引起死循环。
fxworld 2012-07-26
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]

全局Hook是不是要监视进程,将每个进程都注入呢?
[/Quote]

是的,全局Hook首先要写一个dll,内含你的函数挂接安装接口(输出函数),通常情况还要编写一个进程注入程序,可以设置成自动启动的,注入程序启动后即设置监视进程的Hook,监视进程有很多方法,可以参考Windows核心编程一书,讲的算比较详细的。注入程序的目的就是将你的dll装载到被监视的进程空间中,然后启动你的挂接Hook就可以了。

比如一个比较强力的注入方法就是windows的一个设置hook的函数 SetWindowsHookEx ,通过这个函数设置好的Hook,只要一检测到设置的检测事件,Windows就会自动将设置的dll装载进程空间。

jone7319 2012-07-26
  • 打赏
  • 举报
回复
全局Hook是不是要监视进程,将每个进程都注入呢?
fxworld 2012-07-25
  • 打赏
  • 举报
回复
如果是全局Hook,必须放在dll里面,如果只是自己使用,可以放在Project里。
fxworld 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

如果Memo1上一旦有输出,它又调用MyTextOutA,这样就会陷入循环???
[/Quote]

进一步解释一下,Gdi32.dll有两个函数原型,TextOutA 和 TextOutW,如果你要挂接 TextOutA ,则把IDE设置为_TCHAR maps to 选项设置为:wchar_t ;这样Memo1默认调用的应该是 TextOutW,这样就避开了死循环。
fxworld 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

如果Memo1上一旦有输出,它又调用MyTextOutA,这样就会陷入循环???
[/Quote]

试过,不会的,不过你要在MyTextOutA函数里调用 TextOutA前,应该先释放Hook,否则会死循环。
fxworld 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

为什么我的没成功,没看到Memo1上有输出呀
[/Quote]
//设置一个 OnPaint事件
void __fastcall TForm1::FormPaint(TObject *Sender)
{
::TextOutA( Canvas->Handle,120,120,"Dfdfasdfasdf",10 );
}
//------------------------------------------------------------
void __fastcall TForm1::Button12Click(TObject *Sender)
{

CHookClass hk( _T("gdi32.dll"),"TextOutA",MyTextOutA );
hk.HookOn();
ShowMessage((int)hk.IsHooked());//这个消息窗口不要关闭,否则 hk 就被释放掉了。

}
//---------------------------------------------------------------------------




jone7319 2012-07-25
  • 打赏
  • 举报
回复
如果Memo1上一旦有输出,它又调用MyTextOutA,这样就会陷入循环???
jone7319 2012-07-25
  • 打赏
  • 举报
回复
为什么我的没成功,没看到Memo1上有输出呀
fxworld 2012-07-25
  • 打赏
  • 举报
回复

你的这个挂接函数里使用了ShowMessage(lpszString);消息窗口,阻止了程序下一步的运行,把它改一下就可以了。

BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{
ShowMessage(lpszString);
// 这里进行输出lpszString的处理
// 然后调用正版的TextOutA函数
}
fxworld 2012-07-25
  • 打赏
  • 举报
回复
这个挂接类很方便,呵呵。
fxworld 2012-07-25
  • 打赏
  • 举报
回复
我调用是正确的:

void __fastcall TForm1::FormPaint(TObject *Sender)
{


::TextOutA( Canvas->Handle,120,120,"Dfdfasdfasdf",10 );

}
//---------------------------------------------------------------------------
//自定义的处理函数
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{

Form1->Memo1->Lines->Add( lpszString );
//ShowMessage(lpszString);
// 这里进行输出lpszString的处理
// 然后调用正版的TextOutA函数

}
//-------------------------------------------------------------------------------------
void __fastcall TForm1::Button12Click(TObject *Sender)
{

CHookClass hk( _T("gdi32.dll"),"TextOutA",MyTextOutA );
hk.HookOn();
ShowMessage((int)hk.IsHooked());

}
//---------------------------------------------------------------------------
jone7319 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]
// 保存原函数前五字节

//自定义的处理函数
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{
ShowMessage(lpszString);
// 这里进行输出lpszString的处理
那个老的5字节去哪里了?
// 然后调用正版的Te……
[/Quote]

这个工作,是在类里面完成的吧
tiankong_bear 2012-07-25
  • 打赏
  • 举报
回复
// 保存原函数前五字节

//自定义的处理函数
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{
ShowMessage(lpszString);
// 这里进行输出lpszString的处理
那个老的5字节去哪里了?
// 然后调用正版的TextOutA函数
}

tiankong_bear 2012-07-25
  • 打赏
  • 举报
回复
放在dll里方便注入别的进程
jone7319 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
如果是全局Hook,必须放在dll里面,如果只是自己使用,可以放在Project里。
[/Quote]
以下是借用Waiting4you的类来做试验,但没有成功,看错在哪里?

//这是类头文件 TAPIHook.h

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef _HOOKCLASSH_
#define _HOOKCLASSH_

#include <windows.h>
//---------------------------------------------------------------

class CHookClass{
CHookClass(const CHookClass&);
CHookClass &operator=(const CHookClass&); //不准拷贝和赋值

#pragma pack(push,1)
struct TJmpCode{
char Jmp;
DWORD Ptr;
};
#pragma pack(pop)
public:
/* LibName: DLL 文件名 */
/* FuncName: 目标函数名 */
/* NewFuncPtr: 用于替换的函数指针 */
CHookClass(const char *LibName, const char *FuncName, void *NewFuncPtr);
~CHookClass();

void HookOn(); // 开启 API Hook
void HookOff(); // 关闭 API Hook

void Lock(); // 进入临界区
void Unlock(); // 退出临界区

bool IsHooked(){
// 取Hook状态
return _IsHooked;
}
private:
TJmpCode _OrgCode; // 原代码
TJmpCode _NewCode; // 新代码 jmp FuncPtr

void *_TagFuncPtr; // 目标函数指针
HANDLE _CurProcess; // 当前进程
bool _IsHooked; // 显示是否被Hook了

CRITICAL_SECTION _cs; // 临界区
};

//---------------------------------------------------------------------------------
CHookClass::CHookClass(const char *LibName, const char *FuncName, void *NewFuncPtr)
:_TagFuncPtr(NULL),_IsHooked(false),_CurProcess(0)
{
HMODULE hModule=LoadLibrary(LibName);
_TagFuncPtr=GetProcAddress(hModule, FuncName);
if(_TagFuncPtr==NULL)
throw(-1);

CopyMemory(&_OrgCode,_TagFuncPtr,5); // 保存原函数前五字节
_NewCode.Jmp=0xe9; //jmp
_NewCode.Ptr=DWORD(NewFuncPtr)-DWORD(_TagFuncPtr)-5; // 新的五字节为 jmp NewFuncPtr
_CurProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE, GetCurrentProcessId()); // 以特权方式打开当前进程

InitializeCriticalSection(&_cs);
}
//---------------------------------------------------------------------------------
CHookClass::~CHookClass()
{
if(_IsHooked)
HookOff();
DeleteCriticalSection(&_cs);
}
//---------------------------------------------------------------------------------
void CHookClass::HookOn()
{
// !开启 API Hook
if(!_IsHooked)
{
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_READWRITE, &dwOldProtect); // 更改内存属性
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_NewCode, 5, NULL); // 将_TagFuncPtr的前5个字节改为JMP NewFuncPtr
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=true;
}
}
//---------------------------------------------------------------------------------
void CHookClass::HookOff()
{
// !关闭 API Hook
if(_IsHooked)
{
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_OrgCode, 5, NULL); // 恢复_TagFuncPtr的前5个字节
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=false;
}
}
//---------------------------------------------------------------------------------
void CHookClass::Lock() // 进入临界区
{
EnterCriticalSection(&_cs);
}
//---------------------------------------------------------------------------------
void CHookClass::Unlock() // 退出临界区
{
LeaveCriticalSection(&_cs);
}
#endif



//这是我调用的cpp文件

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "tapihook.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
//自定义的处理函数
BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)
{
ShowMessage(lpszString);
// 这里进行输出lpszString的处理
// 然后调用正版的TextOutA函数
}
//-------------------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
CHookClass hk("gdi32.dll","TextOutA",MyTextOutA);
hk.HookOn();
ShowMessage((int)hk.IsHooked());


}
//---------------------------------------------------------------------------

加载更多回复(1)

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧