gslab2022-安卓决赛
2022-11-17
| 2022-11-17
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property
Nov 17, 2022 10:16 AM

外挂分析报告

分析结论

外挂的组成结构

  1. 使用 Java 编写的界面
  1. 使用 C++ 编写的内存读取模块,sock1

外挂程序的储存位置

外挂的加密二进制文件保存在apk的assets目录下,启动后会解密并写出到 /data/user/0/com.tencent.esp/files

ELF启动原理

先原样写出 sock1, 然后读取解密再写出 sock1
cd 到 files 文件夹,然后传递两个参数 屏幕X 与 屏幕Y 执行 sock1

资源的加解密

以字符串 “gamesec” 生成密钥
notion image
解密并输出sock1
notion image
密钥生成算法
notion image
解密算法,一个简单的异或
notion image

反调试

  1. 检测 frida,ida 默认端口
  1. 检测 /proc/self/fd
  1. 检测 /proc/self/task
  1. 检测 frida 临时文件夹 re.frida.server
  1. 循环 BRKT

脱壳

单步调试至壳代码交还执行权时内存dump并修复即可

解混淆

使用 obpo 反混淆

实现外挂的原理

通过 GWorld 与 GName 基址
遍历 ActorList 找到目标 Actor 并读取坐标数据,以JSON的形式输出到 /sdcard/1A.txt
外挂APP在Java层读取1A.txt解析并绘制,而不是在so中进行绘制

外挂读内存的方式

process_vm_readv 系统调用

外挂访问游戏地址对应的含义

读取GWorld → UWorld → ULevel → ActorList 然后遍历 ActorList
找到所有的ThirdPersonCharacter ,读取 RootComponent → RelativeLocation
找到 PlayerCameraManager 读取 CameraCache → POV

分析过程

1. 判断外挂类型

打开安装包,经过分析可以知道该外挂是使用Java与C++开发的外挂。
对于此类外挂,我们需要着重关注so层逻辑,还有assets与res/raw文件下的内容。

2. 初步分析

使用IDA打开 libPutri.so 在到导出表可以观察到该so使用JNI静态注册了一些函数,在Java层寻找对应函数。
notion image
使用JadxGUI打开APK,定位到 com.tencent.esp.Overlay 类,发现只有DrawOn方法被实际使用,其他方法并未使用。则DrawOn方法为核心绘图逻辑入口点。
notion image
经过对Java层反编译结果对阅读,该外挂Java层使用BlackObfuscator进行了混淆。
该程序SO层无加密无混淆,简单分析过后未发现外挂内存读取主逻辑。该SO主要承担绘图功能。通过socket接收相关数据并对其进行绘制。
notion image
在手机上安装外挂和游戏,外挂功能正常,重新分析Java层,在MainActivity中发现运行sock1文件
notion image
在手机上运行外挂,查看名为sock1的进程,即可定位到外挂内存读取逻辑所在的elf文件
notion image
因此Java层的混淆使得反编译后的Java结果不再可靠,重新分析Java层,直接查看smali代码。
notion image
发现sock1文件的写出,由于二进制文件已直接写出,直接分析二进制文件即可,解密算法无需手动还原。
使用IDA载入,发现有壳。
notion image
搜索所有的SVC 0指令,并下断
notion image
结合arm64系统调用表分析可得,从上往下依次为ARM_cacheflush,mmap2,mmap2,mprotect
在调试执行之前,先手动执行一遍程序。出现段错误,说明该二进制文件可能被运行后就被修改,或者有参数未传递。
notion image

2. 找出sock1的运行方法

使用Frida Hook Runtime.exec与 DataOutput.write
notion image
由此可以得知,在执行sock1的时候传递了屏幕分辨率,不过X有一些减小。再次手动运行sock1,可以发现,在 /data/local/tmp 目录下运行的时候会出现null FILE*,说明sock001等文件也是必需的。
notion image

3. 外挂核心二进制文件sock1的脱壳

启动android_server,使用IDA调试启动sock1
notion image
提示文件是动态链接库无法执行,使用010editor将文件类型改成可执行文件。
notion image
修改调试参数,启动
notion image
一路F9,运行到了反调试代码处,此时查看LR寄存器,跳转过去
notion image
notion image
在maps中找到基址, 修复ELF Magic
notion image
使用 https://github.com/maiyao1988/elf-dump-fix dump下来二进制文件并修复,再分析脱壳后代码
notion image

4. 外挂核心ELF分析

使用IDA打开so,首先关注导入表。
notion image
导入表缺少process_vm_readv等函数,dlopen与dlsym显得十分可疑,查找其引用
notion image
dlopen并未实际使用。查看Graph Overview有明显的OLLVM特征,可以使用 https://github.com/obpo-project/obpo-plugin 反混淆。
notion image
分析此sub_29B0函数可以得知,外挂使用dlsym动态解析出部分关键函数的地址并保存到全局的函数表 off_502E4 中。
使用dump出来的文件作为断点参考,直接调试 sock1
notion image
sub_26798为main函数
notion image
sub_26378 函数中创建了反调试线程,在sub_26060中循环调用反调试函数sub_25E94 并 sleep 3秒,反调试函数sub_25E94中调用5个子函数进行反调试
notion image
在调试中可以直接NOP掉 sub_26378,即可过掉反调试。
notion image
根据全局函数表对应的函数,在调试中找到对应函数下断点即可分析。不过有更方便的办法,该外挂未检测ptrace可以直接使用strace分析系统调用。
notion image
游戏主要读内存逻辑在 anon:libc_malloc 内存中
在 strstr strcmp open fopen 下断点
notion image
notion image
notion image
notion image
loc_F737F42C 为读取坐标的代码块
notion image
写出结果

5. 分析外挂原理以及访问游戏地址对应的含义

  1. 使用 strace 查看该外挂系统调用
notion image
notion image
notion image
  1. 寻找GWorld与GName,然后使用 UE4Dumper 导出游戏的SDK。
使用IDA打开游戏的 libUE4.so,搜索GWorld和GNameEntryPoolAllocator
GName = GNameEntryPoolAllocator+0x14
结果:
  1. GWorld = 0x491E6F0
  1. GName = 0x48711B4
使用UE4Dumper 导出SDK与actorlist
notion image
notion image
该外挂还是读取GWorld → UWorld → ULevel → ActorList 然后遍历 ActorList
找到所有的ThirdPersonCharacter ,读取 RootComponent → RelativeLocation
找到 PlayerCameraManager 读取 CameraCache → POV
然后外挂将结果转换为JSON,输出到 /sdcard/1A.txt
Java中读取输出结果:
notion image
Java 绘制函数:
notion image

外挂复现

使用Android Studio开发,process_vm_readv读取内存。
notion image
PS:复现完才发现不需要复现,属实是没仔细看清楚题目。。。
 
  • 腾讯游戏安全竞赛
  • gslab2022-和平精英初赛gslab2022-安卓初赛
    • Giscus
    目录