给网游写一个挂吧(四) – 调用游戏函数

简介:

前面的文章给网游写一个挂吧  启动外挂上给网游写一个挂吧  启动外挂下将外挂启动后,那就可以进行读写游戏内存和调用游戏的一些操作了。

 

读写内存很简单,如果是内挂的话,因为是运行在进程内,甚至都可以使用普通的指针操作就可以了,本文介绍调用游戏内部函数的方法,这里以WOW为例解释调用过程,方法可以在WOW 3.x上使用,大家可以建个私服试试。

 

我们知道WOW里有很多的宏,玩家可以写一些宏做一些辅助的操作,这些宏内部是使用Lua实现的,而Lua呢又可以调用C/C++函数来访问WOW的内部数据。WOW里,玩家只能用公开的宏,还有些宏是WOW程序自用的,也就是说,WOW的程序员用C/C++实现了游戏的内核,然后再用Lua实现周边的辅助功能,这些宏在游戏界面上是不允许被调用的。但那里有很多我们需要的功能……

 

C调用Lua函数

LuaC是可以相互调用的,当然了,看完本系列文章以后,你甚至可以让LuaC#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代码的字符串并执行,演示的代码也是调用luadostring函数的方法,通过lua dostring的方法可以绕过WOW对受限宏的调用控制,不过是在3.x上试的了,后面兴趣点不在这里了,在4.x上就没有看了。

 

文章写到这里,只是把以前做内挂的技术讲了一下,在国内的网站上基本上搜不到使用C#做内挂的方法,因此用几篇文章的篇幅大概讲讲。内挂的缺点是,限制太多,因为是在游戏进程内加载东西,一不小心总是会被游戏检测出来,而调用游戏内部现有函数(比如一些变态的功能)又会被服务器端检测出封杀,所以后面会有一到两篇文章讲讲做纯外挂的方法,也就是不加载任何东西进入游戏进程。

 

如果大家对调试技术感兴趣的话,可以考虑购买我的新书: 应用程序调试技术,这套视频除了讲解调试的技巧外,还尽量完整地讲解了周边用到的技术,这是因为调试技术要好的话,需要基础功和背景知识扎实才行。  

 


本文转自 donjuan 博客园博客,原文链接:  http://www.cnblogs.com/killmyday/archive/2012/06/20/2556420.html ,如需转载请自行联系原作者


相关文章
Springboot项目启动的三种方式
Springboot项目启动的三种方式
926 0
|
新零售 人工智能 安全
云上未来,数智导航:阿里云研究院报告合集
阿里云研究院,甄选了2021-2022年度的10份重磅报告,分别从数字经济、行业转型、数字县域等领域,尝试解读、并推动各行各业的转型升级,展望中国数字经济的未来,迎接数字经济发展的春天。
云上未来,数智导航:阿里云研究院报告合集
|
API
表情包-百度版免费API接口教程
该接口用于通过指定关键词从百度渠道获取表情包,支持POST或GET请求。需提供用户ID和KEY,可选参数包括关键词、页码及结果数量。返回数据包含状态码、信息提示、结果集等。示例中ID与KEY为公共测试用,建议使用个人ID与KEY以享受更高调用频率。
1475 4
|
12月前
|
存储 自然语言处理 机器人
基于的Qwen模型的智能客服Discord机器人,使用🐫 CAMEL、SambaNova、Firecrawl和Qdrant实现RAG Agent
基于Qwen模型的智能客服Discord机器人,使用CAMEL、SambaNova、Firecrawl和Qdrant实现RAG Agent。构建了一个能够处理复杂问题并能进行快速响应的强大聊天机器人。该机器人可在Discord平台上运行,支持实时对话和语义搜索,提供准确、全面的回答。项目包含详细的安装步骤、代码示例及集成指南,适合开发者快速上手。
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
544 4
MySQL基础:事务
|
存储 缓存 监控
深入了解MySQL内存管理:如何查看MySQL使用的内存
深入了解MySQL内存管理:如何查看MySQL使用的内存
1309 1
|
缓存 小程序 开发者
微信小程序如何刷新当前页面
微信小程序如何刷新当前页面
1509 0
|
存储 JavaScript Java
基于 WebSocket 打造聊天室
基于 WebSocket 打造聊天室
|
机器学习/深度学习 数据挖掘 API
【OpenVI—论文解读系列】细粒度分类SoftTriple Loss ICCV高引论文深入解读
SoftTriple Loss论文是在图像细粒度分类领域提出了新型度量学习方法,该方法可以被广泛应用于各种搜索、识别等领域中,目前谷歌学术引用240+,相对高引。相比原始论文文档,本文将介绍更多研究过程中遇到的问题点以及相应创新方法的演进历史。
6758 1
|
Java 关系型数据库 MySQL
jar包的下载
jar包的下载(网站提供+教程步骤)
2268 0
jar包的下载