C++游戏分析与破解方法介绍

news/2024/12/22 0:32:47/

1、C++游戏简介

目前手机游戏直接用C++开发的已经不多,使用C++开发的多是早期的基于cocos2dx的游戏,因此我们这里就以cocos2d-x为例讲解C++游戏的分析与破解方法。

Cocos2d-x是一个移动端游戏开发框架,可以使用C++或者lua进行开发,也可以混合使用。在使用C++开发时,游戏主逻辑模块默认名字是“libgame.so”,跟其他的native模块一样,放在游戏的“lib”目录下。也就是Android手机上的“/data/app-lib/包名/”目录,或者直接apk解包后的“lib\armeabi-v7a”目录,其中“armeabi-v7a”取决于当前CPU架构。

为了进一步确定游戏引擎,可以把“libgame.so”载入IDA分析,搜索是否有包含“cocos2dx”字符串的函数名,如图:
在这里插入图片描述
由于cocos2d-x引擎也支持lua,可以继续搜索lua相关函数,如果没有搜到,基本可以确定这个游戏是基于cocos2d-x引擎且使用C++编写的游戏。

2、C++基础

C++语言以及C++程序的逆向分析是很大的话题,这里仅简单提一下,如果读者很欠缺C++相关的知识,应该先找相关书籍学习,不可急于求成。

2.1 类指针

C++语言是兼容C语言的偏底层语言,因此在介绍C++的面向对象的概念之前首先需要了解一下指针。

通常语境下,我们说“指针”其实全称是“指针变量”,也就是说它其实是一个变量,“指针”其实就是“内存地址”的意思,所以“指针变量”就可以理解为“内存地址变量”,就是一个保存内存地址的变量。对应的,不同类型的指针,说的就是那个内存地址保存的变量的类型,比如“函数指针”,我们就可以理解为,这是一个变量,这个变量保存的是一个地址,这个地址指向的位置是一个函数。

“类指针”就是一种指针变量,这个指针的类型不是C++的基本类型,而是我们自定义的“类”。类指针通常用来作为基址,索引类的成员变量,或者虚函数。所谓“基址”,跟汇编中说的基址是一个意思。

2.2 虚表

如果一个类有虚函数,那么它的内存结构中,头部就首先会有4个字节用来存储一个指针变量。这个指针变量就叫“虚表指针”,它指向的位置是一个函数指针数组,这个数组就叫“虚表”,也就是一连串的函数地址。这个数组里的每一个元素,都是这个类的虚函数的地址。同一个类的所有对象共享一个虚表。如果两个类的虚函数不同,那么就会有不同的虚表。

虚表稍微了解即可,它的存在主要是为了实现多态。这里介绍是方便大家了解类的内存结构,如果一个类有虚函数,则它实例的头部4个字节留给虚表指针,其余位置放置成员变量;如果没有虚函数,则内存全放置成员变量。

2.3 类的成员函数

类的成员函数与一般的全局函数或者静态函数唯一的区别在于,它的第一个参数是一个“隐式”的参数,这个参数就是它所属的对象的this指针。“隐式”说的其实是在语言层面看不见,但是在汇编代码中可以看到。

所以在分析的时候如果看到函数的第一个参数是一个指针,那它可能就是一个对象的指针,而这个函数就有可能是个成员函数。

3、C++游戏分析方法

C++编写的游戏分析起来会相对要难,但具体修改起来就会相对简单,因此破解的重点还是在如何找到关键的函数,或者关键的数据。这是一个逆向发散的过程,因此有许多方法都可以尝试。

这里仅讨论无符号或者仅有少数与游戏逻辑无关的符号下的游戏逻辑模块的分析。区分一个游戏逻辑模块有无符号,可以简单地通过在IDA的函数列表中搜索关键字符串看结束,比如“HP”、“Boss”、“Player”等。

有符号的情况相对就会简单很多,因此如有可能,最好拿到有符号的样本进行分析。有符号的模块样本通常会出现在游戏早期版本,或者某个特定的版本由于开发人员的疏忽而遗漏出来。尽管版本会不一致,但还是有很多可以借鉴的地方。

常规的C++程序逆向分析就是通过看汇编代码,从而理解函数的功能。也可以通过函数的参数以及返回值去猜测函数功能,最后通过理解一个个函数功能而把整个程序的流程厘清,再找到关键点。这是一个费时费力的过程,因此一般仅用在关键函数分析处。整个分析过程还是有许多其他的技巧和方法可以提高效率,下面就介绍几个常用的方法。

3.1 借助字符串信息

由于游戏开发过程中免不了要打印Log用于调试,或者由于别的原因在程序中保留了敏感字符串信息。因此直接在IDA中按快捷键“Shift+F12”列出所有字符串就可以获取到相当多的信息。如图:
在这里插入图片描述
根据字符串信息,可以索引到相关函数,方便对函数的功能进行分析。

3.2 send函数回溯

游戏总会进行网络通信,而Android系统底层处理网络通信的函数就是send函数。动态调试的时候可以在send函数处下断,就可以断到游戏与服务器的交互数据。但send函数过于底层,一般游戏都会有加密,这里断到的数据通常都是加密后的数据,因此需要向上回溯。

在向上回溯的过程中同时注意分析各层函数的作用,有些只是send函数的封装,有些就可能会涉及到加密,或者组包。我们的目的是找到组包函数和它的上层。在组包函数处修改,就可以影响游戏与服务器的底层通信数据;组包函数的上层一般就是功能函数,直接修改功能函数就可以影响游戏逻辑,最终可以更“自然”地影响到游戏的封包。

这个过程中可以借助IDA脚本,过滤一些频繁调用的函数,比如心跳函数;也可以打印log,分析调用来源和它们的调用频率。

3.3 输出log

在一些频繁被调用的函数,或者是有明文信息的函数处,如果有必要,也可以采用IDA脚本编程的方式打印log进行分析。如果调用过于频繁,脚本的速度跟不上,也可以采用注入进程并下Hook的方式打印log,速度就会快很多。具体的注入方法详见其他篇,这里不多说。

4、破解

C++游戏的破解相对比较简单,通常都是注入游戏进程,然后干涉游戏逻辑,具体来说可以用以下几种方法:

   1、Hook关键函数,修改传入参数。比如存在一个set_MaxHP函数,可以修改传入的参数,修改怪物或者玩家的血量。2、Hook关键函数,修改返回值。比如存在一个computeDamge函数,可以修改函数的返回值,实现秒怪或者无敌的功能。3、Hook关键函数,多次调用。比如存在一个hit函数,可以多次调用该函数实现多次打击。4、Hook关键函数,直接返回。比如存在一个dead函数,直接跳过执行,可以实现不死效果。5、直接修改判断逻辑。注入到进程,或者远程ptrace后直接在二进制层面直接修改汇编指令。比如存在一个判断,杀怪数大于10则通关,可以修改为杀怪数小于10则通关。

http://www.ppmy.cn/news/48440.html

相关文章

机器学习 day06(向量化应用于多元线性回归的梯度下降算法,正规方程)

1. 向量化多元线性回归,及梯度下降算法 将W₁,…,Wn写成向量W,将X₁,…,Xn写成向量X,而b还是之前的b注意:在多元线性回归的梯度下降算法中,Wj是指从W₁到Wn中的某一项&…

通识哈夫曼树及其应用,一起来构造属于自己的哈夫曼树

1.哈夫曼树的背景 哈夫曼(霍夫曼、赫夫曼)David Albert Huffman(August9,1925-October7,1999)。计算机科学的先驱,以他的哈夫曼编码闻名,在他的一生中,对于有限状态自动机,开关电路,异步过程和信…

死磕“增长”:火山引擎的实用主义

作者 | 曾响铃 文 | 响铃说 在刘慈欣的科幻小说《三体》中,地外文明为了封锁地球科技,在天文台向地球科学家展现了「宇宙闪烁」这一奇观,试图颠覆人类的认知,从而影响科技进步,促使地球科技发展陷入停滞。 如今&…

playwright实战篇(tx、ali225)

人人都笑金角,人人都是金角推荐文章: 1、https://playwright.dev/python/docs/api/class-playwright //官方文档 2、https://cuiqingcai.com/36045.html //崔庆才教程 3、https://github.com/qqq732004709/ //实战参考 4、https://www.cnblogs.com/ca…

4.17~4.18学习总结

网络编程 概述 1.什么是网络编程 在网络通信协议下,不同计算机上运行的程序,进行的数据传输,计算机跟计算机之间可以通过网络进行数据传输。 2.常见的软件架构: B/S,C/S 3.通信的软件架构CS BS各有什么区别和优点…

java 快排算法详解,java 快排代码

快排是一种高效的数据结构,它使用一个关键字(Key)来表示数据元素的一个集合。也就是说,快排是一个有序数组,而这个有序数组由两个元素组成。 快排的基本思想是:如果数组元素的值比它前面的两个元素都大&…

一文搞懂Java中的异常问题

思考几个问题 1:JavaWeb系统中,我的代码未做任何处理,报错了还会往下执行吗? 2:JavaWeb系统中,我的代码做了 try catch finally, 报错了还会往下执行吗? 3:JavaWeb系统中&#xff0c…

制造业数字化转型评价指标体系构建与应用

数字化转型的过程不是机械简单性的线性组合,而是由一系列分叉、突变、自组织等复杂行为组成,是一个复杂性系统演变的过程。 本文从架构的理念出发,构建制造业数字化转型架构,并基于参考架构给出评估制造业数字化转型发展过程的评估…