bun-memory 1.1.36 → 1.1.37

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 (2) hide show
  1. package/package.json +1 -1
  2. package/structs/Memory.ts +94 -75
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.36",
25
+ "version": "1.1.37",
26
26
  "main": "./index.ts",
27
27
  "keywords": [
28
28
  "bun",
package/structs/Memory.ts CHANGED
@@ -4,27 +4,21 @@ import type { Module, NetworkUtlVector, Point, QAngle, Quaternion, Region, RGB,
4
4
  import Win32Error from './Win32Error';
5
5
 
6
6
  const {
7
- symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualQueryEx, WriteProcessMemory },
7
+ symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualProtectEx, WriteProcessMemory },
8
8
  } = dlopen('kernel32.dll', {
9
9
  CloseHandle: { args: [FFIType.u64], returns: FFIType.bool },
10
- CreateRemoteThread: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.u64 },
11
10
  CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.u64 },
12
11
  GetCurrentProcess: { args: [], returns: FFIType.ptr },
13
- GetExitCodeThread: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
14
12
  GetLastError: { returns: FFIType.u32 },
15
- IsWow64Process2: { args: [FFIType.u64, FFIType.ptr, FFIType.ptr], returns: FFIType.bool },
16
13
  Module32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
17
14
  Module32NextW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
18
15
  OpenProcess: { args: [FFIType.u32, FFIType.bool, FFIType.u32], returns: FFIType.u64 },
19
16
  Process32FirstW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
20
17
  Process32NextW: { args: [FFIType.u64, FFIType.ptr], returns: FFIType.bool },
21
- ReadProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64_fast, FFIType.ptr], returns: FFIType.bool },
22
- VirtualAllocEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.u32], returns: FFIType.u64 },
23
- VirtualFreeEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32], returns: FFIType.bool },
18
+ ReadProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.ptr], returns: FFIType.bool },
24
19
  VirtualProtectEx: { args: [FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u32, FFIType.ptr], returns: FFIType.bool },
25
20
  VirtualQueryEx: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64], returns: FFIType.u64 },
26
- WaitForSingleObject: { args: [FFIType.u64, FFIType.u32], returns: FFIType.u32 },
27
- WriteProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64_fast, FFIType.ptr], returns: FFIType.bool },
21
+ WriteProcessMemory: { args: [FFIType.u64, FFIType.u64, FFIType.ptr, FFIType.u64, FFIType.ptr], returns: FFIType.bool },
28
22
  });
29
23
 
30
24
  /**
@@ -116,17 +110,6 @@ class Memory {
116
110
  throw new Error(`Process not found: ${identifier}…`);
117
111
  }
118
112
 
119
- // public call(address: bigint, args: { type: FFIType, value: any }[] = [], timeout: number = 5_000): bigint {}
120
-
121
- /**
122
- * Memory protection flags for safe and unsafe regions.
123
- * Used to filter readable/writable memory areas.
124
- */
125
- private static readonly MemoryProtections = {
126
- Safe: 0x10 /* PAGE_EXECUTE */ | 0x20 /* PAGE_EXECUTE_READ */ | 0x40 /* PAGE_EXECUTE_READWRITE */ | 0x80 /* PAGE_EXECUTE_WRITECOPY */ | 0x02 /* PAGE_READONLY */ | 0x04 /* PAGE_READWRITE */ | 0x08 /* PAGE_WRITECOPY */,
127
- Unsafe: 0x100 /* PAGE_GUARD */ | 0x01 /* PAGE_NOACCESS */,
128
- };
129
-
130
113
  /**
131
114
  * Regex patterns for matching hex strings and wildcards in memory scans.
132
115
  * Used by the pattern method.
@@ -177,7 +160,6 @@ class Memory {
177
160
  private readonly Scratch16 = new Uint8Array(0x10);
178
161
  private readonly Scratch16Float32Array = new Float32Array(this.Scratch16.buffer, this.Scratch16.byteOffset, 0x04);
179
162
 
180
- private readonly ScratchMemoryBasicInformation = Buffer.allocUnsafe(0x30 /* sizeof(MEMORY_BASIC_INFORMATION) */);
181
163
  private readonly ScratchModuleEntry32W = Buffer.allocUnsafe(0x438 /* sizeof(MODULEENTRY32W) */);
182
164
 
183
165
  private static TextDecoderUTF8 = new TextDecoder('utf-8');
@@ -305,7 +287,7 @@ class Memory {
305
287
  public read<T extends Scratch>(address: bigint, scratch: T): T {
306
288
  const lpBaseAddress = address;
307
289
  const lpBuffer = ptr(scratch);
308
- const nSize = scratch.byteLength;
290
+ const nSize = BigInt(scratch.byteLength);
309
291
  const numberOfBytesRead = 0x00n;
310
292
 
311
293
  const bReadProcessMemory = ReadProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesRead);
@@ -321,25 +303,57 @@ class Memory {
321
303
  * Writes a buffer to memory.
322
304
  * @param address Address to write to.
323
305
  * @param scratch Buffer to write.
306
+ * @param force If true, temporarily changes the page protection to PAGE_EXECUTE_READWRITE using `VirtualProtectEx` while performing the write.
324
307
  * @returns This instance.
325
- * @todo Add a `force: boolean` option that uses `VirtualProtectEx` for a temporary protection change when set to `true`.
326
- * @todo Consider inlining the call in the if to cut a binding… I hate the idea… 🫠…
327
308
  * @example
328
309
  * ```ts
329
310
  * const cs2 = new Memory('cs2.exe');
330
311
  * cs2.write(0x12345678n, new Uint8Array([1,2,3,4]));
312
+ * // Force a write by temporarily changing memory protection
313
+ * cs2.write(0x12345678n, new Uint8Array([1,2,3,4]), true);
331
314
  * ```
332
315
  */
333
- private write(address: bigint, scratch: Scratch): this {
316
+ private write(address: bigint, scratch: Scratch, force: boolean = false): this {
334
317
  const lpBaseAddress = address;
335
318
  const lpBuffer = scratch.ptr;
336
- const nSize = scratch.byteLength;
319
+ const nSize = BigInt(scratch.byteLength);
337
320
  const numberOfBytesWritten = 0x00n;
338
321
 
339
- const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
322
+ if (!force) {
323
+ const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
324
+
325
+ if (!bWriteProcessMemory) {
326
+ throw new Win32Error('WriteProcessMemory', GetLastError());
327
+ }
328
+
329
+ return this;
330
+ }
331
+
332
+ const dwSize = nSize;
333
+ const flNewProtect = 0x40; /* PAGE_EXECUTE_READWRITE */
334
+ const lpflOldProtect = Buffer.allocUnsafe(0x04);
335
+
336
+ const bVirtualProtectEx = VirtualProtectEx(this.hProcess, lpBaseAddress, dwSize, flNewProtect, lpflOldProtect.ptr);
340
337
 
341
- if (!bWriteProcessMemory) {
342
- throw new Win32Error('WriteProcessMemory', GetLastError());
338
+ if (!bVirtualProtectEx) {
339
+ throw new Win32Error('VirtualProtectEx', GetLastError());
340
+ }
341
+
342
+ try {
343
+ const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
344
+
345
+ if (!bWriteProcessMemory) {
346
+ throw new Win32Error('WriteProcessMemory', GetLastError());
347
+ }
348
+ } finally {
349
+ const flNewProtect2 = lpflOldProtect.readUInt32LE(0x00);
350
+ const lpflOldProtect2 = Buffer.allocUnsafe(0x04);
351
+
352
+ const bVirtualProtectEx2 = VirtualProtectEx(this.hProcess, lpBaseAddress, dwSize, flNewProtect2, lpflOldProtect2.ptr);
353
+
354
+ if (!bVirtualProtectEx2) {
355
+ throw new Win32Error('VirtualProtectEx', GetLastError());
356
+ }
343
357
  }
344
358
 
345
359
  return this;
@@ -368,7 +382,7 @@ class Memory {
368
382
 
369
383
  Scratch1[0x00] = value ? 1 : 0;
370
384
 
371
- this.write(address, Scratch1);
385
+ void this.write(address, Scratch1);
372
386
 
373
387
  return this;
374
388
  }
@@ -397,7 +411,7 @@ class Memory {
397
411
 
398
412
  const value = lengthOrValue;
399
413
 
400
- this.write(address, value);
414
+ void this.write(address, value);
401
415
 
402
416
  return this;
403
417
  }
@@ -433,7 +447,7 @@ class Memory {
433
447
 
434
448
  const scratch = Buffer.from(lengthOrValue);
435
449
 
436
- this.write(address, scratch);
450
+ void this.write(address, scratch);
437
451
 
438
452
  return this;
439
453
  }
@@ -461,7 +475,7 @@ class Memory {
461
475
 
462
476
  Scratch4Float32Array[0x00] = value;
463
477
 
464
- this.write(address, Scratch4Float32Array);
478
+ void this.write(address, Scratch4Float32Array);
465
479
 
466
480
  return this;
467
481
  }
@@ -492,7 +506,7 @@ class Memory {
492
506
 
493
507
  const values = lengthOrValues;
494
508
 
495
- this.write(address, values);
509
+ void this.write(address, values);
496
510
 
497
511
  return this;
498
512
  }
@@ -520,7 +534,7 @@ class Memory {
520
534
 
521
535
  Scratch8Float64Array[0x00] = value;
522
536
 
523
- this.write(address, Scratch8Float64Array);
537
+ void this.write(address, Scratch8Float64Array);
524
538
 
525
539
  return this;
526
540
  }
@@ -551,7 +565,7 @@ class Memory {
551
565
 
552
566
  const values = lengthOrValues;
553
567
 
554
- this.write(address, values);
568
+ void this.write(address, values);
555
569
 
556
570
  return this;
557
571
  }
@@ -579,7 +593,7 @@ class Memory {
579
593
 
580
594
  Scratch2Int16Array[0x00] = value;
581
595
 
582
- this.write(address, Scratch2Int16Array);
596
+ void this.write(address, Scratch2Int16Array);
583
597
 
584
598
  return this;
585
599
  }
@@ -610,7 +624,7 @@ class Memory {
610
624
 
611
625
  const values = lengthOrValues;
612
626
 
613
- this.write(address, values);
627
+ void this.write(address, values);
614
628
 
615
629
  return this;
616
630
  }
@@ -638,7 +652,7 @@ class Memory {
638
652
 
639
653
  Scratch4Int32Array[0x00] = value;
640
654
 
641
- this.write(address, Scratch4Int32Array);
655
+ void this.write(address, Scratch4Int32Array);
642
656
 
643
657
  return this;
644
658
  }
@@ -669,7 +683,7 @@ class Memory {
669
683
 
670
684
  const values = lengthOrValues;
671
685
 
672
- this.write(address, values);
686
+ void this.write(address, values);
673
687
 
674
688
  return this;
675
689
  }
@@ -697,7 +711,7 @@ class Memory {
697
711
 
698
712
  Scratch8BigInt64Array[0x00] = value;
699
713
 
700
- this.write(address, Scratch8BigInt64Array);
714
+ void this.write(address, Scratch8BigInt64Array);
701
715
 
702
716
  return this;
703
717
  }
@@ -728,7 +742,7 @@ class Memory {
728
742
 
729
743
  const values = lengthOrValues;
730
744
 
731
- this.write(address, values);
745
+ void this.write(address, values);
732
746
 
733
747
  return this;
734
748
  }
@@ -756,7 +770,7 @@ class Memory {
756
770
 
757
771
  Scratch1Int8Array[0x00] = value;
758
772
 
759
- this.write(address, Scratch1Int8Array);
773
+ void this.write(address, Scratch1Int8Array);
760
774
 
761
775
  return this;
762
776
  }
@@ -787,7 +801,7 @@ class Memory {
787
801
 
788
802
  const values = lengthOrValues;
789
803
 
790
- this.write(address, values);
804
+ void this.write(address, values);
791
805
 
792
806
  return this;
793
807
  }
@@ -819,7 +833,7 @@ class Memory {
819
833
  throw new RangeError('values.length must be 9.');
820
834
  }
821
835
 
822
- this.write(address, values);
836
+ void this.write(address, values);
823
837
 
824
838
  return this;
825
839
  }
@@ -851,7 +865,7 @@ class Memory {
851
865
  throw new RangeError('values.length must be 12.');
852
866
  }
853
867
 
854
- this.write(address, values);
868
+ void this.write(address, values);
855
869
 
856
870
  return this;
857
871
  }
@@ -883,7 +897,7 @@ class Memory {
883
897
  throw new RangeError('values.length must be 16.');
884
898
  }
885
899
 
886
- this.write(address, values);
900
+ void this.write(address, values);
887
901
 
888
902
  return this;
889
903
  }
@@ -917,7 +931,7 @@ class Memory {
917
931
 
918
932
  this.u32(address, values.length);
919
933
 
920
- this.write(elementsPtr, values);
934
+ void this.write(elementsPtr, values);
921
935
 
922
936
  return this;
923
937
  }
@@ -951,7 +965,7 @@ class Memory {
951
965
  Scratch8Float32Array[0x00] = value.x;
952
966
  Scratch8Float32Array[0x01] = value.y;
953
967
 
954
- this.write(address, Scratch8Float32Array);
968
+ void this.write(address, Scratch8Float32Array);
955
969
 
956
970
  return this;
957
971
  }
@@ -999,7 +1013,7 @@ class Memory {
999
1013
  scratch[j + 0x01] = vector2.y;
1000
1014
  }
1001
1015
 
1002
- this.write(address, scratch);
1016
+ void this.write(address, scratch);
1003
1017
 
1004
1018
  return this;
1005
1019
  }
@@ -1015,7 +1029,7 @@ class Memory {
1015
1029
  throw new RangeError('values.length must be 2.');
1016
1030
  }
1017
1031
 
1018
- this.write(address, values);
1032
+ void this.write(address, values);
1019
1033
 
1020
1034
  return this;
1021
1035
  }
@@ -1051,7 +1065,7 @@ class Memory {
1051
1065
  Scratch12Float32Array[0x02] = value.roll;
1052
1066
  Scratch12Float32Array[0x01] = value.yaw;
1053
1067
 
1054
- this.write(address, Scratch12Float32Array);
1068
+ void this.write(address, Scratch12Float32Array);
1055
1069
 
1056
1070
  return this;
1057
1071
  }
@@ -1101,7 +1115,7 @@ class Memory {
1101
1115
  scratch[j + 0x01] = qAngle.yaw;
1102
1116
  }
1103
1117
 
1104
- this.write(address, scratch);
1118
+ void this.write(address, scratch);
1105
1119
 
1106
1120
  return this;
1107
1121
  }
@@ -1129,7 +1143,7 @@ class Memory {
1129
1143
  throw new RangeError('values.length must be 3.');
1130
1144
  }
1131
1145
 
1132
- this.write(address, values);
1146
+ void this.write(address, values);
1133
1147
 
1134
1148
  return this;
1135
1149
  }
@@ -1167,7 +1181,7 @@ class Memory {
1167
1181
  Scratch16Float32Array[0x01] = value.y;
1168
1182
  Scratch16Float32Array[0x02] = value.z;
1169
1183
 
1170
- this.write(address, Scratch16Float32Array);
1184
+ void this.write(address, Scratch16Float32Array);
1171
1185
 
1172
1186
  return this;
1173
1187
  }
@@ -1219,7 +1233,7 @@ class Memory {
1219
1233
  scratch[j + 0x02] = quaternion.z;
1220
1234
  }
1221
1235
 
1222
- this.write(address, scratch);
1236
+ void this.write(address, scratch);
1223
1237
 
1224
1238
  return this;
1225
1239
  }
@@ -1247,7 +1261,7 @@ class Memory {
1247
1261
  throw new RangeError('values.length must be 4.');
1248
1262
  }
1249
1263
 
1250
- this.write(address, values);
1264
+ void this.write(address, values);
1251
1265
 
1252
1266
  return this;
1253
1267
  }
@@ -1283,7 +1297,9 @@ class Memory {
1283
1297
  Scratch3[0x01] = value.g;
1284
1298
  Scratch3[0x02] = value.b;
1285
1299
 
1286
- return this.write(address, Scratch3);
1300
+ void this.write(address, Scratch3);
1301
+
1302
+ return this;
1287
1303
  }
1288
1304
 
1289
1305
  /**
@@ -1309,7 +1325,7 @@ class Memory {
1309
1325
  throw new RangeError('values.length must be 3.');
1310
1326
  }
1311
1327
 
1312
- this.write(address, values);
1328
+ void this.write(address, values);
1313
1329
 
1314
1330
  return this;
1315
1331
  }
@@ -1347,7 +1363,9 @@ class Memory {
1347
1363
  Scratch4[0x02] = value.b;
1348
1364
  Scratch4[0x03] = value.a;
1349
1365
 
1350
- return this.write(address, Scratch4);
1366
+ void this.write(address, Scratch4);
1367
+
1368
+ return this;
1351
1369
  }
1352
1370
 
1353
1371
  /**
@@ -1373,7 +1391,7 @@ class Memory {
1373
1391
  throw new RangeError('values.length must be 4.');
1374
1392
  }
1375
1393
 
1376
- this.write(address, values);
1394
+ void this.write(address, values);
1377
1395
 
1378
1396
  return this;
1379
1397
  }
@@ -1384,6 +1402,7 @@ class Memory {
1384
1402
  * @param lengthOrValue Length to read or string to write.
1385
1403
  * @returns The string at address, or this instance if writing.
1386
1404
  * @notice When writing, remember to null-terminate your string (e.g., 'hello\0').
1405
+ * @todo Compare performance when using CString vs TextDecoder when reading…
1387
1406
  * @example
1388
1407
  * ```ts
1389
1408
  * const cs2 = new Memory('cs2.exe');
@@ -1410,7 +1429,7 @@ class Memory {
1410
1429
 
1411
1430
  const scratch = Memory.TextEncoderUTF8.encode(lengthOrValue);
1412
1431
 
1413
- this.write(address, scratch);
1432
+ void this.write(address, scratch);
1414
1433
 
1415
1434
  return this;
1416
1435
  }
@@ -1438,7 +1457,7 @@ class Memory {
1438
1457
 
1439
1458
  Scratch2Uint16Array[0x00] = value;
1440
1459
 
1441
- this.write(address, Scratch2Uint16Array);
1460
+ void this.write(address, Scratch2Uint16Array);
1442
1461
 
1443
1462
  return this;
1444
1463
  }
@@ -1469,7 +1488,7 @@ class Memory {
1469
1488
 
1470
1489
  const values = lengthOrValues;
1471
1490
 
1472
- this.write(address, values);
1491
+ void this.write(address, values);
1473
1492
 
1474
1493
  return this;
1475
1494
  }
@@ -1497,7 +1516,7 @@ class Memory {
1497
1516
 
1498
1517
  Scratch4Uint32Array[0x00] = value;
1499
1518
 
1500
- this.write(address, Scratch4Uint32Array);
1519
+ void this.write(address, Scratch4Uint32Array);
1501
1520
 
1502
1521
  return this;
1503
1522
  }
@@ -1528,7 +1547,7 @@ class Memory {
1528
1547
 
1529
1548
  const values = lengthOrValues;
1530
1549
 
1531
- this.write(address, values);
1550
+ void this.write(address, values);
1532
1551
 
1533
1552
  return this;
1534
1553
  }
@@ -1556,7 +1575,7 @@ class Memory {
1556
1575
 
1557
1576
  Scratch8BigUint64Array[0x00] = value;
1558
1577
 
1559
- this.write(address, Scratch8BigUint64Array);
1578
+ void this.write(address, Scratch8BigUint64Array);
1560
1579
 
1561
1580
  return this;
1562
1581
  }
@@ -1587,7 +1606,7 @@ class Memory {
1587
1606
 
1588
1607
  const values = lengthOrValues;
1589
1608
 
1590
- this.write(address, values);
1609
+ void this.write(address, values);
1591
1610
 
1592
1611
  return this;
1593
1612
  }
@@ -1615,7 +1634,7 @@ class Memory {
1615
1634
 
1616
1635
  Scratch1[0x00] = value;
1617
1636
 
1618
- this.write(address, Scratch1);
1637
+ void this.write(address, Scratch1);
1619
1638
 
1620
1639
  return this;
1621
1640
  }
@@ -1646,7 +1665,7 @@ class Memory {
1646
1665
 
1647
1666
  const values = lengthOrValues;
1648
1667
 
1649
- this.write(address, values);
1668
+ void this.write(address, values);
1650
1669
 
1651
1670
  return this;
1652
1671
  }
@@ -1754,7 +1773,7 @@ class Memory {
1754
1773
  throw new RangeError('values.length must be 2.');
1755
1774
  }
1756
1775
 
1757
- this.write(address, values);
1776
+ void this.write(address, values);
1758
1777
 
1759
1778
  return this;
1760
1779
  }
@@ -1790,7 +1809,7 @@ class Memory {
1790
1809
  Scratch12Float32Array[0x01] = value.y;
1791
1810
  Scratch12Float32Array[0x02] = value.z;
1792
1811
 
1793
- this.write(address, Scratch12Float32Array);
1812
+ void this.write(address, Scratch12Float32Array);
1794
1813
 
1795
1814
  return this;
1796
1815
  }
@@ -1840,7 +1859,7 @@ class Memory {
1840
1859
  scratch[j + 0x02] = vector3.z;
1841
1860
  }
1842
1861
 
1843
- this.write(address, scratch);
1862
+ void this.write(address, scratch);
1844
1863
 
1845
1864
  return this;
1846
1865
  }
@@ -1856,7 +1875,7 @@ class Memory {
1856
1875
  throw new RangeError('values.length must be 3.');
1857
1876
  }
1858
1877
 
1859
- this.write(address, values);
1878
+ void this.write(address, values);
1860
1879
 
1861
1880
  return this;
1862
1881
  }
@@ -1918,7 +1937,7 @@ class Memory {
1918
1937
  throw new RangeError('values.length must be 4.');
1919
1938
  }
1920
1939
 
1921
- this.write(address, values);
1940
+ void this.write(address, values);
1922
1941
 
1923
1942
  return this;
1924
1943
  }