bun-memory 1.1.4 → 1.1.6
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/example/trigger-bot.ts +153 -0
- package/package.json +2 -1
- package/README.md +0 -81
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { FFIType, dlopen } from 'bun:ffi';
|
|
2
|
+
import { sleep } from 'bun';
|
|
3
|
+
|
|
4
|
+
import Memory from 'bun-memory';
|
|
5
|
+
|
|
6
|
+
// Get the latest client_dll.json and offsets.json from:
|
|
7
|
+
// https://github.com/a2x/cs2-dumper/tree/main/output
|
|
8
|
+
|
|
9
|
+
import ClientDLLJSON from './offsets/client_dll.json';
|
|
10
|
+
import OffsetsJSON from './offsets/offsets.json';
|
|
11
|
+
|
|
12
|
+
const Delay = 2.5;
|
|
13
|
+
|
|
14
|
+
const { random } = Math;
|
|
15
|
+
|
|
16
|
+
// Load user32.dll…
|
|
17
|
+
const {
|
|
18
|
+
symbols: { mouse_event },
|
|
19
|
+
} = dlopen('user32.dll', {
|
|
20
|
+
mouse_event: { args: [FFIType.u32, FFIType.u32, FFIType.u32, FFIType.u32, FFIType.u64], returns: FFIType.void },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Load the needed offsets as bigints…
|
|
24
|
+
const { C_BaseEntity, C_BasePlayerPawn, C_BasePlayerWeapon, C_CSPlayerPawn, C_CSPlayerPawnBase, C_CSWeaponBaseGun, CBasePlayerController, CCSPlayer_WeaponServices, CCSWeaponBaseVData } = Object.fromEntries(
|
|
25
|
+
Object.entries(ClientDLLJSON['client.dll'].classes).map(([class_, { fields }]) => [class_, Object.fromEntries(Object.entries(fields).map(([field, value]) => [field, BigInt(value)]))])
|
|
26
|
+
) as {
|
|
27
|
+
[C in keyof (typeof ClientDLLJSON)['client.dll']['classes']]: { [F in keyof (typeof ClientDLLJSON)['client.dll']['classes'][C]['fields']]: bigint };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Load the needed offsets as bigints…
|
|
31
|
+
const { dwEntityList, dwGlobalVars, dwLocalPlayerController, dwLocalPlayerPawn } = Object.fromEntries(
|
|
32
|
+
Object.entries(OffsetsJSON['client.dll']).map(([key, value]) => [key, BigInt(value)]) //
|
|
33
|
+
) as {
|
|
34
|
+
[K in keyof (typeof OffsetsJSON)['client.dll']]: bigint;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Open a handle to cs2.exe…
|
|
38
|
+
const cs2 = new Memory('cs2.exe');
|
|
39
|
+
|
|
40
|
+
// Get the base for client.dll…
|
|
41
|
+
const ClientPtr = cs2.modules['client.dll']?.base;
|
|
42
|
+
|
|
43
|
+
if (ClientPtr === undefined) {
|
|
44
|
+
throw new TypeError('ClientPtr must not be undefined.');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Create a cache for class name strings… 🫠…
|
|
48
|
+
const Cache_Names = new Map<bigint, string>();
|
|
49
|
+
|
|
50
|
+
let ticks = 0;
|
|
51
|
+
|
|
52
|
+
async function tick(ClientPtr: bigint) {
|
|
53
|
+
try {
|
|
54
|
+
ticks++;
|
|
55
|
+
|
|
56
|
+
// Read relevant info from memory…
|
|
57
|
+
const GlobalVarsPtr = cs2.u64(ClientPtr + dwGlobalVars);
|
|
58
|
+
/* */ const CurTime = cs2.f32(GlobalVarsPtr + 0x30n);
|
|
59
|
+
|
|
60
|
+
const Local_PlayerControllerPtr = cs2.u64(ClientPtr + dwLocalPlayerController);
|
|
61
|
+
/* */ const Local_TickBase = cs2.u32(Local_PlayerControllerPtr + CBasePlayerController.m_nTickBase);
|
|
62
|
+
|
|
63
|
+
const Local_PlayerPawnPtr = cs2.u64(ClientPtr + dwLocalPlayerPawn);
|
|
64
|
+
/* */ const Local_FlashOverlayAlpha = cs2.f32(Local_PlayerPawnPtr + C_CSPlayerPawnBase.m_flFlashOverlayAlpha);
|
|
65
|
+
/* */ const Local_IDEntIndex = cs2.i32(Local_PlayerPawnPtr + C_CSPlayerPawn.m_iIDEntIndex);
|
|
66
|
+
/* */ const Local_IsScoped = cs2.i32(Local_PlayerPawnPtr + C_CSPlayerPawn.m_bIsScoped);
|
|
67
|
+
/* */ const Local_Player_WeaponServicesPtr = cs2.u64(Local_PlayerPawnPtr + C_BasePlayerPawn.m_pWeaponServices);
|
|
68
|
+
/* */ const Local_NextAttack = cs2.f32(Local_Player_WeaponServicesPtr + CCSPlayer_WeaponServices.m_flNextAttack);
|
|
69
|
+
/* */ const Local_TeamNum = cs2.u8(Local_PlayerPawnPtr + C_BaseEntity.m_iTeamNum);
|
|
70
|
+
/* */ const Local_WeaponBasePtr = cs2.u64(Local_PlayerPawnPtr + C_CSPlayerPawn.m_pClippingWeapon);
|
|
71
|
+
/* */ const Local_Clip1 = cs2.i32(Local_WeaponBasePtr + C_BasePlayerWeapon.m_iClip1);
|
|
72
|
+
/* */ const Local_NextPrimaryAttackTick = cs2.u32(Local_WeaponBasePtr + C_BasePlayerWeapon.m_nNextPrimaryAttackTick);
|
|
73
|
+
/* */ const Local_WeaponBaseVDataPtr = cs2.u64(Local_WeaponBasePtr + C_BaseEntity.m_nSubclassID + 0x08n);
|
|
74
|
+
/* */ const Local_IsFullAuto = cs2.bool(Local_WeaponBaseVDataPtr + CCSWeaponBaseVData.m_bIsFullAuto);
|
|
75
|
+
/* */ const Local_WeaponType = cs2.i32(Local_WeaponBaseVDataPtr + CCSWeaponBaseVData.m_WeaponType);
|
|
76
|
+
/* */ const Local_ZoomLevel = cs2.i32(Local_WeaponBasePtr + C_CSWeaponBaseGun.m_zoomLevel);
|
|
77
|
+
|
|
78
|
+
// Conditions where we should not fire…
|
|
79
|
+
if (CurTime < Local_NextAttack) {
|
|
80
|
+
return;
|
|
81
|
+
} else if (Local_Clip1 === 0) {
|
|
82
|
+
return;
|
|
83
|
+
} else if (Local_FlashOverlayAlpha >= 0.75) {
|
|
84
|
+
return;
|
|
85
|
+
} else if (Local_IDEntIndex === -1) {
|
|
86
|
+
return;
|
|
87
|
+
} else if (Local_NextPrimaryAttackTick > Local_TickBase) {
|
|
88
|
+
return;
|
|
89
|
+
} else if (Local_WeaponType === 0 || Local_WeaponType === 9) {
|
|
90
|
+
return;
|
|
91
|
+
} else if (Local_WeaponType === 5 && !(Local_IsScoped && Local_ZoomLevel !== 0)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Weapon types: https://swiftlys2.net/sdk/cs2/types/csweapontype
|
|
96
|
+
|
|
97
|
+
// Get the entity that we're aiming at from the entity list…
|
|
98
|
+
const EntityListPtr = cs2.u64(ClientPtr + dwEntityList);
|
|
99
|
+
/* */ const EntityChunkPtr = cs2.u64(EntityListPtr + (BigInt(Local_IDEntIndex) >> 0x09n) * 0x08n + 0x10n);
|
|
100
|
+
/* */ const BaseEntityPtr = cs2.u64(EntityChunkPtr + (BigInt(Local_IDEntIndex) & 0x1ffn) * 0x78n);
|
|
101
|
+
/* */ const EntityClassInfoPtr = cs2.u64(EntityChunkPtr + (BigInt(Local_IDEntIndex) & 0x1ffn) * 0x78n + 0x08n);
|
|
102
|
+
|
|
103
|
+
let Name = Cache_Names.get(EntityClassInfoPtr);
|
|
104
|
+
|
|
105
|
+
if (Name === undefined) {
|
|
106
|
+
const SchemaClassInfoDataPtr = cs2.u64(EntityClassInfoPtr + 0x30n);
|
|
107
|
+
/* */ const NamePtr = cs2.u64(SchemaClassInfoDataPtr + 0x08n);
|
|
108
|
+
/* */ Name = cs2.cString(NamePtr, 0x80).toString();
|
|
109
|
+
|
|
110
|
+
Cache_Names.set(EntityClassInfoPtr, Name);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check that what we're aiming at it a C_CSPlayerPawn…
|
|
114
|
+
if (Name !== 'C_CSPlayerPawn') {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const PlayerPawnPtr = BaseEntityPtr;
|
|
119
|
+
/* */ const TeamNum = cs2.u8(PlayerPawnPtr + BigInt(C_BaseEntity.m_iTeamNum));
|
|
120
|
+
|
|
121
|
+
if (TeamNum === Local_TeamNum) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await sleep(random() * Delay + Delay);
|
|
126
|
+
|
|
127
|
+
// Pull the trigger…
|
|
128
|
+
mouse_event(0x02, 0x00, 0x00, 0x00, 0n);
|
|
129
|
+
|
|
130
|
+
// If the gun is automatic, hold the trigger until we're no longer aiming at them…
|
|
131
|
+
do {
|
|
132
|
+
await sleep(random() * Delay + Delay);
|
|
133
|
+
} while (Local_IDEntIndex === cs2.u32(Local_PlayerPawnPtr + C_CSPlayerPawn.m_iIDEntIndex) && Local_IsFullAuto);
|
|
134
|
+
|
|
135
|
+
// Release the trigger…
|
|
136
|
+
mouse_event(0x04, 0x00, 0x00, 0x00, 0n);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// console.error(error);
|
|
139
|
+
return;
|
|
140
|
+
} finally {
|
|
141
|
+
setImmediate(tick, ClientPtr);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Start the tick loop…
|
|
146
|
+
setImmediate(tick, ClientPtr);
|
|
147
|
+
|
|
148
|
+
// Log ticks per second…
|
|
149
|
+
setInterval(() => {
|
|
150
|
+
console.clear();
|
|
151
|
+
console.log('[TB] Ticks per second: %d', ticks);
|
|
152
|
+
ticks = 0;
|
|
153
|
+
}, 1_000);
|
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.
|
|
25
|
+
"version": "1.1.6",
|
|
26
26
|
"main": "./index.ts",
|
|
27
27
|
"keywords": [
|
|
28
28
|
"bun",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
],
|
|
38
38
|
"files": [
|
|
39
39
|
"index.ts",
|
|
40
|
+
"example/*.ts",
|
|
40
41
|
"runtime/*.ts",
|
|
41
42
|
"structs/*.ts",
|
|
42
43
|
"types/*.ts",
|
package/README.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# bun-memory
|
|
2
|
-
|
|
3
|
-
High-performance Windows process memory utilities for [Bun](https://bun.sh) using `bun:ffi` and Win32 APIs.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Built for Bun runtime and Windows 10/11
|
|
8
|
-
- Efficient buffer management for high-speed operations
|
|
9
|
-
- Pattern scanning for offsets \*
|
|
10
|
-
- Read and write memory of Windows processes
|
|
11
|
-
|
|
12
|
-
\* — Feature temporarily disabled
|
|
13
|
-
|
|
14
|
-
## Requirements
|
|
15
|
-
|
|
16
|
-
- **Bun** (uses `bun:ffi`)
|
|
17
|
-
- **Windows 10/11** (uses `kernel32.dll`)
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
bun add bun-memory
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Usage
|
|
26
|
-
|
|
27
|
-
See [example/trigger-bot.ts](example/trigger-bot.ts) for a real-world example.
|
|
28
|
-
|
|
29
|
-
### Basic Example
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import Memory from 'bun-memory';
|
|
33
|
-
|
|
34
|
-
// Attach to process by name…
|
|
35
|
-
const memory = new Memory('notepad.exe');
|
|
36
|
-
// …or PID
|
|
37
|
-
const memory = new Memory(1234);
|
|
38
|
-
|
|
39
|
-
// Access loaded modules
|
|
40
|
-
const modules = memory.modules;
|
|
41
|
-
const mainModule = modules['notepad.exe'];
|
|
42
|
-
console.log(`Base address: 0x${mainModule.modBaseAddr.toString(16)}`);
|
|
43
|
-
console.log(`Size: ${mainModule.modBaseSize} bytes`);
|
|
44
|
-
|
|
45
|
-
// Read a 32-bit integer
|
|
46
|
-
const value = memory.i32(0x12345678n);
|
|
47
|
-
|
|
48
|
-
// Write a float
|
|
49
|
-
memory.f32(0x12345678n, 3.14159);
|
|
50
|
-
|
|
51
|
-
// Clean up
|
|
52
|
-
memory.close();
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Pattern Scanning
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
const offset = memory.findPattern('aa??bbccdd??ff', mainModule.modBaseAddr, mainModule.modBaseSize);
|
|
59
|
-
const value = memory.bool(offset + 0x1234n);
|
|
60
|
-
memory.close();
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Efficient Buffer Reads
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
const scratch = Buffer.allocUnsafe(0xf000);
|
|
67
|
-
const view = new BigUint64Array(scratch.buffer, scratch.byteOffset, 0xf000 / 8);
|
|
68
|
-
|
|
69
|
-
while (true) {
|
|
70
|
-
memory.read(myAddress, scratch); // Updates scratch and view, no allocations
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
```ts
|
|
75
|
-
const scratch = Buffer.allocUnsafe(0x100);
|
|
76
|
-
memory.read(myAddress, scratch);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Notes
|
|
80
|
-
|
|
81
|
-
- Only works with Bun and Windows.
|