bun-memory 1.1.34 → 1.1.35
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 +14 -3
- package/example/trigger-bot.ts +0 -17
- package/package.json +1 -1
- package/structs/Memory.ts +170 -103
package/README.md
CHANGED
|
@@ -52,7 +52,8 @@ cs2.close();
|
|
|
52
52
|
## API Highlights
|
|
53
53
|
|
|
54
54
|
- `follow(address, offsets)` — Follow a pointer chain
|
|
55
|
-
- `
|
|
55
|
+
- `indexOf(needle, address, length, [all])` — Search for a buffer or array in memory (returns all matches if all=true)
|
|
56
|
+
- `pattern(needle, address, length, [all])` — Find a byte pattern in memory (supports wildcards, returns all matches if all=true)
|
|
56
57
|
- `read(address, scratch)` — Read memory into a scratch (no allocations)
|
|
57
58
|
- `write(address, scratch)` — Write a scratch to memory
|
|
58
59
|
- Module map: `memory.modules['client.dll']`
|
|
@@ -83,10 +84,16 @@ void cs2.read(0x12345678n, array); // Fills array in-place
|
|
|
83
84
|
const needle = 'deadbeef';
|
|
84
85
|
// const needle = 'de**beef';
|
|
85
86
|
// const needle = 'de????ef';
|
|
87
|
+
// Find first match
|
|
86
88
|
const address = cs2.pattern(needle, 0x10000000n, 0x1000);
|
|
87
89
|
if (address !== -1n) {
|
|
88
90
|
console.log(`Found at 0x${address.toString(16)}`);
|
|
89
91
|
}
|
|
92
|
+
// Find all matches
|
|
93
|
+
const allAddresses = cs2.pattern(needle, 0x10000000n, 0x1000, true);
|
|
94
|
+
for (const addr of allAddresses) {
|
|
95
|
+
console.log(`Found at 0x${addr.toString(16)}`);
|
|
96
|
+
}
|
|
90
97
|
```
|
|
91
98
|
|
|
92
99
|
## Example: Pointer Chains
|
|
@@ -103,11 +110,16 @@ const address = cs2.follow(0x10000000n, [0x10n, 0x20n]);
|
|
|
103
110
|
const needle = Buffer.from([0x01, 0x02, 0x03]);
|
|
104
111
|
// const needle = new Uint8Array([0x01, 0x02, 0x03]);
|
|
105
112
|
// const needle = new Uint32Array([0x012345, 0x123456, 0x234567]);
|
|
106
|
-
//
|
|
113
|
+
// Find first match
|
|
107
114
|
const address = cs2.indexOf(needle, 0x10000000n, 0x1000);
|
|
108
115
|
if (address !== -1n) {
|
|
109
116
|
console.log(`Found at 0x${address.toString(16)}`);
|
|
110
117
|
}
|
|
118
|
+
// Find all matches
|
|
119
|
+
const allAddresses = cs2.indexOf(needle, 0x10000000n, 0x1000, true);
|
|
120
|
+
for (const addr of allAddresses) {
|
|
121
|
+
console.log(`Found at 0x${addr.toString(16)}`);
|
|
122
|
+
}
|
|
111
123
|
```
|
|
112
124
|
|
|
113
125
|
## Example: Typed Arrays
|
|
@@ -117,7 +129,6 @@ if (address !== -1n) {
|
|
|
117
129
|
const array = cs2.f32Array(0x12345678n, 4); // Float32Array of length 4
|
|
118
130
|
// const array = cs2.u64Array(0x12345678n, 4);
|
|
119
131
|
// const array = cs2.vector3Array(0x12345678n, 4);
|
|
120
|
-
// …etc…
|
|
121
132
|
cs2.i32Array(0x12345678n, new Int32Array([1, 2, 3, 4]));
|
|
122
133
|
cs2.u64Array(0x12345678n, new BigUint64Array([1, 2, 3, 4]));
|
|
123
134
|
cs2.vector3Array(0x12345678n, [{ x: 1, y: 2, z: 3 }]);
|
package/example/trigger-bot.ts
CHANGED
|
@@ -38,23 +38,6 @@ if (ClientPtr === undefined) {
|
|
|
38
38
|
throw new TypeError('ClientPtr must not be undefined.');
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// Get client.dll…
|
|
42
|
-
const client = cs2.modules['client.dll'];
|
|
43
|
-
|
|
44
|
-
if (client === undefined) {
|
|
45
|
-
throw new Error('client must not be undefined…');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Byte pattern for AddNametag
|
|
49
|
-
const needle = '40555356488dac24????????4881ec????????488bda488bf14885c9';
|
|
50
|
-
|
|
51
|
-
// Find a byte pattern in memory (supports wildcards: ** and ??)…
|
|
52
|
-
const addNametag = cs2.pattern(needle, client.base, client.size);
|
|
53
|
-
|
|
54
|
-
if (addNametag !== -1n) {
|
|
55
|
-
console.log(`Found at 0x${addNametag.toString(16)}`); // Found at 0x7ffc8964e490
|
|
56
|
-
}
|
|
57
|
-
|
|
58
41
|
// Create a cache for class name strings… 🫠…
|
|
59
42
|
const Cache_Names = new Map<bigint, string>();
|
|
60
43
|
|
package/package.json
CHANGED
package/structs/Memory.ts
CHANGED
|
@@ -124,7 +124,8 @@ class Memory {
|
|
|
124
124
|
*/
|
|
125
125
|
private static readonly Patterns = {
|
|
126
126
|
MatchAll: /(?:[0-9A-Fa-f]{2})+/g,
|
|
127
|
-
Test: /^(?:\*{2}|[0-9A-Fa-f]{2}
|
|
127
|
+
Test: /^(?=.*[0-9A-Fa-f]{2})(?:\*{2}|\?{2}|[0-9A-Fa-f]{2})+$/,
|
|
128
|
+
// Test: /^(?:\*{2}|[0-9A-Fa-f]{2}|\?{2})+$/,
|
|
128
129
|
};
|
|
129
130
|
|
|
130
131
|
/**
|
|
@@ -316,100 +317,6 @@ class Memory {
|
|
|
316
317
|
return;
|
|
317
318
|
}
|
|
318
319
|
|
|
319
|
-
/**
|
|
320
|
-
* Follows a pointer chain with offsets.
|
|
321
|
-
* @param address Base address.
|
|
322
|
-
* @param offsets Array of pointer offsets.
|
|
323
|
-
* @returns Final address after following the chain, or -1n if any pointer is null.
|
|
324
|
-
* @example
|
|
325
|
-
* ```ts
|
|
326
|
-
* const cs2 = new Memory('cs2.exe');
|
|
327
|
-
* const myAddress = cs2.follow(0x10000000n, [0x10n, 0x20n]);
|
|
328
|
-
* ```
|
|
329
|
-
*/
|
|
330
|
-
public follow(address: bigint, offsets: readonly bigint[]): bigint {
|
|
331
|
-
const last = offsets.length - 1;
|
|
332
|
-
|
|
333
|
-
for (let i = 0; i < last; i++) {
|
|
334
|
-
address = this.u64(address + offsets[i]);
|
|
335
|
-
|
|
336
|
-
if (address === 0n) {
|
|
337
|
-
return -1n;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return address + (offsets[last] ?? 0n);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Finds the address of a byte pattern in memory. `**` and `??` match any byte.
|
|
346
|
-
* @param needle Hex string pattern to search for (e.g., 'deadbeed', 'dead**ef', 'dead??ef').
|
|
347
|
-
* @param address Start address to search.
|
|
348
|
-
* @param length Number of bytes to search.
|
|
349
|
-
* @returns Address of the pattern if found, or -1n.
|
|
350
|
-
* @example
|
|
351
|
-
* ```ts
|
|
352
|
-
* const cs2 = new Memory('cs2.exe');
|
|
353
|
-
* const addr = cs2.pattern('dead**ef', 0x10000000n, 0x1000);
|
|
354
|
-
* ```
|
|
355
|
-
*/
|
|
356
|
-
public pattern(needle: string, address: bigint, length: number): bigint {
|
|
357
|
-
const test = Memory.Patterns.Test.test(needle);
|
|
358
|
-
|
|
359
|
-
if (!test) {
|
|
360
|
-
return -1n;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const tokens = [...needle.matchAll(Memory.Patterns.MatchAll)]
|
|
364
|
-
.map((match) => ({ buffer: Buffer.from(match[0], 'hex'), index: match.index >>> 1, length: match[0].length >>> 1 })) //
|
|
365
|
-
.sort(({ length: a }, { length: b }) => b - a);
|
|
366
|
-
|
|
367
|
-
if (tokens.length === 0) {
|
|
368
|
-
return needle.length >>> 1 <= length ? address : -1n;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const anchor = tokens.shift()!;
|
|
372
|
-
|
|
373
|
-
const haystack = this.buffer(address, length);
|
|
374
|
-
|
|
375
|
-
const end = length - (needle.length >>> 1);
|
|
376
|
-
let start = haystack.indexOf(anchor.buffer); // prettier-ignore
|
|
377
|
-
|
|
378
|
-
if (start === -1) {
|
|
379
|
-
return -1n;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
outer: do {
|
|
383
|
-
const base = start - anchor.index;
|
|
384
|
-
|
|
385
|
-
if (base < 0) {
|
|
386
|
-
continue;
|
|
387
|
-
} else if (base > end) {
|
|
388
|
-
return -1n;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
for (const { buffer, index, length } of tokens) {
|
|
392
|
-
const sourceEnd = base + index + length,
|
|
393
|
-
sourceStart = base + index,
|
|
394
|
-
target = buffer,
|
|
395
|
-
targetEnd = length,
|
|
396
|
-
targetStart = 0;
|
|
397
|
-
|
|
398
|
-
const compare = haystack.compare(target, targetStart, targetEnd, sourceStart, sourceEnd);
|
|
399
|
-
|
|
400
|
-
if (compare !== 0) {
|
|
401
|
-
continue outer;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return address + BigInt(base);
|
|
406
|
-
|
|
407
|
-
// Finish…
|
|
408
|
-
} while ((start = haystack.indexOf(anchor.buffer, start + 0x01)) !== -1);
|
|
409
|
-
|
|
410
|
-
return -1n;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
320
|
/**
|
|
414
321
|
* Reads memory into a buffer.
|
|
415
322
|
* @param address Address to read from.
|
|
@@ -2002,30 +1909,190 @@ class Memory {
|
|
|
2002
1909
|
|
|
2003
1910
|
// Public utility methods…
|
|
2004
1911
|
|
|
1912
|
+
/**
|
|
1913
|
+
* Follows a pointer chain with offsets.
|
|
1914
|
+
* @param address Base address.
|
|
1915
|
+
* @param offsets Array of pointer offsets.
|
|
1916
|
+
* @returns Final address after following the chain, or -1n if any pointer is null.
|
|
1917
|
+
* @example
|
|
1918
|
+
* ```ts
|
|
1919
|
+
* const cs2 = new Memory('cs2.exe');
|
|
1920
|
+
* const myAddress = cs2.follow(0x10000000n, [0x10n, 0x20n]);
|
|
1921
|
+
* ```
|
|
1922
|
+
*/
|
|
1923
|
+
public follow(address: bigint, offsets: readonly bigint[]): bigint {
|
|
1924
|
+
const last = offsets.length - 1;
|
|
1925
|
+
|
|
1926
|
+
for (let i = 0; i < last; i++) {
|
|
1927
|
+
address = this.u64(address + offsets[i]);
|
|
1928
|
+
|
|
1929
|
+
if (address === 0n) {
|
|
1930
|
+
return -1n;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
return address + (offsets[last] ?? 0n);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
2005
1937
|
/**
|
|
2006
1938
|
* Finds the address of a buffer within a memory region.
|
|
2007
|
-
* @param needle Buffer to search for.
|
|
1939
|
+
* @param needle Buffer or typed array to search for.
|
|
2008
1940
|
* @param address Start address.
|
|
2009
1941
|
* @param length Number of bytes to search.
|
|
2010
|
-
* @returns
|
|
1942
|
+
* @param all If true, returns all matches as an array. If false or omitted, returns the first match or -1n.
|
|
1943
|
+
* @returns Address of the buffer if found, or -1n. If all is true, returns an array of addresses.
|
|
2011
1944
|
* @example
|
|
2012
1945
|
* ```ts
|
|
2013
1946
|
* const cs2 = new Memory('cs2.exe');
|
|
2014
|
-
* const
|
|
1947
|
+
* const needle = Buffer.from('Hello world!');
|
|
1948
|
+
* // const needle = Buffer.from([0x01, 0x02, 0x03]);
|
|
1949
|
+
* // const needle = new Uint8Array([0x01, 0x02, 0x03]);
|
|
1950
|
+
* // const needle = new Float32Array([0x01, 0x02, 0x03]);
|
|
1951
|
+
* // Find first match
|
|
1952
|
+
* const address = cs2.indexOf(needle, 0x10000000n, 100);
|
|
1953
|
+
* // Find all matches
|
|
1954
|
+
* const allAddressess = cs2.indexOf(needle, 0x10000000n, 100, true);
|
|
2015
1955
|
* ```
|
|
2016
1956
|
*/
|
|
2017
|
-
public indexOf(needle: Scratch, address: bigint, length: number): bigint
|
|
1957
|
+
public indexOf(needle: Scratch, address: bigint, length: number): bigint;
|
|
1958
|
+
public indexOf(needle: Scratch, address: bigint, length: number, all: false): bigint;
|
|
1959
|
+
public indexOf(needle: Scratch, address: bigint, length: number, all: true): bigint[];
|
|
1960
|
+
public indexOf(needle: Scratch, address: bigint, length: number, all: boolean = false): bigint | bigint[] {
|
|
2018
1961
|
const haystack = Buffer.allocUnsafe(length);
|
|
2019
1962
|
|
|
2020
|
-
this.read(address, haystack);
|
|
2021
|
-
|
|
2022
1963
|
const needleBuffer = ArrayBuffer.isView(needle) //
|
|
2023
1964
|
? Buffer.from(needle.buffer, needle.byteOffset, needle.byteLength)
|
|
2024
1965
|
: Buffer.from(needle);
|
|
2025
1966
|
|
|
2026
|
-
|
|
1967
|
+
this.read(address, haystack);
|
|
1968
|
+
|
|
1969
|
+
if (!all) {
|
|
1970
|
+
const indexOf = haystack.indexOf(needleBuffer);
|
|
1971
|
+
|
|
1972
|
+
return indexOf !== -1 ? BigInt(indexOf) + address : -1n;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
const results: bigint[] = [];
|
|
1976
|
+
|
|
1977
|
+
let start = haystack.indexOf(needleBuffer);
|
|
1978
|
+
|
|
1979
|
+
if (start === -1) {
|
|
1980
|
+
return results;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
do {
|
|
1984
|
+
results.push(address + BigInt(start));
|
|
1985
|
+
} while ((start = haystack.indexOf(needleBuffer, start + 0x01)) !== -1);
|
|
1986
|
+
|
|
1987
|
+
return results;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
/**
|
|
1991
|
+
* Finds the address of a byte pattern in memory. `**` and `??` match any byte.
|
|
1992
|
+
* @param needle Hex string pattern to search for (e.g., 'deadbeed', 'dead**ef', 'dead??ef').
|
|
1993
|
+
* @param address Start address to search.
|
|
1994
|
+
* @param length Number of bytes to search.
|
|
1995
|
+
* @param all If true, returns all matches as an array. If false or omitted, returns the first match or -1n.
|
|
1996
|
+
* @returns Address of the pattern if found, or -1n. If all is true, returns an array of addresses.
|
|
1997
|
+
* @example
|
|
1998
|
+
* ```ts
|
|
1999
|
+
* const cs2 = new Memory('cs2.exe');
|
|
2000
|
+
* // Find first match
|
|
2001
|
+
* const address = cs2.pattern('dead**ef', 0x10000000n, 0x1000);
|
|
2002
|
+
* // Find all matches
|
|
2003
|
+
* const allAddresses = cs2.pattern('dead**ef', 0x10000000n, 0x1000, true);
|
|
2004
|
+
* ```
|
|
2005
|
+
*/
|
|
2006
|
+
public pattern(needle: string, address: bigint, length: number): bigint;
|
|
2007
|
+
public pattern(needle: string, address: bigint, length: number, all: false): bigint;
|
|
2008
|
+
public pattern(needle: string, address: bigint, length: number, all: true): bigint[];
|
|
2009
|
+
public pattern(needle: string, address: bigint, length: number, all: boolean = false): bigint | bigint[] {
|
|
2010
|
+
const test = Memory.Patterns.Test.test(needle);
|
|
2011
|
+
|
|
2012
|
+
if (!test) {
|
|
2013
|
+
return !all ? -1n : [];
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// The RegExp test ensures that we have at least one token…
|
|
2017
|
+
|
|
2018
|
+
const tokens = [...needle.matchAll(Memory.Patterns.MatchAll)]
|
|
2019
|
+
.map((match) => ({ buffer: Buffer.from(match[0], 'hex'), index: match.index >>> 1, length: match[0].length >>> 1 })) //
|
|
2020
|
+
.sort(({ length: a }, { length: b }) => b - a);
|
|
2021
|
+
|
|
2022
|
+
const anchor = tokens.shift()!;
|
|
2023
|
+
|
|
2024
|
+
const haystack = this.buffer(address, length);
|
|
2025
|
+
|
|
2026
|
+
const end = length - (needle.length >>> 1);
|
|
2027
|
+
let start = haystack.indexOf(anchor.buffer); // prettier-ignore
|
|
2028
|
+
|
|
2029
|
+
if (start === -1) {
|
|
2030
|
+
return !all ? -1n : [];
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
if (!all) {
|
|
2034
|
+
outer: do {
|
|
2035
|
+
const base = start - anchor.index;
|
|
2036
|
+
|
|
2037
|
+
if (base < 0) {
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
if (base > end) {
|
|
2042
|
+
return -1n;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
for (const { buffer, index, length } of tokens) {
|
|
2046
|
+
const sourceEnd = base + index + length,
|
|
2047
|
+
sourceStart = base + index,
|
|
2048
|
+
target = buffer,
|
|
2049
|
+
targetEnd = length,
|
|
2050
|
+
targetStart = 0; // prettier-ignore
|
|
2051
|
+
|
|
2052
|
+
const compare = haystack.compare(target, targetStart, targetEnd, sourceStart, sourceEnd);
|
|
2053
|
+
|
|
2054
|
+
if (compare !== 0) {
|
|
2055
|
+
continue outer;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
return address + BigInt(base);
|
|
2060
|
+
} while ((start = haystack.indexOf(anchor.buffer, start + 0x01)) !== -1);
|
|
2061
|
+
|
|
2062
|
+
return -1n;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
const results: bigint[] = [];
|
|
2066
|
+
|
|
2067
|
+
outer: do {
|
|
2068
|
+
const base = start - anchor.index;
|
|
2069
|
+
|
|
2070
|
+
if (base < 0) {
|
|
2071
|
+
continue;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
if (base > end) {
|
|
2075
|
+
return results;
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
for (const { buffer, index, length } of tokens) {
|
|
2079
|
+
const sourceEnd = base + index + length,
|
|
2080
|
+
sourceStart = base + index,
|
|
2081
|
+
target = buffer,
|
|
2082
|
+
targetEnd = length,
|
|
2083
|
+
targetStart = 0; // prettier-ignore
|
|
2084
|
+
|
|
2085
|
+
const compare = haystack.compare(target, targetStart, targetEnd, sourceStart, sourceEnd);
|
|
2086
|
+
|
|
2087
|
+
if (compare !== 0) {
|
|
2088
|
+
continue outer;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
results.push(address + BigInt(base));
|
|
2093
|
+
} while ((start = haystack.indexOf(anchor.buffer, start + 0x01)) !== -1);
|
|
2027
2094
|
|
|
2028
|
-
return
|
|
2095
|
+
return results;
|
|
2029
2096
|
}
|
|
2030
2097
|
}
|
|
2031
2098
|
|