-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutils.ts
More file actions
75 lines (65 loc) · 3.48 KB
/
Copy pathutils.ts
File metadata and controls
75 lines (65 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// @ts-nocheck
// TODO: In the future, we plan to add proper typing
const SIZEOF_STDSTRING_32BIT = 24;
const SIZEOF_STDSTRING_64BIT = 32;
const STDSTRING_LENGTH_OFFSET = 0x10;
/**
* Custom string consumer/producer for Structron (due to complexity of `std::string`)
* `std::string` is a container for a string which makes reading/writing to it tricky,
* it will either store the string itself, or a pointer to the string, based on the
* length of the string. When we want to read from or write to a buffer, we need
* to determine if the string is in the buffer itself, or if the buffer
* just contains a pointer to the string. Based on one of these options,
* we can read from or write to the string.
*
* @param handle the handle to the process
* @param structAddress the base address of the structure in memory
* @param platform the architecture of the process, either "32" or "64"
* @param encoding the encoding type of the string
*/
export const STRUCTRON_TYPE_STRING = memoryprocess => (handle, structAddress, platform, encoding = 'utf8') => ({
read(buffer, offset) {
// get string length from `std::string` container
const length = buffer.readUInt32LE(offset + STDSTRING_LENGTH_OFFSET);
// if length > 15, `std::string` has a pointer to the string
if (length > 15) {
const pointer = platform === '64' ? buffer.readBigInt64LE(offset) : buffer.readUInt32LE(offset);
return memoryprocess.readMemory(handle, Number(pointer), 'string');
}
// if length <= 15, `std::string` directly contains the string
return buffer.toString(encoding, offset, offset + length);
},
write(value, context, offset) {
// address containing the length of the string
const lengthAddress = structAddress + offset + STDSTRING_LENGTH_OFFSET;
// get existing `std::string` buffer
const bufferSize = platform === '64' ? SIZEOF_STDSTRING_64BIT : SIZEOF_STDSTRING_32BIT;
const existingBuffer = memoryprocess.readBuffer(handle, structAddress + offset, bufferSize);
// fetch length of string in memory (to determine if it's pointer based)
const length = memoryprocess.readMemory(handle, lengthAddress, 'int');
if ((length > 15 && value.length <= 15) || (length <= 15 && value.length > 15)) {
// there are two ways strings are stored: directly or with a pointer,
// we can't go from one to the other (without introducing more complexity),
// so just skip the bytes to prevent crashing. if a pointer is used, we could
// technically write any length, but the next time we try writing, we will read
// the length and assume it's not stored via pointer and will lead to crashes
// write existing buffer without changes
existingBuffer.copy(context.buffer, offset);
return;
}
// write new length
memoryprocess.writeMemory(handle, lengthAddress, value.length, 'uint32');
existingBuffer.writeUInt32LE(value.length, STDSTRING_LENGTH_OFFSET);
if (length > 15 && value.length > 15) {
// write new string in memory
const pointer = memoryprocess.readMemory(handle, structAddress + offset, 'pointer');
memoryprocess.writeMemory(handle, pointer, value, 'string');
} else if (length <= 15 && value.length <= 15) {
// write new string directly into buffer
existingBuffer.write(value, encoding);
}
// write our new `std::string` buffer into the buffer we are creating
existingBuffer.copy(context.buffer, offset);
},
SIZE: platform === '64' ? SIZEOF_STDSTRING_64BIT : SIZEOF_STDSTRING_32BIT,
});