2025腾讯游戏安全安卓赛道初赛wp

获得Strings,Objects,SDK

使用ida找到GWorld、GName和GUObject的地址:

GWorld:

image-20250328175544315

GName:

image-20250328175640508

GUObject:

image-20250328175729050

使用UE4dumper将Strings,Objects,SDK都dump出来即可。

修复异常

上手玩了一下,发现存在的异常有:移速过快,开火时会锁到一个箱子上,透视,人物和枪贴图错误,子弹碰撞逻辑错误等。

移速过快

分析:

程序给人物设定的初始最大速度过高,将其改成正常数值即可。

修复方式:

sdk中找到maxwalkspeed,这个是类CharacterMovementComponent的一个变量,然后发现movement类被Character.Pawn.Actor.Object调用了,而这个类又是firstperon类的父类,所以计算一次charactermovement类的偏移后读指针,再计算一次maxwalkspeed的偏移即可修改maxwalkspeed,从而让行走速度回复正常。

代码:

1
2
3
4
5
6
7
function change_speed(speed)
{
var player = GetAddr("FirstPersonCharacter_C")
var maxspeed = player.add(0x288).readPointer().add(0x18c)
maxspeed.writeFloat(speed)
console.log("changed")
}

子弹反弹

分析:

子弹对象的ShouldBounce参数错误了,同时子弹的消失逻辑是固定时间消失,所以会出现多次反弹的情况。

修复方式:

在空中有很多子弹的时候去printActor即可找到子弹的对象名和相关类名。

ProjectileMovementComponent中有一个ShouldBounce变量,可以让子弹无法反弹。

利用MyProjectProjectile中的OnHit函数判断子弹是否撞墙,撞到之后将ShouldBounce改成0就可以解决子弹反弹的问题。然后再调用Actor类中的K2_DestroyActor函数让子弹击中实体后直接消失,这样就不会黏在物体上了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function fix_bullet()
{
var addr = GetAddr("FirstPersonProjectile_C")
var should_bunce = addr.add(0x228).readPointer().add(0xf4)
should_bunce.writeU32(0)
console.log("bunce fixed")
var destory_addr = addr.readPointer().add(0x318).readPointer()
var destory = new NativeFunction(destory_addr,'void',['pointer'])
destory(addr)
console.log("destoryed")
}

function hook_onHit()
{
try
{
var func = moduleBase.add(0x6711D34)
Interceptor.attach(func,{
onEnter: function(args)
{
fix_bullet()
}
})
}
catch(e)
{
console.log("hook_onHit throw: " + e)
}
}

开火锁箱子

分析:

每个箱子都有编号,挨个销毁箱子再开枪来看锁的是哪个箱子。

1
2
3
4
5
6
7
8
9
function destory_Cube()
{
var addr = GetAddr("EditorCube8")
var destory_addr = addr.readPointer().add(0x318).readPointer()
var destory = new NativeFunction(destory_addr,'void',['pointer'])
destory(addr)
console.log("destoryed")

}

发现锁的是Cube8。

通过cheatengine监听Cube8的坐标的内存来看什么地方访问了Cube8的内存。

首先获得Cube8坐标的地址:

1
2
3
4
5
6
7
8
9
function get_location(actor)
{
var addr = GetAddr(actor).add(0x130).readPointer().add(0x1d0)
var x = Memory.readFloat(addr)
var y = Memory.readFloat(addr.add(0x4))
var z = Memory.readFloat(addr.add(0x8))
console.log(addr)
console.log("pos: ", x, " ",y," ",z," ")
}

在CE中添加得到的地址,然后查看什么地方访问了这个地址:
image-20250330154427897

image-20250330154442391

找到了读取Cube8的x坐标的地址。CE的偏移是基于start函数的,于是可以计算出在0x670f4c0处读取了地址。

到ida里面分析一下这个函数:

image-20250330154817042

发现得到Cube8坐标后进行了一系列计算并将结果储存到了v82中,然后将v82作为变量调用了一个虚函数表中偏移为1688的函数,也就是SetControlRotation函数。

image-20250330160053454

故开火锁箱子原因是当我们点击屏幕时,程序会获取Cube8的位置,然后让我们的枪口面向那个方向。

修复:

将调用SetControlRotation函数的汇编nop掉即可。

1
2
3
4
5
6
function fix_selfaim() {
var addr = moduleBase.add(0x670F3F8)
Memory.protect(addr,4,"rwx")
addr.writeByteArray([0x1f,0x20,0x03,0xD5]) //NOP
console.log("fixed")
}

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// var GWorld = 0xAFAC398
// var GName = 0xADF07C0
// var GUObject = 0xAE34A98
var moduleBase;
var GWorld;
var GWorld_Offset = 0xAFAC398;
var GName;
var GName_Offset = 0xADF07C0;
var GObjects;
var GObjects_Offset = 0xAE34A98;

var offset_UObject_InternalIndex = 0xC;
var offset_UObject_ClassPrivate = 0x10;
var offset_UObject_FNameIndex = 0x18;
var offset_UObject_OuterPrivate = 0x20;

var GUObject = {
getClass: function (obj) {
return ptr(obj).add(offset_UObject_ClassPrivate).readPointer();
},
getNameId: function (obj) {
try {
return ptr(obj).add(offset_UObject_FNameIndex).readU32();
}
catch (e) {
return 0;
}
},
getName: function(obj) {
if (this.isValid(obj)){
return getFName(this.getNameId(obj));
} else {
return "None";
}
},
getClassName: function(obj) {
if (this.isValid(obj)) {
var classPrivate = this.getClass(obj);
return this.getName(classPrivate);
} else {
return "None";
}
},
isValid: function(obj) {
return (ptr(obj) > 0 && this.getNameId(obj) > 0 && this.getClass(obj) > 0);
}
}

function getFName(id)
{
var FNStride = 0x2;
var offset_GN_FNPool = 0x30;
var offset_FNPool_Blocks = 0x10;

var offset_FNEntry_info = 0;
var FNEntry_lenB = 6;
var offset_FNEntry_String = 0x2;

var block = id >> 16;
var offset = id & 65535;

var FNPool = GName.add(offset_GN_FNPool)
var NPoolChunk = FNPool.add(offset_FNPool_Blocks + block * 8).readPointer();
var FNEntry = NPoolChunk.add(FNStride * offset);

try
{
if(offset_FNEntry_info !== 0)
{
var FNEntryHeader = FNEntry.add(offset_FNEntry_info).readU16()
}
else
{
var FNEntryHeader = FNEntry.readU16()
}

}
catch(e)
{
return "";
}

var str_addr = FNEntry.add(offset_FNEntry_String);
var str_len = FNEntryHeader >> FNEntry_lenB
var wide = FNEntryHeader & 1
if(wide) return "widestr"

if(str_len > 0 && str_len < 250)
{
var str = str_addr.readUtf8String(str_len)
return str
}
else
{
return "None"
}
}

function set(moduleName)
{
moduleBase = Module.findBaseAddress(moduleName)
GWorld = moduleBase.add(GWorld_Offset).readPointer();
GName = moduleBase.add(GName_Offset)
GObjects = moduleBase.add(GObjects_Offset)
}

function GetActorsAddr()
{
var Level_off = 0x30
var Actors_off = 0x98

var Level = GWorld.add(Level_off).readPointer()
var Actors = Level.add(Actors_off).readPointer()
var Actors_num = Level.add(Actors_off).add(8).readU32()
var Actors_addr = {}
for(var i = 0;i<Actors_num; i++)
{
var Actor_addr = Actors.add(i*8).readPointer()
var Actor_name = GUObject.getName(Actor_addr)
Actors_addr[Actor_name] = Actor_addr;
}
return Actors_addr;
}

function GetAddr(arg)
{
var Actors_addr = GetActorsAddr()
var Addr = Actors_addr[arg]
return Addr
}

function change_collide()
{
var wall1 = GetAddr("BigWall")
var wall2 = GetAddr("BigWall2")
var func = moduleBase.add(0x88A4884)
var set_collide = new NativeFunction(func, 'void', ['pointer', 'char'])
set_collide(ptr(wall1),1)
set_collide(ptr(wall2),1)
console.log("changed")
}

function set_speed(speed)
{
var player = GetAddr("FirstPersonCharacter_C")
var maxspeed = player.add(0x288).readPointer().add(0x18c)
maxspeed.writeFloat(speed)
// console.log("speed set to " ,speed)
}

function fix_bullet()
{
var addr = GetAddr("FirstPersonProjectile_C")
var should_bunce = addr.add(0x228).readPointer().add(0xf4)
should_bunce.writeU32(0)
console.log("bunce fixed")
var destory_addr = addr.readPointer().add(0x318).readPointer()
var destory = new NativeFunction(destory_addr,'void',['pointer'])
destory(addr)
console.log("destoryed")
}

function hook_onHit()
{
try
{
var func = moduleBase.add(0x6711D34)
Interceptor.attach(func,{
onEnter: function(args)
{
fix_bullet()
}
})
}
catch(e)
{
console.log("hook_onHit throw: " + e)
}
}

function destory_Cube()
{
var addr = GetAddr("EditorCube8")
console.log(addr)
var destory_addr = addr.readPointer().add(0x318).readPointer()
var destory = new NativeFunction(destory_addr,'void',['pointer'])
destory(addr)
console.log("destoryed")
}

function track_Cube()
{
var cube = GetAddr("EditorCube8")
var addr = cube.add(0x130).readPointer().add(0x1d0).add(0x4)
MemoryAccessMonitor.enable(
{
base:ptr(addr),
size:0x4
},{
onAccess:function(details)
{
console.log((details.from - moduleBase ).toString(16) + "\noperation: " + details.operation + "\n")
console.log(details.context)
}
}
)
}

function fix_selfaim() {
// var xaddr = moduleBase.add(0x670FEAC)
// Memory.protect(xaddr,4,"rwx");
// xaddr.writeByteArray([0xE1,0x03,0x27,0x1E]);
// var yaddr = xaddr.add(0x4)
// Memory.protect(yaddr,4,"rwx")
// yaddr.writeByteArray([0xE4,0x03,0x27,0x1E]);
// var zaddr = yaddr.add(0x4)
// Memory.protect(zaddr,4,"rwx")
// zaddr.writeByteArray([0xE5,0x03,0x27,0x1E]);
// console.log("fixed!")
var addr = moduleBase.add(0x670F3F8)
Memory.protect(addr,4,"rwx")
addr.writeByteArray([0x1f,0x20,0x03,0xD5]) //NOP
console.log("fixed")
}

function get_location(actor)
{
var addr = GetAddr(actor).add(0x130).readPointer().add(0x1d0)
var x = Memory.readFloat(addr)
var y = Memory.readFloat(addr.add(0x4))
var z = Memory.readFloat(addr.add(0x8))
console.log(addr)
console.log("pos: ", x, " ",y," ",z," ")
}

function hook_spwanBullet()
{
var loc = moduleBase.add(0x8D2EB60);
Interceptor.attach(loc, {
onEnter: function(args) {
console.log(this.context.X24.readByteArray(4));
}
});
}

function main()
{
Java.perform(function()
{
set("libUE4.so")
// change_collide()
set_speed(500)
// fix_bullet()
// hook_onHit()
// destory_Cube()
// track_Cube()
get_location("EditorCube8")
// hook_spwanBullet()
// fix_selfaim()
}
)
}

setImmediate(main);