Faster memory access, pid skipping, file rename
This commit is contained in:
parent
eca1b2112b
commit
c8a33191cc
1 changed files with 33 additions and 128 deletions
|
@ -1,7 +1,9 @@
|
||||||
import ctypes
|
import ctypes
|
||||||
import struct
|
import struct
|
||||||
|
from struct import pack, unpack
|
||||||
from ctypes import wintypes, sizeof, addressof, POINTER, pointer
|
from ctypes import wintypes, sizeof, addressof, POINTER, pointer
|
||||||
from ctypes.wintypes import DWORD, ULONG, LONG, WORD
|
from ctypes.wintypes import DWORD, ULONG, LONG, WORD
|
||||||
|
from multiprocessing import shared_memory
|
||||||
|
|
||||||
# Various Windows structs/enums needed for operation
|
# Various Windows structs/enums needed for operation
|
||||||
NULL = 0
|
NULL = 0
|
||||||
|
@ -84,8 +86,8 @@ class PSAPI_WORKING_SET_EX_INFORMATION(ctypes.Structure):
|
||||||
# print(i, getattr(self, i))
|
# print(i, getattr(self, i))
|
||||||
|
|
||||||
|
|
||||||
# The following code is a port of aldelaro5's Dolphin memory access methods
|
# The find_dolphin function is based on WindowsDolphinProcess::findPID() from
|
||||||
# for Windows into Python+ctypes.
|
# aldelaro5's Dolphin memory engine
|
||||||
# https://github.com/aldelaro5/Dolphin-memory-engine
|
# https://github.com/aldelaro5/Dolphin-memory-engine
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -114,12 +116,11 @@ SOFTWARE."""
|
||||||
class Dolphin(object):
|
class Dolphin(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pid = -1
|
self.pid = -1
|
||||||
self.handle = -1
|
self.shmem = None
|
||||||
|
|
||||||
self.address_start = 0
|
def reset(self):
|
||||||
self.mem1_start = 0
|
self.pid = -1
|
||||||
self.mem2_start = 0
|
self.memory = None
|
||||||
self.mem2_exists = False
|
|
||||||
|
|
||||||
def find_dolphin(self, skip_pids=[]):
|
def find_dolphin(self, skip_pids=[]):
|
||||||
entry = PROCESSENTRY32()
|
entry = PROCESSENTRY32()
|
||||||
|
@ -130,7 +131,6 @@ class Dolphin(object):
|
||||||
a = ULONG(addressof(entry))
|
a = ULONG(addressof(entry))
|
||||||
|
|
||||||
self.pid = -1
|
self.pid = -1
|
||||||
self.handle = -1
|
|
||||||
|
|
||||||
if ctypes.windll.kernel32.Process32First(snapshot, pointer(entry)):
|
if ctypes.windll.kernel32.Process32First(snapshot, pointer(entry)):
|
||||||
if entry.th32ProcessID not in skip_pids and entry.szExeFile in (b"Dolphin.exe", b"DolphinQt2.exe", b"DolphinWx.exe"):
|
if entry.th32ProcessID not in skip_pids and entry.szExeFile in (b"Dolphin.exe", b"DolphinQt2.exe", b"DolphinWx.exe"):
|
||||||
|
@ -148,108 +148,36 @@ class Dolphin(object):
|
||||||
if self.pid == -1:
|
if self.pid == -1:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.handle = ctypes.windll.kernel32.OpenProcess(
|
|
||||||
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
|
|
||||||
False, self.pid)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_emu_info(self):
|
def init_shared_memory(self):
|
||||||
info = MEMORY_BASIC_INFORMATION()
|
self.mem = shared_memory.SharedMemory('dolphin-emu.'+str(self.pid))
|
||||||
MEM1_found = False
|
|
||||||
|
|
||||||
p = NULL
|
|
||||||
|
|
||||||
while ctypes.windll.kernel32.VirtualQueryEx(self.handle, ctypes.c_void_p(p), pointer(info), sizeof(info)) == sizeof(info):
|
|
||||||
|
|
||||||
p += info.RegionSize
|
|
||||||
|
|
||||||
if info.RegionSize == 0x4000000:
|
|
||||||
region_base_address = info.BaseAddress
|
|
||||||
|
|
||||||
if MEM1_found and info.BaseAddress > self.address_start + 0x10000000:
|
|
||||||
break
|
|
||||||
|
|
||||||
page_info = PSAPI_WORKING_SET_EX_INFORMATION()
|
|
||||||
page_info.VirtualAddress = info.BaseAddress
|
|
||||||
|
|
||||||
if ctypes.windll.psapi.QueryWorkingSetEx(
|
|
||||||
self.handle,
|
|
||||||
pointer(page_info),
|
|
||||||
sizeof(PSAPI_WORKING_SET_EX_INFORMATION)
|
|
||||||
):
|
|
||||||
if (page_info.Valid):
|
|
||||||
self.mem2_start = region_base_address
|
|
||||||
self.mem2_exists = True
|
|
||||||
|
|
||||||
elif not MEM1_found and info.RegionSize == 0x2000000 and info.Type == MEM_MAPPED:
|
|
||||||
page_info = PSAPI_WORKING_SET_EX_INFORMATION()
|
|
||||||
page_info.VirtualAddress = info.BaseAddress
|
|
||||||
|
|
||||||
if ctypes.windll.psapi.QueryWorkingSetEx(
|
|
||||||
self.handle,
|
|
||||||
pointer(page_info),
|
|
||||||
sizeof(PSAPI_WORKING_SET_EX_INFORMATION)
|
|
||||||
):
|
|
||||||
print(page_info.Valid)
|
|
||||||
if (page_info.Valid):
|
|
||||||
self.address_start = info.BaseAddress
|
|
||||||
MEM1_found = True
|
|
||||||
|
|
||||||
if MEM1_found and self.mem2_exists:
|
|
||||||
break
|
|
||||||
|
|
||||||
if self.address_start == 0:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def read_ram(self, offset, size):
|
def read_ram(self, offset, size):
|
||||||
buffer = (ctypes.c_char*size)()
|
return self.mem.buf[offset:offset+size]
|
||||||
read = ctypes.c_ulong(0)
|
|
||||||
|
|
||||||
result = ctypes.windll.kernel32.ReadProcessMemory(
|
|
||||||
self.handle,
|
|
||||||
ctypes.c_void_p(self.address_start+offset),
|
|
||||||
ctypes.pointer(buffer),
|
|
||||||
size,
|
|
||||||
ctypes.pointer(read))
|
|
||||||
return result and read.value == size, buffer
|
|
||||||
|
|
||||||
def write_ram(self, offset, data):
|
def write_ram(self, offset, data):
|
||||||
buffer = (ctypes.c_char*len(data))(*data)
|
self.mem.buf[offset:offset+len(data)] = data
|
||||||
read = ctypes.c_ulong(0)
|
|
||||||
|
|
||||||
result = ctypes.windll.kernel32.WriteProcessMemory(
|
|
||||||
self.handle,
|
|
||||||
ctypes.c_void_p(self.address_start+offset),
|
|
||||||
ctypes.pointer(buffer),
|
|
||||||
len(data),
|
|
||||||
ctypes.pointer(read))
|
|
||||||
|
|
||||||
return result and read.value == len(data)
|
|
||||||
|
|
||||||
def read_uint32(self, addr):
|
def read_uint32(self, addr):
|
||||||
assert addr >= 0x80000000
|
assert addr >= 0x80000000
|
||||||
success, value = self.read_ram(addr-0x80000000, 4)
|
value = self.read_ram(addr-0x80000000, 4)
|
||||||
|
|
||||||
if success:
|
return unpack(">I", value)[0]
|
||||||
return struct.unpack(">I", value)[0]
|
|
||||||
else:
|
def write_uint32(self, addr, val):
|
||||||
return None
|
assert addr >= 0x80000000
|
||||||
|
return self.write_ram(addr - 0x80000000, pack(">I", val))
|
||||||
|
|
||||||
def read_float(self, addr):
|
def read_float(self, addr):
|
||||||
assert addr >= 0x80000000
|
assert addr >= 0x80000000
|
||||||
success, value = self.read_ram(addr - 0x80000000, 4)
|
success, value = self.read_ram(addr - 0x80000000, 4)
|
||||||
|
|
||||||
if success:
|
return unpack(">f", value)[0]
|
||||||
return struct.unpack(">f", value)[0]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def write_float(self, addr, val):
|
def write_float(self, addr, val):
|
||||||
assert addr >= 0x80000000
|
assert addr >= 0x80000000
|
||||||
return self.write_ram(addr - 0x80000000, struct.pack(">f", val))
|
return self.write_ram(addr - 0x80000000, pack(">f", val))
|
||||||
|
|
||||||
|
|
||||||
"""with open("ctypes.txt", "w") as f:
|
"""with open("ctypes.txt", "w") as f:
|
||||||
|
@ -267,54 +195,31 @@ if __name__ == "__main__":
|
||||||
else:
|
else:
|
||||||
print("Didn't find Dolphin")
|
print("Didn't find Dolphin")
|
||||||
|
|
||||||
print(dolphin.pid, dolphin.handle)
|
print(dolphin.pid)
|
||||||
"""pipe = r'\\.\\PIPE\\dolphin-emu.'+str(dolphin.pid)
|
|
||||||
pipe = r'\\.\\pipe\\WiFiNetworkManagerTask'
|
|
||||||
print(pipe)
|
|
||||||
|
|
||||||
with open(pipe, "r+b") as f:
|
|
||||||
pass"""
|
|
||||||
|
|
||||||
|
|
||||||
|
dolphin.init_shared_memory()
|
||||||
|
"""
|
||||||
if dolphin.get_emu_info():
|
if dolphin.get_emu_info():
|
||||||
print("We found MEM1 and/or MEM2!", dolphin.address_start, dolphin.mem2_start)
|
print("We found MEM1 and/or MEM2!", dolphin.address_start, dolphin.mem2_start)
|
||||||
else:
|
else:
|
||||||
print("We didn't find it...")
|
print("We didn't find it...")"""
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
randint = random.randint
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
|
|
||||||
start = default_timer()
|
start = default_timer()
|
||||||
|
|
||||||
randint = random.randint
|
|
||||||
pack = struct.pack
|
|
||||||
unpack = struct.unpack
|
|
||||||
write_ram = dolphin.write_ram
|
|
||||||
read_ram = dolphin.read_ram
|
|
||||||
|
|
||||||
print("Testing WinApi method")
|
|
||||||
for i in range(500000):
|
|
||||||
value = randint(0, 2**32-1)
|
|
||||||
write_ram(0, pack(">I", value))
|
|
||||||
|
|
||||||
success, result = read_ram(0, 4)
|
|
||||||
assert unpack(">I", result)[0] == value
|
|
||||||
|
|
||||||
print(default_timer()-start)
|
|
||||||
|
|
||||||
from multiprocessing import shared_memory
|
|
||||||
mem = shared_memory.SharedMemory('dolphin-emu.'+str(dolphin.pid))
|
|
||||||
buf = mem.buf
|
|
||||||
|
|
||||||
print("Testing Shared Memory Method")
|
print("Testing Shared Memory Method")
|
||||||
start = default_timer()
|
start = default_timer()
|
||||||
for i in range(500000):
|
count = 500000
|
||||||
|
for i in range(count):
|
||||||
value = randint(0, 2**32-1)
|
value = randint(0, 2**32-1)
|
||||||
buf[0:4] = pack(">I", value)
|
dolphin.write_uint32(0x80000000, value)
|
||||||
|
|
||||||
result = bytes(buf[0:4])
|
result = dolphin.read_uint32(0x80000000)
|
||||||
assert unpack(">I", result)[0] == value
|
assert result == value
|
||||||
|
diff = default_timer()-start
|
||||||
print(default_timer()-start)
|
print(count/diff, "per sec")
|
||||||
|
print("time: ", diff)
|
||||||
|
|
Loading…
Reference in a new issue