@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.
Files changed (87) hide show
  1. package/dist/api/android.d.ts +41 -0
  2. package/dist/api/android.js +1 -0
  3. package/dist/bridges.d.ts +4 -0
  4. package/dist/bridges.js +8 -0
  5. package/dist/cmodule/scan_adrp.d.ts +9 -0
  6. package/{src/cmodule/scan_adrp.ts → dist/cmodule/scan_adrp.js} +19 -30
  7. package/dist/config.d.ts +26 -0
  8. package/dist/config.js +27 -0
  9. package/dist/consts.d.ts +18 -0
  10. package/dist/consts.js +23 -0
  11. package/dist/elf/insn.d.ts +10 -0
  12. package/dist/elf/insn.js +43 -0
  13. package/dist/elf/module.d.ts +95 -0
  14. package/dist/elf/module.js +632 -0
  15. package/dist/elf/struct.d.ts +235 -0
  16. package/{src/elf/struct.ts → dist/elf/struct.js} +63 -149
  17. package/dist/elf/tools.d.ts +6 -0
  18. package/dist/elf/tools.js +25 -0
  19. package/dist/elf/verifier.d.ts +11 -0
  20. package/dist/elf/verifier.js +57 -0
  21. package/dist/elf/xref.d.ts +32 -0
  22. package/dist/elf/xref.js +271 -0
  23. package/dist/func.d.ts +7 -0
  24. package/dist/func.js +23 -0
  25. package/dist/helper.d.ts +130 -0
  26. package/dist/helper.js +527 -0
  27. package/{src/index.ts → dist/index.d.ts} +0 -1
  28. package/dist/index.js +9 -0
  29. package/dist/jni/env.d.ts +821 -0
  30. package/dist/jni/env.js +1054 -0
  31. package/{src/jni/struct.ts → dist/jni/struct.d.ts} +8 -54
  32. package/dist/jni/struct.js +173 -0
  33. package/dist/lib/libc.d.ts +68 -0
  34. package/dist/lib/libc.js +125 -0
  35. package/dist/lib/libssl.d.ts +23 -0
  36. package/dist/lib/libssl.js +60 -0
  37. package/dist/message.d.ts +18 -0
  38. package/dist/message.js +21 -0
  39. package/dist/net/ssl.d.ts +29 -0
  40. package/dist/net/ssl.js +249 -0
  41. package/dist/net/struct.d.ts +34 -0
  42. package/{src/net/struct.ts → dist/net/struct.js} +4 -18
  43. package/dist/net/tools.js +1 -0
  44. package/dist/process.d.ts +43 -0
  45. package/dist/process.js +77 -0
  46. package/dist/rpc.d.ts +1 -0
  47. package/dist/rpc.js +248 -0
  48. package/dist/utils/array_pointer.d.ts +21 -0
  49. package/dist/utils/array_pointer.js +81 -0
  50. package/dist/utils/queue.d.ts +19 -0
  51. package/dist/utils/queue.js +89 -0
  52. package/dist/utils/scan.d.ts +35 -0
  53. package/dist/utils/scan.js +72 -0
  54. package/dist/utils/std.d.ts +40 -0
  55. package/dist/utils/std.js +128 -0
  56. package/dist/utils/text_endec.d.ts +8 -0
  57. package/dist/utils/text_endec.js +29 -0
  58. package/dist/utils/utils.d.ts +28 -0
  59. package/dist/utils/utils.js +66 -0
  60. package/package.json +18 -5
  61. package/src/api/android.ts +0 -80
  62. package/src/bridges.ts +0 -18
  63. package/src/cmodule/scan_adrp.c +0 -81
  64. package/src/config.ts +0 -56
  65. package/src/consts.ts +0 -31
  66. package/src/elf/insn.ts +0 -61
  67. package/src/elf/module.ts +0 -751
  68. package/src/elf/tools.ts +0 -33
  69. package/src/elf/verifier.ts +0 -74
  70. package/src/elf/xref.ts +0 -360
  71. package/src/func.ts +0 -32
  72. package/src/helper.ts +0 -685
  73. package/src/jni/env.ts +0 -1439
  74. package/src/lib/libc.ts +0 -161
  75. package/src/lib/libssl.ts +0 -95
  76. package/src/message.ts +0 -26
  77. package/src/net/ssl.ts +0 -360
  78. package/src/process.ts +0 -137
  79. package/src/rpc.ts +0 -268
  80. package/src/runtime-globals.d.ts +0 -11
  81. package/src/utils/array_pointer.ts +0 -102
  82. package/src/utils/queue.ts +0 -102
  83. package/src/utils/scan.ts +0 -103
  84. package/src/utils/std.ts +0 -165
  85. package/src/utils/text_endec.ts +0 -35
  86. package/src/utils/utils.ts +0 -111
  87. /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
-