不死不休的一条不归路。。。。 这几所有天看了一下学习资料,补充知识来解决自己遇到的问题(易游验证更换KEY打补丁无效),小生大牛说hook掉所有接口地址,从此我就走上了不归路,睡觉前拿手机学习,路上看,下班看,我就不信不能解决我的问题,内心呐喊不止。。。。。。 这是搞到的教程,链接:http://pan.baidu.com/s/1o8o1pGI 密码:n6ja 还有一个是从度娘上找到的,链接:http://pan.baidu.com/s/1jInn2iq 密码:id7r(绝对适合新手看,如果不了解汇编,当我没说) 网上还有其他教程,大家自己搜搜看看
0、hook简介
简介: Hook是一个针对程序执行过程中挂钩技术。它主要用来拦截一些数据,并对这些数据进行处理,此时,程序转到我们的Hook代码,我们拥有整个程序的执行权限,我们可以选择跳过此处,也可以选择修改数据,或者出错退出程序等等。
系统应用范围: Hook技术应用非常广泛,可以应用在客户层(程序),也可以应用在硬件层(内核),本专题针对客户层进行介绍。
外部和内部: 我们一般用Hook主要是用在外部程序,来监视一个程序的某个动作是否满足我们的条件。 也可以用在本程序,这种作用我们以后介绍。
Hook的种类: Hook主要是用在拦截这方面,那么最重要的就是API了。也就是APIHook。 也可以是拦截程序API执行过程。
前提:
学习Hook,你需要有一点汇编基础(为了能看懂本专题中的一些例子和图示)。
在这里我使用吾爱破解版本的OllyDBG,下载地址:http://115.com/file/c44d0s9x API伴侣可以使用钟少敏写的易用API伴侣,下载地址:http://115.com/file/e6dje67n
1、HOOK原理
有学过PE文件的朋友可能都会这样一个感染文件的方法:
1、 新建一个区段。 2、 把代码放入这个区段里。 3、 在原始代码入口前,增加一条指令,jmp到这个区段中。 4、 执行完整个区段之后,在区段的末尾,jmp回到原始代码的入口。
这样就完成了一个程序的Hook,我们可以直接在程序入口添加一个Hook,弹出信息框,选确定方可进入程序,选否则退出程序。 其实这也就是一个hook,不过这样的Hook并不实用。因为我们并不是想控制程序的运行与否,而是控制程序执行过程而达到我们的一些目的。
我们来用OD写第一个Hook。 下面是一个Windows窗口程序,我们在_启动子程序下写如下代码:
2、远程Hook
上一节我们知道了怎样在OllyDBG中Hook修改一个数据,然后转存。 这节课我们主要学习一下远程修改指定进程的代码来达到我们Hook的目的。 其实这节课也就是编写程序来实现OD中的修改代码的操作。 这节课我们需要学习几个API函数。 1、OpenProcess 打开一个进程,返回进程句柄 2、WriteProcessMemory 在一个进程中写入数据 3、CloseHandle 关闭一个内核对象 4、ReadProcessMemory 读取进程数据 5、VirtualAllocEx 在目标进程中申请一段内存空间(存放Hook代码) 6、VirtualFreeEx 在目标进程中释放申请的内存空间 因为是要动态修改程序代码,所以这节课的原程序有所改变,是一个静态编译的Windows窗口程序。
3、APIHook 上
本章,我们将介绍如何对本程序中的函数调用进行Hook 学习这一章前,我们先认识几个API函数。 GetModuleHandle 获取库句柄 参数 lpModuleName 库名称,如 kernel32.dll
GetProcAddress 获取库函数地址 参数 hModule 库句柄 lpProcName 库函数名称
VirtualProtect 修改虚拟保护 参数 lpAddress 修改的虚拟保护区域首地址 dwSize 修改的虚拟保护长度 flNewProtect 新的虚拟保护 lpflOldProtect 保存旧的虚拟保护
我们要知道,程序的任何地方都可以调用API函数,所以我们不能Hook程序的某个地方,我们要Hook API函数的某个地方。一般情况下,我们都选择Hook API首地址的前5个字节。
4、APIHOOK 中
首先,使用LoadLibrary 函数载入动态链接库,获取动态链接库的句柄。 其次判断句柄是否为0,如果为零则重新载入一下。 接着就是取库函数地址了。 取好之后,修改内存保护属性为可读可写,接着就是重点了,为了照顾新手朋友,我会逐一分析。 原字节 = 指针到字节集 (函数地址, 5) 这句代码保存了API函数的前5个字节。 新字节 = { 233 } + 到字节集 (到整数 (新函数地址 - (函数地址 + 5))) 这句代码是计算跳转到 新函数地址 这个参数子程序处的机器码。 写到内存 (新字节, 函数地址, 5) 修改API入口前5字节 原字节 = 原字节 + { 233, 0, 0, 0, 0 } 今天的重点内容,把原字节和{ 233, 0, 0, 0, 0 }并加,
原地址 = _取指针_字节集 (原字节, 原字节, 0) 写到内存 (到整数 (函数地址 + 5 - (原地址 + 10)), 原地址 + 6, 4)
先是取出 原字节 变量的数据指针,接着从原地址 + 6的地方,也就是{ 233, 0, 0, 0, 0 }的 {0, 0, 0, 0 }这个地方开始写入数据,内容是从{ 233, 0, 0, 0, 0 } 这条指令(jmp xxxxxx)跳转到API函数后5个字节的距离。 函数地址 + 5 ,这就是API函数的后5个字节的地址;原地址 + 10 就是 原字节 变量的后10个字节,也就是计算机器码跳转的地方,把他们两个相减,就算出了距离。 接着写入这个 原字节 变量中,就完整的实现了这个API函数: 执行API函数的前5个字节 -> 跳转到API函数的后5个字节处执行 我们再来看下 暂停 和 继续 方法: 5、APIHook - 下
我们在启动窗口创建完毕后Hook send函数。 其他的如同上一章的一样,主要是 修改代码 变量做了一些改变。 首先 修改代码 初始化为 {201,88} 转换为汇编指令也就是leave pop eax, 我们知道 leave也就是mov esp,ebp pop ebp,所以,这两句也就是把call压入的下一条代码指针弹出到eax里. 接着再加上函数指针前5个字节,最后加上{255,224} 汇编指令jmp eax.也就是跳转到call压入的下一条代码指针处。 接着取New_Send 函数的真实地址,新代码为 call 新函数地址 这里我们用到call了,没有使用上一章的jmp指令,因为call是在堆栈中压入下一条指令的地址,所以这一点对我们来说方便很多。 最后修改函数前5个字节,取到修改代码的指针。 接着就是我们的New_send函数了:
6、APIHOOK_扩展 7、Windows消息Hook 8、拦截API返回值(完结)
我们这一章还是实例,内容相信大家也已经知道了,那么我们拦截API函数返回值有何用处呢? 首先,我们针对一些恶意程序,比如像全局消息钩子,是使用像SetWindowsHookEx一类的函数来实现的,它返回的是一个钩子句柄,一样的,如果大家希望不要让某个程序使用OpenProcess函数打开自己的进程,就需要hook获取 OpenProcess函数的返回值,然后CloseHandle使这个进程操作句柄无效。当然这是我们用户层所使用的方法,实际上,OpenProcess是在内核中调用NtOpenProcess函数的,这里我们不讨论它。
那么我们如何下手呢?
我们知道,程序的任何地方都有可能调用指定的API函数,也就是不可能Hook程序的某个部分,那么只好从API来下手了,我们在考虑在API头部来实现,程序Call这个API,会把从程序调用API的某个地方的下一条代码压入堆栈,我们获取它,再对它Hook也可以完成,但是我们这样做太麻烦了——首先要保存被修改的代码,其次还要计算被毁坏的代码。 所以,这种方法是不可取的。 我们再考虑从API的返回代码,也就是ret xx 来下手。
修改返回代码->手写一段汇编,保存寄存器等->跳转到Hook子程序区->进行处理->返回到保存的API的返回代码(ret xxxx)进行返回。
|