第一次聽說這比賽是上年偶然和舍友聊天時他告訴我的,沒想到還有以遊戲安全為主的比賽,當時看到有安卓的賽道就報名了,然後比賽時就被那門卡了2天,然後就沒有然後了。
今年沒意外的話是我大學生涯的最後一年,也許也是最後一年打這個比賽了吧,下年也不知道有沒有空看看題。
以下是我的解題記錄,一部份是比賽時寫的,一部份是賽後補充的,有寫錯的還請指正。
版本:4.27
GName:0xADF07C0
GObject:0xAE34A98
dump sdk by GObject,記為SDKO.txt
dump all objects,記為Objects.txt
題目說明如下,純粹的UE4逆向,無任何反調試。
hook pthread_create
,patch掉libGame.so
創建唯一一個線程後,速度不再異常。
由此可知相關邏輯就在libGame.so
創建的線程中。接下來分析它的實現原理。
用IDA動調線程回調函數sub_1B9C
。
進入後會看到明顯的控制流平坦化,先不管。
打斷點進入case 12623
,分析後發現就是通過/proc/self/maps
獲取libUE4.so
的基址。
之後本想手動還原下控制流,但突然想起IDA有個D-810插件貌似能解控制流混淆,嘗試下,發現效果很好。
獲取了libUE4_base
後會賦給infos[19]
。
然後*(_QWORD *)(libUE4_base_1 + 0xAFAC398)
獲取了libUE4.so
的一個全局變量,猜測是GWorld
。
用ue4dumper來驗證,發現能順利dump出SDK,由此可知0xAFAC398
的確是GWorld
。
記dump出來的文件為SDKW.txt
。
獲取GWorld
後,就能通過遍歷其中的屬性定位到FirstPersonCharacter_C
,具體原理如下,這是用frida實現的。
其中用了vtabs
( UObject
的第0
個成員屬性,虛表 )的函數偏移是否等於0xA63BE28
來確定是否FirstPersonCharacter_C
對象,0xA63BE28
大概是FirstPersonCharacter_C
的一個特徵?
最終通過修改CharacterMovementComponent
的MaxAcceleration
和MaxWalkSpeed
來改變人物速度。
在SDKO.txt
裡可以看到我的角色類裡有個ProjectileClass
成員,而它有個OnHit
成員函數
嘗試hook OnHit
,分別在enter和leave時打印CameraRotation
,發現兩者相等,即在enter前就已經完成自瞄,代表相關的自瞄邏輯不在這裡。
對CameraRotation
下硬斷( 寫 ),命中信息如下:
命中PC:0x799F6637C0
libUE4 base:0x7996b2b000
計算得Offset為0x8B387C0
IDA跳到0x8B387C0
,如下:
記0x8B387C0
所在函數為mb_aimbot
,嘗試直接patch掉mb_aimbot
,發現patch後人物無法轉動視角。
hook mb_aimbot
,打印調用棧,未點擊時,調用棧如下
點擊後,多了一個不同的調用棧0x670f3fc
。
嘗試patch掉0x670f3fc
所在函數0x670F110
,雖然點擊後不會再自動瞄到某處,但子彈射不出。
由此猜測0x670F110
是射擊的回調函數,自瞄邏輯應該就在裡面。
記0x670F110
為process_before_shoot
。
在0x670F110
中從調用mb_aimbot
處向上分析,發現是否調用mb_aimbot
邏輯是由sub_680B790(v32, "E")
決定的。
hook sub_680B790
,打印參數和返回值。
注:hexdump
後可知是unicode編碼的字符串,因此要用readUtf16String
。
輸出如下,可以看出是字符串對比函數,res
是a0
、a1
第1個不相等字符的差值,若相等則為0
( 不區分大小寫 )。記sub_680B790
為utf16_cmp
。
可以看到前面一直在和EditorCube8
對比,明顯它就是自瞄的目標,
嘗試在a1
為EditorCube8
時將返回值固定replace為一個大於0
的值。
結果是射擊時不再自動瞄到指定目標,但手槍在射完後會向上抬一下,類似後座力?不知是否屬於異常點。
下面簡單看看它的自瞄實現原理:
從process_before_shoot
開始看,一開始先遍歷自瞄目標。
然後調用calcTargetOffset
計算自瞄值,然後根據這個值來設置CameraRotation
( 人物相機的轉向,使它朝向目標以實現自瞄的效果 )。
calcTargetOffset
實現大概像這樣:利用目標location與人物的location向量來計算。
可以明顯看出子彈發射的起始位置是隨機的。
猜測可能與MyProjectCharacter
的GunOffset
有關。
對GunOffset
下硬斷( 讀 )。
命中如下兩處地址:
0x6930A6C
所在函數是sub_6930A3C
。
hook sub_6930A3C
打印調用棧。
其中0x670f658
位於0x670F110
函數( 即process_before_shoot
)。
process_before_shoot
中有調用rand()
生成隨機值,猜測這與槍口的隨機有關。
嘗試hook rand
固定其返回值。
結果是子彈發射位置固定了,但是固定在了人物的頭上偏左的位置。
繼續嘗試其他修復思路。
讓process_before_shoot
中的a1[0x14A] & 1
不為0
,目的是讓執行流無法走到上述的0x6930A6C
位置。
結果同樣可以固定子彈發射的位置,但這次是在人物的下方固定向正前方發射,上下抬頭時不會改變發射方向。
以下部份是賽後的分析。
若a1[0x14A] & 1
為0
,會調用about_bullt_loc1
生成一些隨機值,調用about_bullt_loc2
生成一個基於GunOffset
等參數而來的值,最終傳入mb_process_bullet_shoot_loc
做最後的處理。
而當a1[0x14A] & 1
為1
時,則會從VR_MuzzleLocation
裡獲取一些參數,最終同樣傳入mb_process_bullet_shoot_loc
。
注:通過hook所在函數,將*((QWORD*)a1 + 155)
當成UObject
來打印它的名字,從而確定它是VR_MuzzleLocation
對象。
但VR_MuzzleLocation
看名字來說是給VR設備使用的,安卓設備感覺是使用FP_MuzzleLocation
才對。
因此合理懷疑這也是一個異常點。
hook process_before_shoot
,從IDA裡可知args[0].add(0x4D8)
保存著VR_MuzzleLocation
對象的地址,嘗試將它改為FP_MuzzleLocation
的地址。
結果是子彈終於會隨著槍口的變化而變化,但卻是從槍口往左發射的,正常應該是往前才對。
接下來嘗試修改FP_MuzzleLocation
裡的一些參數,看看能否改變發射方向。
FP_MuzzleLocation
屬於USceneComponent
類,其中有以下這兩個屬性:
利用K2_SetRelativeLocation
和K2_SetRelativeRotation
函數來修改。通過不斷嘗試,發現只需要將Rotation設置為[0, 90, 0]
即可,相當於旋轉了90度。完整修複代碼如下:
注:不能直接通過內存來修改,要用API來修改。
在Objects.txt
裡可以看到FirstPersonCharacter_C
和ThirdPersonCharacter_C
,它們分別是我控制的人物和假人。
嘗試一:替換Material。( 沒效果 )
嘗試二:設置bDisableDepthTest
為0
。( 沒效果 )
嘗試三:利用SetTexture
隨便設置一個Texture。( 沒效果 )
以下部份是賽後的分析。
找資料時發現類似這遊戲的人物透視效果基本上有以下兩種實現思路:
但嘗試後發現遊戲似乎不是用上述方法實現透視效果的( 不太確定,也有可能是我修改的地方不對 )?
找了很久都沒有什麼思路,最終只好退而求其次,用一種「掩耳盜鈴」的方式來修復,具體思路如下:
具體調用LineTraceSingle
、獲取HitResult.Distance
的代碼如下:
時機選擇在Actor
類的ReceiveTick
函數,在其中判斷是否渲染:
當然這肯定不是正解,而且效果也非常一般,之後看看有沒有其他大佬分析下正解吧。
子彈射在白色的Cube上不會反彈。
白色的Cube應是就是EditorCubeN
。
子彈射在EditorCubeN
上會瞬間消失,但EditorCubeN
是有被擊退的效果,而子彈射在黑色的Cube上能正常被反彈。
嘗試一:看看是否因為物理模擬未啟用。( 沒效果 )
嘗試二:設置物理材質的反彈系數為1。( 沒效果 )
嘗試三:設置與所有物體的碰撞響應都為Block( 具體值是2 )。( 沒效果 )
經過上述嘗試,可知子彈消失大概率與Collision無關。
猜測子彈是在擊中EditorCubeN
時執行了一段Destroy邏輯。
hook MyProjectProjectile
的OnHit
,打印調用棧:
Destroy邏輯可能就在其中,但沒時間看了。。
以下部份是賽後的分析。
OnHit
最後調會return sub_88A8D2C((__int64)v4, 0, 1)
,而sub_88A8D2C
函數如下。
about_ActorDestroying
中有"ActorDestroying"
字符串,猜測會不會就是那段Destroy邏輯。
嘗試直接patch掉該函數,使其固定返回1
。
結果是射到EditorCubeN
時也會正常反彈,成功修復該異常點。
在測試過程中還發現以下一些不確定算不算異常點的:
frida -U -f com.ACE2025.Game -l final.js
今年跟上年一樣是UE4的題型,猜到了會出UE4,賽前本想找些遊戲來練練手,但一直沒找到合適的,只能說可惜了。這也導致了比賽前2天基本都在熟悉UE4,直到最後也沒有完整地修復幾個異常點。
本以為決賽無望的,沒想到運氣挺好居然進了,算是圓了上一年的遺憾吧。
./ue4dumper64 --sdku --newue+ --gname 0xADF07C0 --guobj 0xAE34A98 --package com.ACE2025.Game
./ue4dumper64 --sdku --newue+ --gname 0xADF07C0 --guobj 0xAE34A98 --package com.ACE2025.Game
./ue4dumper64 --objs --newue+ --gname 0xADF07C0 --guobj 0xAE34A98 --package com.ACE2025.Game
./ue4dumper64 --objs --newue+ --gname 0xADF07C0 --guobj 0xAE34A98 --package com.ACE2025.Game
function hook_pthread() {
var pthread_create_addr = Module.findExportByName(null,
'pthread_create'
);
console.
log
(
"pthread_create_addr,"
, pthread_create_addr);
var pthread_create =
new
NativeFunction(pthread_create_addr,
"int"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"pointer"
]);
Interceptor.replace(pthread_create_addr,
new
NativeCallback(function (parg0, parg1, parg2, parg3) {
var so_name = Process.findModuleByAddress(parg2).name;
var so_path = Process.findModuleByAddress(parg2).path;
var so_base = Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
var PC = 0;
if
((so_name.indexOf(
"libGame.so"
) > -1)) {
console.
log
(
"find thread func offset"
, so_name, offset);
if
((7068 === offset)) {
console.
log
(
"anti bypass"
);
}
else
{
PC = pthread_create(parg0, parg1, parg2, parg3);
console.
log
(
"ordinary sequence"
, PC)
}
}
else
{
PC = pthread_create(parg0, parg1, parg2, parg3);
}
return
PC;
},
"int"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"pointer"
]))
}
function hook_pthread() {
var pthread_create_addr = Module.findExportByName(null,
'pthread_create'
);
console.
log
(
"pthread_create_addr,"
, pthread_create_addr);
var pthread_create =
new
NativeFunction(pthread_create_addr,
"int"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"pointer"
]);
Interceptor.replace(pthread_create_addr,
new
NativeCallback(function (parg0, parg1, parg2, parg3) {
var so_name = Process.findModuleByAddress(parg2).name;
var so_path = Process.findModuleByAddress(parg2).path;
var so_base = Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
var PC = 0;
if
((so_name.indexOf(
"libGame.so"
) > -1)) {
console.
log
(
"find thread func offset"
, so_name, offset);
if
((7068 === offset)) {
console.
log
(
"anti bypass"
);
}
else
{
PC = pthread_create(parg0, parg1, parg2, parg3);
console.
log
(
"ordinary sequence"
, PC)
}
}
else
{
PC = pthread_create(parg0, parg1, parg2, parg3);
}
return
PC;
},
"int"
, [
"pointer"
,
"pointer"
,
"pointer"
,
"pointer"
]))
}
.
/ue4dumper64
--sdkw --newue+ --gname 0xADF07C0 --gworld 0xAFAC398 --package com.ACE2025.Game
.
/ue4dumper64
--sdkw --newue+ --gname 0xADF07C0 --gworld 0xAFAC398 --package com.ACE2025.Game
let GWorld = base.add(0xAFAC398).readPointer();
let PersistentLevel = GWorld.add(0x30).readPointer()
let StreamingLevels = PersistentLevel.add(0x98).readPointer();
let StreamingLevelsNum = PersistentLevel.add(0xA0).readU32();
let FirstPersonCharacter_C = null;
for
(let i = 0; i < StreamingLevelsNum; i++) {
let StreamingLevel = StreamingLevels.add(i * 8).readPointer();
let vtabs = StreamingLevel.readPointer();
if
(vtabs.sub(base) == 0xA63BE28) {
FirstPersonCharacter_C = StreamingLevel;
}
}
let CharacterMovementComponent = FirstPersonCharacter_C.add(0x288).readPointer()
CharacterMovementComponent.add(0x1a0).writeFloat(1000000000)
CharacterMovementComponent.add(0x18c).writeFloat(1000000000)
let GWorld = base.add(0xAFAC398).readPointer();
let PersistentLevel = GWorld.add(0x30).readPointer()
let StreamingLevels = PersistentLevel.add(0x98).readPointer();
let StreamingLevelsNum = PersistentLevel.add(0xA0).readU32();
let FirstPersonCharacter_C = null;
for
(let i = 0; i < StreamingLevelsNum; i++) {
let StreamingLevel = StreamingLevels.add(i * 8).readPointer();
let vtabs = StreamingLevel.readPointer();
if
(vtabs.sub(base) == 0xA63BE28) {
FirstPersonCharacter_C = StreamingLevel;
}
}
let CharacterMovementComponent = FirstPersonCharacter_C.add(0x288).readPointer()
CharacterMovementComponent.add(0x1a0).writeFloat(1000000000)
CharacterMovementComponent.add(0x18c).writeFloat(1000000000)
Class: MyProjectCharacter.Character.Pawn.Actor.Object
SkeletalMeshComponent* Mesh1P;
SkeletalMeshComponent* FP_Gun;
SceneComponent* FP_MuzzleLocation;
SkeletalMeshComponent* VR_Gun;
SceneComponent* VR_MuzzleLocation;
CameraComponent* FirstPersonCameraComponent;
MotionControllerComponent* R_MotionController;
MotionControllerComponent* L_MotionController;
float
BaseTurnRate;
float
BaseLookUpRate;
Vector GunOffset;
class
MyProjectProjectile* ProjectileClass;
SoundBase* FireSound;
AnimMontage* FireAnimation;
bool
bUsingMotionControllers;
float
RecoilPitch;
float
RecoilYaw;
float
RecoilRecoverySpeed;
float
RecoilAccumulationRate;
Class: MyProjectProjectile.Actor.Object
SphereComponent* CollisionComp;
ProjectileMovementComponent* ProjectileMovement;
void
OnHit(PrimitiveComponent* HitComp, Actor* OtherActor, PrimitiveComponent* OtherComp, Vector NormalImpulse, out
const
HitResult Hit);
Class: MyProjectCharacter.Character.Pawn.Actor.Object
SkeletalMeshComponent* Mesh1P;
SkeletalMeshComponent* FP_Gun;
SceneComponent* FP_MuzzleLocation;
SkeletalMeshComponent* VR_Gun;
SceneComponent* VR_MuzzleLocation;
CameraComponent* FirstPersonCameraComponent;
MotionControllerComponent* R_MotionController;
MotionControllerComponent* L_MotionController;
float
BaseTurnRate;
float
BaseLookUpRate;
Vector GunOffset;
class
MyProjectProjectile* ProjectileClass;
SoundBase* FireSound;
AnimMontage* FireAnimation;
bool
bUsingMotionControllers;
float
RecoilPitch;
float
RecoilYaw;
float
RecoilRecoverySpeed;
float
RecoilAccumulationRate;
Class: MyProjectProjectile.Actor.Object
SphereComponent* CollisionComp;
ProjectileMovementComponent* ProjectileMovement;
void
OnHit(PrimitiveComponent* HitComp, Actor* OtherActor, PrimitiveComponent* OtherComp, Vector NormalImpulse, out
const
HitResult Hit);
function hook_onHit() {
Interceptor.attach(base.add(0x6711D34), {
onEnter: function(args) {
console.
log
(
"[onHit] enter: "
, JSON.stringify(getCameraRotation()))
},
onLeave: function() {
console.
log
(
"[onHit] leave: "
, JSON.stringify(getCameraRotation()))
}
})
}
function hook_onHit() {
Interceptor.attach(base.add(0x6711D34), {
onEnter: function(args) {
console.
log
(
"[onHit] enter: "
, JSON.stringify(getCameraRotation()))
},
onLeave: function() {
console.
log
(
"[onHit] leave: "
, JSON.stringify(getCameraRotation()))
}
})
}
function patch_mb_aimbot() {
Interceptor.replace(base.add(0x8B3861C),
new
NativeCallback(() => {
console.
log
(
"patch mb_aimbot"
)
},
"void"
, []))
}
function patch_mb_aimbot() {
Interceptor.replace(base.add(0x8B3861C),
new
NativeCallback(() => {
console.
log
(
"patch mb_aimbot"
)
},
"void"
, []))
}
[hook_aimbot]
799fa8e604 is in libUE4.so offset: 0x8f9b604
799fa92444 is in libUE4.so offset: 0x8f9f444
799fa9a358 is in libUE4.so offset: 0x8fa7358
799fcf0b8c is in libUE4.so offset: 0x91fdb8c
799d2c1bb0 is in libUE4.so offset: 0x67cebb0
799d2c1730 is in libUE4.so offset: 0x67ce730
799d2c0e24 is in libUE4.so offset: 0x67cde24
799fcecc04 is in libUE4.so offset: 0x91f9c04
799fcea3bc is in libUE4.so offset: 0x91f73bc
799f82e760 is in libUE4.so offset: 0x8d3b760
799f6f98f0 is in libUE4.so offset: 0x8c068f0
799d93f614 is in libUE4.so offset: 0x6e4c614
799c5ee728 is in libUE4.so offset: 0x5afb728
799c5e83bc is in libUE4.so offset: 0x5af53bc
799c5e6514 is in libUE4.so offset: 0x5af3514
[hook_aimbot]
79a03df660 is in libUE4.so offset: 0x98ec660
799fcf0b8c is in libUE4.so offset: 0x91fdb8c
799d2c1bb0 is in libUE4.so offset: 0x67cebb0
799d2c1730 is in libUE4.so offset: 0x67ce730
799d2c0e24 is in libUE4.so offset: 0x67cde24
799fcecc04 is in libUE4.so offset: 0x91f9c04
799fcea3bc is in libUE4.so offset: 0x91f73bc
799f82e760 is in libUE4.so offset: 0x8d3b760
799f6f98f0 is in libUE4.so offset: 0x8c068f0
799d93f614 is in libUE4.so offset: 0x6e4c614
799c5ee728 is in libUE4.so offset: 0x5afb728
799c5e83bc is in libUE4.so offset: 0x5af53bc
799c5e6514 is in libUE4.so offset: 0x5af3514
[hook_aimbot]
799fa8e604 is in libUE4.so offset: 0x8f9b604
799fa92444 is in libUE4.so offset: 0x8f9f444
799fa9a358 is in libUE4.so offset: 0x8fa7358
799fcf0b8c is in libUE4.so offset: 0x91fdb8c
799d2c1bb0 is in libUE4.so offset: 0x67cebb0
799d2c1730 is in libUE4.so offset: 0x67ce730
799d2c0e24 is in libUE4.so offset: 0x67cde24
799fcecc04 is in libUE4.so offset: 0x91f9c04
799fcea3bc is in libUE4.so offset: 0x91f73bc
799f82e760 is in libUE4.so offset: 0x8d3b760
799f6f98f0 is in libUE4.so offset: 0x8c068f0
799d93f614 is in libUE4.so offset: 0x6e4c614
799c5ee728 is in libUE4.so offset: 0x5afb728
799c5e83bc is in libUE4.so offset: 0x5af53bc
799c5e6514 is in libUE4.so offset: 0x5af3514
[hook_aimbot]
79a03df660 is in libUE4.so offset: 0x98ec660
799fcf0b8c is in libUE4.so offset: 0x91fdb8c
799d2c1bb0 is in libUE4.so offset: 0x67cebb0
799d2c1730 is in libUE4.so offset: 0x67ce730
799d2c0e24 is in libUE4.so offset: 0x67cde24
799fcecc04 is in libUE4.so offset: 0x91f9c04
799fcea3bc is in libUE4.so offset: 0x91f73bc
799f82e760 is in libUE4.so offset: 0x8d3b760
799f6f98f0 is in libUE4.so offset: 0x8c068f0
799d93f614 is in libUE4.so offset: 0x6e4c614
799c5ee728 is in libUE4.so offset: 0x5afb728
799c5e83bc is in libUE4.so offset: 0x5af53bc
799c5e6514 is in libUE4.so offset: 0x5af3514
[hook_aimbot]
799d2f83fc is in libUE4.so offset: 0x670f3fc
7a136f0c94 is in libart.so offset: 0x2e6c94
799d2f8eb0 is in libUE4.so offset: 0x670feb0
799fe51e38 is in libUE4.so offset: 0x9268e38
799fe4fe04 is in libUE4.so offset: 0x9266e04
799fb8958c is in libUE4.so offset: 0x8fa058c
799fb886f4 is in libUE4.so offset: 0x8f9f6f4
799d3b9420 is in libUE4.so offset: 0x67d0420
799fb88374 is in libUE4.so offset: 0x8f9f374
799f49b7bc is in libUE4.so offset: 0x88b27bc
799fb90358 is in libUE4.so offset: 0x8fa7358
799fde6b8c is in libUE4.so offset: 0x91fdb8c
799d3b7bb0 is in libUE4.so offset: 0x67cebb0
799d3b7730 is in libUE4.so offset: 0x67ce730
799d3b6e24 is in libUE4.so offset: 0x67cde24
799fde2c04 is in libUE4.so offset: 0x91f9c04
[hook_aimbot]
799d2f83fc is in libUE4.so offset: 0x670f3fc
7a136f0c94 is in libart.so offset: 0x2e6c94
799d2f8eb0 is in libUE4.so offset: 0x670feb0
799fe51e38 is in libUE4.so offset: 0x9268e38
799fe4fe04 is in libUE4.so offset: 0x9266e04
799fb8958c is in libUE4.so offset: 0x8fa058c
799fb886f4 is in libUE4.so offset: 0x8f9f6f4
799d3b9420 is in libUE4.so offset: 0x67d0420
799fb88374 is in libUE4.so offset: 0x8f9f374
799f49b7bc is in libUE4.so offset: 0x88b27bc
799fb90358 is in libUE4.so offset: 0x8fa7358
799fde6b8c is in libUE4.so offset: 0x91fdb8c
799d3b7bb0 is in libUE4.so offset: 0x67cebb0
799d3b7730 is in libUE4.so offset: 0x67ce730
799d3b6e24 is in libUE4.so offset: 0x67cde24
799fde2c04 is in libUE4.so offset: 0x91f9c04
Interceptor.replace(base.add(0x670F110),
new
NativeCallback(() => {
return
1;
},
"int"
, []))
Interceptor.replace(base.add(0x670F110),
new
NativeCallback(() => {
return
1;
},
"int"
, []))
function hook_680B790() {
Interceptor.attach(base.add(0x680B790), {
onEnter: function(args) {
this
.a1 = args[1];
console.
log
(
"a0: "
, args[0].readUtf16String());
console.
log
(
"a1: "
, args[1].readUtf16String());
},
onLeave: function(retval) {
console.
log
(
"res: "
, retval);
}
})
}
function hook_680B790() {
Interceptor.attach(base.add(0x680B790), {
onEnter: function(args) {
this
.a1 = args[1];
console.
log
(
"a0: "
, args[0].readUtf16String());
console.
log
(
"a1: "
, args[1].readUtf16String());
},
onLeave: function(retval) {
console.
log
(
"res: "
, retval);
}
})
}
a0: BigWall
a1: EditorCube8
res: 0xfffffffd
a0: BigWall2
a1: EditorCube8
res: 0xfffffffd
a0: EditorCube10
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube11
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube12
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube13
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube14
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube15
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube16
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube17
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube18
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube19
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube20
a1: EditorCube8
res: 0xfffffffa
a0: EditorCube21
a1: EditorCube8
res: 0xfffffffa
a0: EditorCube8
a1: EditorCube8
res: 0x0
a0: EditorCube9
a1: EditorCube8
res: 0x1
a0: Floor_12
a1: EditorCube8
res: 0x1
a0: Wall1
a1: EditorCube8
res: 0x12
a0: Wall2_11
a1: EditorCube8
res: 0x12
a0: Wall3
a1: EditorCube8
res: 0x12
a0: Wall4
a1: EditorCube8
res: 0x12
a0: ../../../MyProject/Saved/Config/Android/Engine.ini
a1: ../../../MyProject/Saved/Config/Android/Engine.ini
res: 0x0
a0:
true
a1: True
res: 0x0
a0: Android
a1: Android
res: 0x0
a0: Android
a1: Android
res: 0x0
a0: Android
a1: Android
res: 0x0
a0: BigWall
a1: EditorCube8
res: 0xfffffffd
a0: BigWall2
a1: EditorCube8
res: 0xfffffffd
a0: EditorCube10
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube11
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube12
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube13
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube14
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube15
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube16
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube17
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube18
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube19
a1: EditorCube8
res: 0xfffffff9
a0: EditorCube20
a1: EditorCube8
res: 0xfffffffa
a0: EditorCube21
a1: EditorCube8
res: 0xfffffffa
a0: EditorCube8
a1: EditorCube8
res: 0x0
a0: EditorCube9
a1: EditorCube8
res: 0x1
a0: Floor_12
a1: EditorCube8
res: 0x1
a0: Wall1
a1: EditorCube8
res: 0x12
a0: Wall2_11
a1: EditorCube8
res: 0x12
a0: Wall3
a1: EditorCube8
res: 0x12
a0: Wall4
a1: EditorCube8
res: 0x12
a0: ../../../MyProject/Saved/Config/Android/Engine.ini
a1: ../../../MyProject/Saved/Config/Android/Engine.ini
res: 0x0
a0:
true
a1: True
res: 0x0
a0: Android
a1: Android
res: 0x0
a0: Android
a1: Android
res: 0x0
a0: Android
a1: Android
res: 0x0
Interceptor.attach(base.add(0x680B790), {
onEnter: function(args) {
this
.a1 = args[1];
},
onLeave: function(retval) {
if
(
this
.a1.readUtf16String() ==
"EditorCube8"
) {
retval.replace(5);
}
}
})
Interceptor.attach(base.add(0x680B790), {
onEnter: function(args) {
this
.a1 = args[1];
},
onLeave: function(retval) {
if
(
this
.a1.readUtf16String() ==
"EditorCube8"
) {
retval.replace(5);
}
}
})
function calcTargetOffset(targetLoc, cameraLoc) {
let x = targetLoc.x - cameraLoc.x;
let y = targetLoc.y - cameraLoc.y;
let z = targetLoc.z - cameraLoc.z;
let angleX = 0;
let angleY = 0;
if
(x > 0 && y == 0) angleX = 0;
if
(x > 0 && y > 0) angleX = Math.
abs
(Math.
atan
(y / x)) / Math.PI * 180;
if
(x == 0 && y > 0) angleX = 90;
if
(x < 0 && y > 0) angleX = 90 + Math.
abs
(Math.
atan
(x / y)) / Math.PI * 180;
if
(x < 0 && y == 0) angleX = 180;
if
(x < 0 && y < 0) angleX = 180 + Math.
abs
(Math.
atan
(y / x)) / Math.PI * 180;
if
(x == 0 && y < 0) angleX = 270;
if
(x > 0 && y < 0) angleX = 270 + Math.
abs
(Math.
atan
(x / y)) / Math.PI * 180;
if
(angleX < 0) {
angleX += 360;
}
if
(angleX > 360) {
angleX -= 360;
}
angleY = Math.
atan
(z / Math.
sqrt
(x * x + y * y)) / Math.PI * 180;
if
(angleY < 0) {
angleY += 360;
}
return
[angleY, angleX, 0]
}
function calcTargetOffset(targetLoc, cameraLoc) {
let x = targetLoc.x - cameraLoc.x;
let y = targetLoc.y - cameraLoc.y;
let z = targetLoc.z - cameraLoc.z;
let angleX = 0;
let angleY = 0;
if
(x > 0 && y == 0) angleX = 0;
if
(x > 0 && y > 0) angleX = Math.
abs
(Math.
atan
(y / x)) / Math.PI * 180;
if
(x == 0 && y > 0) angleX = 90;
if
(x < 0 && y > 0) angleX = 90 + Math.
abs
(Math.
atan
(x / y)) / Math.PI * 180;
if
(x < 0 && y == 0) angleX = 180;
if
(x < 0 && y < 0) angleX = 180 + Math.
abs
(Math.
atan
(y / x)) / Math.PI * 180;
if
(x == 0 && y < 0) angleX = 270;
if
(x > 0 && y < 0) angleX = 270 + Math.
abs
(Math.
atan
(x / y)) / Math.PI * 180;
if
(angleX < 0) {
angleX += 360;
}
if
(angleX > 360) {
angleX -= 360;
}
angleY = Math.
atan
(z / Math.
sqrt
(x * x + y * y)) / Math.PI * 180;
if
(angleY < 0) {
angleY += 360;
}
return
[angleY, angleX, 0]
}
Class: MyProjectCharacter.Character.Pawn.Actor.Object
Vector GunOffset;
Class: MyProjectCharacter.Character.Pawn.Actor.Object
Vector GunOffset;
1. PC: 0x6F7307EA6C (0x6930A6C) LR: 0x6F7307EA68
2. PC: 0x6F7307EA7C (0x6930A7C) LR: 0x6F7307EA68
1. PC: 0x6F7307EA6C (0x6930A6C) LR: 0x6F7307EA68
2. PC: 0x6F7307EA7C (0x6930A7C) LR: 0x6F7307EA68
6f72e75e24 is in libUE4.so offset: 0x670fe24
6f72e75658 is in libUE4.so offset: 0x670f658 (位於0x670F110)
6f72e75eb0 is in libUE4.so offset: 0x670feb0
6f72e75eb0 is in libUE4.so offset: 0x670feb0
6f759cee38 is in libUE4.so offset: 0x9268e38
6f759cce04 is in libUE4.so offset: 0x9266e04
6fe951f09c is in libart.so offset: 0x59b09c
6f72e75e24 is in libUE4.so offset: 0x670fe24
6f72e75658 is in libUE4.so offset: 0x670f658 (位於0x670F110)
6f72e75eb0 is in libUE4.so offset: 0x670feb0
6f72e75eb0 is in libUE4.so offset: 0x670feb0
6f759cee38 is in libUE4.so offset: 0x9268e38
6f759cce04 is in libUE4.so offset: 0x9266e04
6fe951f09c is in libart.so offset: 0x59b09c
function hook_rand() {
Interceptor.attach(Module.findExportByName(null,
"rand"
), {
onLeave: function(retval) {
retval.replace(100);
console.
log
(
"[rand] res: "
, retval);
}
})
}
function hook_rand() {
Interceptor.attach(Module.findExportByName(null,
"rand"
), {
onLeave: function(retval) {
retval.replace(100);
console.
log
(
"[rand] res: "
, retval);
}
})
}
function hook_process_before_shoot() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
let val = args[0].add(0x528).readU8();
args[0].add(0x528).writeU8(val | 1);
console.
log
(
"[process_before_shoot] a1[0x14A] & 1: "
, args[0].add(0x528).readU8() & 1)
},
onLeave: function(retval) {
}
})
}
function hook_process_before_shoot() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
let val = args[0].add(0x528).readU8();
args[0].add(0x528).writeU8(val | 1);
console.
log
(
"[process_before_shoot] a1[0x14A] & 1: "
, args[0].add(0x528).readU8() & 1)
},
onLeave: function(retval) {
}
})
}
Class: MyProjectCharacter.Character.Pawn.Actor.Object
SkeletalMeshComponent* Mesh1P;
SkeletalMeshComponent* FP_Gun;
SceneComponent* FP_MuzzleLocation;
SkeletalMeshComponent* VR_Gun;
SceneComponent* VR_MuzzleLocation;
Class: MyProjectCharacter.Character.Pawn.Actor.Object
SkeletalMeshComponent* Mesh1P;
SkeletalMeshComponent* FP_Gun;
SceneComponent* FP_MuzzleLocation;
SkeletalMeshComponent* VR_Gun;
SceneComponent* VR_MuzzleLocation;
function hook_test() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
console.
log
(
"[process_before_shoot]"
);
let VR_MuzzleLocation = args[0].add(0x4D8)
VR_MuzzleLocation.writePointer(All_Objects[
"MuzzleLocation"
])
printName(VR_MuzzleLocation.readPointer());
},
onLeave: function(retval) {
}
})
}
function hook_test() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
console.
log
(
"[process_before_shoot]"
);
let VR_MuzzleLocation = args[0].add(0x4D8)
VR_MuzzleLocation.writePointer(All_Objects[
"MuzzleLocation"
])
printName(VR_MuzzleLocation.readPointer());
},
onLeave: function(retval) {
}
})
}
Class: SceneComponent.ActorComponent.Object
Vector RelativeLocation;
Rotator RelativeRotation;
Class: SceneComponent.ActorComponent.Object
Vector RelativeLocation;
Rotator RelativeRotation;
function fix_MuzzleLocation() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
console.
log
(
"[process_before_shoot]"
);
let K2_SetRelativeLocation =
new
NativeFunction(base.add(0x8AE6D70),
"void"
, [
"pointer"
,
"float"
,
"float"
,
"float"
,
"bool"
,
"pointer"
,
"bool"
]);
let K2_SetRelativeRotation =
new
NativeFunction(base.add(0x8AE6F00),
"void"
, [
"pointer"
,
"float"
,
"float"
,
"float"
,
"bool"
,
"pointer"
,
"bool"
]);
K2_SetRelativeRotation(All_Objects[
"MuzzleLocation"
], 0, 90, 0, 0, ptr(0), 0);
let RelativeLocation = All_Objects[
"MuzzleLocation"
].add(0x11c);
let RelativeRotation = All_Objects[
"MuzzleLocation"
].add(0x128);
console.
log
(
"location: "
, JSON.stringify(readVector(RelativeLocation)))
console.
log
(
"rotation: "
, JSON.stringify(readVector(RelativeRotation)))
let MuzzleLocation = args[0].add(0x4D8)
MuzzleLocation.writePointer(All_Objects[
"MuzzleLocation"
])
},
onLeave: function(retval) {
}
})
}
function fix_MuzzleLocation() {
Interceptor.attach(base.add(0x670F110), {
onEnter: function(args) {
console.
log
(
"[process_before_shoot]"
);
let K2_SetRelativeLocation =
new
NativeFunction(base.add(0x8AE6D70),
"void"
, [
"pointer"
,
"float"
,
"float"
,
"float"
,
"bool"
,
"pointer"
,
"bool"
]);
let K2_SetRelativeRotation =
new
NativeFunction(base.add(0x8AE6F00),
"void"
, [
"pointer"
,
"float"
,
"float"
,
"float"
,
"bool"
,
"pointer"
,
"bool"
]);
K2_SetRelativeRotation(All_Objects[
"MuzzleLocation"
], 0, 90, 0, 0, ptr(0), 0);
let RelativeLocation = All_Objects[
"MuzzleLocation"
].add(0x11c);
let RelativeRotation = All_Objects[
"MuzzleLocation"
].add(0x128);
console.
log
(
"location: "
, JSON.stringify(readVector(RelativeLocation)))
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课