@zsa233/frida-analykit-agent 2.0.0
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/LICENSE +21 -0
- package/README.md +5 -0
- package/package.json +41 -0
- package/src/api/android.ts +80 -0
- package/src/bridges.ts +18 -0
- package/src/cmodule/scan_adrp.c +81 -0
- package/src/cmodule/scan_adrp.ts +118 -0
- package/src/config.ts +56 -0
- package/src/consts.ts +31 -0
- package/src/elf/insn.ts +61 -0
- package/src/elf/module.ts +751 -0
- package/src/elf/struct.ts +271 -0
- package/src/elf/tools.ts +33 -0
- package/src/elf/verifier.ts +74 -0
- package/src/elf/xref.ts +360 -0
- package/src/func.ts +32 -0
- package/src/helper.ts +685 -0
- package/src/index.ts +10 -0
- package/src/jni/env.ts +1439 -0
- package/src/jni/struct.ts +217 -0
- package/src/lib/libc.ts +161 -0
- package/src/lib/libssl.ts +95 -0
- package/src/message.ts +26 -0
- package/src/net/ssl.ts +360 -0
- package/src/net/struct.ts +51 -0
- package/src/net/tools.ts +0 -0
- package/src/process.ts +137 -0
- package/src/rpc.ts +268 -0
- package/src/runtime-globals.d.ts +11 -0
- package/src/utils/array_pointer.ts +102 -0
- package/src/utils/queue.ts +102 -0
- package/src/utils/scan.ts +103 -0
- package/src/utils/std.ts +165 -0
- package/src/utils/text_endec.ts +35 -0
- package/src/utils/utils.ts +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ZSA233
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zsa233/frida-analykit-agent",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Frida agent runtime for frida-analykit",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"frida",
|
|
7
|
+
"reverse-engineering",
|
|
8
|
+
"instrumentation",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/ZSA233/frida-analykit#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/ZSA233/frida-analykit/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ZSA233/frida-analykit.git",
|
|
18
|
+
"directory": "packages/frida-analykit-agent"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"files": [
|
|
22
|
+
"src/**/*",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./src/index.ts",
|
|
28
|
+
"./rpc": "./src/rpc.ts",
|
|
29
|
+
"./*": "./src/*.ts"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"check": "tsc -p tsconfig.json --noEmit"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"frida-java-bridge": "^7.0.8"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/frida-gum": "^18.7.2",
|
|
39
|
+
"typescript": "^5.8.3"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export type NP = NativePointer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export interface EnvJvmti {
|
|
8
|
+
handle: NP
|
|
9
|
+
vm: NP,
|
|
10
|
+
vtable: NP
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// frida-java-bridge/lib/android.js
|
|
16
|
+
export interface VMApi {
|
|
17
|
+
vm: NP
|
|
18
|
+
|
|
19
|
+
module: Module
|
|
20
|
+
|
|
21
|
+
flavor: 'art' | 'dalvik'
|
|
22
|
+
|
|
23
|
+
addLocalRefrence: null
|
|
24
|
+
|
|
25
|
+
find(name: string): NativePointer, // export => symbol => null
|
|
26
|
+
|
|
27
|
+
artRuntime: NativePointer
|
|
28
|
+
|
|
29
|
+
artClassLinker: {
|
|
30
|
+
address: NativePointer,
|
|
31
|
+
quickResolutionTrampoline: NativePointer,
|
|
32
|
+
quickImtConflictTrampoline: NativePointer,
|
|
33
|
+
quickGenericJniTrampoline: NativePointer,
|
|
34
|
+
quickToInterpreterBridgeTrampoline: NativePointer,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
jvmti: EnvJvmti
|
|
38
|
+
|
|
39
|
+
$new(size: number): NativePointer
|
|
40
|
+
$delete(pointer: NativePointer): void
|
|
41
|
+
|
|
42
|
+
// jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs);
|
|
43
|
+
JNI_GetCreateJavaVMs(vmBuf: NP, bufLen: number, nVMs: NP): number
|
|
44
|
+
|
|
45
|
+
// jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
|
|
46
|
+
['art::JavaVMExt::AddGlobalRef']: (vm: NP, self: NP, obj: NP) => NP
|
|
47
|
+
|
|
48
|
+
// void ReaderWriterMutex::ExclusiveLock(Thread* self)
|
|
49
|
+
['art::ReaderWriterMutex::ExclusiveLock']: (lock: NP, self: NP) => void
|
|
50
|
+
|
|
51
|
+
// IndirectRef IndirectReferenceTable::Add(IRTSegmentState previous_state, ObjPtr<mirror:: Object> obj, std::string * error_msg)
|
|
52
|
+
['art::IndirectReferenceTable::Add']: (table: NP, previous_state: NP, obj: number, error_msg: NP) => NP
|
|
53
|
+
|
|
54
|
+
// ObjPtr<mirror::Object> JavaVMExt::DecodeGlobal(IndirectRef ref)
|
|
55
|
+
// thread: 7 > Android >= 6
|
|
56
|
+
['art::JavaVMExt::DecodeGlobal']: (vm: NP, thread: NP, ref: NP) => NP
|
|
57
|
+
|
|
58
|
+
// ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const
|
|
59
|
+
['art::Thread::DecodeJObject']: (thread: NP, obj: NP) => NP
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// TODO:
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
declare global {
|
|
69
|
+
namespace Java {
|
|
70
|
+
const api: VMApi,
|
|
71
|
+
Env: {
|
|
72
|
+
handle: NativePointer
|
|
73
|
+
vm: Java.VM & {
|
|
74
|
+
handle: NativePointer
|
|
75
|
+
}
|
|
76
|
+
throwIfExceptionPending(): Error
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
package/src/bridges.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import JavaBridge from "frida-java-bridge";
|
|
2
|
+
|
|
3
|
+
type BridgeGlobals = typeof globalThis & {
|
|
4
|
+
Java?: typeof JavaBridge;
|
|
5
|
+
ObjC?: unknown;
|
|
6
|
+
Swift?: unknown;
|
|
7
|
+
__FRIDA_ANALYKIT_CONFIG__?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const globals = globalThis as BridgeGlobals;
|
|
11
|
+
|
|
12
|
+
export const Java = globals.Java ?? JavaBridge;
|
|
13
|
+
export const ObjC = globals.ObjC;
|
|
14
|
+
export const Swift = globals.Swift;
|
|
15
|
+
|
|
16
|
+
if (!("Java" in globals)) {
|
|
17
|
+
globals.Java = Java;
|
|
18
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#include <glib.h>
|
|
2
|
+
#include <gum/gummemory.h>
|
|
3
|
+
#include <gum/gumdefs.h>
|
|
4
|
+
|
|
5
|
+
#define PAGE_SIZE 0x1000
|
|
6
|
+
#define GET_ADDR_PAGE(x) ((uintptr_t)(x) & ~(PAGE_SIZE - 1))
|
|
7
|
+
#define ADRP_IMM_LEN_MASK 0x1fffff
|
|
8
|
+
#define ADRP_FIXED28_24_BITSET_MASK (0b10000 << 24)
|
|
9
|
+
#define ADRP_PAGE_INSTR_MASK 0x9fffffe0
|
|
10
|
+
|
|
11
|
+
typedef struct _MemoryScanRes MemoryScanRes;
|
|
12
|
+
typedef struct _ScanUserData ScanUserData;
|
|
13
|
+
|
|
14
|
+
static gboolean on_match_fuzzy_adrp(GumAddress address, gsize size, gpointer user_data);
|
|
15
|
+
|
|
16
|
+
struct _ScanUserData
|
|
17
|
+
{
|
|
18
|
+
gpointer target_address;
|
|
19
|
+
gint align_offset;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
struct _MemoryScanRes
|
|
24
|
+
{
|
|
25
|
+
GArray *results;
|
|
26
|
+
ScanUserData *user_data;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
void _dispose(const MemoryScanRes *res)
|
|
30
|
+
{
|
|
31
|
+
g_array_free(res->results, TRUE);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static gboolean on_match_fuzzy_adrp(GumAddress address, gsize size, gpointer user_data)
|
|
35
|
+
{
|
|
36
|
+
MemoryScanRes *scan_res = (MemoryScanRes *)user_data;
|
|
37
|
+
const guintptr target_page = (guintptr)GET_ADDR_PAGE(scan_res->user_data->target_address);
|
|
38
|
+
const guintptr align_offset = (guintptr)scan_res->user_data->align_offset;
|
|
39
|
+
const guintptr addr_val = (guintptr)address - align_offset;
|
|
40
|
+
const gpointer pc_addr = (gpointer)addr_val;
|
|
41
|
+
|
|
42
|
+
// 4字节指令对齐
|
|
43
|
+
if ((addr_val & (sizeof(guint32) - 1)) != 0)
|
|
44
|
+
return TRUE;
|
|
45
|
+
|
|
46
|
+
// 按pc页差进行匹配
|
|
47
|
+
const guintptr pc_page = (guintptr)GET_ADDR_PAGE(address);
|
|
48
|
+
const guint32 page_delta = (guint32)((target_page - pc_page) >> 12) & ADRP_IMM_LEN_MASK;
|
|
49
|
+
const guint32 immlo = page_delta & 0b11;
|
|
50
|
+
const guint32 immhi = page_delta >> 2;
|
|
51
|
+
const guint32 op = 0x1;
|
|
52
|
+
const guint32 adrp_sign =
|
|
53
|
+
(op << 31) |
|
|
54
|
+
(immlo << 29) |
|
|
55
|
+
ADRP_FIXED28_24_BITSET_MASK |
|
|
56
|
+
(immhi << 5);
|
|
57
|
+
|
|
58
|
+
if (((*(guint32 *)pc_addr) & ADRP_PAGE_INSTR_MASK) != (adrp_sign & ADRP_PAGE_INSTR_MASK))
|
|
59
|
+
return TRUE;
|
|
60
|
+
|
|
61
|
+
g_array_append_val(scan_res->results, pc_addr);
|
|
62
|
+
return TRUE;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
gpointer scan(const GumAddress base_address,
|
|
66
|
+
const gsize size,
|
|
67
|
+
const gchar *pattern_str,
|
|
68
|
+
MemoryScanRes *const scan_res)
|
|
69
|
+
{
|
|
70
|
+
if (scan_res == NULL)
|
|
71
|
+
return NULL;
|
|
72
|
+
|
|
73
|
+
scan_res->results = g_array_new(FALSE, FALSE, sizeof(gpointer));
|
|
74
|
+
|
|
75
|
+
const GumMemoryRange range = {base_address, size};
|
|
76
|
+
const GumMatchPattern *pattern = gum_match_pattern_new_from_string(pattern_str);
|
|
77
|
+
|
|
78
|
+
gum_memory_scan(&range, pattern, on_match_fuzzy_adrp, scan_res);
|
|
79
|
+
|
|
80
|
+
return scan_res->results;
|
|
81
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
|
|
2
|
+
import { nativeFunctionOptions } from "../consts.js"
|
|
3
|
+
import { CMemoryScanRes } from "../utils/scan.js"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const CM = new CModule(`
|
|
7
|
+
#include <glib.h>
|
|
8
|
+
#include <gum/gummemory.h>
|
|
9
|
+
#include <gum/gumdefs.h>
|
|
10
|
+
|
|
11
|
+
#define PAGE_SIZE 0x1000
|
|
12
|
+
#define GET_ADDR_PAGE(x) ((uintptr_t)(x) & ~(PAGE_SIZE - 1))
|
|
13
|
+
#define ADRP_IMM_LEN_MASK 0x1fffff
|
|
14
|
+
#define ADRP_FIXED28_24_BITSET_MASK (0b10000 << 24)
|
|
15
|
+
#define ADRP_PAGE_INSTR_MASK 0x9fffffe0
|
|
16
|
+
|
|
17
|
+
typedef struct _MemoryScanRes MemoryScanRes;
|
|
18
|
+
typedef struct _ScanUserData ScanUserData;
|
|
19
|
+
|
|
20
|
+
static gboolean on_match_fuzzy_adrp(GumAddress address, gsize size, gpointer user_data);
|
|
21
|
+
|
|
22
|
+
struct _ScanUserData
|
|
23
|
+
{
|
|
24
|
+
gpointer target_address;
|
|
25
|
+
gint align_offset;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
struct _MemoryScanRes
|
|
30
|
+
{
|
|
31
|
+
GArray *results;
|
|
32
|
+
ScanUserData *user_data;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
void _dispose(const MemoryScanRes *res)
|
|
36
|
+
{
|
|
37
|
+
g_array_free(res->results, TRUE);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static gboolean on_match_fuzzy_adrp(GumAddress address, gsize size, gpointer user_data)
|
|
41
|
+
{
|
|
42
|
+
MemoryScanRes *scan_res = (MemoryScanRes *)user_data;
|
|
43
|
+
const guintptr target_page = (guintptr)GET_ADDR_PAGE(scan_res->user_data->target_address);
|
|
44
|
+
const guintptr align_offset = (guintptr)scan_res->user_data->align_offset;
|
|
45
|
+
const guintptr addr_val = (guintptr)address - align_offset;
|
|
46
|
+
const gpointer pc_addr = (gpointer)addr_val;
|
|
47
|
+
|
|
48
|
+
// 4字节指令对齐
|
|
49
|
+
if ((addr_val & (sizeof(guint32) - 1)) != 0)
|
|
50
|
+
return TRUE;
|
|
51
|
+
|
|
52
|
+
// 按pc页差进行匹配
|
|
53
|
+
const guintptr pc_page = (guintptr)GET_ADDR_PAGE(address);
|
|
54
|
+
const guint32 page_delta = (guint32)((target_page - pc_page) >> 12) & ADRP_IMM_LEN_MASK;
|
|
55
|
+
const guint32 immlo = page_delta & 0b11;
|
|
56
|
+
const guint32 immhi = page_delta >> 2;
|
|
57
|
+
const guint32 op = 0x1;
|
|
58
|
+
const guint32 adrp_sign =
|
|
59
|
+
(op << 31) |
|
|
60
|
+
(immlo << 29) |
|
|
61
|
+
ADRP_FIXED28_24_BITSET_MASK |
|
|
62
|
+
(immhi << 5);
|
|
63
|
+
|
|
64
|
+
if (((*(guint32 *)pc_addr) & ADRP_PAGE_INSTR_MASK) != (adrp_sign & ADRP_PAGE_INSTR_MASK))
|
|
65
|
+
return TRUE;
|
|
66
|
+
|
|
67
|
+
g_array_append_val(scan_res->results, pc_addr);
|
|
68
|
+
return TRUE;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
gpointer scan(const GumAddress base_address,
|
|
72
|
+
const gsize size,
|
|
73
|
+
const gchar *pattern_str,
|
|
74
|
+
MemoryScanRes *const scan_res)
|
|
75
|
+
{
|
|
76
|
+
if (scan_res == NULL)
|
|
77
|
+
return NULL;
|
|
78
|
+
|
|
79
|
+
scan_res->results = g_array_new(FALSE, FALSE, sizeof(gpointer));
|
|
80
|
+
|
|
81
|
+
const GumMemoryRange range = {base_address, size};
|
|
82
|
+
const GumMatchPattern *pattern = gum_match_pattern_new_from_string(pattern_str);
|
|
83
|
+
|
|
84
|
+
gum_memory_scan(&range, pattern, on_match_fuzzy_adrp, scan_res);
|
|
85
|
+
|
|
86
|
+
return scan_res->results;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
`)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
export class ScanAdrpCMod {
|
|
93
|
+
static readonly cm: CModule = CM
|
|
94
|
+
|
|
95
|
+
static readonly $scan = new NativeFunction(this.cm.scan, 'pointer', ['pointer', 'size_t', 'pointer', 'pointer'], nativeFunctionOptions)
|
|
96
|
+
|
|
97
|
+
static scan(scanRange: { base: NativePointer, size: number }, pattern: string, targetAddr: NativePointer, alignOffset: number) {
|
|
98
|
+
let matcheResults: NativePointer[] = []
|
|
99
|
+
|
|
100
|
+
const userData = Memory.alloc(8 + 4)
|
|
101
|
+
userData.writePointer(targetAddr)
|
|
102
|
+
userData.add(8).writeU32(alignOffset)
|
|
103
|
+
|
|
104
|
+
const scanRes = new CMemoryScanRes(userData)
|
|
105
|
+
const { base, size } = scanRange
|
|
106
|
+
this.$scan(
|
|
107
|
+
base, size, Memory.allocUtf8String(pattern), scanRes.$handle,
|
|
108
|
+
)
|
|
109
|
+
if (scanRes.data.length > 0) {
|
|
110
|
+
matcheResults = scanRes.data.toArray().map(v => v.readPointer())
|
|
111
|
+
}
|
|
112
|
+
this.$dispose(scanRes.$handle)
|
|
113
|
+
return matcheResults
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static readonly $dispose = new NativeFunction(this.cm._dispose, 'void', ['pointer'], nativeFunctionOptions)
|
|
117
|
+
}
|
|
118
|
+
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
type InjectedConfig = {
|
|
2
|
+
OnRPC?: boolean
|
|
3
|
+
OutputDir?: string
|
|
4
|
+
LogLevel?: number
|
|
5
|
+
LogCollapse?: boolean
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const injectedConfig = ((globalThis as typeof globalThis & {
|
|
9
|
+
__FRIDA_ANALYKIT_CONFIG__?: InjectedConfig
|
|
10
|
+
}).__FRIDA_ANALYKIT_CONFIG__) || {}
|
|
11
|
+
|
|
12
|
+
export function setGlobalProperties(keyValues: { [key: string]: any }): void {
|
|
13
|
+
for (let [k, v] of Object.entries(keyValues)) {
|
|
14
|
+
if (k in globalThis) {
|
|
15
|
+
throw new Error(`global property[${k}] exists already`)
|
|
16
|
+
}
|
|
17
|
+
;(globalThis as typeof globalThis & { [key: string]: unknown })[k] = v
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
export const LogLevel = {
|
|
23
|
+
DEBUG: 0,
|
|
24
|
+
INFO: 1,
|
|
25
|
+
WARN: 2,
|
|
26
|
+
ERROR: 3,
|
|
27
|
+
_MUST_LOG: 9999999,
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
declare global {
|
|
35
|
+
const LogLevel: {
|
|
36
|
+
DEBUG: number
|
|
37
|
+
INFO: number
|
|
38
|
+
WARN: number
|
|
39
|
+
ERROR: number
|
|
40
|
+
_MUST_LOG: number
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class Config {
|
|
45
|
+
static OnRPC: boolean = injectedConfig.OnRPC ?? false
|
|
46
|
+
static OutputDir?: string = injectedConfig.OutputDir
|
|
47
|
+
static LogLevel: number = injectedConfig.LogLevel ?? LogLevel.INFO
|
|
48
|
+
static LogCollapse: boolean = injectedConfig.LogCollapse ?? true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
setGlobalProperties({
|
|
54
|
+
'Config': Config,
|
|
55
|
+
'LogLevel': LogLevel,
|
|
56
|
+
})
|
package/src/consts.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const nativeFunctionOptions: NativeABI | NativeFunctionOptions = {
|
|
6
|
+
exceptions: 'propagate',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export enum SYM_INFO_BIND {
|
|
13
|
+
STB_LOCAL = 0x0,
|
|
14
|
+
STB_GLOBAL = 0x1,
|
|
15
|
+
STB_WEAK = 0x2,
|
|
16
|
+
STB_GNU_UNIQUE = 0x3,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export enum SYM_INFO_TYPE {
|
|
21
|
+
STT_NOTYPE = 0x0,
|
|
22
|
+
STT_OBJECT = 0x1,
|
|
23
|
+
STT_FUNC = 0x2,
|
|
24
|
+
STT_SECTION = 0x3,
|
|
25
|
+
STT_FILE = 0x4,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export enum SYM_SHNDX {
|
|
29
|
+
SHN_UNDEF = 0,
|
|
30
|
+
SHN_ABS = 0xfff1,
|
|
31
|
+
}
|
package/src/elf/insn.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { setGlobalProperties } from "../config.js"
|
|
2
|
+
import { NativePointerObject } from "../helper.js"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class InstructionSequence extends NativePointerObject {
|
|
7
|
+
protected readonly entryInsn: Arm64Instruction
|
|
8
|
+
protected readonly insns: Arm64Instruction[] = []
|
|
9
|
+
protected eoi?: Arm64Instruction
|
|
10
|
+
|
|
11
|
+
constructor(entry: Arm64Instruction) {
|
|
12
|
+
const handle = entry.address
|
|
13
|
+
super(handle)
|
|
14
|
+
this.entryInsn = entry
|
|
15
|
+
this.insns = [entry]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static loadFromPointer<T extends InstructionSequence>(
|
|
19
|
+
this: new (insn: Arm64Instruction) => T,
|
|
20
|
+
handle: NativePointer
|
|
21
|
+
): T {
|
|
22
|
+
const insn = Instruction.parse(handle) as Arm64Instruction
|
|
23
|
+
return new this(insn)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
*[Symbol.iterator]() {
|
|
27
|
+
let insns = this.insns
|
|
28
|
+
let insn: Arm64Instruction = this.entryInsn
|
|
29
|
+
let inc = 0
|
|
30
|
+
const that = this
|
|
31
|
+
|
|
32
|
+
let value: Arm64Instruction | undefined
|
|
33
|
+
|
|
34
|
+
while (true) {
|
|
35
|
+
value = insns[inc]
|
|
36
|
+
if (value === undefined && that.eoi === undefined) {
|
|
37
|
+
try {
|
|
38
|
+
insn = Instruction.parse(insns[inc - 1].next) as Arm64Instruction
|
|
39
|
+
insns.push(insn)
|
|
40
|
+
} catch (error) {
|
|
41
|
+
that.eoi = insn
|
|
42
|
+
break
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
inc++
|
|
46
|
+
yield insn
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
clearCache() {
|
|
52
|
+
this.insns.length = 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
setGlobalProperties({
|
|
60
|
+
InstructionSequence,
|
|
61
|
+
})
|