@cheatron/nthread 1.0.1 → 1.0.3
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/README.md +198 -46
- package/dist/crt.d.ts +1 -0
- package/dist/crt.d.ts.map +1 -1
- package/dist/crt.js +1 -0
- package/dist/crt.js.map +1 -1
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +20 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/heap.d.ts +2 -2
- package/dist/memory/heap.d.ts.map +1 -1
- package/dist/memory/heap.js +5 -5
- package/dist/memory/heap.js.map +1 -1
- package/dist/memory/romem.d.ts +3 -3
- package/dist/memory/romem.d.ts.map +1 -1
- package/dist/memory/romem.js +2 -1
- package/dist/memory/romem.js.map +1 -1
- package/dist/nthread-file.d.ts +82 -0
- package/dist/nthread-file.d.ts.map +1 -0
- package/dist/nthread-file.js +164 -0
- package/dist/nthread-file.js.map +1 -0
- package/dist/nthread-heap.d.ts +1 -1
- package/dist/nthread-heap.d.ts.map +1 -1
- package/dist/nthread.d.ts +67 -5
- package/dist/nthread.d.ts.map +1 -1
- package/dist/nthread.js +163 -32
- package/dist/nthread.js.map +1 -1
- package/dist/thread/proxy-thread.d.ts +8 -3
- package/dist/thread/proxy-thread.d.ts.map +1 -1
- package/dist/thread/proxy-thread.js +13 -6
- package/dist/thread/proxy-thread.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as Native from '@cheatron/native';
|
|
2
|
+
import { NThreadHeap } from './nthread-heap.js';
|
|
3
|
+
import type { CapturedThread } from './thread/captured-thread.js';
|
|
4
|
+
import type { ProxyThread } from './thread/proxy-thread.js';
|
|
5
|
+
import type { GeneralPurposeRegs } from './globals.js';
|
|
6
|
+
/** Per-proxy file channel state. */
|
|
7
|
+
interface FileChannelState {
|
|
8
|
+
/** Local temp file path used as the bidirectional I/O channel. */
|
|
9
|
+
filePath: string;
|
|
10
|
+
/** `FILE*` handle kept open in the target process (`"w+b"` mode). */
|
|
11
|
+
stream: Native.NativePointer;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Default maximum bytes transferred before rotating temp file paths.
|
|
15
|
+
* Reserved for future path-rotation support.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_FILE_MAX_TRANSFER: number;
|
|
18
|
+
/**
|
|
19
|
+
* NThreadFile extends {@link NThreadHeap} with filesystem-based I/O channels.
|
|
20
|
+
*
|
|
21
|
+
* Instead of `ReadProcessMemory` / `WriteProcessMemory` (or the base class's
|
|
22
|
+
* decomposed `memset` write strategy), all data flows through a single temp file:
|
|
23
|
+
*
|
|
24
|
+
* - **Write channel** (attacker → target): attacker writes to temp file locally,
|
|
25
|
+
* then `fseek(0)` + `fread` in the target reads it into the destination address.
|
|
26
|
+
* - **Read channel** (target → attacker): `fseek(0)` + `fwrite` + `fflush` in
|
|
27
|
+
* the target dumps memory to the file, then attacker reads it locally.
|
|
28
|
+
*
|
|
29
|
+
* The file is opened once during `inject()` with `"w+b"` mode (read+write) and
|
|
30
|
+
* kept open for the lifetime of the proxy. `fseek(0, SEEK_SET)` resets the
|
|
31
|
+
* stream position before each operation.
|
|
32
|
+
*
|
|
33
|
+
* ### When to prefer NThreadFile
|
|
34
|
+
* - Large bulk transfers: one `fread`/`fwrite` call vs many `memset` calls
|
|
35
|
+
* - Stealth: avoids RPM/WPM API calls entirely
|
|
36
|
+
*
|
|
37
|
+
* ### Lifecycle
|
|
38
|
+
* - `inject()` opens a single temp file and configures the proxy delegates.
|
|
39
|
+
* - `proxy.write()` / `proxy.read()` transparently route through the file channel.
|
|
40
|
+
* - `proxy.close()` closes the stream, deletes the temp file, restores the thread.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const nt = new NThreadFile();
|
|
45
|
+
* const [proxy] = await nt.inject(tid);
|
|
46
|
+
*
|
|
47
|
+
* const ptr = await proxy.alloc(256, { fill: 0 });
|
|
48
|
+
* await proxy.write(ptr, myBuffer); // goes through file channel
|
|
49
|
+
* const data = await proxy.read(ptr); // goes through file channel
|
|
50
|
+
*
|
|
51
|
+
* await proxy.close(); // closes stream, deletes temp file, destroys heaps, restores thread
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare class NThreadFile extends NThreadHeap {
|
|
55
|
+
constructor(heapSize?: number, maxSize?: number, processId?: number, sleepAddress?: Native.NativePointer, pushretAddress?: Native.NativePointer, regKey?: GeneralPurposeRegs);
|
|
56
|
+
inject(thread: Native.Thread | number): Promise<[ProxyThread, CapturedThread]>;
|
|
57
|
+
/**
|
|
58
|
+
* Closes the file channel: closes the `FILE*` stream in the target, deletes
|
|
59
|
+
* the temp file, then delegates to the base `threadClose` for heap destruction
|
|
60
|
+
* and thread restore.
|
|
61
|
+
*/
|
|
62
|
+
protected fileChannelClose(proxy: ProxyThread, state: FileChannelState, captured: CapturedThread, suicide?: number): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Writes data to the target process through the filesystem channel.
|
|
65
|
+
*
|
|
66
|
+
* 1. Writes `data` to the local temp file (truncates).
|
|
67
|
+
* 2. `fseek(stream, 0, SEEK_SET)` to reset the target's stream position.
|
|
68
|
+
* 3. `fread` in the target reads from the file into the destination address.
|
|
69
|
+
*/
|
|
70
|
+
protected fileChannelWrite(proxy: ProxyThread, state: FileChannelState, address: Native.NativePointer, data: Buffer | Native.NativePointer, size?: number): Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Reads data from the target process through the filesystem channel.
|
|
73
|
+
*
|
|
74
|
+
* 1. `fseek(stream, 0, SEEK_SET)` to reset the target's stream position.
|
|
75
|
+
* 2. `fwrite` in the target dumps memory to the file.
|
|
76
|
+
* 3. `fflush` ensures data reaches disk.
|
|
77
|
+
* 4. Reads the temp file locally.
|
|
78
|
+
*/
|
|
79
|
+
protected fileChannelRead(proxy: ProxyThread, state: FileChannelState, address: Native.NativePointer, size: number): Promise<Buffer>;
|
|
80
|
+
}
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=nthread-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nthread-file.d.ts","sourceRoot":"","sources":["../src/nthread-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAavD,oCAAoC;AACpC,UAAU,gBAAgB;IACxB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC;CAC9B;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAAc,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,WAAY,SAAQ,WAAW;gBAExC,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,CAAC,aAAa,EACnC,cAAc,CAAC,EAAE,MAAM,CAAC,aAAa,EACrC,MAAM,CAAC,EAAE,kBAAkB;IASd,MAAM,CACnB,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,GAC7B,OAAO,CAAC,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IA8CzC;;;;OAIG;cACa,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAgBhB;;;;;;OAMG;cACa,gBAAgB,CAC9B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,CAAC,aAAa,EAC7B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,aAAa,EACnC,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC;IAgClB;;;;;;;OAOG;cACa,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,CAAC,aAAa,EAC7B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC;CAgBnB"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import * as Native from '@cheatron/native';
|
|
2
|
+
import { NThreadHeap } from './nthread-heap.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
4
|
+
import { FileError, WriteSizeRequiredError } from './errors.js';
|
|
5
|
+
import { writeFileSync, readFileSync, unlinkSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { randomBytes } from 'node:crypto';
|
|
9
|
+
const fileLog = log.child('File');
|
|
10
|
+
/** SEEK_SET constant for fseek — seek from beginning of file. */
|
|
11
|
+
const SEEK_SET = 0;
|
|
12
|
+
/**
|
|
13
|
+
* Default maximum bytes transferred before rotating temp file paths.
|
|
14
|
+
* Reserved for future path-rotation support.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_FILE_MAX_TRANSFER = 1024 * 1024; // 1 MiB
|
|
17
|
+
/**
|
|
18
|
+
* NThreadFile extends {@link NThreadHeap} with filesystem-based I/O channels.
|
|
19
|
+
*
|
|
20
|
+
* Instead of `ReadProcessMemory` / `WriteProcessMemory` (or the base class's
|
|
21
|
+
* decomposed `memset` write strategy), all data flows through a single temp file:
|
|
22
|
+
*
|
|
23
|
+
* - **Write channel** (attacker → target): attacker writes to temp file locally,
|
|
24
|
+
* then `fseek(0)` + `fread` in the target reads it into the destination address.
|
|
25
|
+
* - **Read channel** (target → attacker): `fseek(0)` + `fwrite` + `fflush` in
|
|
26
|
+
* the target dumps memory to the file, then attacker reads it locally.
|
|
27
|
+
*
|
|
28
|
+
* The file is opened once during `inject()` with `"w+b"` mode (read+write) and
|
|
29
|
+
* kept open for the lifetime of the proxy. `fseek(0, SEEK_SET)` resets the
|
|
30
|
+
* stream position before each operation.
|
|
31
|
+
*
|
|
32
|
+
* ### When to prefer NThreadFile
|
|
33
|
+
* - Large bulk transfers: one `fread`/`fwrite` call vs many `memset` calls
|
|
34
|
+
* - Stealth: avoids RPM/WPM API calls entirely
|
|
35
|
+
*
|
|
36
|
+
* ### Lifecycle
|
|
37
|
+
* - `inject()` opens a single temp file and configures the proxy delegates.
|
|
38
|
+
* - `proxy.write()` / `proxy.read()` transparently route through the file channel.
|
|
39
|
+
* - `proxy.close()` closes the stream, deletes the temp file, restores the thread.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const nt = new NThreadFile();
|
|
44
|
+
* const [proxy] = await nt.inject(tid);
|
|
45
|
+
*
|
|
46
|
+
* const ptr = await proxy.alloc(256, { fill: 0 });
|
|
47
|
+
* await proxy.write(ptr, myBuffer); // goes through file channel
|
|
48
|
+
* const data = await proxy.read(ptr); // goes through file channel
|
|
49
|
+
*
|
|
50
|
+
* await proxy.close(); // closes stream, deletes temp file, destroys heaps, restores thread
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export class NThreadFile extends NThreadHeap {
|
|
54
|
+
constructor(heapSize, maxSize, processId, sleepAddress, pushretAddress, regKey) {
|
|
55
|
+
super(heapSize, maxSize, processId, sleepAddress, pushretAddress, regKey);
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// inject override
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
async inject(thread) {
|
|
61
|
+
const [proxy, captured] = await super.inject(thread);
|
|
62
|
+
try {
|
|
63
|
+
// Generate a unique temp path
|
|
64
|
+
const id = randomBytes(8).toString('hex');
|
|
65
|
+
const filePath = join(tmpdir(), `nt_${id}`);
|
|
66
|
+
// Open the file in the target with read+write mode (kept open for the
|
|
67
|
+
// proxy's lifetime); fileOpen handles remote string alloc/free internally.
|
|
68
|
+
const stream = await this.fileOpen(proxy, filePath, 'w+b');
|
|
69
|
+
if (stream.address === 0n) {
|
|
70
|
+
throw new FileError(`fopen("${filePath}", "w+b") returned NULL`);
|
|
71
|
+
}
|
|
72
|
+
const state = { filePath, stream };
|
|
73
|
+
// Replace writer: file-based attacker→target channel
|
|
74
|
+
proxy.setWriter((_proxy, address, data, size) => this.fileChannelWrite(_proxy, state, address, data, size));
|
|
75
|
+
// Replace reader: file-based target→attacker channel
|
|
76
|
+
proxy.setReader((_proxy, address, size) => this.fileChannelRead(_proxy, state, address, size));
|
|
77
|
+
// Replace closer: clean up file channel, then delegate to base
|
|
78
|
+
proxy.setCloser((_proxy, suicide) => this.fileChannelClose(_proxy, state, captured, suicide));
|
|
79
|
+
fileLog.info(`File channel established: ${filePath}`);
|
|
80
|
+
return [proxy, captured];
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
// If file channel setup fails, clean up the base injection
|
|
84
|
+
await proxy.close();
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// File Channel I/O
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Closes the file channel: closes the `FILE*` stream in the target, deletes
|
|
93
|
+
* the temp file, then delegates to the base `threadClose` for heap destruction
|
|
94
|
+
* and thread restore.
|
|
95
|
+
*/
|
|
96
|
+
async fileChannelClose(proxy, state, captured, suicide) {
|
|
97
|
+
// Close the FILE* stream (thread is still alive at this point;
|
|
98
|
+
// termination happens in the base threadClose call below).
|
|
99
|
+
await proxy.fclose(state.stream.address);
|
|
100
|
+
// Delete temp file (best-effort)
|
|
101
|
+
try {
|
|
102
|
+
unlinkSync(state.filePath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* file may not exist */
|
|
106
|
+
}
|
|
107
|
+
// Heap destruction + thread restore
|
|
108
|
+
await this.threadClose(proxy, captured, suicide);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Writes data to the target process through the filesystem channel.
|
|
112
|
+
*
|
|
113
|
+
* 1. Writes `data` to the local temp file (truncates).
|
|
114
|
+
* 2. `fseek(stream, 0, SEEK_SET)` to reset the target's stream position.
|
|
115
|
+
* 3. `fread` in the target reads from the file into the destination address.
|
|
116
|
+
*/
|
|
117
|
+
async fileChannelWrite(proxy, state, address, data, size) {
|
|
118
|
+
let buf;
|
|
119
|
+
let writeSize;
|
|
120
|
+
if (data instanceof Native.NativePointer) {
|
|
121
|
+
if (!size)
|
|
122
|
+
throw new WriteSizeRequiredError();
|
|
123
|
+
buf = Native.currentProcess.memory.read(data, size);
|
|
124
|
+
writeSize = size;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
buf = data instanceof Buffer ? data : Buffer.from(data);
|
|
128
|
+
writeSize = size ?? buf.length;
|
|
129
|
+
if (writeSize < buf.length)
|
|
130
|
+
buf = buf.subarray(0, writeSize);
|
|
131
|
+
}
|
|
132
|
+
if (writeSize === 0)
|
|
133
|
+
return 0;
|
|
134
|
+
// 1. Write to local temp file
|
|
135
|
+
writeFileSync(state.filePath, buf);
|
|
136
|
+
// 2. Reset stream position in target
|
|
137
|
+
await proxy.fseek(state.stream, 0n, BigInt(SEEK_SET));
|
|
138
|
+
// 3. Read file contents into target address
|
|
139
|
+
const result = await proxy.fread(address.address, 1n, BigInt(writeSize), state.stream);
|
|
140
|
+
return Number(result.address);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Reads data from the target process through the filesystem channel.
|
|
144
|
+
*
|
|
145
|
+
* 1. `fseek(stream, 0, SEEK_SET)` to reset the target's stream position.
|
|
146
|
+
* 2. `fwrite` in the target dumps memory to the file.
|
|
147
|
+
* 3. `fflush` ensures data reaches disk.
|
|
148
|
+
* 4. Reads the temp file locally.
|
|
149
|
+
*/
|
|
150
|
+
async fileChannelRead(proxy, state, address, size) {
|
|
151
|
+
if (size === 0)
|
|
152
|
+
return Buffer.alloc(0);
|
|
153
|
+
// 1. Reset stream position in target
|
|
154
|
+
await proxy.fseek(state.stream, 0n, BigInt(SEEK_SET));
|
|
155
|
+
// 2. Write target memory to file
|
|
156
|
+
await proxy.fwrite(address.address, 1n, BigInt(size), state.stream);
|
|
157
|
+
// 3. Flush to disk
|
|
158
|
+
await proxy.fflush(state.stream.address);
|
|
159
|
+
// 4. Read the file locally
|
|
160
|
+
const result = readFileSync(state.filePath);
|
|
161
|
+
return result.subarray(0, size);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=nthread-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nthread-file.js","sourceRoot":"","sources":["../src/nthread-file.ts"],"names":[],"mappings":"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"}
|
package/dist/nthread-heap.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export declare class NThreadHeap extends NThread {
|
|
|
48
48
|
private state;
|
|
49
49
|
constructor(heapSize?: number, maxSize?: number, processId?: number, sleepAddress?: Native.NativePointer, pushretAddress?: Native.NativePointer, regKey?: GeneralPurposeRegs);
|
|
50
50
|
protected threadClose(proxy: ProxyThread, captured: CapturedThread, suicide?: number): Promise<void>;
|
|
51
|
-
protected threadAlloc(proxy: ProxyThread, size: number, opts?: AllocOptions): Promise<Native.
|
|
51
|
+
protected threadAlloc(proxy: ProxyThread, size: number, opts?: AllocOptions): Promise<Native.NativeMemory>;
|
|
52
52
|
protected threadFree(proxy: ProxyThread, ptr: Native.NativePointer): Promise<void>;
|
|
53
53
|
private getState;
|
|
54
54
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nthread-heap.d.ts","sourceRoot":"","sources":["../src/nthread-heap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,+CAA+C;AAC/C,eAAO,MAAM,yBAAyB,QAAQ,CAAC;AAE/C,8FAA8F;AAC9F,eAAO,MAAM,6BAA6B,QAAgC,CAAC;AAc3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACtC,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,KAAK,CAAsC;gBAGjD,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,CAAC,aAAa,EACnC,cAAc,CAAC,EAAE,MAAM,CAAC,aAAa,EACrC,MAAM,CAAC,EAAE,kBAAkB;cAWJ,WAAW,CAClC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;cAYS,WAAW,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"nthread-heap.d.ts","sourceRoot":"","sources":["../src/nthread-heap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,+CAA+C;AAC/C,eAAO,MAAM,yBAAyB,QAAQ,CAAC;AAE/C,8FAA8F;AAC9F,eAAO,MAAM,6BAA6B,QAAgC,CAAC;AAc3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,WAAY,SAAQ,OAAO;IACtC,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,KAAK,CAAsC;gBAGjD,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,CAAC,aAAa,EACnC,cAAc,CAAC,EAAE,MAAM,CAAC,aAAa,EACrC,MAAM,CAAC,EAAE,kBAAkB;cAWJ,WAAW,CAClC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;cAYS,WAAW,CAClC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;cAoBN,UAAU,CACjC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,MAAM,CAAC,aAAa,GACxB,OAAO,CAAC,IAAI,CAAC;IAiBhB,OAAO,CAAC,QAAQ;IAShB;;;OAGG;YACW,aAAa;IA4C3B,4FAA4F;IAC5F,OAAO,CAAC,QAAQ;IAQhB,wDAAwD;IACxD,OAAO,CAAC,UAAU;YAIJ,eAAe;CA0D9B"}
|
package/dist/nthread.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { STACK_ADD } from './thread/captured-thread.js';
|
|
|
9
9
|
* All values are ultimately converted to bigint for register assignment (RCX, RDX, R8, R9).
|
|
10
10
|
* Accepts NativePointer (→ .address) and number (→ BigInt()) for convenience.
|
|
11
11
|
*/
|
|
12
|
-
export type Arg = bigint | number | Native.NativePointer;
|
|
12
|
+
export type Arg = bigint | number | Native.NativePointer | string;
|
|
13
13
|
/**
|
|
14
14
|
* NThread: Orchestrates non-invasive thread hijacking.
|
|
15
15
|
*
|
|
@@ -60,7 +60,7 @@ export declare class NThread {
|
|
|
60
60
|
*
|
|
61
61
|
* @returns `true` if the module is loaded, `false` otherwise.
|
|
62
62
|
*/
|
|
63
|
-
protected checkModuleLoaded(captured: CapturedThread, moduleBase: Arg, phModule?: Arg): Promise<boolean>;
|
|
63
|
+
protected checkModuleLoaded(proxy: ProxyThread, captured: CapturedThread, moduleBase: Arg, phModule?: Arg): Promise<boolean>;
|
|
64
64
|
/** Writes data to the target process; dispatches NativePointer vs Buffer. */
|
|
65
65
|
private threadWrite;
|
|
66
66
|
/**
|
|
@@ -75,7 +75,7 @@ export declare class NThread {
|
|
|
75
75
|
* delegates to `msvcrt!realloc` when `opts.address` is provided.
|
|
76
76
|
* Subclasses can override to use a pre-allocated heap instead.
|
|
77
77
|
*/
|
|
78
|
-
protected threadAlloc(proxy: ProxyThread, size: number, opts?: AllocOptions): Promise<Native.
|
|
78
|
+
protected threadAlloc(proxy: ProxyThread, size: number, opts?: AllocOptions): Promise<Native.NativeMemory>;
|
|
79
79
|
/**
|
|
80
80
|
* Hook: frees a pointer in the target process.
|
|
81
81
|
* Default: `msvcrt!free`.
|
|
@@ -91,7 +91,69 @@ export declare class NThread {
|
|
|
91
91
|
* @param encoding Buffer encoding — defaults to `'utf16le'` (Windows wide string).
|
|
92
92
|
* @param opts Optional alloc options forwarded to `proxy.alloc()`.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
/**
|
|
95
|
+
/**
|
|
96
|
+
* Resolves an argument list, converting `string` values to remote pointers.
|
|
97
|
+
* Uses `resolveEncoding` to auto-detect encoding (ASCII → utf8, non-ASCII → utf16le)
|
|
98
|
+
* so callers can pass plain strings to both A and W variant Windows functions.
|
|
99
|
+
*/
|
|
100
|
+
protected resolveArgs(proxy: ProxyThread, args: Arg[]): Promise<bigint[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Allocates a null-terminated wide string (UTF-16LE) in the target process.
|
|
103
|
+
* Use `encoding` to override — e.g. `'utf8'` for ANSI (A-variant) APIs.
|
|
104
|
+
*/
|
|
105
|
+
allocString(proxy: ProxyThread, str: string, opts?: AllocOptions): Promise<Native.NativeMemory>;
|
|
106
|
+
/**
|
|
107
|
+
* Encodes `str` with a null terminator and writes it into an already-allocated
|
|
108
|
+
* remote address. Auto-detects encoding via `resolveEncoding`
|
|
109
|
+
* (ASCII → UTF-8 + 1-byte null, non-ASCII → UTF-16LE + 2-byte null).
|
|
110
|
+
*
|
|
111
|
+
* @returns Number of bytes written.
|
|
112
|
+
*/
|
|
113
|
+
writeString(proxy: ProxyThread, dest: Native.NativePointer, str: string): Promise<number>;
|
|
114
|
+
/**
|
|
115
|
+
* Opens a file in the target process via `msvcrt!fopen`.
|
|
116
|
+
* Both `path` and `mode` are automatically allocated as null-terminated ANSI
|
|
117
|
+
* strings and freed after the call.
|
|
118
|
+
*
|
|
119
|
+
* @returns `FILE*` pointer (`address === 0n` on failure).
|
|
120
|
+
*/
|
|
121
|
+
fileOpen(proxy: ProxyThread, path: string | Native.NativePointer, mode: string | Native.NativePointer): Promise<Native.NativePointer>;
|
|
122
|
+
/**
|
|
123
|
+
* Writes data to an open `FILE*` stream via `msvcrt!fwrite`.
|
|
124
|
+
*
|
|
125
|
+
* **Two modes:**
|
|
126
|
+
* - `data: Buffer | string` — encodes locally, allocates a remote scratch buffer,
|
|
127
|
+
* calls `fwrite`, then frees it automatically.
|
|
128
|
+
* Strings are encoded as UTF-8 (raw bytes, no null terminator).
|
|
129
|
+
* - `data: NativeMemory` — already in the target process; byte count is taken
|
|
130
|
+
* from `data.size` automatically.
|
|
131
|
+
*
|
|
132
|
+
* @returns Number of bytes written.
|
|
133
|
+
*/
|
|
134
|
+
fileWrite(proxy: ProxyThread, stream: Native.NativePointer, data: Buffer | string | Native.NativeMemory): Promise<number>;
|
|
135
|
+
/**
|
|
136
|
+
* Reads bytes from a `FILE*` stream via `msvcrt!fread`.
|
|
137
|
+
*
|
|
138
|
+
* **Two modes:**
|
|
139
|
+
* - `dest: NativeMemory` — reads directly into an existing remote buffer;
|
|
140
|
+
* byte count is taken from `dest.size` automatically. Returns number of bytes read.
|
|
141
|
+
* - `dest: number` (= byteCount) — allocates a remote scratch buffer,
|
|
142
|
+
* calls `fread`, copies the result back as a local `Buffer`, then frees the scratch.
|
|
143
|
+
*
|
|
144
|
+
* `size` is always `1` — byte-granular I/O.
|
|
145
|
+
*/
|
|
146
|
+
fileRead(proxy: ProxyThread, stream: Native.NativePointer, dest: Native.NativeMemory | number): Promise<number | Buffer>;
|
|
147
|
+
/**
|
|
148
|
+
* Flushes a `FILE*` stream via `msvcrt!fflush`.
|
|
149
|
+
* Returns `0` on success, non-zero on failure (mirrors fflush).
|
|
150
|
+
*/
|
|
151
|
+
fileFlush(proxy: ProxyThread, stream: Native.NativePointer): Promise<number>;
|
|
152
|
+
/**
|
|
153
|
+
* Closes a `FILE*` stream via `msvcrt!fclose`.
|
|
154
|
+
* Returns `0` on success, `EOF` on failure (mirrors fclose).
|
|
155
|
+
*/
|
|
156
|
+
fileClose(proxy: ProxyThread, stream: Native.NativePointer): Promise<number>;
|
|
95
157
|
/**
|
|
96
158
|
* Executes a function call on a captured thread using the Windows x64 calling convention.
|
|
97
159
|
* The thread must be parked at the sleep address (after inject()).
|
|
@@ -105,7 +167,7 @@ export declare class NThread {
|
|
|
105
167
|
* @param timeoutMs Timeout in ms for waiting on the function return (default: 5000).
|
|
106
168
|
* @returns RAX value as NativePointer.
|
|
107
169
|
*/
|
|
108
|
-
threadCall(thread: CapturedThread, target: Native.NativePointer | bigint, args?: Arg[], timeoutMs?: number): Promise<Native.NativePointer>;
|
|
170
|
+
threadCall(proxy: ProxyThread, thread: CapturedThread, target: Native.NativePointer | bigint, args?: Arg[], timeoutMs?: number): Promise<Native.NativePointer>;
|
|
109
171
|
/**
|
|
110
172
|
* Writes arbitrary data to the target process memory using hijacked memset calls.
|
|
111
173
|
* Decomposes the source buffer into runs of equal bytes and issues one
|
package/dist/nthread.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nthread.d.ts","sourceRoot":"","sources":["../src/nthread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"nthread.d.ts","sourceRoot":"","sources":["../src/nthread.ts"],"names":[],"mappings":"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"}
|