@zsa233/frida-analykit-agent 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/android.d.ts +41 -0
- package/dist/api/android.js +1 -0
- package/dist/bridges.d.ts +4 -0
- package/dist/bridges.js +8 -0
- package/dist/cmodule/scan_adrp.d.ts +9 -0
- package/{src/cmodule/scan_adrp.ts → dist/cmodule/scan_adrp.js} +19 -30
- package/dist/config.d.ts +26 -0
- package/dist/config.js +27 -0
- package/dist/consts.d.ts +18 -0
- package/dist/consts.js +23 -0
- package/dist/elf/insn.d.ts +10 -0
- package/dist/elf/insn.js +43 -0
- package/dist/elf/module.d.ts +95 -0
- package/dist/elf/module.js +632 -0
- package/dist/elf/struct.d.ts +235 -0
- package/{src/elf/struct.ts → dist/elf/struct.js} +63 -149
- package/dist/elf/tools.d.ts +6 -0
- package/dist/elf/tools.js +25 -0
- package/dist/elf/verifier.d.ts +11 -0
- package/dist/elf/verifier.js +57 -0
- package/dist/elf/xref.d.ts +32 -0
- package/dist/elf/xref.js +271 -0
- package/dist/func.d.ts +7 -0
- package/dist/func.js +23 -0
- package/dist/helper.d.ts +130 -0
- package/dist/helper.js +527 -0
- package/{src/index.ts → dist/index.d.ts} +0 -1
- package/dist/index.js +9 -0
- package/dist/jni/env.d.ts +821 -0
- package/dist/jni/env.js +1054 -0
- package/{src/jni/struct.ts → dist/jni/struct.d.ts} +8 -54
- package/dist/jni/struct.js +173 -0
- package/dist/lib/libc.d.ts +68 -0
- package/dist/lib/libc.js +125 -0
- package/dist/lib/libssl.d.ts +23 -0
- package/dist/lib/libssl.js +60 -0
- package/dist/message.d.ts +18 -0
- package/dist/message.js +21 -0
- package/dist/net/ssl.d.ts +29 -0
- package/dist/net/ssl.js +249 -0
- package/dist/net/struct.d.ts +34 -0
- package/{src/net/struct.ts → dist/net/struct.js} +4 -18
- package/dist/net/tools.js +1 -0
- package/dist/process.d.ts +43 -0
- package/dist/process.js +77 -0
- package/dist/rpc.d.ts +1 -0
- package/dist/rpc.js +248 -0
- package/dist/utils/array_pointer.d.ts +21 -0
- package/dist/utils/array_pointer.js +81 -0
- package/dist/utils/queue.d.ts +19 -0
- package/dist/utils/queue.js +89 -0
- package/dist/utils/scan.d.ts +35 -0
- package/dist/utils/scan.js +72 -0
- package/dist/utils/std.d.ts +40 -0
- package/dist/utils/std.js +128 -0
- package/dist/utils/text_endec.d.ts +8 -0
- package/dist/utils/text_endec.js +29 -0
- package/dist/utils/utils.d.ts +28 -0
- package/dist/utils/utils.js +66 -0
- package/package.json +18 -5
- package/src/api/android.ts +0 -80
- package/src/bridges.ts +0 -18
- package/src/cmodule/scan_adrp.c +0 -81
- package/src/config.ts +0 -56
- package/src/consts.ts +0 -31
- package/src/elf/insn.ts +0 -61
- package/src/elf/module.ts +0 -751
- package/src/elf/tools.ts +0 -33
- package/src/elf/verifier.ts +0 -74
- package/src/elf/xref.ts +0 -360
- package/src/func.ts +0 -32
- package/src/helper.ts +0 -685
- package/src/jni/env.ts +0 -1439
- package/src/lib/libc.ts +0 -161
- package/src/lib/libssl.ts +0 -95
- package/src/message.ts +0 -26
- package/src/net/ssl.ts +0 -360
- package/src/process.ts +0 -137
- package/src/rpc.ts +0 -268
- package/src/runtime-globals.d.ts +0 -11
- package/src/utils/array_pointer.ts +0 -102
- package/src/utils/queue.ts +0 -102
- package/src/utils/scan.ts +0 -103
- package/src/utils/std.ts +0 -165
- package/src/utils/text_endec.ts +0 -35
- package/src/utils/utils.ts +0 -111
- /package/{src/net/tools.ts → dist/net/tools.d.ts} +0 -0
package/src/helper.ts
DELETED
|
@@ -1,685 +0,0 @@
|
|
|
1
|
-
import { Libc } from './lib/libc.js'
|
|
2
|
-
import { FixedQueue } from './utils/queue.js'
|
|
3
|
-
import { RPCMsgType, saveFileSource } from './message.js'
|
|
4
|
-
import { Config, LogLevel, setGlobalProperties } from './config.js'
|
|
5
|
-
import { TextEncoder } from './utils/text_endec.js'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export class NativePointerObject {
|
|
9
|
-
protected readonly _handle: NativePointer
|
|
10
|
-
|
|
11
|
-
constructor(handle: NativePointer){
|
|
12
|
-
this._handle = handle
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
get $handle(): NativePointer {
|
|
16
|
-
return this._handle
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
$isNull(): boolean {
|
|
20
|
-
return this.$handle.isNull()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
declare class File {
|
|
27
|
-
constructor(filePath: string, mode: string)
|
|
28
|
-
static readAllText(filePath: string): string
|
|
29
|
-
static readAllBytes(filePath: string): ArrayBuffer
|
|
30
|
-
write(data: string | ArrayBuffer | number[]): void
|
|
31
|
-
flush(): void;
|
|
32
|
-
close(): void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
export function downAlign(value: number, alignTo: number) { return Math.floor(value / alignTo) * alignTo }
|
|
37
|
-
export function upAlign(value: number, alignTo: number) { return Math.ceil(value / alignTo) * alignTo }
|
|
38
|
-
export function page_start(value: number) { return downAlign(value, Process.pageSize) }
|
|
39
|
-
export function page_end(value: number) { return upAlign(value, Process.pageSize) }
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
export class LoggerState {
|
|
43
|
-
private msgs: FixedQueue<string>
|
|
44
|
-
private base_msgs: FixedQueue<string>
|
|
45
|
-
private match_offset: number = 0
|
|
46
|
-
|
|
47
|
-
private depth: number = 1
|
|
48
|
-
private counter: number = 1
|
|
49
|
-
private index: number = 0
|
|
50
|
-
|
|
51
|
-
constructor(depth: number = 1) {
|
|
52
|
-
this.depth = depth
|
|
53
|
-
this.index = 0
|
|
54
|
-
this.msgs = new FixedQueue<string>(depth)
|
|
55
|
-
this.base_msgs = new FixedQueue<string>(depth)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
onLog(msg: string): string[] {
|
|
60
|
-
this.index++
|
|
61
|
-
|
|
62
|
-
const earliest_msg = this.msgs.push(msg)
|
|
63
|
-
if (earliest_msg === undefined) {
|
|
64
|
-
this.base_msgs.push(msg)
|
|
65
|
-
return [msg]
|
|
66
|
-
} else {
|
|
67
|
-
let outMsgs: string[] = []
|
|
68
|
-
|
|
69
|
-
if (this.base_msgs.index(this.match_offset) === msg) {
|
|
70
|
-
this.match_offset++
|
|
71
|
-
if (this.match_offset === this.depth) {
|
|
72
|
-
this.counter++
|
|
73
|
-
this.match_offset = 0
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
if (this.counter > 1) {
|
|
77
|
-
outMsgs = (this.base_msgs.list as string[]).map(v => `#${this.counter}# | ${v}`)
|
|
78
|
-
outMsgs.push(msg)
|
|
79
|
-
this.base_msgs.clear()
|
|
80
|
-
} else {
|
|
81
|
-
outMsgs = [msg]
|
|
82
|
-
}
|
|
83
|
-
this.base_msgs.push(msg)
|
|
84
|
-
this.match_offset = 0
|
|
85
|
-
this.counter = 1
|
|
86
|
-
}
|
|
87
|
-
return outMsgs
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const AID_USER_OFFSET = 100000
|
|
95
|
-
|
|
96
|
-
function multiuser_get_user_id(uid: number){
|
|
97
|
-
return Math.floor(uid / AID_USER_OFFSET)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
export class FileHelper extends NativePointerObject {
|
|
103
|
-
private _isClosed: boolean = false
|
|
104
|
-
private readonly _weakRefId: WeakRefId
|
|
105
|
-
constructor(pathname: string, mode: string) {
|
|
106
|
-
const handle = Helper.libc.fopen(pathname, mode)
|
|
107
|
-
if(handle.isNull()) {
|
|
108
|
-
throw new Error(`can't open file[${pathname}], mode[${mode}]`)
|
|
109
|
-
}
|
|
110
|
-
super(handle)
|
|
111
|
-
const weakRef = ptr(handle.toString())
|
|
112
|
-
this._weakRefId = Script.bindWeak(this.$handle, () => {
|
|
113
|
-
return Helper.libc.fclose(weakRef)
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
close() {
|
|
118
|
-
return this._isClosed ? 0 : (this._isClosed = true, Script.unbindWeak(this._weakRefId), Helper.libc.fclose(this.$handle))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
writeLine(data: string, append='\n'){
|
|
122
|
-
return Helper.libc.fputs(data + append, this.$handle)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
flush() {
|
|
126
|
-
return Helper.libc.fflush(this.$handle)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
export type MemoryProtect = {
|
|
132
|
-
originProts: string
|
|
133
|
-
newProts: string
|
|
134
|
-
range: RangeDetails | null
|
|
135
|
-
protectResult?: boolean
|
|
136
|
-
recoverResult?: boolean
|
|
137
|
-
readable: boolean
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export type MemoryPage = {
|
|
141
|
-
base: NativePointer
|
|
142
|
-
size: number
|
|
143
|
-
} & MemoryProtect
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
export class BatchSender {
|
|
147
|
-
private _source: string
|
|
148
|
-
private _batch_list: {
|
|
149
|
-
message: any,
|
|
150
|
-
data?: ArrayBuffer | null,
|
|
151
|
-
}[] = []
|
|
152
|
-
|
|
153
|
-
constructor(source: string) {
|
|
154
|
-
this._source = source
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
send(message: any, data?: ArrayBuffer | null) {
|
|
158
|
-
this._batch_list.push({
|
|
159
|
-
message: message,
|
|
160
|
-
data: data,
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
rpcResponse() {
|
|
165
|
-
if (!this._batch_list.length) {
|
|
166
|
-
return []
|
|
167
|
-
}
|
|
168
|
-
let totalBuffLen = this._batch_list.reduce((acc, cur) => acc + (cur.data?.byteLength || 0), 0)
|
|
169
|
-
const batchBuff = new Uint8Array(totalBuffLen)
|
|
170
|
-
const buffSizeList = []
|
|
171
|
-
const messageList = []
|
|
172
|
-
let buffIndex = 0
|
|
173
|
-
for (let i = 0; i < this._batch_list.length; i++) {
|
|
174
|
-
const data = this._batch_list[i]
|
|
175
|
-
messageList.push(data.message)
|
|
176
|
-
const buffSize = data.data?.byteLength || 0
|
|
177
|
-
buffSizeList.push(buffSize)
|
|
178
|
-
if (data.data && buffSize > 0) {
|
|
179
|
-
batchBuff.set(new Uint8Array(data.data), buffIndex)
|
|
180
|
-
buffIndex += buffSize
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return [{
|
|
184
|
-
type: RPCMsgType.BATCH,
|
|
185
|
-
source: this._source,
|
|
186
|
-
data: {
|
|
187
|
-
message_list: messageList,
|
|
188
|
-
data_sizes: buffSizeList,
|
|
189
|
-
}
|
|
190
|
-
}, batchBuff.buffer]
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
clear(){
|
|
194
|
-
this._batch_list = []
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
flush(){
|
|
198
|
-
const [message, buff] = this.rpcResponse()
|
|
199
|
-
if(!message && !buff) {
|
|
200
|
-
return
|
|
201
|
-
}
|
|
202
|
-
Helper.$send(message, buff as ArrayBuffer)
|
|
203
|
-
this.clear()
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let PROGRESS_INC: number = 0
|
|
210
|
-
|
|
211
|
-
export class ProgressNotify {
|
|
212
|
-
private readonly ID: number
|
|
213
|
-
readonly tag: string
|
|
214
|
-
private step: number = 0
|
|
215
|
-
private startTime: Date
|
|
216
|
-
|
|
217
|
-
constructor(tag: string) {
|
|
218
|
-
PROGRESS_INC++
|
|
219
|
-
this.ID = PROGRESS_INC
|
|
220
|
-
this.tag = tag
|
|
221
|
-
this.startTime = new Date()
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
notify(extra: { [key: string]: any } = {}, err?: Error){
|
|
225
|
-
sendProgressMsg(this.tag, this.ID, this.step, extra, err)
|
|
226
|
-
this.step ++
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
log(name: any, extra: any, lines?: string[]) {
|
|
230
|
-
const now = new Date()
|
|
231
|
-
console.error(`[+] | ${this.tag} | <${name}> - ${extra} (${now.getTime() - this.startTime.getTime()} ms)`)
|
|
232
|
-
if(lines?.length) {
|
|
233
|
-
console.error('[>] ' + lines.map(v => `${v}`).join('\n'))
|
|
234
|
-
}
|
|
235
|
-
this.startTime = now
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
function sendProgressMsg(tag: string, id: number, step: number, extra: { [key: string]: any } = {}, err?: Error){
|
|
242
|
-
Helper.$send({
|
|
243
|
-
type: RPCMsgType.PROGRESSING,
|
|
244
|
-
data: {
|
|
245
|
-
tag: tag,
|
|
246
|
-
id: id,
|
|
247
|
-
step: step,
|
|
248
|
-
time: new Date().getTime(),
|
|
249
|
-
extra: extra,
|
|
250
|
-
error: err ? {
|
|
251
|
-
message: err?.message,
|
|
252
|
-
stack: err?.stack
|
|
253
|
-
}: null,
|
|
254
|
-
}
|
|
255
|
-
})
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
function getScanPatternSize(pattern: string): number {
|
|
261
|
-
if (pattern.startsWith('/') && pattern.endsWith('/')) {
|
|
262
|
-
throw new Error("Regular expression patterns are not allowed")
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const bytesPart = pattern.split(':', 1)[0].trim()
|
|
266
|
-
if (bytesPart === '') {
|
|
267
|
-
return 0
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const bytes = bytesPart.split(/\s+/)
|
|
271
|
-
return bytes.length
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
class Helper {
|
|
276
|
-
public static libc = new Libc()
|
|
277
|
-
private static _logStates: { [key: string]: LoggerState } = {}
|
|
278
|
-
private static _android_api_level?: number
|
|
279
|
-
private static _dataDir: string
|
|
280
|
-
private static _logfiles: {[key: string]: FileHelper}
|
|
281
|
-
|
|
282
|
-
static get dataDir(): string {
|
|
283
|
-
if (!Helper._dataDir) {
|
|
284
|
-
const cmdline = this.readCmdline(Process.id)
|
|
285
|
-
const uid = this.libc.getuid()
|
|
286
|
-
const dataDir = `/data/user/${multiuser_get_user_id(uid)}/${cmdline}`
|
|
287
|
-
Helper._dataDir = dataDir
|
|
288
|
-
}
|
|
289
|
-
return Helper._dataDir
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
static setOutputDir(dir: string) {
|
|
293
|
-
Config.OutputDir = dir
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
static get outputDir(): string {
|
|
297
|
-
return Config.OutputDir ? Config.OutputDir : this.dataDir
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
private static _loggerPrefix(): any {
|
|
301
|
-
return String(Process.getCurrentThreadId())
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
private static _prelog(states: { [key: string]: LoggerState }, prefix: string, ...args: any[]) {
|
|
305
|
-
let state = states[prefix]
|
|
306
|
-
const msg = Array.from(args).map(v => String(v)).join(' ')
|
|
307
|
-
if (!state) {
|
|
308
|
-
state = new LoggerState(6)
|
|
309
|
-
states[prefix] = state
|
|
310
|
-
}
|
|
311
|
-
return state.onLog(msg)
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
static assert(cond: any) {
|
|
315
|
-
if (!cond) {
|
|
316
|
-
throw new Error(`assert false`)
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
static $log(level: LogLevel, logger: (...args: any[]) => void, ...args: any) {
|
|
321
|
-
if (level < Config.LogLevel) {
|
|
322
|
-
return
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const prefix = this._loggerPrefix()
|
|
326
|
-
if (Config.LogCollapse) {
|
|
327
|
-
const msgs = this._prelog(this._logStates, prefix, ...args)
|
|
328
|
-
for (let v of msgs) {
|
|
329
|
-
logger(`${prefix}|`, v)
|
|
330
|
-
}
|
|
331
|
-
}else{
|
|
332
|
-
logger(`${prefix}|`, ...args)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
static $debug(...args: any) {
|
|
337
|
-
this.$log(LogLevel.DEBUG, console.log, ...args)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
static $info(...args: any) {
|
|
341
|
-
this.$log(LogLevel.INFO, console.log, ...args)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
static $warn(...args: any) {
|
|
345
|
-
this.$log(LogLevel.WARN, console.log, ...args)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
static $error(...args: any) {
|
|
349
|
-
this.$log(LogLevel.WARN, console.error, ...args)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
static walkDir(path: string, fn: AnyFunction) {
|
|
353
|
-
const libc = this.libc
|
|
354
|
-
const dir = libc.opendir(path)
|
|
355
|
-
if (dir.isNull()) {
|
|
356
|
-
console.error(`[walkDir] path[${path}] 打开失败.`)
|
|
357
|
-
return null
|
|
358
|
-
}
|
|
359
|
-
const nameOffset = Process.pointerSize * 2 + 2 + 1
|
|
360
|
-
let dirent: any
|
|
361
|
-
while (!(dirent = libc.readdir(dir)).isNull()) {
|
|
362
|
-
const name = dirent.add(nameOffset).readCString()
|
|
363
|
-
const fp = `${path}/${name}`
|
|
364
|
-
const link = libc.readlink(fp)
|
|
365
|
-
if (!fn(name, link)) {
|
|
366
|
-
break
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
libc.closedir(dir)
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
static getFdLinked(fd: number) {
|
|
373
|
-
return this.libc.readlink(`/proc/self/fd/${fd}`)
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
static getFileStreamLinked(stream: any) {
|
|
377
|
-
const libc = this.libc
|
|
378
|
-
const fd = libc.fileno(stream)
|
|
379
|
-
let link: string | null = null
|
|
380
|
-
if (fd >= 0) {
|
|
381
|
-
link = libc.readlink(`/proc/self/fd/${fd}`)
|
|
382
|
-
}
|
|
383
|
-
return link
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
static readProcMaps(pid: number | string = 'self') {
|
|
387
|
-
return this.readTextFile(`/proc/${pid}/maps`)
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
static readCmdline(pid: number | string = 'self') {
|
|
391
|
-
const cmdline = this.readFile(`/proc/${pid}/cmdline`)
|
|
392
|
-
const sepList = []
|
|
393
|
-
let lastIdx = 0
|
|
394
|
-
const u8bs = new Uint8Array(cmdline)
|
|
395
|
-
for (let i = 0; i < u8bs.byteLength; i ++) {
|
|
396
|
-
const b = u8bs[i]
|
|
397
|
-
if (b === 0) {
|
|
398
|
-
if (lastIdx < i-1) {
|
|
399
|
-
let result = ''
|
|
400
|
-
const view = u8bs.slice(lastIdx, i)
|
|
401
|
-
for (let i = 0; i < view.length; i++) {
|
|
402
|
-
result += String.fromCharCode(view[i])
|
|
403
|
-
}
|
|
404
|
-
if(result.length > 0) sepList.push(result)
|
|
405
|
-
}
|
|
406
|
-
lastIdx = i
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return sepList.join(' ')
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
static readFile(path: string) {
|
|
413
|
-
return File.readAllBytes(path)
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
static openFile(pathname: string, mode: string): FileHelper {
|
|
418
|
-
return new FileHelper(pathname, mode)
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
static isFilePath(str: string): boolean {
|
|
422
|
-
if(!str.length) {
|
|
423
|
-
return false
|
|
424
|
-
}
|
|
425
|
-
return str[0] === '/' && str[str.length - 1] !== '/'
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
static joinPath(dir: string, file: string): string {
|
|
429
|
-
if(!dir.length){
|
|
430
|
-
return dir
|
|
431
|
-
}
|
|
432
|
-
return dir.replace(/\/+$/, '') + '/' + file.replace(/^\/+/, '')
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
static readTextFile(path: string) {
|
|
437
|
-
return File.readAllText(path)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
static dumpProcMaps(tag: string, pid: number | string = 'self') {
|
|
441
|
-
const prog = new ProgressNotify('Helper.dumpProcMaps')
|
|
442
|
-
const sm = this.readProcMaps(pid)
|
|
443
|
-
this.saveFile(tag, sm, 'w', saveFileSource.procMaps)
|
|
444
|
-
prog.log(pid, `[${sm.length}]${tag}`)
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
static dumpTextFile(tag: string, srcPath: string) {
|
|
448
|
-
const prog = new ProgressNotify('Helper.dumpTextFile')
|
|
449
|
-
const sm = File.readAllText(srcPath)
|
|
450
|
-
this.saveFile(tag, sm, 'w', saveFileSource.textFile)
|
|
451
|
-
prog.log(srcPath, `[${sm.length}](${tag})`)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
static backtrace({ context = undefined, addrHandler = DebugSymbol.fromAddress, backtracer = Backtracer.ACCURATE }: {
|
|
455
|
-
context?: undefined | CpuContext,
|
|
456
|
-
addrHandler?: (addr: any) => any,
|
|
457
|
-
backtracer?: Backtracer,
|
|
458
|
-
} = {}) {
|
|
459
|
-
const prog = new ProgressNotify('Helper.backtrace')
|
|
460
|
-
const stacks = Thread.backtrace(context, backtracer).map(addr => {
|
|
461
|
-
return `${addrHandler(addr)}`
|
|
462
|
-
})
|
|
463
|
-
prog.log(Process.getCurrentThreadId(), '', stacks)
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
static saveFile(tag: string, bs: string | ArrayBuffer | null, mode: string, source: string) {
|
|
468
|
-
if (bs === null || bs === undefined) {
|
|
469
|
-
return false
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (Config.OnRPC) {
|
|
473
|
-
let buff: ArrayBuffer
|
|
474
|
-
if(bs instanceof String) {
|
|
475
|
-
const enc = new TextEncoder()
|
|
476
|
-
const view = enc.encode(bs as string)
|
|
477
|
-
buff = view.buffer as ArrayBuffer
|
|
478
|
-
}else{
|
|
479
|
-
buff = bs as ArrayBuffer
|
|
480
|
-
}
|
|
481
|
-
Helper.$send({
|
|
482
|
-
type: RPCMsgType.SAVE_FILE,
|
|
483
|
-
data: {
|
|
484
|
-
source,
|
|
485
|
-
filepath: Helper.joinPath(this.outputDir, tag),
|
|
486
|
-
mode,
|
|
487
|
-
}
|
|
488
|
-
}, buff)
|
|
489
|
-
}else{
|
|
490
|
-
const savedFile = new File(tag, mode)
|
|
491
|
-
savedFile.write(bs)
|
|
492
|
-
savedFile.close()
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
static androidGetApiLevel(): number {
|
|
498
|
-
if (this._android_api_level === undefined) {
|
|
499
|
-
this._android_api_level = parseInt(this.libc.__system_property_get('ro.build.version.sdk'))
|
|
500
|
-
}
|
|
501
|
-
return this._android_api_level
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
static memoryReadDo(address: NativePointer, size: number, doFunc: (makeReadable: () => MemoryProtect[], makeRecovery: ()=>MemoryProtect[])=>void ) {
|
|
505
|
-
const page_infos: MemoryProtect[] = []
|
|
506
|
-
const makeReadable = () => {
|
|
507
|
-
let cur = address
|
|
508
|
-
const end = address.add(size)
|
|
509
|
-
while (cur < end) {
|
|
510
|
-
const range = Process.findRangeByAddress(cur)
|
|
511
|
-
let originProts = ''
|
|
512
|
-
let newProts = ''
|
|
513
|
-
let readable = false
|
|
514
|
-
if(range !== null) {
|
|
515
|
-
cur = range.base.add(range.size)
|
|
516
|
-
originProts = range.protection
|
|
517
|
-
if(range.protection[0] !== 'r') {
|
|
518
|
-
newProts = 'r' + originProts.slice(1)
|
|
519
|
-
}else{
|
|
520
|
-
readable = true
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
page_infos.push({
|
|
524
|
-
readable,
|
|
525
|
-
originProts,
|
|
526
|
-
newProts,
|
|
527
|
-
range,
|
|
528
|
-
})
|
|
529
|
-
}
|
|
530
|
-
for(let v of page_infos) {
|
|
531
|
-
if(v.range && v.newProts !== '') {
|
|
532
|
-
v.protectResult = Memory.protect(v.range.base, v.range.size, v.newProts)
|
|
533
|
-
if(v.protectResult) {
|
|
534
|
-
v.readable = true
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
return page_infos
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
const makeRecovery = () => {
|
|
542
|
-
for (let v of page_infos) {
|
|
543
|
-
if (v.range && v.newProts !== '' && v.protectResult) {
|
|
544
|
-
v.recoverResult = Memory.protect(v.range.base, v.range.size, v.originProts)
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return page_infos
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
doFunc(makeReadable, makeRecovery)
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
static memoryReadPageDo(base: NativePointer, size: number, doFunc: (page: MemoryPage)=>boolean){
|
|
555
|
-
const page_infos: MemoryPage[] = []
|
|
556
|
-
let cur = base
|
|
557
|
-
const end = base.add(size)
|
|
558
|
-
let isAbort = false
|
|
559
|
-
|
|
560
|
-
while (!isAbort && cur < end) {
|
|
561
|
-
const range = Process.findRangeByAddress(cur)
|
|
562
|
-
let mp: MemoryPage = {
|
|
563
|
-
base: cur.and(ptr(Process.pageSize-1).not()),
|
|
564
|
-
size: Process.pageSize,
|
|
565
|
-
protectResult: false,
|
|
566
|
-
originProts: '',
|
|
567
|
-
newProts: '',
|
|
568
|
-
readable: false,
|
|
569
|
-
range,
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
if (range !== null) {
|
|
573
|
-
mp.originProts = range.protection
|
|
574
|
-
if (range.protection[0] !== 'r') {
|
|
575
|
-
mp.newProts = 'r' + mp.originProts.slice(1)
|
|
576
|
-
mp.protectResult = Memory.protect(mp.base, mp.size, mp.newProts)
|
|
577
|
-
if(mp.protectResult) {
|
|
578
|
-
mp.readable = true
|
|
579
|
-
}
|
|
580
|
-
}else{
|
|
581
|
-
mp.readable = true
|
|
582
|
-
}
|
|
583
|
-
isAbort = doFunc(mp)
|
|
584
|
-
if(mp.protectResult) {
|
|
585
|
-
mp.recoverResult = Memory.protect(mp.base, mp.size, mp.originProts)
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
page_infos.push(mp)
|
|
589
|
-
cur = mp.base.add(mp.size)
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
return page_infos
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
static newBatchSender(source: string): BatchSender {
|
|
596
|
-
return new BatchSender(source)
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
static getLogfile(tag: string, mode: string): FileHelper {
|
|
600
|
-
const filepath = Helper.isFilePath(tag) ? tag : Helper.joinPath(Helper.outputDir, tag)
|
|
601
|
-
let fp = Helper._logfiles[filepath]
|
|
602
|
-
if (!fp) {
|
|
603
|
-
fp = Helper.openFile(filepath, mode)
|
|
604
|
-
Helper._logfiles[filepath] = fp
|
|
605
|
-
}
|
|
606
|
-
return fp
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
static $send(message: any, data?: ArrayBuffer | number[] | null): void {
|
|
610
|
-
send(message, data)
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
static scanMemory(
|
|
615
|
-
scanRange: { base: NativePointer, size: number },
|
|
616
|
-
pattern: string,
|
|
617
|
-
{ limit = Process.pageSize, maxMatchNum = -1, onMatch }: {
|
|
618
|
-
limit?: number,
|
|
619
|
-
maxMatchNum?: number,
|
|
620
|
-
onMatch?: (match: MemoryScanMatch) => boolean,
|
|
621
|
-
},
|
|
622
|
-
) {
|
|
623
|
-
const patternSize = getScanPatternSize(pattern)
|
|
624
|
-
const { base, size } = scanRange
|
|
625
|
-
const end = base.add(size)
|
|
626
|
-
let cursor = base
|
|
627
|
-
|
|
628
|
-
const scanResults: MemoryScanMatch[] = []
|
|
629
|
-
this.memoryReadDo(base, size, (makeReadable, makeRecovery) => {
|
|
630
|
-
makeReadable()
|
|
631
|
-
while (cursor < end) {
|
|
632
|
-
const nextCur = cursor.add(Math.min(Number(end.sub(cursor)), limit))
|
|
633
|
-
const cur = Number(cursor.sub(base)) > patternSize ? cursor.sub(patternSize) : cursor
|
|
634
|
-
let results: MemoryScanMatch[]
|
|
635
|
-
try {
|
|
636
|
-
results = Memory.scanSync(cur, Number(nextCur.sub(cur)), pattern)
|
|
637
|
-
if (onMatch) {
|
|
638
|
-
results = results.filter(v => onMatch(v))
|
|
639
|
-
}
|
|
640
|
-
scanResults.push(...results)
|
|
641
|
-
} catch (e) {
|
|
642
|
-
// TODO: Error: access violation accessing 0xxxxxx
|
|
643
|
-
console.error(`[scanMemory] e[${e}]`)
|
|
644
|
-
} finally {
|
|
645
|
-
if (maxMatchNum > 0 && scanResults.length >= maxMatchNum) {
|
|
646
|
-
break
|
|
647
|
-
}
|
|
648
|
-
cursor = nextCur
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
makeRecovery()
|
|
652
|
-
})
|
|
653
|
-
|
|
654
|
-
return scanResults
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
export { Helper as help }
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
declare global {
|
|
667
|
-
const help: Helper
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
export const print = Helper.$log.bind(Helper, LogLevel._MUST_LOG, console.log)
|
|
672
|
-
export const printErr = Helper.$log.bind(Helper, LogLevel._MUST_LOG, console.error)
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
declare global {
|
|
676
|
-
function print(...args: any): void
|
|
677
|
-
function printErr(...args: any): void
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
setGlobalProperties({
|
|
681
|
-
'help': Helper,
|
|
682
|
-
'print': print,
|
|
683
|
-
'printErr': printErr,
|
|
684
|
-
})
|
|
685
|
-
|