HOOK+消息钩子实践——脱离极域电子教室控制【半弃坑状态】

前方施工篇

因为篇幅较长,较难施工,可能你会遇到灾难现场,请带好安全帽。

入坟篇

不可抗拒的原因源代码丢失(其实就是没备份),可能后面更新速度及其慢。

拙著篇

可能有不少的错误出现在文章,如果有任何错误的地方可以在下面指正,谢谢!φ(>ω<*)

 

前序

在我初中的时候,当时电脑课对于我这个内宿生来说很重要,毕竟就只能周末回去,能玩一点算一点qaq。然后老师讲的大部分内容自己都会,不想听了就私底下打算怎么脱离电子极域教室的控制。

想不到现在到了大学,想不到学校还是在用这个,正好重新整活。

2020年12月21日00:03:45更新

由于Inline Hook的不稳定性,从现在开始使用IAT Hook代替,但是Inline Hook我还是会被放在后面讲解

开源地址

DLL:LSStudentMainHook

主程序:DLL还没写完呢,急什么23333.

指导思想

通过注入DLL对控制流程进行HOOK,达到改变程序的控制流程甚至监控。

准备工作

极域电子教室2016豪华版(软件自行百度)

吾爱破解专用版Ollydbg

注意:由于2012年版本的极域电子教室使用了内核保护,用了原版的OD在线挂载的时候可能会出现拒绝访问,请留意。

IAT Hook

咕咕咕

current time:2020年12月21日00:11:01

status:咕咕咕咕咕咕

Inline Hook

Inline Hook原理

通过Inline Hook改变程序流程,将API代码的前5个字节修改为JMP xxxxxx 指令来钩取API(xxxxxx是要跳转到Hook函数的内存地址)。

调用执行被钩取的API时,JMP xxxxxx指令被执行,转而跳转至指定的Hook函数处理后再调用AIP(或者直接返回),这样达到了拦截修改的目的。

Inline Hook实现

大部分程序被编译连接后为个进制文件。在二进制文件中,代码部分都是CPU可以用来执行的机器码,机器码和汇编指令又是一一对应的。

Inine Hook是在程序中嵌入jmp汇编指令后跳转到流程处继续执行的,jmp 指令的用法是jmp目的地址。

在汇编指令中,jmp后面跟随的参数是要跳转的“目的地址”。用OD随便打开一个程序,并且修改它的某条指令为jmp指令。

跳转的目的为一个任意地址,如图所示。

所以说我们需要改写AIP函数上的地址开始的5个字节,替换成我们的jmp指令跳转到我们的函数。

我们先从鼠标键盘锁定拦截介绍。鼠标键盘锁定其实去调用一个叫SetWindowsHook的一个AIP进行锁定。

(由于SetWindowsHookEx存在两个版本:SetWindowsHookExA和SetWindowsHookExW,假如你要兼容全部版本的极域电子教室话也可以对着两个函数处理。)

该函数声明如下:

HHOOK SetWindowsHookExA(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId
);

改函数上idHook表示要安装钩子的类型,可以按安装WH_MOUSE类型钩子,监视鼠标消息或进行拦截;同样,安装WH_KEYBOAED类型钩子,键盘鼠标消息进行拦截。

所以说我们目的是Hook这个AIP。(感觉我是在以Hook制Hook)

我们先看看汇编是怎样调用SetWindowsHookEx的。

在OD里面选择开始→附加,选择极域电子教室的主进程student.exe后选择确定。

由于我们不知道该程序会先调用那个函数,所以先设置一个在SetWindowsHookExA和SetWindowsHookExW函数断点,然后让教师端黑屏(或者屏幕广播)后查看OD。

提醒一下:假如你要进行黑屏操作的话你得需要在OD的窗口设置为总先在前,不然......黑屏的时候你就没办法回到OD了,GG。

可以看到,OD显示在SetWindowsHookExA断下。

前3行汇编代码如下:

76A56CDC 8BFF mov edi,edi
76A56CDE 55 push ebp
76A56CDF 8BEC mov ebp,esp

刚好是5个字节,5个字节可以做一个JMP指令。假如不是5字节的话,剩下的字节会转换为其他汇编代码,这样程序执行的时候会出现各种问题。如修改后突然多出现了一行push ebp,这样会导致堆栈不平衡从而程序运行时崩溃。

前堆栈信息如下:

0012A4CC 100029E9 /CALL 到 SetWindowsHookExA 来自 libTDMas.100029E7
0012A4D0 0000000E |HookType = 14.
0012A4D4 10001590 |Hookproc = libTDMas.10001590
0012A4D8 10000000 |hModule = 10000000 (libTDMas)
0012A4DC 00000000 \ThreadID = 0x0

堆栈信息看出函数HookType变量赋予了14,对应WH_MOUSE。

注:微软开发文档下对SetWindowsHookExA函数HookType变量解释是:当该变量赋予了14应该对应的是WH_MOUSE_LL(低级鼠标输入事件)。虽然都是拦截鼠标信息也没什么区别,但是WH_MOUSE_LL可以拦截可以截获整个系统所有模块的鼠标事件。毕竟比较给力嘛~~~

然后,就可以随手一发暴力插入JMP指令了?

并不是,在运行时我们已经破坏了SetWindowsHookExA函数的头部部分,也就是替换掉的那个部分。导致我们想再回去调用SetWindowsHookExA时候发现程序崩溃了。

所以我们要这样写代码:

//我们自己的SetWindowsHookExA,每调用SetWindowsHookExA都要跳到MySetWindowsHookExA来处理
void HHOOK 
    MySetWindowsHookExA(
    int idHook,
    HOOKPROC lpfn,
    HINSTANCE hmod,
    DWORD dwThreadId)
{
     if(idHook==14);
}

注意:1、假如你要进行内联汇编的话,里面不能含有编译器自动添加的代码,所以在MySetWindowsHookExA头部要加上_declspec(naked)

2、在一些版本的编译器,编译出的debug版本每执行一个函数都要来验证堆栈的。所以看你怎么平衡堆栈了,我也可以举个例子:vs2010的debug版本每执行一个函数都要 cmp esi,esp 来验证堆栈的。所以还要加一句push esi 和pop esi。

点赞
  1. 洛水.山岭居室 洛水.山岭居室说道:
    Google Chrome Windows 10
    代码并没有写完 ,等我回来填坑吧。实在头都秃了(ಥ_ಥ)

发表回复

电子邮件地址不会被公开。必填项已用 * 标注