本次题目基于 UE4 引擎 开发的简化版射击游戏 Demo。游戏中存在多个 被刻意修改的异常功能点,导致角色行为、渲染效果等出现明显异常。参 赛者需通过逆向分析定位并修复这些问题,使游戏恢复正常逻辑。修复方 法包括但不仅限于静态修复或动态修改代码(inline hook 等)。 游戏内,左右两侧陀螺仪分别是控制人物的移动和转向,点击屏幕进行子弹 射击,没有跳跃功能。 本赛题没有检测调试工具,如果机器闪退,说明游戏版本不兼容,请及时更 换设备
评分标准
- 需要分析出游戏中存在的异常功能, 分析出越多的异常功能得分越高。 如果仅修复异常,而没有给出异常功能的原理分析,不得分。注意某个异常功能可能存在多个影响因素。
- 注意修复方案必须保证游戏所有原生 .so 库正常加载。通过库加载失败的方法修复,不得分。分析报告越详细、越全面,获得的分数也会越高。
也就是要完成下面的步骤
- 通过逆向和查看软件,分析出异常功能点
- 探究其原理
- 给出修复方法(同时保证原生库正常加载)
- 左陀螺仪移动异常:移动不是一步步走,而是直接朝着某个方向移动到碰撞发生
- 右陀螺仪无异常
- 子弹射击有异常:并非朝着视角正中心发射,而是有向着某个地方发射,其发射方式尚不清楚
- 渲染效果异常:人物存在透视情况
首先尝试静态分析 包名 com.ACE2025.Game
得到引擎是 4.27 版本,
可能需要学习一下 ue,我注意到这个项目和官方的 First Person 很像,可能就是通过修改而来,那么贴图也被修改了
竟然是 debugable 的,还挺良心
找到一个长得很像的 demo,开始对照逆向
通过 dump sdk 搞定偏移
GWorld 得查这个字符串才行(靠上面一点)Travel aborted - new world is the same as current world
GWorld 0xAFAC398
GName 0xADF07C0
GUObject 0xAE34A98
Class: DefaultPawn.Pawn.Actor.Object
float BaseTurnRate;//[Offset: 0x27c, Size: 0x4]
float BaseLookUpRate;//[Offset: 0x280, Size: 0x4]
PawnMovementComponent* MovementComponent;//[Offset: 0x288, Size: 0x8]
SphereComponent* CollisionComponent;//[Offset: 0x290, Size: 0x8]
StaticMeshComponent* MeshComponent;//[Offset: 0x298, Size: 0x8]
bool bAddDefaultMovementBindings;//(ByteOffset: 0, ByteMask: 1, FieldMask: 1)[Offset: 0x2a0, Size: 0x1]
void TurnAtRate(float Rate);// 0x938eadc
void MoveUp_World(float Val);// 0x938eb8c
void MoveRight(float Val);// 0x938ec3c
void MoveForward(float Val);// 0x938ecec
void LookUpAtRate(float Rate);// 0x938ea2c
之后是找 libGame.so
去看看外挂逻辑
是在 .init_array
里面起了一个线程,线程运行的主函数是 sub_1B9C
sub_30A0 sub_29A4 sub_2B6C sub_2D1C 之类的函数都是解密字符串的
0xB80 的函数是通过 pid 和库函数名找基地址的
- 择映射文件路径:
- 如果第一个参数小于 0,读取
/proc/self/maps
(当前进程) - 否则,使用
/proc/%d/maps
格式读取特定进程的映射
- 如果第一个参数小于 0,读取
- 打开并读取内存映射文件:
- 调用
fopen
打开映射文件 - 检查是否成功打开
- 调用
- 循环处理映射文件内容:
- 循环读取映射文件的每一行(使用
fgets
) - 对于每一行,检查是否包含目标库名(通过
strstr
)
- 循环读取映射文件的每一行(使用
- 解析内存地址:
- 当找到目标库名时,提取该行的第一个部分(内存地址)
- 使用
strtok
分割字符串,获取地址部分 - 使用
strtoul
将十六进制字符串转换为基址值
找关键结构:https://www.cnblogs.com/revercc/p/17641855.html dump skd:https://github.com/revercc/UE4Dumper.git
GWorld 得查这个字符串才行(靠上面一点)
Travel aborted - new world is the same as current world
照着 UE4 源码看
GWorld 0xAFAC398
GName 0xADF07C0
GUObject 0xAE34A98
dump 到 sdcard 下,然后 pull
#!/bin/sh
adb push libs/arm64-v8a/ue4dumper64 /data/local/tmp/ue4dumper64
adb shell "su -c 'chmod 755 /data/local/tmp/ue4dumper64'"
adb shell "su -c '/data/local/tmp/ue4dumper64 --newue+ --strings --gname 0xADF07C0 --package com.ACE2025.Game --output /sdcard/Download'"
adb shell "su -c '/data/local/tmp/ue4dumper64 --newue+ --objs --gname 0xADF07C0 --guobj 0xAE34A98 --package com.ACE2025.Game --output /sdcard/Download'"
./ue4dumper64 --newue+ --sdkw --gname 0xADF07C0 --gworld 0xAFAC398 --package com.ACE2025.Game --output /sdcard/Download
./ue4dumper64 --newue+ --actors --gname 0xADF07C0 --gworld 0xAFAC398 --package com.ACE2025.Game
dump 结果储存在 dump/ 下
分析外挂
函数 sub_1B9C 分析
第一眼看有:
sub_30A0
- 解密特定数据的函数sub_B80
- 可能从文件获取配置或地址的函数usleep(0x2710u)
- 10 毫秒延时,可能用于降低性能影响
辅助函数分析
sub_30A0 - 数据解密函数
int8_t *__fastcall sub_30A0(int8_t *p_ones, int8_t *p_unkown_bytes) {
if (dword_B664 == 1)
return p_ones;
for (i = 0; i < 10; ++i)
p_ones[i] = p_unkown_bytes[i + 26] ^ p_unkown_bytes[i % 26];
dword_B664 = 1;
return p_ones;
}
类似的还有 sub_29A4 sub_2B6C sub_2D1C
0xB80 的函数
memory_patch_loop 是通过 pid 和库函数名找基地址的
- 择映射文件路径:
- 如果第一个参数小于 0,读取
/proc/self/maps
(当前进程) - 否则,使用
/proc/%d/maps
格式读取特定进程的映射
- 如果第一个参数小于 0,读取
- 打开并读取内存映射文件:
- 调用
fopen
打开映射文件 - 检查是否成功打开
- 调用
- 循环处理映射文件内容:
- 循环读取映射文件的每一行(使用
fgets
) - 对于每一行,检查是否包含目标库名(通过
strstr
)
- 循环读取映射文件的每一行(使用
- 解析内存地址:
- 当找到目标库名时,提取该行的第一个部分(内存地址)
- 使用
strtok
分割字符串,获取地址部分 - 使用
strtoul
将十六进制字符串转换为基址值
继续分析函数
decrypt_data_xor(library_name, encrypted_data);// libUE4.so
lib_base = find_library_base(0xFFFFFFFF, library_name);
app->base = lib_base;
v19 = sA0_1->base > 0x10000uLL;
if ( !v19 ){
break;
}
base = app->base;
app->gworld =*(base + 0xAFAC398);
if ( sA0_2->gworld >= 0x10000uLL )
break;
后面根据 SDK.txt 内容看偏移
Level SDK 看这里是 padding,因为这里和具体 UE4 版本有关了,参考 ue4dumper 的偏移量:
void patchUE422_64(){
//Class: FNameEntry
FNameEntryToNameString = 0xc;
//Class: UStruct
UStructToSuperStruct = 0x40;
UStructToChildren = 0x48;
//Class: UFunction
UFunctionToFunctionFlags = 0x98;
UFunctionToFunc = 0xc0;
//Class: ULevel
ULevelToAActors = 0x98;
ULevelToAActorsCount = 0xa0;
}
继续用 dumper 分析 Actor 偏移情况
newue+ --actors --gname 0xADF07C0 --gworld 0xAFAC398 --package com.ACE2025.Game --output /sdcard/Download <
Process name: com.ACE2025.Game, Pid: 28221
Base Address of libUE4.so Found At 744acbf000
UWorld: 7455c6b398 | World: 739672d060 | Name: FirstPersonExampleMap
Level: 739cba68c0 | Name: PersistentLevel
ActorList: 7396756880, ActorCount: 47
Id: 0, Addr: 7399787a20, Actor: WorldInfo
Id: 1, Addr: 739c95f380, Actor: LightmassImportanceVolume
Id: 2, Addr: 7399790d00, Actor: EditorCube8
Id: 3, Addr: 7399790ac0, Actor: EditorCube9
Id: 4, Addr: 7399792800, Actor: EditorCube10
Id: 5, Addr: 73997925c0, Actor: EditorCube11
Id: 6, Addr: 7399792380, Actor: EditorCube12
Id: 7, Addr: 7399792140, Actor: EditorCube13
Id: 8, Addr: 7399791f00, Actor: EditorCube14
Id: 9, Addr: 7399791cc0, Actor: EditorCube15
Id: 10, Addr: 7399791a80, Actor: EditorCube16
Id: 11, Addr: 7399791840, Actor: EditorCube17
Id: 12, Addr: 7399791600, Actor: EditorCube18
Id: 13, Addr: 73997913c0, Actor: EditorCube19
Id: 14, Addr: 7399791180, Actor: EditorCube20
Id: 15, Addr: 7399790f40, Actor: EditorCube21
Id: 16, Addr: 739e94e080, Actor: TemplateLabel
Id: 17, Addr: 7396737100, Actor: SkySphereBlueprint
Id: 18, Addr: 73997937c0, Actor: AtmosphericFog
Id: 19, Addr: 7399792ec0, Actor: SphereReflectionCapture
Id: 20, Addr: 7399790880, Actor: Floor
Id: 21, Addr: 7399790640, Actor: Wall1
Id: 22, Addr: 7399790400, Actor: Wall2
Id: 23, Addr: 73997901c0, Actor: Wall3
Id: 24, Addr: 739e94e2c0, Actor: Wall4
Id: 25, Addr: 7399792c80, Actor: BigWall
Id: 26, Addr: 7399792a40, Actor: BigWall2
Id: 27, Addr: 739c95ec00, Actor: NetworkPlayerStart
Id: 28, Addr: 7399793340, Actor: LightSource
Id: 29, Addr: 7398d6b0a0, Actor: PostProcessVolume
Id: 30, Addr: 7399793100, Actor: SkyLight
Id: 31, Addr: 739c957180, Actor: DefaultPhysicsVolume
Id: 32, Addr: 739cbacbc0, Actor: MyProjectGameMode
Id: 33, Addr: 739668e080, Actor: GameSession
Id: 34, Addr: 739668f4c0, Actor: ParticleEventManager
Id: 35, Addr: 73995d6d00, Actor: GameNetworkManager
Id: 36, Addr: 744392c800, Actor: AIController
Id: 37, Addr: 739e94d780, Actor: FirstPersonExampleMap_C
Id: 38, Addr: 73958c93a0, Actor: FirstPersonCharacter_C
Id: 39, Addr: 7399585b50, Actor: ThirdPersonCharacter
Id: 40, Addr: 739c958a80, Actor: GameStateBase
Id: 41, Addr: 7395f06970, Actor: AbstractNavData-Default
Id: 42, Addr: 73958cece0, Actor: PlayerController
Id: 43, Addr: 744395cf00, Actor: PlayerState
Id: 44, Addr: 73962c5580, Actor: PlayerCameraManager
Id: 45, Addr: 7398d67120, Actor: CameraActor
Id: 46, Addr: 744395c480, Actor: MyProjectHUD
之后找到 ActorList 中指向偏移 0xA63BE28 的那个 Actor
好像一般 Actors 数组获取应该是:先用 Level + 0xd8 获取 ActorCluster 指针,然后用 ActorCluster + 0x28 获取 Actors 数组,这里直接用引擎的 offset 了
*p_now_actor = *(int64_t **)(app->now + 8LL * app->i);
v32 = (unsigned __int64)*p_now_actor < 0x10000;
if ( v32 ){
goto LABEL_29;
}
app->p_now_actor = *p_now_actor;
app->now_actor = *(_QWORD *)app->p_now_actor;
*p_now_actor_1 = app->now_actor;
if ( *p_now_actor_1 - app->lib_base == 0xA63BE28LL )
但是 dump 出来的东西里没有,推测是覆盖了,导致换了一个,接下去看
之后将 patched 位置 true
float RecoilAccumulationRate;//[Offset: 0x538, Size: 0x4]
CharacterMovementComponent* CharacterMovement;//[Offset: 0x288, Size: 0x8]
pawn charactor class
CharacterMovementComponent class
app->p_RecoilAccumulationRate4 = (char *)*p_now_actor + 0x538;
*(_DWORD *)app->p_RecoilAccumulationRate4 = 0;// 修改后坐力
app2 = app;
*(_QWORD *)p_CharacterMovement = (*p_now_actor)->move;
app2->move = *(move **)p_CharacterMovement;
*(_QWORD *)&app->p_MaxAcceleration = *(_QWORD *)p_CharacterMovement + 416LL;
*(_QWORD *)&app->MaxAcceleration = *(_QWORD *)&app->p_MaxAcceleration;
**(_DWORD **)&app->MaxAcceleration = 0x4E6E6B28;// 15625000f
sA0_4->p_movement = *(_QWORD *)p_CharacterMovement;
*(_DWORD *)(app->p_movement + 396LL) = 0x4E6E6B28; //float MaxWalkSpeed;//[Offset: 0x18c, Size: 0x4]
::patch_applied_flag = 1;
总结就是把后坐力关了,把加速度和上限给调高了,在这里把最终的赋值语句 nop 掉就行了
之后用 mt 重打包回去
继续分析异常
自瞄
尝试搜索 setrotation,在 Class: Controller.Actor.Object 搜到了
好像一般 UE 不是这么搞的?不管了
Id: 42, Addr: 73958cece0, Actor: PlayerController
Actor 里面有一个 Controller 控制位置和方向之类的,看看这个类:
现在是 Id: 42, Addr: 73941de020, Actor: PlayerController
所以应该找找 0x7390cce680+0x288 = 0x7390cce908
./stackplz -n com.ACE2025.Game --brk 0x6d8593cf88:rw --stack
在几个位置:
Process name: com.ACE2025.Game, Pid: 12999
Base Address of libUE4.so Found At 6db3d12000
UWorld: 6dbecbe398 | World: 6d8607e040 | Name: FirstPersonExampleMap
Level: 6d8c768440 | Name: PersistentLevel
ActorList: 6d86858c80, ActorCount: 47
0000000008b3860c
0000000008b3869c
0000000008b387c0 # w 修改点
函数 sub_8B3861C
[12999|13053] event_addr:0x6d8593cf88 hit_count:5, Backtrace:
#00 pc 0000000008b387c0 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#01 pc 000000000670f3f8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#02 pc 000000000670feac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#03 pc 0000000009268e34 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#04 pc 0000000009266e00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#05 pc 0000000008fa0588 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#06 pc 0000000008f9f6f0 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#07 pc 0000000008f9f370 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#08 pc 0000000008fa7354 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#09 pc 00000000091fdb88 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#10 pc 00000000067cebac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#11 pc 00000000067ce72c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#12 pc 00000000067cde20 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#13 pc 00000000091f9c00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#14 pc 00000000091f73b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#15 pc 0000000008d3b75c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#16 pc 0000000008c068ec /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#17 pc 0000000005af53b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#18 pc 0000000005af3510 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
[12999|13053] event_addr:0x6d8593cf88 hit_count:6, Backtrace:
#00 pc 0000000008b387c0 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#01 pc 0000000008f9b600 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#02 pc 0000000008fa7354 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#03 pc 00000000091fdb88 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#04 pc 00000000067cebac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#05 pc 00000000067ce72c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#06 pc 00000000067cde20 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#07 pc 00000000091f9c00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#08 pc 00000000091f73b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#09 pc 0000000008d3b75c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#10 pc 0000000008c068ec /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#11 pc 0000000005af53b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#12 pc 0000000005af3510 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
12 个的是一般情况,18 个是额外的
把 18 那个调用的 B 给 nop 就行了
function patch_rotate() {
var lib = Module.findBaseAddress(so_name)
if (!lib) {
console.log("[x] cannot find lib");
}
var targetAddress=lib.add(0x670f3f8)
Memory.patchCode(targetAddress, 4, code => {
const writer = new Arm64Writer(code, { pc: targetAddress });
writer.putNop();
writer.flush();
});
}
子弹乱飞
尝试定位到角色类,参考 https://dev.epicgames.com/documentation/zh-cn/unreal-engine/3---implementing-projectiles?application_version=4.27#%E5%AE%9E%E7%8E%B0%E5%8F%91%E5%B0%84%E5%87%BD%E6%95%B0 这个官方教程,能够大概了解发射东西是怎么实现的:
void AFPSCharacter::Fire()
{
// 试图发射发射物。
if (ProjectileClass)
{
// 获取摄像机变换。
FVector CameraLocation;
FRotator CameraRotation;
GetActorEyesViewPoint(CameraLocation, CameraRotation);
// 设置MuzzleOffset,在略靠近摄像机前生成发射物。
MuzzleOffset.Set(100.0f, 0.0f, 0.0f);
// 将MuzzleOffset从摄像机空间变换到世界空间。
FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
// 使目标方向略向上倾斜。
FRotator MuzzleRotation = CameraRotation;
MuzzleRotation.Pitch += 10.0f;
UWorld* World = GetWorld();
if (World)
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
SpawnParams.Instigator = GetInstigator();
// 在枪口位置生成发射物。
AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
if (Projectile)
{
// 设置发射物的初始轨迹。
FVector LaunchDirection = MuzzleRotation.Vector();
Projectile->FireInDirection(LaunchDirection);
}
}
}
}
首先是在 Charact 类里面有一个 AFPSCharacter::Fire 方法,在前面有提前绑定的操作 PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
,在开火的函数里面:
- 先找到摄像机的位置和朝向
- 往前一点点有一个移动矩阵,计算生成位置=摄像机位置 + 移动矩阵 * 摄像机朝向
- 生成朝向赋值摄像机朝向,向上抬一点
- 调用 SpawnActor,参数
ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams
- 调用生成的 Actor 的方法
FireInDirection
角色的 SKD 中的方法有:
现在 Id: 38, Addr: 6d821fc6a0, Actor: FirstPersonCharacter_C
没找到具体 fire 的函数,但是相关的成员还是找到了:
class MyProjectProjectile* ProjectileClass; // [Offset: 0x510, Size: 0x8]
这个是发射出去的东西SceneComponent* FP_MuzzleLocation; // [Offset: 0x4c8, Size: 0x8]
这个是发射出去的位置
下个断点:
./stackplz -n com.ACE2025.Game --brk 0x6D821FCBB0:rw --brk 0x6D821FCB68:rw --stack
findBTFAssets btf_file=a12-5.10-arm64_min.btf
[*] save maps to maps_20627.txt
set breakpoint at kernel:false, addr:0x6d821fcb68, type:3
start 1 modules
[20627|20678] event_addr:0x6d821fcb68 hit_count:1, Backtrace:
#00 pc 000000000670f48c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#01 pc 000000000670feac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#02 pc 0000000009268e34 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#03 pc 0000000009266e00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#04 pc 0000000008fa0588 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#05 pc 0000000008f9f6f0 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#06 pc 0000000008f9f370 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#07 pc 0000000008fa7354 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#08 pc 00000000091fdb88 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#09 pc 00000000067cebac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#10 pc 00000000067ce72c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#11 pc 00000000067cde20 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#12 pc 00000000091f9c00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#13 pc 00000000091f73b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#14 pc 0000000008d3b75c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#15 pc 0000000008c068ec /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#16 pc 0000000005af53b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#17 pc 0000000005af3510 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
[20627|20678] event_addr:0x6d821fcb68 hit_count:2, Backtrace:
#00 pc 000000000670fdd4 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#01 pc 000000000670f654 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#02 pc 000000000670feac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#03 pc 0000000009268e34 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#04 pc 0000000009266e00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#05 pc 0000000008fa0588 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#06 pc 0000000008f9f6f0 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#07 pc 0000000008f9f370 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#08 pc 0000000008fa7354 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#09 pc 00000000091fdb88 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#10 pc 00000000067cebac /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#11 pc 00000000067ce72c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#12 pc 00000000067cde20 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#13 pc 00000000091f9c00 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#14 pc 00000000091f73b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#15 pc 0000000008d3b75c /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#16 pc 0000000008c068ec /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#17 pc 0000000005af53b8 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
#18 pc 0000000005af3510 /data/app/~~1bxVHLcN_QNIlP4v2RHkWQ==/com.ACE2025.Game-M2L3aUB2Sn8YNEaDJpLBsQ==/lib/arm64/libUE4.so
0x670feac 嗯?怎么这么熟悉,不是之前 patch 过自瞄的函数吗?看来这就是我们需要重点分析的对象了
v36 = (float *)*((_QWORD *)a1 + 0x99); // 在这里read了发射位置?
x = location[116];
y = location[117];
z = location[118]; // 拿出来
往上翻翻,if ( *((_QWORD *)a1 + 75) )
这个块应该是一个开火状态标志,
v3 = rand(); // 获取随机数
v4 = a1[334]; // 获取 a1 对象偏移 334*sizeof(float) 处的浮点数,可能是基础散射度/力度等
// 下面这行是核心计算,看起来在调整某个值,可能是子弹的初始偏移角度或力度
v6 = a1[336] + (float)(v4 * (float)((float)((float)((float)(v3 & 0xFFFFFF) / 16777000.0) + -0.5) + a1[332]));
// (v3 & 0xFFFFFF) / 16777000.0: 将一个24位随机数归一化到 [0.0, 1.0) 区间
// + -0.5: 变为 [-0.5, 0.5) 区间
// + a1[332]: 再加上一个 a1 对象的成员值作为偏移
// * v4: 乘以 v4 进行缩放
// + a1[336]: 累加到 a1[336] 上
a1[335] = a1[335] + (float)(a1[331] * v4); // 另一个属性调整
a1[336] = v6; // 更新 a1[336]