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,用户进入小程序,或者说,小程 ...
随机推荐
- hdu 1242 Rescue (BFS)
Rescue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- 更改Debian的console分辨率
1.通过apt-get install hwinfo来安装 2.通过命令hwinfo --framebuffer来获取 eric@debian:~$ sudo sudo hwinfo --frameb ...
- cpj-swagger分别整合struts2、spring mvc、servlet
cpj-swagger 原文地址:https://github.com/3cpj/swagger 1. Swagger是什么? 官方说法:Swagger是一个规范和完整的框架,用于生成.描述.调用和可 ...
- eclipse 导出burpsuite插件包含第三方lib包
第一步:右键项目点击export: 2.选择Runable JAR file: 点击Finish后会爆出一个错误(Jar export finished with problems. See deta ...
- Codeforces #105 DIV2 ABCDE
开始按照顺序刷刷以前的CF. #include <map> #include <set> #include <list> #include <cmath> ...
- 获取URL中的文件的扩展名
问题: 尽可能多地写出获取文件扩展名的方法: //方法一(分割数组) function getExt($url){ $arr = explode('.',$url); $len = count($ar ...
- hdu 3264(枚举+二分+圆的公共面积)
Open-air shopping malls Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- 解决ASP.NET裁剪图片失真
//有的时候剪切图片时,出现图片失真的问题,是因为图片质量下降造成的 //按照指定的数据画出画板(位图) System.Drawing.Image imgPhoto = System.Drawing. ...
- [BZOJ4990][Usaco2017 Feb]Why Did the Cow Cross the Road II dp
4990: [Usaco2017 Feb]Why Did the Cow Cross the Road II Time Limit: 10 Sec Memory Limit: 128 MBSubmi ...
- 学习PHP注意事项
1 多阅读手册和源代码 没什么比阅读手册更值得强调的事了–仅仅通过阅读手册你就可以学习到很多东西,特别是很多有关于字符串和数组的函数.就在这些函数里面包括许多有用的功能,如果你仔细阅读手册,你会经常发 ...