正文
),
0x224
);
// LOGD("crc_val: 0x%llx", crc_val);
return
crc_val !=
0x49d5c836
;
}
在線程中不斷調用
is_sub_6711A54_modify
來檢測是否被修改,當
libGame.so
注入後,成功檢測。
當然更通用的做法可能是對整個
.text
段進行crc32,或者對一些重要的函數分別進行crc32,這裡針對單一函數的做法只是作為一個演示。
注:不知為何我用Xiaomi8 Lite( Magisk環境 )在測試時發現有時雖然
libGame.so
成功注入,但卻修改失敗?有時卻能修改成功,有點玄學。而在另一部非Magisk環境的手機手動注入
libGame.so
時卻能100%修改成功,有點神奇。
cheat分析
elf可執行文件的起始執行函數是
start
,如下。
一開始以為
br x16
那裡會跳到具體邏輯,但嘗試用frida stalker hook那處地址時並沒有觸發。
用frida stalker簡單trace後發現,
__libc_init
會跳到
0x241d90
。
复制代码 隐藏代码
0x241b04: bl #0x5f6bc47440
0x2b0440: adrp x16, #0x5f6bc4b000
0x2b0444: ldr x17, [x16, #0xfb0]
0x2b0448: add x16, x16, #0xfb0
0x2b044c: br x17
0x241d90: sub sp, sp, #0x70
注:後來用IDA9看才發現原來之前是因為沒有正確解析
__libc_init
的參數,導致看不到
sub_241d90
。
記
0x241d90
為
start_process
,這裡會通過am start來啟動APP,啟動成功後會調用
usleep
等待APP加載so,然後調用
sub_241BF0
實現外掛邏輯。
sub_241BF0
如下,一開始先初始化了ImGui,然後循環調用
MainLoopStep
。
對比ImGui源碼,以此手動還原
MainLoopStep
中的一些符號。
可以看到點擊「初始化輔助」按鈕後,會調用
init_cheat
進行初始化,看看它的實現。
「初始化輔助」分析
init_cheat
初始化流程大致如下。
從
/proc/
pidof com.ACE2025.Game
/maps
獲取
libUE4.so
的基址,保存到全局變量。
通過
process_vm_readv
系統調用來跨內存訪問訪問
libUE4.so
中的一些值,保存到全局變量。
遍歷獲取
MyProjectCharacter
對象( 暫時未知是基於libUE4的哪個全局變量來獲取的 ),然後保存其中的
PlayerCameraManager
屬性到全局變量。
將上述遍歷過程用frida實現,如下:
复制代码 隐藏代码
function test_cheat_init() {
let unknow1 = base.add(0xAF75B08).readPointer();
let unknow2 = base.add(0xAF75B08).add(8).readU32();
console.log("unknow1: ", hexdump(unknow1));
console.log("FirstPersonCharacter_C: ", All_Objects["FirstPersonCharacter_C"]);
for(let i = 0; i < unknow2; i++) {
let uobj = unknow1.add(i * 24).readPointer();
console.log(`${i}: ${uobj}`);
printName(uobj);
}
}
由此可以看出
0xAF75B08
指向的位置保存著
Character
對象數組,
0xAF75B08 + 8
指向的位置保存著數組大小。
最後調用
get_ThirdPerson
遍歷獲取 & 保存
TP_ThirdPersonCharacter
對象( 同上 ),後面還進行了一些操作,但應該不太重要,先不看了。
透視繪制分析
init_cheat
初始化後,
inited
會置為true,然後會調用
process_cheat_options
處理勾選的外掛功能。
process_cheat_options
是個巨大的函數,一開始會遍歷所有
TP_ThirdPersonCharacter
對象,收集它們的信息( 同樣利用
process_vm_readv
系統調用 ),用來計算繪制的參數。
中間一大片類似如下結構的代碼,應該是在獲取 & 處理UE4角色的骨骼信息。
最後根據勾選的參數來繪制。