首页
社区
课程
招聘
[原创] 某 PUBG 内核辅助逆向分析
发表于: 3天前 2041

[原创] 某 PUBG 内核辅助逆向分析

3天前
2041

最近一个朋友发了一个 PUBG 的内核挂过来,名字就不说了,避免麻烦。久仰外挂隐藏之大名,正好拿来看看现在的内核辅助是怎么写的,用了什么技术、怎么隐藏、怎么和反作弊系统对抗。

样本是一个 .sh 自解压脚本,要求 root 权限运行。下面是完整的分析过程。

拿到的文件是 PUBG公益内核.sh,一个 shell 脚本。打开看头部:

经典的自解压结构:tail +48 跳过前 48 行 shell 头,剩下的是 gzip 压缩的 payload,解压出来就是主程序 ditpro_main

有意思的是最后那个 sleep 5 && rm -rf "$0"——执行完 5 秒后把自己删了。不留尸体,取证的时候磁盘上已经没有原始文件了。

写个 Python 脚本把 payload 提取出来:

解压出来是个 40MB 的 ELF,AArch64 架构,动态链接的 PIE 可执行文件。NDK r27d 编译,target API 23。大得离谱——后面会知道为什么这么大。

ditpro_main.bin 丢进 IDA,总共 8484 个函数,7937 个没名字(stripped)。段布局值得注意:

.rodata 占了 34.5MB,比代码段还大好几倍。这就是那 40MB 体积的来源——所有内核模块的数据都塞在这里面。

逆向外挂最核心的问题:内核驱动在哪?

最开始尝试在 binary 里直接搜 ELF magic \x7fELF,搜完发现除了主程序自己的 ELF 头之外,没有第二个 \x7fELF 签名。所以 .ko 不是以原始二进制形式嵌在里面的。

换个思路,搜和内核模块相关的字符串。搜 insmod 找到了 sub_21BA524

加载完就删,标准的反取证操作。那 ko_path 从哪来?往上追调用链。

追到 sub_21BA204,这个函数负责把数据「解码」成 .ko 文件:

每次读 2 个字符,strtoul 按十六进制解析,写一个字节。所以 .ko 是以 ASCII hex 字符串的形式存储的——不是加密,就是简单的 hex 编码。

比如 ELF 头 \x7fELF\x02\x01\x01 在 .rodata 里长这样:7f454c46020101...

在 IDA 里搜这个 ASCII 字符串,一搜搜出来 17 个。所有的 .ko 都找到了。

再追上一层,到 sub_21C4898。这个函数是 .ko 的分发入口:

uname -r 拿内核版本,然后 switch/case 选对应版本编译的 .ko。内嵌了 17 个版本,覆盖 4.14.117 到 6.6.87,基本涵盖了主流 Android 设备的内核。

全局变量到内核版本的对应关系:

这些全局变量在 .init_arraysub_21CE444 里被初始化,就是简单的 memcpy 把 .rodata 里的 hex 字符串拷贝到 std::string 对象里。

知道了编码方式,提取就很简单了:

提取结果:

所有模块名都叫 hack,license 声称 GPL,作者 大大怪

拿 5.15.178 版本(最大的那个,62KB)丢进 IDA。这次有符号,分析起来舒服多了。

init_module 做了三件事:

misc 结构体里写的很清楚:minor 号 255(MISC_DYNAMIC_MINOR,动态分配),设备名 niuto01,file_operations 指向 dispatch_functions

关键是后面两步:list_del_init 把自己从内核的模块链表里摘掉,kobject_del/sys/module/hack/ 目录干掉。这样 lsmod 看不到、/sys 下找不到,但设备节点 /dev/niuto01 已经注册好了,ioctl 通道照常工作。

配合用户态的 insmod 后立即 remove() 删文件,三重消失:磁盘上没文件、模块列表里没记录、sysfs 里没入口。

dispatch_ioctl 是核心,4 个命令:

26212 是握手命令——用户态打开 /dev/niuto01 后先发这个,检查返回值是不是 10086,确认驱动已经活着。

这是整个外挂的技术核心。它不走 process_vm_readv 这种正经 API(会被反作弊监控),而是自己手动遍历页表,直接操作物理内存。

第一步:手动页表遍历

translate_linear_address 实现了完整的 AArch64 四级页表遍历:

其中物理地址到内核虚拟地址的转换用的是:(phys & 0x7FFFFFF000) - memstart_addr) | 0xFFFFFF8000000000,这是 ARM64 Linux 的线性映射公式。

第二步:物理内存读取

拿到物理地址之后,read_physical_address 通过 ioremap_cache 把物理地址映射到内核虚拟空间:

先检查 mem_section(SPARSEMEM 模型下的物理页面有效性校验),然后 ioremap_cache 映射、copy_to_user 拷贝到用户态、iounmap 解除映射。一气呵成。

第三步:跨页读写

ReadProcPhyMem 处理了跨页的情况。因为页表是以 4KB 为单位映射的,如果要读的数据跨越了页面边界,就得分多次:

注意这个版本更暴力——它直接用 (phys - memstart_addr) | 0xFFFFFF8000000000 算出内核线性映射地址,连 ioremap 都省了。直接当内核指针用,copy_to_user 拷走。

get_module_base 用来在目标进程里找某个 .so 的加载地址(比如游戏引擎 libUE4.so):

遍历目标进程的 VMA(Virtual Memory Area)链表,对每个 VMA 用 file_path 拿到映射文件路径,strrchr 取文件名,和目标模块名比较。匹配上了就返回 vm_start

内核驱动只是基础设施,用户态的 ditpro_main 才是外挂本体。它还用了一堆花活来隐藏自己。

外挂要画 ESP(透视框)和准心,但不能让截图、录屏看到。sub_21BEFEC 是整个渲染隐藏的初始化函数——3900 字节,144 个基本块,做了一件事:根据 Android 版本动态解析 SurfaceFlinger 的 C++ API。

第一步:获取 Android 版本

日志 tag 是 AImGui——Android ImGui 的缩写,整个渲染系统基于 Dear ImGui。版本低于 5 直接退出。

第二步:dlopen 系统库

没有直接调用 dlopen,而是通过传入的函数指针表间接调用。这样 GOT 表里就不会出现 dlopen 的记录,增加一点静态分析的难度。

第三步:解析 35+ 个 C++ mangled 符号

这是这个函数的主体。它往一个 288 字节的结构体里填充函数指针,每个指针对应一个 SurfaceComposerClient 的方法。结构体布局:

最有意思的是 createSurface 的版本适配。Android 每个大版本都改过这个函数的签名,所以外挂针对每个版本 dlsym 不同的 mangled name:

7 个不同的 C++ 函数签名,7 个不同的 mangled symbol name。只要有一个对不上,dlsym 返回 NULL,Surface 就创建不了。这就是为什么函数要这么大——大部分代码都在做版本分发。

事务 API 的版本分裂

Android 9 之前用的是全局事务模型:

Android 9+ 改成了 Transaction 对象:

Transaction::apply 的参数都从 Android 13 开始多了一个 bool。外挂专门处理了这个差异:Android 9-12 用 apply(bool),13+ 用 apply(bool, bool)

核心隐藏机制:setTrustedOverlay


[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 12
打赏
分享
最新回复 (8)
雪    币: 88
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
牛批
3天前
0
雪    币: 2843
活跃值: (5602)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
懂了 写挂去了
3天前
0
雪    币: 1549
活跃值: (5108)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
666
2天前
0
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
666
1天前
0
雪    币: 144
活跃值: (2558)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
666
1天前
0
雪    币: 11579
活跃值: (8922)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
没有附件我好象看不懂!
16小时前
0
雪    币: 1454
活跃值: (1275)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
还是依旧 内核老套路
13小时前
0
雪    币: 64
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
附件给个链接谢谢啦~
9小时前
0
游客
登录 | 注册 方可回帖
返回