`
cloud21
  • 浏览: 399481 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

用HOOK Call提升挂的效率和及时性

阅读更多
Lotyong 的 [轉帖]用HOOK Call提升挂的效率和及时性

来到广海也一年了,没做什么贡献(发过一篇2分文),看到不少朋友发文章帮助新手成长,确实很高兴,同时自己也比较汗颜,没怎么帮到大家。一年来,不少新朋友都已经从小菜鸟,成长到了中/高级菜鸟,也许发现自己的挂和市面上的还有一定差距,现在我来帮大家缩小这个差距。
-------------------------
以下阅读最好是具备一定基础的中级菜鸟(能熟练应用HOOK对游戏进行注入的),因为不会一一解释太过基础的词汇,请在论坛搜索相关知识。
--------------------------
下面从取游戏数据的角度来说明目前的情况
1、按键精灵,通过取色来进行,效率很低(由于找基址的普及,现在按键也用内存取值了)
2、内存挂,通过基址+偏移的方式进行,用定时轮询来保证及时性。
3、注入挂,同样通过基址+偏移方式进行,也采用定时器保证及时性,好处是内call调用方便,也省过了ReadProcessMemory读取函数,可以直取内存。
这是目前广海菜菜们的三种挂,相比以前来说,注入的开始多起来,这是好事情,说明大家水平都提高了,有人说安全性不高,注入的容易被反外挂检测到。实际上,无论是内存型,还是注入型,都有对应的API函数让反外挂检测到(像内存用的ReadProcessMemory),所以关键还是在分析反外挂检测,拦截检测函数,改变检测结果。这里顺便提一下,不是今天的主题。
我们提到了一个概念,就是及时性,为什么要保证及时性呢,外挂的一个基础功能,就是保护角色不死亡,自动加血,如果不能及时加血,那么后果,大家都很清楚。同样的,高级一些的功能,如根据怪物剩余血量选择技能进行攻击,也是对及时性要求高的。再有一点,大家能比较的,打怪效率,好的挂怪物刚死亡,就开始打下一个了,而有的挂要等一会儿,这是为什么?同样也是及时性判断。目前用定时器来判断,就有这个问题,当然你可以把定时间隔设得很短,那你一个挂要用到多少定时器?怪物血量,人物血量,背包是否满,任务是否完成等等,都需要判断。而且我们做的是内挂,游戏就占了很多资源,在多开的情况下,尽量避免浪费资源,也是一个挂是否优秀的首要条件。
也许有人说,现在电脑硬件条件好,无所谓,那我们单纯从程序角度来看,用定时轮询,是一种什么样的浪费,有没有更好的方式?有一句话,监视不如自觉,从程序上翻译,就是监视不如触发。通过定时器来监视,一般都是1ms一次,频繁的检测,却只有极低的命中率(即确实血量变化了),当然还有一种方法,就是注入到recv(收包),在每次收包时触发一次血量检测,这就是一种好的方式,大大提高了命中率。
注入到收发包函数,网上有很多相关的资料,但这还不是我推荐大家使用的方式,我们仔细分析下,游戏中很多动作都会造成收发包,包括其他人物移动,攻击,怪物移动,等等,有很多都和血量无关的,所以事实上,命中率还是很低,如何做到只在血量发生变化时调用我们的血量判断呢?这就要主角上场了,HOOK Call
进阶
现在大家有调用call的经验,自然也就有了od找call的经验,我们以一个游戏“武林”为例,在武林中,你可以通过OD断下一个地方,然后会发现,只要你受到攻击,它就会断下来。很好,这就是我们要的地方,然后我们在它断下时,查看寄存器值,eax +4,血量,eax +8 蓝量,好了,数据也有了。实际上,这和用CE找数据基址是一样的,eax的值实际上就来自于[一级基址]+偏移+[二级基址]这样的组合(和内存挂取值一样),只是由于我们已经在call的内部,所以能一下就取到值。
找到了合适的地方,接下来如何去HOOK它呢,需要注意的是,这里的HOOK,我们不需要用到API,只需要直接改汇编代码就行了(API实际上也是同样操作)。在我们断下的那个点附近,上下看看,有没有call(HOOK call嘛,肯定要找call),好,我们找到一个,我们在call的第一行下个断点,进游戏受攻击,断下来,看eax+4的值,是正确的。恭喜这个call可用,然后说明一下汇编中call的环境。
大家知道,一个call就是一个函数,可带参数,也可不带参数,参数在进call以前,被压入堆栈里,进call后从栈中取出。由于我们要HOOK call,也就是把call 0425142改为call 自己函数的地址,我们就应该像警察一样,要对现场进行保护。下面用Delphi给出一个自己函数的例子

Copy code
{人物血量信息拦截函数 }
function Char_call(): longint;
begin
  asm
    pushad  //将当前寄存器环境保存
    mov ebx,dword ptr ds:[esi+$254] //将值取出
    mov Char_ohp,ebx  //将值赋给变量
    mov ebx,dword ptr ds:[esi+$26c]
    mov Char_mhp,ebx
    mov ebx,dword ptr ds:[esi+$258]
    mov Char_omp,ebx
    mov ebx,dword ptr ds:[esi+$270]
    mov Char_mmp,ebx
    mov Char_hpChgFlag ,eax
    mov ebx,_char_c_addr //将原有call地址写入
    call ebx //执行原有的call
  end;
  Ctrl_Char_call(); //进入自己的人物处理函数(负责判断加血)
  asm
    popad  //恢复环境
    ret;  //返回
  end;
end;

大家可以看到,在这里取血量,没有用一级基址了,至于为什么血量不能直接赋给变量,要用二行代码,这就是语言的限制了。如果嵌入的是C,就可以一行搞定。最后为什么要写一个ret呢,实际上编译器在编译delphi代码后,会自动生成ret的,但有的时候,我们需要的是ret 4,或者是add esp,4,再ret,这时候就不能依靠编译器了,只能自己处理,所以我就习惯了干脆都自己处理。
接下来说一个很重要的概念“堆栈平衡”,由于我们修改了call,在我们的call里又要调用原来的call,所以必须保证堆栈里是每次call所需要的数据,否则你就会看到程序崩溃。通过od你可以看到,如果堆栈不平衡,你在返回时,将返回到别的地方去了,自然就执行不下去。HOOK call,一定要哪里来,回哪里去。
我们的call写好了,就可以通过写内存的方法,将原来的call xxxxxx,改为call 我们的函数,初学这个,需要多次调试,一不小心就会程序崩溃,所以需要你受得了打击。
使用这个技术,还需要注意你要取的值,在call前在,还是call后在,以方便你在你的函数里取值,我例子里是call前在,call后就没有了。
找HOOK call的原则:
1、越简单的call越好,也就是参数少,进call后,代码也少,更不要看到有一堆case的call。
2、层次越少越好,被你替换的call里面,最好没有别的call,这样你甚至不用调用它这个call,直接在你的代码里实现它的功能就行了。
3、参数不要有esp,如果在call里面通过esp读了参数,那就在恢复环境时比较麻烦,要做额外处理,让esp在它希望的位置。
再次进阶
也许在你使用一段时间后,你发现,你找着了关键位置,断下来命中率很高,可附近没有call,或者只有一个很麻烦的call,应该怎么办。
我们一样有办法,这就是HOOK anywhere,任意地方都可以HOOK,原理就是把普通的汇编代码,改为call 我们的函数,然后在我们的函数里执行它原有代码,再取数据。你也可以动手试一下,和HOOK call一样的写法,只是由于环境不同,需要具体处理而已。
选择语言
我个人来说,从VB开始,由于工作需要,学了JAVA和.net,可惜这二样都不能用来做外挂,因为它们是高级语言,对底层处理都自动了,这不是我们需要的。后来学了VC,VC写外挂很好很强大,可惜MFC我太不喜欢了(.net用习惯了),才改用了DELPHI。所以推荐大家用C++和Delphi来做,E和VB会很困难,基本上不要去考虑了。
总结
HOOK call极大的提升了效率,命中率很高,但同时对技术要求也高,必须要熟悉汇编的知识,容易受到打击(程序崩溃),找call来HOOK,比找call调用要简单一些,主要工作量还是在hook后的堆栈平衡调试上,有基础的朋友可以试下。
由于我这是写的介绍文,不是教程,所以代码不多,有的地方也是一句带过,没有介绍具体的实现方法,主要在引导大家,网上这方面资料确实不多,欢迎大家提问。我有时间会回答的。
分享到:
评论

相关推荐

    API HOOK 模块

    5. **VTable Hook**:对于使用C++多态性的对象,可以使用VTable Hook来替换虚函数的指针,达到Hook的目的。这种方法主要用于类对象的方法调用。 6. **Detouring技术**:Microsoft Research的Detours库提供了一种...

    SR_rootkit

    总的来说,“SR_rootkit”揭示了内核级hook技术的复杂性和潜在危害,同时也提醒我们网络安全的重要性,以及持续学习和防御这些高级威胁的必要性。通过深入理解和掌握这些技术,我们可以更好地保护我们的系统免受类似...

    内核安全软件仿XT,开源,支持LUA脚本

    通过监控进程和线程的创建、修改和销毁,仿XT可以及时发现异常行为,比如非法的权限提升、隐藏进程或者恶意线程注入。这种检测有助于预防病毒、木马和其他恶意软件的活动。 CrashRootkit这个名字可能代表了一个用于...

    用ring3代码可靠地枚举Windows进程.pdf

    ### 用Ring3代码可靠地枚举Windows进程 #### 概述 本文旨在探讨如何使用Ring3级别的代码来实现对Windows操作系统中运行的进程进行可靠的枚举。这涉及到使用多种技术,包括Psapi库中的`EnumProcesses()`函数、...

    iOS监控笔记之启动crash

    通过上述方式,开发者可以建立一个相对完善的启动crash监控系统,及时发现并定位问题,从而提高应用的稳定性和用户体验。在实际开发中,还需要根据项目需求和资源,权衡性能、安全性和复杂性,选择最适合的监控策略...

    增强Linux内核中访问控制安全的方法

    在Linux环境中,有多种方法可以增强内核的安全性,防止未授权的访问和攻击。本文将详细探讨几种常见的技术,包括动态库劫持、系统调用劫持以及Linux Security Modules (LSM)。 首先,动态库劫持是一种利用`LD_...

    易语言-eWOW64Ext v1.21 - 加载任意 32/64 模块|动态调用|64 位汇编|64 位进程读写

    使用过动态调用DLL的都清楚取模块基址和函数指针,微软默认使用字符串对比,本模块可使用哈希对比效率和易用上相对提升,本函数用于计算模块或函数哈希 X64Call 调用 64 位函数通用版本 X64CallArr 调用 64 位函数...

    防止鼠标回滚

    在IT领域,编程时常会遇到各种需求,其中之一就是如何控制鼠标的行为。本篇文章将深入探讨“防止鼠标回滚”这一...当然,实际应用中可能需要考虑更多细节,例如处理多线程、异常情况等,以确保程序的稳定性和兼容性。

    易写 64 位子程序|易读写 64 位进程 - eWOW64Ext 模块纯源码-易语言

    与很多语言不同,易的置入代码接受的是硬编码(即编译后的 opcode)而不是汇编助记符,虽然直观性没有了,但可以使我们更灵活的在一段子程序中使用 x86/x64 混编,也就是你可以使用 64 位的通用寄存器来编写 x64 ...

Global site tag (gtag.js) - Google Analytics