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 CHANGED
@@ -52,7 +52,8 @@ cs2.close();
52
52
  ## API Highlights
53
53
 
54
54
  - `follow(address, offsets)` — Follow a pointer chain
55
- - `pattern(needle, address, length)` — Find a byte pattern in memory (supports wildcards)
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
- // …etc…
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 }]);
@@ -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
@@ -22,7 +22,7 @@
22
22
  "url": "git://github.com/obscuritysrl/bun-memory.git"
23
23
  },
24
24
  "type": "module",
25
- "version": "1.1.34",
25
+ "version": "1.1.35",
26
26
  "main": "./index.ts",
27
27
  "keywords": [
28
28
  "bun",
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}|\?{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 Address of the buffer if found, or -1n.
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 myAddress = cs2.indexOf(new Uint8Array([1,2,3]), 0x10000000n, 100);
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
- const indexOf = haystack.indexOf(needleBuffer);
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 indexOf !== -1 ? BigInt(indexOf) + address : -1n;
2095
+ return results;
2029
2096
  }
2030
2097
  }
2031
2098