HOOK大法实现不修改程序代码给程序添加功能
【文章标题】: HOOK大法实现不修改程序代码给程序添加功能
【文章作者】: 0x18c0
【软件名称】: Scylla
【使用工具】: OD、Stub_PE、ResHacker
【版权声明】: 本文原创于0x18c0, 转载请注明作者并保持文章的完整, 谢谢!
菜鸟第一次发帖,写的不好的地方请各位多多包含
本来是第三次培训的作业,要给Scylla加上弹窗
@Kido 老师在上课的时候也演示了,没什么难度,但是按照上课的方法来搞,程序一运行就弹个窗口,太粗暴,强迫症完全不能忍好吧,所以我想在窗口上加个按钮,等点击按钮的时候再弹出窗口,这样就感觉友好多了。
<ignore_js_op>
这么做其实也不难,方法就是找到窗口的过程函数,然后改写指令让程序先跳到我们自己写的函数里,最后再跳转回原窗口过程函数
比如@苏紫方璇 大牛这篇帖子的方法,无源码给程序添加功能-记事本标题添加当前时间
但是,这么搞太麻烦了,需要自己定位窗口过程,还要各种修改指令实现跳转,完全不适合我这种懒人
但是,懒人有懒人的方法,俗话说的好,懒是推动科技进步的根本动力——0x18c0
这里我已经忍不住要高喊一句——HOOK大法好!
先介绍一下方法,我修改了Scylla的导入表,添加了一个我自己编写的DLL,然后在DLL的DllMain函数里下消息hook,每当按钮被按下时,WM_COMMAND消息就会被hook住,从而弹出窗口。
基本方法介绍完了,下面介绍一下HOOK和DLL的基本知识
一、HOOK
Hook,字面意思就是钩子,是windows系统提供给开发者用来改变windows消息处理流程的编程接口。hook也分好几种,拿下面我要用到的消息hook来举例,每当我们按下一个窗口上的按钮时,系统就会捕获到一个WM_COMMAND消息,消息会被Windows系统传递给软件提前编写好的一个函数,这个函数叫做窗口过程函数,过程函数会根据不同的消息做出不同的处理。但是当我们想在消息被操作系统传递给过程函数处理之前先处理怎么办呢?这个时候就要用到消息hook了,操作系统提供给了开发者改变消息的能力,我们只需要调用相关的API,在相应的消息上设置hook钩子,并且告诉操作系统当消息被钩子钩住的时候因该怎么办,操作系统就会按照我们的意愿来处理消息。
比如我们hook按钮被按下的消息WM_COMMAND,并且告诉操作系统,当钩子被触发的时候把消息传递给我自己编写的函数HookMSG,于是我们每次按下按钮,钩子都会被触发,并且操作系统会自动
调用HookMSG函数。
二、DLL
DLL,动态链接库,可以导出变量和函数供其他程序调用,也可以包含资源文件,DLL有一个DllMain函数,每当DLL被链接时都会被调用,并且不同的调用原因可以有不同的处理办法。所以我们用Stub_PE将一个DLL添加到Scylla的倒入表里,每次Scylla运行时操作系统都回自动载入我们添加的DLL,并且运行DllMain里的代码,所以我们在DllMain里写上我们的hook代码,那么每次Scylla运行都会被自动hook了,这样就达到了我们的目的。
方法和基本原理都说了,下面就应该开始实战了
一、添加按钮资源
首先得给Scylla加一个按钮,用ResHacker打开Scylla,在对话框上要添加按钮的地方右键——>insert control,出现添加控件的窗口
<ignore_js_op>
选择控件类型为BUTTON,caption这里填写需要显示在按钮上的字,最后别忘了给按钮添加ID,ID需要和其他控件不同以免冲突,这里我填写1099
,点击ok后界面上了出现我们添加的按钮,接下来不要忘了编译和保存
<ignore_js_op>
二、编写DLL
接下来我们编写DLL,我电脑上只有vs2013,所以我就用它了,你们也可以用其他编译器,只要可以编写Windows系统上的DLL就可以。
1.新建工程
选择win32项目,填写工程名,点击确定
<ignore_js_op>
选择DLL和空项目,点击完成,项目创建完成,然后添加main.cpp到工程
<ignore_js_op>
2.编写代码
首先编写DllMain函数
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: //dll载入时执行 { g_hModule = hModule; //保存句柄到全局变量 hhk = StartHook(); break ; } case DLL_PROCESS_DETACH: //dll卸载时执行 { EndHook(); break ; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break ; } return TRUE; } |
DllMain函数的ul_reason_for_call指明了函数被调用的原因,DLL_PROCESS_ATTACH指DLL被调用,DLL_PROCESS_DETACH指DLL被卸载,而case DLL_THREAD_ATTACH和case DLL_THREAD_DETACH分别表示线程被创建和销毁。我们在dll加载时调用StartHook函数,dll卸载时调用EndHook函数,下面我们看看这两个函数
1
2
3
4
5
6
7
8
9
|
HHOOK StartHook() { return SetWindowsHookEx(WH_CALLWNDPROC, HookProc, g_hModule, GetCurrentThreadId()); //设置hook,类型为WH_CALLWNDPROC,过程函数为HookProc,hook当前线程 } BOOL EndHook() { return UnhookWindowsHookEx(hhk); //结束hook } |
这两个函数只是很简单的封装了俩个API,重点在于SetWindowsHookEx的参数设置,由于我们hook的是WM_COMMAND消息,所以我们选择hook类型为WH_CALLWNDPROC,表明当窗口过程函数被调用时触发hook,并且我们是hook当前线程,hook过程函数在dll里,所以第三个参数填dll模块句柄或者NULL都行,第四个参赛则直接利用GetCurrentThreadId()获取当前线程id
这里有一篇文章介绍hook的类型,写的很不错,有兴趣的可以看看http://blog.csdn.net/whatday/article/details/8006225
重点还在hook过程函数,我们需要在这里过滤出我们需要的消息,并编写功能代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) { CWPSTRUCT* cwps = (CWPSTRUCT*)lParam; if (WM_COMMAND == cwps->message) { INT wmId = LOWORD(cwps->wParam); if (wmId == 1099) DialogBoxParam(g_hModule, ( LPCTSTR )IDD_DIALOG, NULL, DlgProc, NULL); } } return CallNextHookEx(hhk, nCode, wParam, lParam); } |
由于我们只需要添加按钮弹窗功能,所以我们只过滤WM_COMMAND消息,前面我们添加按钮资源的时候id填写的是1099,这里就派上用场了。
这里我调用了DialogBoxParam函数来弹出对话框,弹出对话框需要添加对话框资源,并且编写过程函数。
选择vs2013的菜单项->项目->添加资源->Dialog->新建
<ignore_js_op>
vs中出现我们新建的对话框资源
<ignore_js_op>
我就不编辑资源了,直接开始编写对话框的过程函数,这里我没有添加任何功能代码
01
02
03
04
05
06
07
08
09
10
|
BOOL CALLBACK DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CLOSE: EndDialog(hDlg, NULL); } return FALSE; } |
到此为止,代码编写工作就完成了,但是这个dll没有一个导出函数,我们没法把它加到Scylla的导入表里,不过我们可以写一个空的导出函数
1
2
3
4
|
__declspec ( dllexport ) void EmptyFunc() { //Do nothing } |
3.编译dll
接下来我们编译dll,将工具条上的编译选项设为release,点击编译。
<ignore_js_op>
如果你用的也是vs2013,这里需要修改两个地方的设置,否则编译出来的dll在xp上不能运行。
VS2013菜单->项目->属性->配置属性->常规->平台工具集->Visual Studio 2013 - Windows XP (v120_xp)
VS2013菜单->项目->属性->配置属性->c/c++->代码生成->运行库->多线程 (/MT)
在项目文件夹里找到HookMSG.dll,拷贝到Scylla目录下。
三、修改Scylla导入表
Stub_PE载入Scylla,选择“函数”选项卡,右键添加函数,选择HookMSG.dll,选择EmptyFunc函数,确定添加并保存。
<ignore_js_op>
运行一下看结果,点击about按钮,对话框成功弹出,大功告成。
<ignore_js_op>
写在最后:
其实整个过程没有什么技术含量,懂Windows编程的人看一眼就懂,但是作为新手弄这些东西还是有点难,整个过程当中我也是遇到各种问题,不过结果总算是好的
发这篇帖子的目的是希望与大家共勉,同时分享一下成功的喜悦,写的不好的地方希望大家多多包涵
最后感谢论坛提供这个学习的机会,也感谢各位讲师@Hmily @Kido 的指导
同时附上HookMSG.dll的完整源代码,链接:http://pan.baidu.com/s/1c0GvFOW 密码: v7um
ps:其实Scylla是开源软件,想要汉化或者改界面的可以下载源代码自己编译,https://github.com/NtQuery/Scylla
HOOK大法实现不修改程序代码给程序添加功能的更多相关文章
- master-worker常驻型程序代码修改哪些需要重启master或者worker
之前在yii的项目里用redis作为消息队列,现在很多任务需要延迟需求,于是把之前redis的消息队列替换成了rabbitmq 于是使用yii的yii2-queue这个组件 但是由于提供的yii qu ...
- 一套代码小程序&Web&Native运行的探索05——snabbdom
接上文:一套代码小程序&Web&Native运行的探索04——数据更新 对应Git代码地址请见:https://github.com/yexiaochai/wxdemo/tree/ma ...
- 一套代码小程序&Web&Native运行的探索03——处理模板及属性
接上文:一套代码小程序&Web&Native运行的探索02 对应Git代码地址请见:https://github.com/yexiaochai/wxdemo/tree/master/m ...
- 如何快速读懂大型C++程序代码
要搞清楚别人的代码,首先,你要了解代码涉及的领域知识,这是最重要的,不懂领域知识,只看代码本身,不可能搞的明白.其次,你得找各种文档:需求文档(要做什么),设计文档(怎么做的),先搞清楚你即将要阅读是 ...
- 用ildasm/ilasm修改IL代码
原文地址:http://www.cnblogs.com/dudu/archive/2011/05/17/ildasm_ilasm_il.html 在开发中遇到这样一个场景,需要修改一个dll文件(.N ...
- 反编译工具 使用.NET JustDecompile来反编译你的程序代码
原文地址:http://www.it165.net/pro/html/201310/7383.html 前言 在项目的进行中有时会碰到需要去了解由第三方所开发的程序代码或者因为年久已经遗失原始码的程序 ...
- C++ Primer Plus(第6版)中文版——课后练习程序代码
博客内容经历了一次整理,以前发的博文太散.没什么水准,搞的随笔分类越来越多orz,这次把CPP这本书的课后练习的程序代码放到一起方便查阅与修改..嗯 9.6.1 #ifndef _9..1_H_ #d ...
- 本地修改js代码并时时生效的解决办法
js作为客户端语言(当然它也可以作服务端语言),非常强悍,一般情况下,我们都是在开发阶段不停的改,然后上线之后就作为稳定运行的代码. 然而有时候可能因为js写得有问题,导致上线后,某些功能无法使用,这 ...
- 小程序代码包压缩 策略&方案
微信小程序自推出以来,逐渐发展,目前正受到越来越多的青睐.其中很重要的一点得益于小程序的轻量级特性,每个小程序最多不超过2MB,招之即来挥之即去,相比于几十上百兆的APP,用户进入小程序,或者说,小程 ...
随机推荐
- 【bzoj3144】[Hnoi2013]切糕 网络流最小割
题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤ ...
- Android中如何为自定义控件增加状态?
在android开发中我们常常需要对控件进行相关操作,虽然网上已有很多对控件酷炫的操作,但小编今天给大家分享的纯属实用出发.在查看了一些列安卓教程和文档后,发现了一位大牛分享的非常不错的有关andro ...
- Rust安装配置
Rust安装配置 话说前面: 如果你 之前安装过老版本的 rust 请先卸载 我说的是以 msi 文件安装的那种, 请进控制面板–> 程序中进行卸载 首先 下载官网 的 rustup-init. ...
- 【距离GDKOI:44天&GDOI:107天】【BZOJ1040】[ZJOI2008] 骑士 (环套树DP)
其实已经准备退役了,但GDOI之前还是会继续学下去的!!当成兴趣在学,已经对竞赛失去信心了的样子,我还是回去跪跪文化课吧QAQ 第一道环套树DP...其实思想挺简单的,就把环拆开,分类处理.若拆成开的 ...
- Printed Circuit Board (board)
Printed Circuit Board (board) 题目描述 给出一个N个顶点的简单多边形,对于每个顶点,假如它和原点连成的线段只在这个顶点处和多边形相交,就称为满足要求的顶点.你的任务是输出 ...
- bzoj2178:圆的面积并
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=2178 sol :是谁.......是谁往题里下毒...... 辛普森积分,每次判断左边+右边 ...
- npm下载包失败的几个原因
1. 可能是由于网络问题导致下载包失败,因为qiang,所以,直接使用npm有些情况会导致下载包失败,使用cnpm源或者yarn下载等方法可以解决这个问题. 2. 这个包不存在,检查一下包的拼写或者路 ...
- HDU2824 The Euler function
Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u Description The Eule ...
- 阿里的iptables,保存一份
# Generated by iptables-save v1.4.7 on Fri Apr 14 16:37:31 2017 *filter :INPUT ACCEPT [0:0] :FORWARD ...
- 如何理解java反射?
一.反射基本概念 反射之中包含了一个"反"的概念,所以要想解释反射就必须先从"正"开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产 ...