-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy path_dolphin_memory_engine.pyx
231 lines (155 loc) · 6.73 KB
/
_dolphin_memory_engine.pyx
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
from typing import List
from libc.stdint cimport uint8_t, uint32_t, uint64_t
from libcpp cimport bool as c_bool
from libcpp.string cimport string
cdef extern from "Common/MemoryCommon.h" namespace "Common::MemType":
cdef enum MemType:
type_word
cdef extern from "Common/MemoryCommon.h" namespace "Common::MemBase":
cdef enum MemBase:
base_decimal
cdef extern from "Common/MemoryCommon.h" namespace "Common::MemOperationReturnCode":
cdef enum MemOperationReturnCode:
invalidInput
operationFailed
inputTooLong
invalidPointer
OK
cdef extern from "Common/CommonUtils.h" namespace "Common":
uint32_t dolphinAddrToOffset(uint32_t, c_bool)
uint32_t offsetToDolphinAddr(uint32_t, c_bool)
cdef extern from "DolphinProcess/DolphinAccessor.h" namespace "DolphinComm::DolphinAccessor":
cpdef enum class DolphinStatus:
hooked
notRunning
noEmu
unHooked
cdef extern from "DolphinProcess/DolphinAccessor.h" namespace "DolphinComm":
cdef cppclass DolphinAccessor:
@staticmethod
void init()
@staticmethod
void free()
@staticmethod
void hook()
@staticmethod
void unHook()
@staticmethod
c_bool readFromRAM(uint32_t, char*, const size_t, c_bool)
@staticmethod
c_bool writeToRAM(uint32_t, const char*, const size_t, c_bool)
@staticmethod
int getPID()
@staticmethod
DolphinStatus getStatus()
@staticmethod
c_bool isValidConsoleAddress(uint32_t)
@staticmethod
c_bool isARAMAccessible()
cdef extern from "MemoryWatch/MemWatchEntry.h":
cdef cppclass MemWatchEntry:
MemWatchEntry()
MemWatchEntry(string, uint32_t, MemType, MemBase, c_bool, size_t, c_bool)
char* getMemory()
void addOffset(int)
MemOperationReturnCode readMemoryFromRAM()
MemOperationReturnCode writeMemoryFromString(string)
cdef buffer_to_word(char* buffer):
cdef uint32_t* value = <uint32_t*> buffer
return value[0]
cdef buffer_to_float(char* buffer):
cdef float* value = <float*> buffer
return value[0]
cdef buffer_to_double(char* buffer):
cdef double* value = <double*> buffer
return value[0]
cdef class MemWatch:
cdef MemWatchEntry c_entry
def __cinit__(self, label: str, console_address: int, is_pointer: bool):
self.c_entry = MemWatchEntry(label.encode("utf-8"), console_address, MemType.type_word, MemBase.base_decimal, False, 1, is_pointer)
def add_offset(self, offset: int):
self.c_entry.addOffset(offset)
def get_value(self):
return buffer_to_word(self.c_entry.getMemory())
def read_memory_from_ram(self):
return self.c_entry.readMemoryFromRAM() == MemOperationReturnCode.OK
def write_memory_from_string(self, value: str):
return self.c_entry.writeMemoryFromString(value.encode("utf-8")) == MemOperationReturnCode.OK
def hook():
return DolphinAccessor.hook()
def un_hook():
return DolphinAccessor.unHook()
def is_hooked() -> bool:
if DolphinAccessor.getStatus() == DolphinStatus.hooked:
return True
else:
return False
def assert_hooked():
if not is_hooked():
raise RuntimeError("not hooked")
def get_status() -> DolphinStatus:
return DolphinAccessor.getStatus()
def follow_pointers(console_address: int, pointer_offsets: List[int]) -> int:
assert_hooked()
real_console_address = console_address
is_aram_accessible = DolphinAccessor.isARAMAccessible()
cdef char memory_buffer[4]
for offset in pointer_offsets:
if DolphinAccessor.readFromRAM(dolphinAddrToOffset(real_console_address, is_aram_accessible), memory_buffer, 4, True):
real_console_address = buffer_to_word(memory_buffer)
if DolphinAccessor.isValidConsoleAddress(real_console_address):
real_console_address += offset
else:
raise RuntimeError(f"Address {real_console_address} is not valid")
else:
raise RuntimeError(f"Could not read memory at {real_console_address}")
return real_console_address
cdef _read_memory(console_address, char* memory_buffer, int size):
assert_hooked()
if not DolphinAccessor.readFromRAM(dolphinAddrToOffset(console_address, DolphinAccessor.isARAMAccessible()), memory_buffer, size, True):
raise RuntimeError(f"Could not read memory at {console_address}")
def read_byte(console_address: int) -> int:
cdef char memory_buffer[1]
_read_memory(console_address, memory_buffer, 1)
return (<uint8_t*> memory_buffer)[0]
def read_word(console_address: int) -> int:
cdef char memory_buffer[4]
_read_memory(console_address, memory_buffer, 4)
return (<uint32_t*> memory_buffer)[0]
def read_float(console_address: int) -> float:
cdef char memory_buffer[4]
_read_memory(console_address, memory_buffer, 4)
return (<float*> memory_buffer)[0]
def read_double(console_address: int) -> double:
cdef char memory_buffer[8]
_read_memory(console_address, memory_buffer, 8)
return (<double*> memory_buffer)[0]
def read_bytes(console_address: int, size: int) -> bytes:
memory = bytearray(size)
if not DolphinAccessor.readFromRAM(dolphinAddrToOffset(console_address, DolphinAccessor.isARAMAccessible()), memory, size, False):
raise RuntimeError(f"Could not read memory at {console_address}")
return bytes(memory)
cdef _write_memory(console_address, char* memory_buffer, int size):
assert_hooked()
if not DolphinAccessor.writeToRAM(dolphinAddrToOffset(console_address, DolphinAccessor.isARAMAccessible()), memory_buffer, size, True):
raise RuntimeError(f"Could not write memory at {console_address}")
def write_byte(console_address: int, value: int):
cdef char memory_buffer[1]
(<uint8_t*> memory_buffer)[0] = value
_write_memory(console_address, memory_buffer, 1)
def write_word(console_address: int, value: int):
cdef char memory_buffer[4]
(<uint32_t*> memory_buffer)[0] = value
_write_memory(console_address, memory_buffer, 4)
def write_float(console_address: int, value: float):
cdef char memory_buffer[4]
(<float*> memory_buffer)[0] = value
_write_memory(console_address, memory_buffer, 4)
def write_double(console_address: int, value: double):
cdef char memory_buffer[8]
(<double*> memory_buffer)[0] = value
_write_memory(console_address, memory_buffer, 8)
def write_bytes(console_address: int, memory: bytes):
assert_hooked()
if not DolphinAccessor.writeToRAM(dolphinAddrToOffset(console_address, DolphinAccessor.isARAMAccessible()), memory, len(memory), False):
raise RuntimeError(f"Could not write memory at {console_address}")