给网游写一个挂吧(四) – 调用游戏函数
前面的文章给网游写一个挂吧 – 启动外挂上或给网游写一个挂吧 – 启动外挂下将外挂启动后,那就可以进行读写游戏内存和调用游戏的一些操作了。
读写内存很简单,如果是内挂的话,因为是运行在进程内,甚至都可以使用普通的指针操作就可以了,本文介绍调用游戏内部函数的方法,这里以WOW为例解释调用过程,方法可以在WOW 3.x上使用,大家可以建个私服试试。
我们知道WOW里有很多的宏,玩家可以写一些宏做一些辅助的操作,这些宏内部是使用Lua实现的,而Lua呢又可以调用C/C++函数来访问WOW的内部数据。WOW里,玩家只能用公开的宏,还有些宏是WOW程序自用的,也就是说,WOW的程序员用C/C++实现了游戏的内核,然后再用Lua实现周边的辅助功能,这些宏在游戏界面上是不允许被调用的。但那里有很多我们需要的功能……
C调用Lua函数
Lua和C是可以相互调用的,当然了,看完本系列文章以后,你甚至可以让Lua、C#和C相互调用。Lua好像是基于堆栈虚拟机实现的,就是说操作数(oprand)都在堆栈上,Lua解释器根据操作符的要求,在操作数堆栈上取相应数目的参数。比如说,要在C里调用下面这个Lua函数:
function f(x, y) return (x ^ 2 * math.sin(y)) / (1 – x) end |
那么在C里,调用的方法是:
1 2 3 4 5 |
lua_getglobal(L, "f"); lua_pushnumber(L, x); lua_pushnumber(L, y); lua_pcall(L, 2, 1, 0); |
具体详情和原理请参见:Lua文档。当然要在C#里调用Lua函数的话,说白了就是将P/Invoke技术和上面的方法结合起来就可以了。
在C#里调用任意函数
在C/C++里是可以跳转到任意地址执行代码,只要将一个地址显式转换成函数指针再调用即可,那么在C#里,方法也是类似的:
1. 定义一个委托,即跟在P/Invoke里调用函数指针的方式是一样。
2. 使用函数Marshal.GetDelegateForFunctionPointer将给定的地址(也就是一个数字)转换成委托的实例。
3. 传入参数调用即可。
如果要调用的不是现有函数的话,那么可以在进程里分配一段内存,使用Marshal类里的AllocHGlobal函数来分配内存,将我们要执行的代码以机器码的形式写进去,然后通过上面讲的方式调用。这里介绍一个库,可以把上面的流程简化,BlackMagic(如果找不到的话,可以联系我要也行,不过我不一定总是回邮件的):
源码下载:http://www.shynd.com/public/BlackMagic.1.1.source.rar
文档下载:http://www.shynd.com/public/BlackMagic.1.0.Doc.zip
库下载:http://www.gamedeception.net/threads/14468-BlackMagic-Managed-Memory-Manipulation
用BlackMagic,在进程里动态注入代码并执行的方式如下面的代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
private void Synchronize() { while (_magic.ReadInt((uint)Offsets.LuaThreadLock) != 0) { Thread.Sleep(0); } ThreadSusspender.SuspendThread(MainThread); } private void AsmUpdateCurrentManager() { _magic.Asm.AddLine("mov EDX, {0}", CurrentManager); _magic.Asm.AddLine("FS mov EAX, [0x2C]"); _magic.Asm.AddLine("mov EAX, [EAX]"); _magic.Asm.AddLine("add EAX, 8"); _magic.Asm.AddLine("mov [EAX], edx"); } private void ResumeMainThread() { ThreadSusspender.ResumeThread(MainThread); } public void DoString(string lua) { Synchronize(); uint codeCave = _magic.AllocateMemory(0x2048); _magic.WriteASCIIString(codeCave + 0x1024, lua); _magic.Asm.Clear(); AsmUpdateCurrentManager(); _magic.Asm.AddLine("push {0}", 0); _magic.Asm.AddLine("mov eax, {0}", codeCave + 0x1024); _magic.Asm.AddLine("push eax"); _magic.Asm.AddLine("push eax"); _magic.Asm.AddLine("call {0}", (uint) Offsets.LuaDoString); _magic.Asm.AddLine("add esp, 0xC"); _magic.Asm.AddLine("retn"); _magic.Asm.InjectAndExecute(codeCave); _magic.FreeMemory(codeCave); ResumeMainThread(); } private uint CurrentManager { get { return _magic.ReadUInt(_magic.ReadUInt((uint)Offsets.ClientConnection) + (uint)Offsets.ClientManager); } } |
第26行代码将主线程暂停,以便我们的线程修改进程的对象时,不会影响到主线程显式的画面。第27行在游戏进程里分配了2K字节的内存,29行将lua代码拷贝到内存的后半段,31 – 32行做一些初始化的操作,比如清除上一次动态注入的汇编码,32行是跟游戏相关的代码,后面会提到。第34 – 40行插入要动态执行的代码,而代码的一些参数 – 主要就是数字。第42行注入和执行刚生成的代码,第43行代码在代码执行完毕之后释放内存,并在第44行恢复线程的执行。
而第47 – 53行代码是获取游戏(这里是WOW)里全局对象,因为WOW里可以从这个全局对象抓取到所有的数据 – 例如游戏的人物、障碍物之类的信息。
上面的代码也演示了WOW里的一个技巧,Lua里有一个函数dostring,可以接受一段lua代码的字符串并执行,演示的代码也是调用lua里dostring函数的方法,通过lua dostring的方法可以绕过WOW对受限宏的调用控制,不过是在3.x上试的了,后面兴趣点不在这里了,在4.x上就没有看了。
文章写到这里,只是把以前做内挂的技术讲了一下,在国内的网站上基本上搜不到使用C#做内挂的方法,因此用几篇文章的篇幅大概讲讲。内挂的缺点是,限制太多,因为是在游戏进程内加载东西,一不小心总是会被游戏检测出来,而调用游戏内部现有函数(比如一些变态的功能)又会被服务器端检测出封杀,所以后面会有一到两篇文章讲讲做纯外挂的方法,也就是不加载任何东西进入游戏进程。
如果大家对调试技术感兴趣的话,可以考虑购买我的新书: 应用程序调试技术,这套视频除了讲解调试的技巧外,还尽量完整地讲解了周边用到的技术,这是因为调试技术要好的话,需要基础功和背景知识扎实才行。
给网游写一个挂吧(四) – 调用游戏函数相关推荐
- 给网游写一个挂吧(三) – 启动外挂下
前面的文章给网游写一个挂吧 – 启动外挂上介绍了输入法注入的方法,本文解释第二种方法. 有的游戏限制比较多,可能会将输入法注入也禁用掉--这个时候就需要另想方法了.其实我们的目的很简单,就是要让不知道 ...
- 给网游写一个挂吧(二) – 启动外挂上
前面的文章给网游写一个挂吧– 反反外挂驱动的驱动,我们已经可以访问游戏的内存之后,接下来需要: 1. 找到游戏里关键元素的偏移量,比如生命值的内存的位置.一般来说,大部分大型3D游戏都 ...
- 给网游写一个挂吧(一) – 反反外挂驱动的驱动
去年做了一些研究,研究做外挂的一些相关技术,打算放出来跟大家分享,分享一下我们做挂的一些思路,挂的原理,希望抛砖引玉. 外挂说白了就是用程序代替人去操纵游戏,模拟人向游戏程序发送键盘.鼠标消息.一般的 ...
- div+css静态网页设计游戏网站设计——仿阴阳师游戏官网首页(1页) 学生动手游页设计模板下载 网游大学生HTML网页制作作品 简单游戏网页设计成品 dreamweaver学生网站模板
HTML5期末大作业:仿阴阳师游戏网站设计--仿阴阳师游戏官网首页(1页) 学生动手游页设计模板下载 网游大学生HTML网页制作作品 简单游戏网页设计成品 dreamweaver学生网站模板 常见网页 ...
- python抽奖游戏_利用Python写一个抽奖程序,解密游戏内抽奖的秘密
原标题:利用Python写一个抽奖程序,解密游戏内抽奖的秘密 前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 极客 ...
- 用js写出数据结构中的自定义队列,利用队列思想写出一个击鼓传花的游戏函数,优先级队列
队列的核心是先进先出 1.用js写出数据结构中的自定义队列 class Queue{constructor(){this.item = [];}// 1.入队enqueue(ele){this.ite ...
- 用Java写一个简单的回合制游戏
用Java写一个简单的回合制游戏 创建基本属性,血量,名字,技能,技能伤害. 如下: public class One3 {//创建三个属性private String name;private St ...
- 利用random 的randint 方法写一个猜数字的小游戏
学习python第二天,编写的一款数字小游戏 昨天学习完条件语句和while循环,老师留下的作业:利用random 的randint 方法写一个猜数字的小游戏. 第一次在CSDN上记录,小白一枚.希望 ...
- HTML5期末大作业:仿阴阳师游戏网站设计——仿阴阳师游戏官网首页(1页) 学生动手游页设计模板下载 网游大学生HTML网页制作作品 简单游戏网页设计成品 dreamweaver学生网站模板
HTML5期末大作业:仿阴阳师游戏网站设计--仿阴阳师游戏官网首页(1页) 学生动手游页设计模板下载 网游大学生HTML网页制作作品 简单游戏网页设计成品 dreamweaver学生网站模板 常见网页 ...
最新文章
- 【CCNA考试】2010-06-17-杭州-1000(PASS)
- hdu 5569(二维dp,水题)
- bootstrap-dist的下载和使用bootstrap可视化布局代码无样式解决
- 【pnglib】解析png格式的图像
- linux 内核连接跟踪,Linux内核连接跟踪锁的优化分析(1)
- python学习笔记--迭代
- 第三次学JAVA再学不好就吃翔(part6)--基础语法之char数据类型
- 通过python基于netconf协议获取网络中网元的配置数据,助力企业网络控制自动化轻松实现!
- 初中英语听力软件测试,初中英语听力训练
- c++频繁读取数据会丢失_异常堆栈信息丢失?到底是怎么回事?
- UGUI更换图片的三种方法
- 【神经网络】2. 神经网络设计过程
- php import mdf,excel表格怎么导入数据库数据格式转换-已有excel表格导入sql server生成*.mdf *.ldf文件......
- C# 使用HTMLhelp生成chm文件添加搜索并解决搜索找不到主题的问题
- 动态规划之LCS算法
- QT 打开PDF文件或图片文件
- JavaWeb(10.21)
- 2060显卡驱动最新版本_显卡驱动需更新,铭瑄RTX显卡受益大
- 通过实例彻底理解闭包
- UBOOT----基于itop4412开发板,从0开始,慢慢摸索UBOOT的启动流程和系统组织结构(一)
热门文章
- 是否允许一部分人“先富起来”
- ThreadLocal在Spring中的应用
- 反射通过配置文件运行的步骤
- Stream流中的常用方法_forEach
- SpringBoot_日志-SpringBoot日志关系
- 非对称加密算法 - Java加密与安全
- 其他类型的链表和线性表的总结(一级)
- 128位java_求一个java算法,用128位密钥的AES加密128位明文,得出的密文还是128位...很着急,非常感谢各位大神,求救!...
- Activemq-In-action(三)
- 解决Hibernate报错The server time zone value is unrecognized or represents more than one time zone