Files
2026-04-15 22:24:44 -07:00

112 lines
4.6 KiB
Python

import ctypes, ctypes.wintypes as wt, os, sys, time, subprocess
DLL = r"X:\Users\user\fallendoll\dumper\Dumper-7\build2\bin\Dumper-7.dll"
EXE = r"C:\SteamLibrary\steamapps\common\Operation Lovecraft Fallen Doll Playtest\Paralogue\Binaries\Win64\Paralogue-Win64-Shipping.exe"
CWD = os.path.dirname(EXE)
OUT = r"C:\Dumper-7"
# Steam appid shim
appid_file = os.path.join(CWD, "steam_appid.txt")
if not os.path.exists(appid_file):
open(appid_file, "w").write("1810920")
# Find or spawn game
def pid_by_name(name):
import ctypes.wintypes as wt
k32 = ctypes.windll.kernel32
TH32CS_SNAPPROCESS = 0x2
class PE(ctypes.Structure):
_fields_ = [("dwSize", wt.DWORD), ("cntUsage", wt.DWORD),
("th32ProcessID", wt.DWORD), ("th32DefaultHeapID", ctypes.c_void_p),
("th32ModuleID", wt.DWORD), ("cntThreads", wt.DWORD),
("th32ParentProcessID", wt.DWORD), ("pcPriClassBase", ctypes.c_long),
("dwFlags", wt.DWORD), ("szExeFile", ctypes.c_wchar*260)]
snap = k32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
pe = PE(); pe.dwSize = ctypes.sizeof(PE)
pids = []
if k32.Process32FirstW(snap, ctypes.byref(pe)):
while True:
if pe.szExeFile.lower() == name.lower():
pids.append(pe.th32ProcessID)
if not k32.Process32NextW(snap, ctypes.byref(pe)): break
k32.CloseHandle(snap)
return pids
existing = pid_by_name("Paralogue-Win64-Shipping.exe")
if existing:
# prefer the larger PID (most recently spawned)
pid = max(existing)
print(f"[*] attaching to running pid={pid}")
else:
print(f"[*] spawning game")
p = subprocess.Popen([EXE], cwd=CWD)
time.sleep(12)
pids = pid_by_name("Paralogue-Win64-Shipping.exe")
if not pids:
print("[-] spawn failed"); sys.exit(1)
pid = max(pids)
print(f"[*] spawned pid={pid}")
# DLL injection via CreateRemoteThread + LoadLibraryW
PROCESS_ALL_ACCESS = 0x1F0FFF
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_READWRITE = 0x04
k32 = ctypes.windll.kernel32
k32.OpenProcess.restype = wt.HANDLE
k32.VirtualAllocEx.restype = ctypes.c_void_p
k32.VirtualAllocEx.argtypes = [wt.HANDLE, ctypes.c_void_p, ctypes.c_size_t, wt.DWORD, wt.DWORD]
k32.WriteProcessMemory.argtypes = [wt.HANDLE, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)]
k32.GetProcAddress.restype = ctypes.c_void_p
k32.GetProcAddress.argtypes = [wt.HMODULE, ctypes.c_char_p]
k32.GetModuleHandleA.restype = wt.HMODULE
k32.CreateRemoteThread.restype = wt.HANDLE
k32.CreateRemoteThread.argtypes = [wt.HANDLE, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p, ctypes.c_void_p, wt.DWORD, ctypes.POINTER(wt.DWORD)]
hProc = k32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if not hProc:
print(f"[-] OpenProcess failed: {ctypes.get_last_error()}"); sys.exit(1)
dll_w = (DLL + "\0").encode("utf-16-le")
addr = k32.VirtualAllocEx(hProc, None, len(dll_w), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)
written = ctypes.c_size_t(0)
k32.WriteProcessMemory(hProc, addr, dll_w, len(dll_w), ctypes.byref(written))
h_k32 = k32.GetModuleHandleA(b"kernel32.dll")
loadlib = k32.GetProcAddress(h_k32, b"LoadLibraryW")
print(f"[*] LoadLibraryW @ {hex(loadlib)}, remote alloc @ {hex(addr)}")
tid = wt.DWORD(0)
hThread = k32.CreateRemoteThread(hProc, None, 0, loadlib, addr, 0, ctypes.byref(tid))
if not hThread:
print(f"[-] CreateRemoteThread failed: {ctypes.get_last_error()}"); sys.exit(1)
print(f"[*] remote thread tid={tid.value}, waiting for LoadLibrary return...")
k32.WaitForSingleObject(hThread, 30000)
rc = wt.DWORD(0)
k32.GetExitCodeThread(hThread, ctypes.byref(rc))
print(f"[*] LoadLibraryW returned HMODULE={hex(rc.value)} (0 = failed)")
print(f"[*] polling {OUT} for SDK output (up to 3 min)...")
for i in range(36):
time.sleep(5)
if os.path.isdir(OUT):
entries = os.listdir(OUT)
if entries:
print(f"[+] t={5*(i+1)}s: {len(entries)} entries: {entries[:15]}")
# Check for common dumper-7 markers of completion
has_sdk = any(e.endswith(".hpp") or "SDK" in e for e in entries)
if has_sdk:
print("[+] SDK appears generated. Stopping poll.")
break
print("[*] final SDK listing:")
if os.path.isdir(OUT):
for e in sorted(os.listdir(OUT)):
p = os.path.join(OUT, e)
try:
sz = os.path.getsize(p) if os.path.isfile(p) else sum(os.path.getsize(os.path.join(dp,f)) for dp,_,fs in os.walk(p) for f in fs)
print(f" {e} ({sz} B)")
except Exception as ex:
print(f" {e} <err {ex}>")
print("[*] done")