Repository navigation
Expand file tree
/
Copy pathmemory_reader.py
More file actions
161 lines (134 loc) · 6.26 KB
/
Copy pathmemory_reader.py
File metadata and controls
161 lines (134 loc) · 6.26 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
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
import pymem
import struct
import ctypes
import logging
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class WoWMemoryReader:
def __init__(self, process_name="Ascension.exe"):
self.pm = pymem.Pymem(process_name)
self.base_address = pymem.process.module_from_name(self.pm.process_handle, process_name).lpBaseOfDll
self.process_id = self.pm.process_id
logging.info(f"Module Base Address for {process_name}: {hex(self.base_address)}")
def register_function(self, function_address, return_type=None, args=None):
"""Register a function for calling from memory"""
if return_type is None:
return_type = ctypes.c_int
if args is None:
args = []
function_prototype = ctypes.WINFUNCTYPE(return_type, *args)
return function_prototype(function_address)
def read_memory(self, address, data_type):
try:
return self.pm.read_memory(address, data_type)
except Exception as e:
logging.error(f"Error reading memory at {hex(address)}: {e}")
return None
def write_memory(self, address, data_type, value):
try:
self.pm.write_memory(address, data_type, value)
return True
except Exception as e:
logging.error(f"Error writing memory at {hex(address)}: {e}")
return False
def read(self, address, size):
"""Reads raw bytes from memory at the specified address."""
try:
return self.pm.read_bytes(address, size)
except pymem.exception.MemoryReadError as e:
logging.error(f"Failed to read memory at {hex(address)}: {e}")
return None
def write(self, address, buffer):
"""Writes raw bytes to memory at the specified address."""
if not address or not buffer:
logging.error("Invalid address or buffer.")
return False
try:
self.pm.write_bytes(address, buffer, len(buffer))
return True
except pymem.exception.MemoryWriteError as e:
logging.error(f"Failed to write memory at {hex(address)}: {e}")
return False
except Exception as e:
logging.error(f"Unexpected error while writing memory at {hex(address)}: {e}")
return False
def write_uint(self, address, value):
"""Writes a 32-bit unsigned integer to memory."""
if not address or value is None:
logging.error("Invalid address or value for write_uint.")
return False
if not (0 <= value <= 0xFFFFFFFF):
logging.error(f"Value {value} is out of range for a 32-bit unsigned integer.")
return False
try:
buffer = struct.pack('I', value)
self.write(address, buffer)
logging.info(f"Wrote uint value {value} to address {hex(address)}")
return True
except Exception as e:
logging.error(f"Failed to write uint at {hex(address)}: {e}")
return False
def write_uint64(self, address, value):
"""Writes a 64-bit unsigned integer to memory."""
if not address or value is None:
logging.error("Invalid address or value for write_uint64.")
return False
if not (0 <= value <= 0xFFFFFFFFFFFFFFFF):
logging.error(f"Value {value} is out of range for a 64-bit unsigned integer.")
return False
try:
buffer = struct.pack('Q', value)
self.write(address, buffer)
logging.info(f"Wrote uint64 value {value} to address {hex(address)}")
return True
except Exception as e:
logging.error(f"Failed to write uint64 at {hex(address)}: {e}")
return False
def read_string(self, address, max_length=12):
"""Reads a string from memory, stopping at a null terminator or max_length."""
raw_data = self.pm.read_bytes(address, max_length + 1)
logging.info(f"Raw data read from address {hex(address)}: {raw_data}")
name = ""
for byte in raw_data:
if byte == 0: # Null terminator found
break
name += chr(byte)
return name[:12]
def read_byte(self, address):
"""Reads a single byte from memory."""
data = self.read(address, 1)
return struct.unpack('B', data)[0] if data else None
def read_struct(self, address, struct_type):
"""Reads a structure from memory and returns it as an instance of struct_type."""
data = self.read(address, ctypes.sizeof(struct_type))
if data is None:
return None
return struct_type.from_buffer_copy(data)
def read_uint64(self, address):
"""Reads a 64-bit unsigned integer from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_uint64))
return struct.unpack('Q', data)[0] if data else None
def read_int64(self, address):
"""Reads a 64-bit signed integer from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_int64))
return struct.unpack('q', data)[0] if data else None
def read_int32(self, address):
"""Reads a 32-bit signed integer from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_int32))
return struct.unpack('i', data)[0] if data else None
def read_int(self, address):
"""Reads a 32-bit signed integer (common int) from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_int))
return struct.unpack('i', data)[0] if data else None
def read_float(self, address):
"""Reads a 32-bit floating-point number from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_float))
return struct.unpack('f', data)[0] if data else None
def read_pointer32(self, address):
"""Reads a 32-bit pointer (address) from memory and returns it as a c_void_p."""
value = self.read_int32(address)
return ctypes.c_void_p(value) if value is not None else None
def read_uint(self, address):
"""Reads a 32-bit unsigned integer from memory."""
data = self.read(address, ctypes.sizeof(ctypes.c_uint))
return struct.unpack('I', data)[0] if data else None