手游指针和基址详解

在手游作弊中,最常见的数值定位方式有2种,特征码定位和指针基址定位

特征码定位
offsetvalue
01001
11002
21003
31004

假设我们想要精确1002这个数值,直接在内存遍历这个值肯定会有很多的结构,那么特征码定位的作用就是减小定位的结果数量,精确我们想要的值
分析上面表格我们可以得知:

1002 偏移 -1 值是1001
1002 偏移 1 值是1003
1002 偏移 2 值是1004

根据这个特征,我们就能定位出想要的数值。但是,如果内存中有很多一样的特征,就很难再精确定位,再或者这个值附近的值都是随时变化的,那我们就不能特征定位这个值,怎么办,这时候有了个新的方法:基址指针定位

在讲解怎么找指针和基址之前,我们先来了解一下

什么是指针
指针是C语言的一个概念,也是C语言中比较困难的部分。

简单来说,指针也就是内存地址,指针变量是用来存放内存地址的变量,可对存储数据的变量地址进行操作。
不同类型的指针变量所占用的存储单元长度是相同的。

怎么在游戏内存中寻找指针
在32位游戏中,指针地址的存储是long int类型(4字节)
在64位游戏中,指针地址的存储是long long类型(8字节)

我这里写个例子

struct player{
    DWORD id; //ID
    DWORD hp; //血量
    DWORD hurt; //攻击力
    …
}

struct game{
    struct player *p1 = new struct player;
    struct player *p2 = new struct player;
    …
}

//游戏初始化
void init(){
    struct game* sg;
    sg = new struct game;
}
游戏初始化后,sg在内存中的地址是固定的,这就是基地址(简称基址)

(例子写的比较粗劣,仅供参考,并非代表实际结构)

如果说,我们要定位p1的血量,那逻辑就是:模块初始化地址–>基址–>p1–>hp

假设,这是在libGame.so中的代码,那么我们可以从/proc/游戏PID/maps中找到模块的初始化地址

根据上面的数据,我们可以知道,p1在内存中的结构如下:

{
    模块地址
    …
    sg地址(基址){
        p1地址{
            ID,
            血量,
            攻击力
        },
        p2地址{
            ID,
            血量,
            攻击力
        },
        …
    }
}

我们只需要一级一级往下跳就能找到血量的值
找基址的话,也就是逆向思维,很简单的,GG修改器作者恩比也写了相关脚本:下载地址
指针搜索脚本:下载地址

### 如何合并三个数组对象并去重 对于合并三个数组对象并且去除重复元素的任务,可以采用多种方法来完成这一目标。当处理的是基本类型的数组时,利用集合(`Set`)是一种高效的方式[^4];然而,如果是对象数组,则需要更复杂的逻辑来进行比较。 #### 使用 JavaScript 实现基于 `Set` 的简单去重 针对基本类型的数据,下面是一个简单的例子: ```javascript function mergeAndDeduplicateArrays(arr1, arr2, arr3) { const combinedArray = [...arr1, ...arr2, ...arr3]; return [...new Set(combinedArray)]; } ``` 这段代码首先通过扩展运算符(`...`)将所有的输入数组连接成一个新的单一数组,之后再创建一个新集合作为返回的结果,在此过程中自动过滤掉了任何重复项。 #### 对象数组的合并与去重 但是,如果要处理的对象不是基础数据类型而是复杂结构体的话,上述方法就不再适用了。此时应该考虑按照特定属性进行对比或者使用JSON字符串化的方式来辅助判断两个对象是否相等。 这里给出一种解决方案,它会根据指定键名对对象数组执行去重操作: ```javascript function dedupeObjectsByKey(arrayOfObjects, keyName) { let seenKeys = new Map(); return arrayOfObjects.filter(item => !seenKeys.has(item[keyName]) && seenKeys.set(item[keyName], true)); } // 假设有如下三个对象数组待合并 const arrayOne = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}]; const arrayTwo = [{id: 2, name: 'Charlie'}, {id: 3, name: 'David'}]; const arrayThree = [{id: 4, name: 'Eve'}, {id: 5, name: 'Frank'}]; // 首先合并这些数组 let merged = [...arrayOne, ...arrayTwo, ...arrayThree]; // 接着调用函数按'id'字段去重 let uniqueById = dedupeObjectsByKey(merged, "id"); console.log(uniqueById); ``` 在这个例子中,定义了一个名为 `dedupeObjectsByKey()` 的函数接收两个参数:一个是对象数组列表,另一个是要用来作为唯一性的依据的关键字名称。该算法遍历整个数组,并只保留那些其给定关键字首次出现过的条目。 #### PHP 处理多维数组的情况 考虑到PHP环境下的情况,特别是涉及到二维或多维度关联数组的情况下,可以通过序列化或自定义条件来进行有效的去重工作[^2]。例如: ```php <?php $allComments = [ ['post_id'=>1,'comment'=>'Comment A'], ['post_id'=>2,'comment'=>'Comment B'], ['post_id'=>1,'comment'=>'Different Comment'] ]; // 序列化方式适用于完全相同的子数组 $result = array_unique($allComments,SORT_REGULAR); print_r($result); // 这里只会移除真正意义上完全一样的记录 // 如果想要根据某个具体字段比如'post_id'来做去重 $temp = []; foreach ($allComments as $item){ $temp[$item['post_id']]=$item; } $result = array_values($temp); print_r($result); // 此种情况下即使其他字段不同也会被视作同一个项目而覆盖掉之前的值 ?> ``` 以上展示了两种不同的场景下如何有效地合并多个数组以及如何去除非必要的冗余信息。无论是JavaScript还是PHP环境下都有各自适合的技术手段可供选择。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'小五'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值