Function bodies 388 total
PUPExtractor class · python · L42-L98 (57 LOC)research/pupps3/extract_premo.py
class PUPExtractor:
"""Extract files from a PS3 PUP (PlayStation Update Package)"""
def __init__(self, pup_path):
self.pup_path = pup_path
self.data = open(pup_path, "rb").read()
def extract(self, output_dir):
"""Extract all sections from the PUP"""
os.makedirs(output_dir, exist_ok=True)
# PUP Header
magic = self.data[0:8]
# Parse header
pkg_version = struct.unpack(">Q", self.data[0x08:0x10])[0]
img_version = struct.unpack(">Q", self.data[0x10:0x18])[0]
file_count = struct.unpack(">Q", self.data[0x18:0x20])[0]
header_length = struct.unpack(">Q", self.data[0x20:0x28])[0]
data_length = struct.unpack(">Q", self.data[0x28:0x30])[0]
log("info", f"PUP version: {pkg_version}, files: {file_count}")
# File entries start at offset 0x30
# Each entry: id(8) + offset(8) + size(8) = 24 bytes
# Then hash entries follow
entries = []
for i in r__init__ method · python · L45-L47 (3 LOC)research/pupps3/extract_premo.py
def __init__(self, pup_path):
self.pup_path = pup_path
self.data = open(pup_path, "rb").read()extract method · python · L49-L98 (50 LOC)research/pupps3/extract_premo.py
def extract(self, output_dir):
"""Extract all sections from the PUP"""
os.makedirs(output_dir, exist_ok=True)
# PUP Header
magic = self.data[0:8]
# Parse header
pkg_version = struct.unpack(">Q", self.data[0x08:0x10])[0]
img_version = struct.unpack(">Q", self.data[0x10:0x18])[0]
file_count = struct.unpack(">Q", self.data[0x18:0x20])[0]
header_length = struct.unpack(">Q", self.data[0x20:0x28])[0]
data_length = struct.unpack(">Q", self.data[0x28:0x30])[0]
log("info", f"PUP version: {pkg_version}, files: {file_count}")
# File entries start at offset 0x30
# Each entry: id(8) + offset(8) + size(8) = 24 bytes
# Then hash entries follow
entries = []
for i in range(file_count):
off = 0x30 + i * 0x20
entry_id = struct.unpack(">Q", self.data[off:off+8])[0]
entry_offset = struct.unpack(">Q", self.data[off+8:off+16])[0]
extract_tar_packages function · python · L101-L108 (8 LOC)research/pupps3/extract_premo.py
def extract_tar_packages(tar_path, output_dir):
"""Extract .pkg files from update_files.tar"""
os.makedirs(output_dir, exist_ok=True)
with tarfile.open(tar_path, "r") as tar:
tar.extractall(output_dir)
files = os.listdir(output_dir)
log("ok", f"Extracted {len(files)} files from update_files.tar")
return filesfind_and_extract_core_os function · python · L111-L200 (90 LOC)research/pupps3/extract_premo.py
def find_and_extract_core_os(pkg_dir, output_dir):
"""
The CORE_OS_PACKAGE.pkg contains a tar of dev_flash.
It's an SCE-signed package. We need to find the data section and extract it.
"""
pkg_path = os.path.join(pkg_dir, "CORE_OS_PACKAGE.pkg")
if not os.path.exists(pkg_path):
log("err", "CORE_OS_PACKAGE.pkg not found!")
return None
data = open(pkg_path, "rb").read()
log("info", f"CORE_OS_PACKAGE.pkg: {len(data):,} bytes")
# SCE header: magic "SCE\x00" at offset 0
if data[:4] != b"SCE\x00":
log("err", "Not a valid SCE package")
return None
# SCE header structure (simplified):
# 0x00: magic (4)
# 0x04: version (4)
# 0x08: key_revision (2)
# 0x0A: type (2)
# 0x0C: metadata_offset (4) — usually 0
# 0x10: header_length (8)
# 0x18: data_length (8)
header_length = struct.unpack(">Q", data[0x10:0x18])[0]
data_length = struct.unpack(">Q", data[0x18:0x20])[0]
log("info", f"SCscan_for_sprx_files function · python · L203-L219 (17 LOC)research/pupps3/extract_premo.py
def scan_for_sprx_files(search_dir, output_dir):
"""Search for premo SPRX files in extracted firmware"""
os.makedirs(output_dir, exist_ok=True)
found = []
for root, dirs, files in os.walk(search_dir):
for f in files:
if "premo" in f.lower():
src = os.path.join(root, f)
dst = os.path.join(output_dir, f)
with open(src, "rb") as sf:
with open(dst, "wb") as df:
df.write(sf.read())
found.append(dst)
log("ok", f"Found: {f} ({os.path.getsize(src):,} bytes) at {os.path.relpath(src, search_dir)}")
return foundtry_decrypt_sprx function · python · L222-L242 (21 LOC)research/pupps3/extract_premo.py
def try_decrypt_sprx(sprx_path, elf_path, scetool_path, unself_path):
"""Try to decrypt SPRX using available tools"""
log("step", f"Decrypting {os.path.basename(sprx_path)}...")
# Try scetool first
if scetool_path and os.path.exists(scetool_path):
scetool_dir = os.path.dirname(scetool_path)
ret = os.system(f'cd "{scetool_dir}" && ./scetool --decrypt "{sprx_path}" "{elf_path}" 2>&1')
if ret == 0 and os.path.exists(elf_path) and os.path.getsize(elf_path) > 0:
log("ok", f"Decrypted with scetool: {elf_path} ({os.path.getsize(elf_path):,} bytes)")
return True
# Try unself
if unself_path and os.path.exists(unself_path):
ret = os.system(f'"{unself_path}" "{sprx_path}" "{elf_path}" 2>&1')
if ret == 0 and os.path.exists(elf_path) and os.path.getsize(elf_path) > 0:
log("ok", f"Decrypted with unself: {elf_path} ({os.path.getsize(elf_path):,} bytes)")
return True
log("err", f"CoulOpen data scored by Repobility · https://repobility.com
scan_raw_for_elf function · python · L245-L288 (44 LOC)research/pupps3/extract_premo.py
def scan_raw_for_elf(data_path, output_dir):
"""
Last resort: scan raw binary data for ELF headers or SELF/SCE headers
that might be premo_plugin embedded in the firmware
"""
log("step", "Scanning raw firmware data for SPRX/ELF signatures...")
data = open(data_path, "rb").read()
os.makedirs(output_dir, exist_ok=True)
found = []
# Search for SCE headers (SELF/SPRX files start with "SCE\x00")
offset = 0
file_idx = 0
while offset < len(data) - 4:
# SCE magic
if data[offset:offset+4] == b'SCE\x00':
# Read header length and data length
if offset + 0x20 <= len(data):
try:
hdr_len = struct.unpack(">Q", data[offset+0x10:offset+0x18])[0]
dat_len = struct.unpack(">Q", data[offset+0x18:offset+0x20])[0]
total = hdr_len + dat_len
if 0x1000 < total < 0x1000000: # Between 4KB and 16MB (reasonable SPRX size)
main function · python · L291-L400 (110 LOC)research/pupps3/extract_premo.py
def main():
script_dir = Path(__file__).parent
pup_file = script_dir / "PS3UPDAT.PUP"
work_dir = script_dir / "extraction"
output_dir = work_dir / "output"
tools_dir = work_dir / "tools"
scetool_path = tools_dir / "scetool" / "scetool"
unself_path = tools_dir / "ps3tools" / "unself"
if not pup_file.exists():
log("err", f"PS3UPDAT.PUP not found at {pup_file}")
sys.exit(1)
print(f"\n\033[36m{'='*60}\033[0m")
print(f"\033[36m PS3 Firmware Extraction — Python Pipeline\033[0m")
print(f"\033[36m{'='*60}\033[0m\n")
# Phase 1: Extract PUP
log("step", "Phase 1: Extracting PUP...")
pup_dir = output_dir / "pup_contents"
extractor = PUPExtractor(str(pup_file))
extracted = extractor.extract(str(pup_dir))
# Phase 2: Extract update_files.tar
update_tar = pup_dir / "update_files.tar"
if not update_tar.exists():
log("err", "update_files.tar not found in PUP")
sys.exit(1)
log("step", "PVaioFridaHooker class · python · L227-L346 (120 LOC)research/re-windows/frida_hook_vaio.py
class VaioFridaHooker:
def __init__(self):
self.session: Optional[frida.Session] = None
self.script: Optional[frida.Script] = None
def find_wine_process(self) -> Optional[int]:
"""Find VAIO process running under Wine."""
try:
processes = frida.enumerate_processes()
for proc in processes:
name = proc.name.lower()
# Look for VAIO installer or VAIO Remote Play process
if "vaio" in name or "vrpsdk" in name or "vaio" in proc.name:
print(f"[+] Found VAIO process: {proc.name} (PID: {proc.pid})")
return proc.pid
# Also look for common Windows process names
if "wineserver" in name or "explorer.exe" in name or "setup.exe" in name:
print(f"[*] Found potential Wine process: {proc.name} (PID: {proc.pid})")
# If no specific VAIO process found, list Wine processes
print("\n[__init__ method · python · L228-L230 (3 LOC)research/re-windows/frida_hook_vaio.py
def __init__(self):
self.session: Optional[frida.Session] = None
self.script: Optional[frida.Script] = Nonefind_wine_process method · python · L232-L255 (24 LOC)research/re-windows/frida_hook_vaio.py
def find_wine_process(self) -> Optional[int]:
"""Find VAIO process running under Wine."""
try:
processes = frida.enumerate_processes()
for proc in processes:
name = proc.name.lower()
# Look for VAIO installer or VAIO Remote Play process
if "vaio" in name or "vrpsdk" in name or "vaio" in proc.name:
print(f"[+] Found VAIO process: {proc.name} (PID: {proc.pid})")
return proc.pid
# Also look for common Windows process names
if "wineserver" in name or "explorer.exe" in name or "setup.exe" in name:
print(f"[*] Found potential Wine process: {proc.name} (PID: {proc.pid})")
# If no specific VAIO process found, list Wine processes
print("\n[*] Available processes:")
for proc in processes:
if any(x in proc.name.lower() for x in ["wine", "setup", "installer", "vaioattach_and_hook method · python · L257-L274 (18 LOC)research/re-windows/frida_hook_vaio.py
def attach_and_hook(self, pid: int):
"""Attach to process and install hooks."""
print(f"[+] Attaching to process {pid}...")
try:
self.session = frida.attach(pid)
except Exception as e:
print(f"[-] Failed to attach: {e}")
print(" Make sure VAIO process is running and you have permissions")
return False
print("[+] Creating Frida script...")
self.script = self.session.create_script(HOOK_SCRIPT)
self.script.on("message", self._on_message)
print("[+] Loading script...")
self.script.load()
return True_on_message method · python · L276-L333 (58 LOC)research/re-windows/frida_hook_vaio.py
def _on_message(self, message, data):
"""Handle messages from Frida script."""
if message["type"] == "send":
payload = message["payload"]
msg_type = payload.get("type")
if msg_type == "status":
print(f"[*] {payload.get('message')}")
elif msg_type == "ready":
print(f"[SUCCESS] {payload.get('message')}")
elif msg_type == "error":
print(f"[-] {payload.get('message')}")
elif msg_type == "crypto_param":
operation = payload.get("operation")
dwParam = payload.get("dwParam")
paramName = payload.get("paramName")
data_val = payload.get("data")
# Convert bytes to hex
data_hex = ""
if data_val:
try:
# data is already bytes
data_hex = bytes(data_val).hex()
exceptrun method · python · L335-L346 (12 LOC)research/re-windows/frida_hook_vaio.py
def run(self):
"""Main loop - wait for events."""
print("\n[*] Waiting for registration events...")
print("[*] Press Ctrl+C to stop\n")
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print("\n\n[+] Detaching...")
if self.session:
self.session.detach()
print("[SUCCESS] Done")Repobility — the code-quality scanner for AI-generated software · https://repobility.com
main function · python · L348-L379 (32 LOC)research/re-windows/frida_hook_vaio.py
def main():
print("""
╔════════════════════════════════════════════════════════════════╗
║ VAIO DLL Frida Hook - IV Context Capture ║
║ ║
║ This will hook VAIO crypto operations and log: ║
║ - CryptEncrypt plaintext/ciphertext ║
║ - CryptSetKeyParam calls (especially KP_IV) ║
║ - Memory operations on key material ║
║ ║
║ Goal: Find the 8-byte IV context value for registration ║
╚════════════════════════════════════════════════════════════════╝
""")
hooker = VaioFridaHooker()
# Find VAIO process
pid = hooker.find_wine_process()
if not pid:
print("\n[-] No VAIO process found.")
print("[*] Make sure VAIO is running:")
print(" WINEPREFIX=~/.wine_vaio wine vaio_installer.exe")
print("\n[*] Then run tentry function · c · L205-L233 (29 LOC)research/rmp_dll.dll.c
undefined8 entry(undefined4 param_1,int param_2)
{
HMODULE hModule;
undefined4 extraout_ECX;
undefined4 extraout_ECX_00;
undefined4 uVar1;
uint in_EDX;
undefined4 extraout_EDX;
undefined4 extraout_EDX_00;
undefined4 uVar2;
longlong lVar3;
lVar3 = (ulonglong)in_EDX << 0x20;
if (param_2 == 1) {
hModule = GetModuleHandleA(s_kernelbase_dll_00402013);
uVar1 = extraout_ECX;
uVar2 = extraout_EDX;
if (hModule != (HMODULE)0x0) {
lstrcmpW_exref = GetProcAddress(hModule,s_lstrcmpW_00402022);
uVar1 = extraout_ECX_00;
uVar2 = extraout_EDX_00;
}
_DAT_0040202b = lstrcmpW_exref + 5;
lVar3 = FUN_004010bf(uVar1,uVar2,lstrcmpW_exref,0x40104f);
}
return CONCAT44((int)((ulonglong)lVar3 >> 0x20),1);
}FUN_004010bf function · c · L234-L247 (14 LOC)research/rmp_dll.dll.c
undefined8 __fastcall
FUN_004010bf(undefined4 param_1,undefined4 param_2,undefined1 *param_3,int param_4)
{
undefined4 in_EAX;
VirtualProtect(param_3,5,0x40,(PDWORD)&DAT_00402000);
*param_3 = 0xe9;
*(int *)(param_3 + 1) = (param_4 - (int)param_3) + -5;
return CONCAT44(param_2,in_EAX);
}GetProcAddress function · c · L248-L260 (13 LOC)research/rmp_dll.dll.c
FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName)
{
FARPROC pFVar1;
// WARNING: Could not recover jumptable at 0x004010eb. Too many branches
// WARNING: Treating indirect jump as call
pFVar1 = GetProcAddress(hModule,lpProcName);
return pFVar1;
}VirtualProtect function · c · L261-L273 (13 LOC)research/rmp_dll.dll.c
BOOL VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,PDWORD lpflOldProtect)
{
BOOL BVar1;
// WARNING: Could not recover jumptable at 0x004010f7. Too many branches
// WARNING: Treating indirect jump as call
BVar1 = VirtualProtect(lpAddress,dwSize,flNewProtect,lpflOldProtect);
return BVar1;
}GetModuleHandleA function · c · L274-L286 (13 LOC)research/rmp_dll.dll.c
HMODULE GetModuleHandleA(LPCSTR lpModuleName)
{
HMODULE pHVar1;
// WARNING: Could not recover jumptable at 0x00401103. Too many branches
// WARNING: Treating indirect jump as call
pHVar1 = GetModuleHandleA(lpModuleName);
return pHVar1;
}decrypt_xor_only function · python · L21-L28 (8 LOC)research/tools/decrypt_vrpsdk.py
def decrypt_xor_only(data, key=0x6cfd7e36):
"""Decrypt by XORing each DWORD with key."""
result = bytearray(data)
for i in range(0, len(result) - 3, 4):
val = struct.unpack_from('<I', result, i)[0]
val ^= key
struct.pack_into('<I', result, i, val & 0xFFFFFFFF)
return bytes(result)decrypt_xor_add function · python · L30-L38 (9 LOC)research/tools/decrypt_vrpsdk.py
def decrypt_xor_add(data, key=0x6cfd7e36, add_val=0):
"""Decrypt by XORing each DWORD with key, then adding add_val."""
result = bytearray(data)
for i in range(0, len(result) - 3, 4):
val = struct.unpack_from('<I', result, i)[0]
val ^= key
val = (val + add_val) & 0xFFFFFFFF
struct.pack_into('<I', result, i, val & 0xFFFFFFFF)
return bytes(result)Repobility · code-quality intelligence · https://repobility.com
find_pe_sections function · python · L40-L70 (31 LOC)research/tools/decrypt_vrpsdk.py
def find_pe_sections(data):
"""Parse PE headers to find sections."""
if data[:2] != b'MZ':
print("Not a PE file")
return []
e_lfanew = struct.unpack_from('<I', data, 0x3C)[0]
if data[e_lfanew:e_lfanew+4] != b'PE\x00\x00':
print("Invalid PE signature")
return []
num_sections = struct.unpack_from('<H', data, e_lfanew + 6)[0]
opt_header_size = struct.unpack_from('<H', data, e_lfanew + 20)[0]
section_offset = e_lfanew + 24 + opt_header_size
sections = []
for i in range(num_sections):
off = section_offset + i * 40
name = data[off:off+8].rstrip(b'\x00').decode('ascii', errors='replace')
vsize = struct.unpack_from('<I', data, off + 8)[0]
vaddr = struct.unpack_from('<I', data, off + 12)[0]
raw_size = struct.unpack_from('<I', data, off + 16)[0]
raw_ptr = struct.unpack_from('<I', data, off + 20)[0]
chars = struct.unpack_from('<I', data, off + 36)[0]
sections.appecheck_decryption function · python · L72-L101 (30 LOC)research/tools/decrypt_vrpsdk.py
def check_decryption(data, label):
"""Check if decrypted data looks valid (has strings, PE structures, etc.)."""
# Count printable ASCII strings of length >= 4
strings = []
current = b''
for b in data:
if 0x20 <= b < 0x7f:
current += bytes([b])
else:
if len(current) >= 6:
strings.append(current.decode('ascii'))
current = b''
if len(current) >= 6:
strings.append(current.decode('ascii'))
# Check for interesting strings
interesting = [s for s in strings if any(kw in s.lower() for kw in
['regist', 'premo', 'encrypt', 'aes', 'context', 'pin', 'key', 'sce/',
'http', 'session', 'client', 'machine', 'bcrypt', 'dll', 'vrp'])]
print(f"\n{label}:")
print(f" Total strings (>=6 chars): {len(strings)}")
print(f" Interesting strings: {len(interesting)}")
if interesting[:30]:
for s in interesting[:30]:
print(f" {s}")
if len(interestmain function · python · L103-L165 (63 LOC)research/tools/decrypt_vrpsdk.py
def main():
dll_path = sys.argv[1] if len(sys.argv) > 1 else \
"/Users/mihailurmanschi/Work/PsOldRemotePlay/research/repos/ps3-remote-play/cualquiercosa327-Remote-Play/extracted/vrp_files/App/VRPSDK.dll"
if not os.path.exists(dll_path):
print(f"File not found: {dll_path}")
sys.exit(1)
with open(dll_path, 'rb') as f:
data = f.read()
print(f"File: {dll_path}")
print(f"Size: {len(data)} bytes")
print(f"\nPE Sections:")
sections = find_pe_sections(data)
# Try decrypting each code section
out_dir = os.path.dirname(dll_path) or '.'
for sect in sections:
if sect['raw_size'] == 0:
continue
start = sect['raw_ptr']
size = sect['raw_size']
sect_data = data[start:start+size]
# Try XOR-only decryption
decrypted = decrypt_xor_only(sect_data)
score = check_decryption(decrypted, f"Section {sect['name']} XOR-only (key=0x6cfd7e36)")
if score > 5:
main function · c · L8-L132 (125 LOC)research/tools/dump_vrpsdk2.c
int main(void) {
const char *dll_path = "C:\\Program Files (x86)\\Sony\\Remote Play with PlayStation 3\\VRPSDK.dll";
const char *out_path = "Z:\\Users\\mihailurmanschi\\Work\\PsOldRemotePlay\\research\\tools\\";
printf("Loading VRPSDK.dll...\n");
HMODULE hMod = LoadLibraryA(dll_path);
if (!hMod) {
printf("LoadLibrary failed: %lu\n", GetLastError());
return 1;
}
/* Dump the key name strings at 0x00405000 */
printf("\n=== Key name strings at 0x00405000+ ===\n");
unsigned char *p = (unsigned char *)0x00405000;
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(p, &mbi, sizeof(mbi)) && mbi.State == MEM_COMMIT) {
/* Dump 256 bytes as hex + ascii */
for (int i = 0; i < 256; i += 16) {
printf(" 0x%08X: ", (unsigned)(size_t)(p + i));
for (int j = 0; j < 16; j++) printf("%02X ", p[i+j]);
printf(" |");
for (int j = 0; j < 16; j++) {
char c = p[i+j];
main function · c · L30-L185 (156 LOC)research/tools/dump_vrpsdk3.c
int main(void) {
const char *dll_path = "C:\\Program Files (x86)\\Sony\\Remote Play with PlayStation 3\\VRPSDK.dll";
printf("Loading VRPSDK.dll...\n");
HMODULE hMod = LoadLibraryA(dll_path);
if (!hMod) {
printf("LoadLibrary failed: %lu\n", GetLastError());
return 1;
}
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hMod;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)hMod + dos->e_lfanew);
DWORD image_size = nt->OptionalHeader.SizeOfImage;
unsigned char *base = (unsigned char *)hMod;
HMODULE hSelf = GetModuleHandleA(NULL);
printf("VRPSDK.dll at 0x%p, size 0x%lX\n", hMod, image_size);
printf("Our EXE at 0x%p\n", hSelf);
/* 1. Search for AES S-box in VRPSDK.dll */
printf("\n=== Searching VRPSDK.dll for AES S-box ===\n");
for (DWORD i = 0; i + 256 <= image_size; i++) {
if (memcmp(base + i, aes_sbox_start, 32) == 0) {
printf(" FOUND AES S-box at VRPSDK+0x%lX (VA 0x%p)\n", i, base+i);
main function · c · L14-L187 (174 LOC)research/tools/dump_vrpsdk4.c
int main(void) {
const char *dll_path = "C:\\Program Files (x86)\\Sony\\Remote Play with PlayStation 3\\VRPSDK.dll";
const char *out_base = "Z:\\Users\\mihailurmanschi\\Work\\PsOldRemotePlay\\research\\tools\\";
printf("Loading VRPSDK.dll...\n");
HMODULE hMod = LoadLibraryA(dll_path);
if (!hMod) {
printf("LoadLibrary failed: %lu\n", GetLastError());
return 1;
}
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hMod;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)hMod + dos->e_lfanew);
DWORD image_size = nt->OptionalHeader.SizeOfImage;
unsigned char *base = (unsigned char *)hMod;
DWORD base_addr = (DWORD)hMod;
printf("VRPSDK.dll at 0x%08lX, size 0x%lX\n", base_addr, image_size);
/* The S-box is at base+0x27010, which is VA 0x10027010 */
/* Find code that references this address (as a 32-bit immediate) */
DWORD sbox_va = base_addr + 0x27010;
DWORD pc_nonce_va = base_addr + 0x273C8;
printf("\n=== Findsearch_memory_range function · c · L31-L48 (18 LOC)research/tools/dump_vrpsdk.c
void search_memory_range(const char *region_name, unsigned char *base, SIZE_T size) {
for (int k = 0; k < NUM_KEYS; k++) {
for (SIZE_T i = 0; i + keys[k].len <= size; i++) {
if (memcmp(base + i, keys[k].data, keys[k].len) == 0) {
printf(" FOUND %s at %s+0x%lX (VA 0x%p)\n",
keys[k].name, region_name, (unsigned long)i, base + i);
/* Print 32 bytes of context */
printf(" Context: ");
SIZE_T ctx_start = (i > 16) ? i - 16 : 0;
for (SIZE_T j = ctx_start; j < i + 32 && j < size; j++) {
printf("%02X ", base[j]);
}
printf("\n");
}
}
}
}load_and_dump_dll function · c · L51-L63 (13 LOC)research/tools/dump_vrpsdk.c
void load_and_dump_dll(const char *name, const char *path) {
printf("\nLoading %s...\n", name);
HMODULE h = LoadLibraryA(path);
if (!h) {
printf(" Failed: %lu\n", GetLastError());
return;
}
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)h;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)h + dos->e_lfanew);
DWORD sz = nt->OptionalHeader.SizeOfImage;
printf(" Loaded at 0x%p, size 0x%lX (%lu bytes)\n", h, sz, sz);
search_memory_range(name, (unsigned char *)h, sz);
}Repobility · MCP-ready · https://repobility.com
main function · c · L64-L164 (101 LOC)research/tools/dump_vrpsdk.c
int main(void) {
const char *base_path = "C:\\Program Files (x86)\\Sony\\Remote Play with PlayStation 3\\";
char path[512];
/* Load VRPSDK.dll first (main target) */
sprintf(path, "%sVRPSDK.dll", base_path);
printf("Loading VRPSDK.dll...\n");
HMODULE hVRPSDK = LoadLibraryA(path);
if (!hVRPSDK) {
printf("LoadLibrary VRPSDK.dll failed: %lu\n", GetLastError());
return 1;
}
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hVRPSDK;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char *)hVRPSDK + dos->e_lfanew);
DWORD vrpsdk_size = nt->OptionalHeader.SizeOfImage;
printf("VRPSDK.dll at 0x%p, size 0x%lX\n", hVRPSDK, vrpsdk_size);
/* Dump VRPSDK.dll to file */
const char *out_path = "Z:\\Users\\mihailurmanschi\\Work\\PsOldRemotePlay\\research\\tools\\vrpsdk_dumped.bin";
FILE *f = fopen(out_path, "wb");
if (f) {
char *base = (char *)hVRPSDK;
for (DWORD off = 0; off < vrpsdk_size; off += 4096) {
log_setkey function · c · L52-L89 (38 LOC)research/tools/hook_aes.c
void __cdecl log_setkey(DWORD this_ptr, DWORD key_ptr) {
if (!g_log) return;
g_call_count++;
fprintf(g_log, "\n=== SetKey call #%d ===\n", g_call_count);
fprintf(g_log, " this = 0x%08X\n", this_ptr);
fprintf(g_log, " key_ptr = 0x%08X\n", key_ptr);
/* Dump the key (16 bytes) */
unsigned char *key = (unsigned char *)key_ptr;
fprintf(g_log, " AES Key: ");
for (int i = 0; i < 16; i++) fprintf(g_log, "%02X ", key[i]);
fprintf(g_log, "\n");
/* The IV should be near the key in the parent object.
The parent object layout seems to be:
+0x0C = CAesCipher (this)
+0x460 = key buffer
The IV for CBC is typically stored separately.
Let me dump the parent object area to find the IV. */
/* The parent object = this - 0x0C (since caller does lea ecx, [esi+0xC]) */
unsigned char *parent = (unsigned char *)(this_ptr - 0x0C);
fprintf(g_log, " Parent object dump (+0x440 to +0x480):\n ");
for (int i = 0x4main function · c · L93-L179 (87 LOC)research/tools/hook_aes.c
int main(void) {
const char *dll_path = "C:\\Program Files (x86)\\Sony\\Remote Play with PlayStation 3\\VRPSDK.dll";
const char *log_path = "Z:\\Users\\mihailurmanschi\\Work\\PsOldRemotePlay\\research\\tools\\aes_hook_log.txt";
g_log = fopen(log_path, "w");
if (!g_log) {
printf("Cannot open log file\n");
return 1;
}
printf("Loading VRPSDK.dll...\n");
HMODULE hMod = LoadLibraryA(dll_path);
if (!hMod) {
printf("LoadLibrary failed: %lu\n", GetLastError());
return 1;
}
DWORD base = (DWORD)hMod;
printf("VRPSDK.dll at 0x%08lX\n", base);
/* SetKey is at base + 0x1D60 */
/* Instead of hooking, let's use a different approach:
Find and call the registration function via COM, then
scan memory for the key/IV. */
/* Actually, the simplest approach:
Find the CAesCipher vtable, and look for the IV storage.
The AES CBC mode needs an IV. Let me find where the IV is stored
by hexdump function · c · L38-L48 (11 LOC)research/tools/hook_registration.c
static void hexdump(const char *label, const BYTE *data, int len) {
printf(" %s: ", label);
for (int i = 0; i < len; i++) printf("%02X ", data[i]);
printf("\n");
if (g_log) {
fprintf(g_log, "%s: ", label);
for (int i = 0; i < len; i++) fprintf(g_log, "%02X", data[i]);
fprintf(g_log, "\n");
fflush(g_log);
}
}veh_handler function · c · L51-L148 (98 LOC)research/tools/hook_registration.c
static LONG WINAPI veh_handler(EXCEPTION_POINTERS *ep) {
DWORD eip = ep->ContextRecord->Eip;
if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) {
if (eip == g_setkey_addr) {
g_setkey_count++;
DWORD ecx = ep->ContextRecord->Ecx;
DWORD esp = ep->ContextRecord->Esp;
/* __thiscall: ECX=this, stack: [ret_addr][key_ptr] */
DWORD key_ptr = *(DWORD *)(esp + 4);
printf("\n=== [HOOK] SetKey #%d ===\n", g_setkey_count);
printf(" this=0x%08X key_ptr=0x%08X\n", ecx, key_ptr);
if (key_ptr) hexdump("AES KEY", (BYTE *)key_ptr, 16);
/* Also dump parent object areas where IV might be stored */
/* Parent = this - 0x0C (CAesCipher is at parent+0x0C) */
DWORD parent = ecx - 0x0C;
printf(" Parent object dump around key/IV storage:\n");
hexdump(" parent+0x460", (BYTE *)(parent + 0x460), 16);
hexdump(" parentinstall_hooks function · c · L151-L180 (30 LOC)research/tools/hook_registration.c
static void install_hooks(DWORD base) {
DWORD old;
g_setkey_addr = base + 0x1D60;
g_setiv_addr = base + 0x1010;
g_encrypt_addr = base + 0x1E60;
printf("[+] SetKey at 0x%08X\n", g_setkey_addr);
printf("[+] SetIV at 0x%08X\n", g_setiv_addr);
printf("[+] Encrypt at 0x%08X\n", g_encrypt_addr);
/* Save original bytes */
VirtualProtect((void *)g_setkey_addr, 1, PAGE_EXECUTE_READWRITE, &old);
g_setkey_orig = *(BYTE *)g_setkey_addr;
*(BYTE *)g_setkey_addr = 0xCC;
VirtualProtect((void *)g_setkey_addr, 1, old, &old);
VirtualProtect((void *)g_setiv_addr, 1, PAGE_EXECUTE_READWRITE, &old);
g_setiv_orig = *(BYTE *)g_setiv_addr;
*(BYTE *)g_setiv_addr = 0xCC;
VirtualProtect((void *)g_setiv_addr, 1, old, &old);
VirtualProtect((void *)g_encrypt_addr, 1, PAGE_EXECUTE_READWRITE, &old);
g_encrypt_orig = *(BYTE *)g_encrypt_addr;
*(BYTE *)g_encrypt_addr = 0xCC;
VirtualProtect((void *)g_encrypt_addr, 1, old, &old);
my_lstrcmpW function · c · L191-L237 (47 LOC)research/tools/hook_registration.c
static int __stdcall my_lstrcmpW(const wchar_t *s1, const wchar_t *s2) {
/* Check if either string contains "Sony" */
const wchar_t sony[] = L"Sony";
int is_sony = 0;
if (s1 && s2) {
/* Simple substring check */
for (const wchar_t *p = s1; *p; p++) {
if (p[0] == 'S' && p[1] == 'o' && p[2] == 'n' && p[3] == 'y') {
is_sony = 1;
break;
}
}
if (!is_sony) {
for (const wchar_t *p = s2; *p; p++) {
if (p[0] == 'S' && p[1] == 'o' && p[2] == 'n' && p[3] == 'y') {
is_sony = 1;
break;
}
}
}
}
if (is_sony) {
printf("[BYPASS] lstrcmpW Sony check intercepted - returning match\n");
return 0; /* Match */
}
/* Call original for non-Sony comparisons */
/* Restore original, call, re-patch */
DWORD old;
VirtualProtect((void *)g_lstrcmpw_addr, 8, PAGE_EXECUinstall_vaio_bypass function · c · L238-L263 (26 LOC)research/tools/hook_registration.c
static void install_vaio_bypass(void) {
HMODULE hKernel = GetModuleHandleA("kernelbase.dll");
if (!hKernel) hKernel = GetModuleHandleA("kernel32.dll");
FARPROC pLstrcmpW = GetProcAddress(hKernel, "lstrcmpW");
if (!pLstrcmpW) {
printf("[-] lstrcmpW not found\n");
return;
}
g_lstrcmpw_addr = (DWORD)pLstrcmpW;
printf("[+] lstrcmpW at 0x%08X - installing VAIO bypass\n", g_lstrcmpw_addr);
DWORD old;
VirtualProtect((void *)g_lstrcmpw_addr, 8, PAGE_EXECUTE_READWRITE, &old);
memcpy(g_lstrcmpw_orig, (void *)g_lstrcmpw_addr, 8);
BYTE jmp_patch[5];
jmp_patch[0] = 0xE9;
*(DWORD *)(jmp_patch + 1) = (DWORD)my_lstrcmpW - g_lstrcmpw_addr - 5;
memcpy((void *)g_lstrcmpw_addr, jmp_patch, 5);
VirtualProtect((void *)g_lstrcmpw_addr, 8, old, &old);
printf("[+] VAIO hardware bypass installed\n");
}Open data scored by Repobility · https://repobility.com
main function · c · L289-L604 (316 LOC)research/tools/hook_registration.c
int main(int argc, char **argv) {
const char *pin_str = "12345678"; /* Default test PIN */
if (argc > 1) pin_str = argv[1];
printf("╔══════════════════════════════════════════════════╗\n");
printf("║ VRPSDK Registration Hook Tool ║\n");
printf("║ Captures AES Key + IV during registration ║\n");
printf("╚══════════════════════════════════════════════════╝\n\n");
printf("[*] PIN: %s\n", pin_str);
/* Open log file */
g_log = fopen("Z:\\Users\\mihailurmanschi\\Work\\PsOldRemotePlay\\research\\tools\\aes_hook_log.txt", "w");
if (g_log) {
fprintf(g_log, "=== VRPSDK Registration Hook Log ===\n");
fprintf(g_log, "PIN: %s\n\n", pin_str);
}
/* Step 1: Register VEH (before loading anything) */
printf("[1] Registering VEH handler...\n");
AddVectoredExceptionHandler(1, veh_handler);
/* Step 2: Install VAIO bypass (hook lstrcmpW) */
printf("[2] Installing VAIO hardware bypass...\n");
inderive_key_psp function · python · L91-L93 (3 LOC)research/tools/iv_context_generator.py
def derive_key_psp(km: bytes) -> bytes:
"""PSP: key[i] = (km[i] ^ PSP_XOR[i]) - i - 0x25"""
return bytes(((km[i] ^ PSP_XOR[i]) - i - 0x25) & 0xFF for i in range(16))derive_key_phone function · python · L95-L97 (3 LOC)research/tools/iv_context_generator.py
def derive_key_phone(km: bytes) -> bytes:
"""Phone: key[i] = (km[i] - i - 0x28) ^ PHONE_XOR[i]"""
return bytes(((km[i] - i - 0x28) & 0xFF) ^ PHONE_XOR[i] for i in range(16))derive_key_pc function · python · L99-L101 (3 LOC)research/tools/iv_context_generator.py
def derive_key_pc(km: bytes) -> bytes:
"""PC: key[i] = (km[i] ^ PC_XOR[i]) - i - 0x2B"""
return bytes(((km[i] ^ PC_XOR[i]) - i - 0x2B) & 0xFF for i in range(16))derive_iv_psp function · python · L108-L113 (6 LOC)research/tools/iv_context_generator.py
def derive_iv_psp(ctx8: bytes) -> bytes:
"""PSP: XOR first 8 bytes of IV base with context"""
iv = bytearray(PSP_IV)
for i in range(8):
iv[i] ^= ctx8[i]
return bytes(iv)derive_iv_phone function · python · L115-L120 (6 LOC)research/tools/iv_context_generator.py
def derive_iv_phone(ctx8: bytes) -> bytes:
"""Phone: XOR last 8 bytes of IV base with context"""
iv = bytearray(PHONE_IV)
for i in range(8):
iv[8 + i] ^= ctx8[i]
return bytes(iv)derive_iv_pc function · python · L122-L127 (6 LOC)research/tools/iv_context_generator.py
def derive_iv_pc(ctx8: bytes) -> bytes:
"""PC: XOR first 8 bytes of IV base with context (same pattern as PSP)"""
iv = bytearray(PC_IV)
for i in range(8):
iv[i] ^= ctx8[i]
return bytes(iv)pkcs7_pad function · python · L134-L136 (3 LOC)research/tools/iv_context_generator.py
def pkcs7_pad(data: bytes, block_size: int = 16) -> bytes:
pad_len = block_size - (len(data) % block_size)
return data + bytes([pad_len] * pad_len)Repobility — the code-quality scanner for AI-generated software · https://repobility.com
pkcs7_unpad function · python · L138-L146 (9 LOC)research/tools/iv_context_generator.py
def pkcs7_unpad(data: bytes) -> bytes:
if not data:
return data
pad_len = data[-1]
if pad_len < 1 or pad_len > 16:
return data
if data[-pad_len:] != bytes([pad_len] * pad_len):
return data
return data[:-pad_len]generate_all_contexts function · python · L153-L403 (251 LOC)research/tools/iv_context_generator.py
def generate_all_contexts(pin_str: str) -> List[Tuple[bytes, str, str]]:
"""
Generate all plausible 8-byte IV context values from the PIN.
Returns list of (context_bytes, label, category).
"""
pin_int = int(pin_str)
contexts = []
def add(data: bytes, label: str, category: str):
assert len(data) == 8, f"Context must be 8 bytes, got {len(data)} for {label}"
contexts.append((data, label, category))
# =========================================================================
# Category: PIN-based interpretations
# =========================================================================
# All zeros (baseline — IV base used as-is)
add(bytes(8), "all_zeros", "pin")
# PIN as big-endian int64 (longlong cast from int — code shows this pattern)
add(pin_int.to_bytes(8, 'big'), "pin_be64", "pin")
# PIN as little-endian int64
add(pin_int.to_bytes(8, 'little'), "pin_le64", "pin")
# PIN as big-endian int32, left-make_sample_body function · python · L494-L504 (11 LOC)research/tools/iv_context_generator.py
def make_sample_body(client_type: str, client_id: str = "0123456789abcdef0123456789abcdef",
client_mac: str = "001122334455",
client_nickname: str = "TestDevice") -> bytes:
"""Build a sample registration body matching the PS3 expected format."""
body = (
f"Client-Type: {client_type}\r\n"
f"Client-Id: {client_id}\r\n"
f"Client-Mac: {client_mac}\r\n"
f"Client-Nickname: {client_nickname}\r\n"
)
return body.encode('ascii')