Yarpe, acronimo di Yet another Ren’Py PlayStation exploit, si presenta come un progetto tecnico di rilievo sviluppato da Helloyunho, capace di portare nel mondo delle visual novel basate su Ren’Py metodologie già consolidate nell’analisi e nello sfruttamento di giochi costruiti su altri motori come Lua.

Questo adattamento non è solo un esercizio tecnico, ma rappresenta una naturale evoluzione della scena homebrew, che nel tempo ha imparato a muoversi con sempre maggiore disinvoltura tra engine differenti, seguendo la diffusione crescente di strumenti di sviluppo accessibili nel panorama indie.
https://twitter.com/TeRex777_/status/2034693909155049619
Con l’arrivo della versione 3.3.0, Yarpe compie un passo decisivo introducendo il supporto alla versione PlayStation 5 di Arcade Spirits: The New Challengers, segnando un traguardo importante per questo tipo di exploit.
Fino a poco tempo fa, infatti, i titoli nativi PS5 risultavano più complessi da gestire in questo contesto, ma l’aggiornamento dimostra come le tecniche basate sulla manipolazione dei salvataggi possano essere adattate con successo anche alla nuova generazione.
Si tratta di un segnale forte e concreto di maturità, che evidenzia come certi limiti tecnici possano essere progressivamente superati grazie a un lavoro mirato e approfondito.
Il funzionamento di Yarpe ruota attorno alla modifica dei file di salvataggio, che diventano il punto d’ingresso per alterare il comportamento del gioco. Intervenendo sulle variabili interne, è possibile ottenere effetti che vanno dal semplice sblocco di contenuti fino a modifiche più profonde.
L’aspetto più significativo è però la possibilità di eseguire codice Python direttamente all’interno del gioco, sfruttando un server TCP attivo sulla porta 9025.
Questo meccanismo consente una connessione diretta tra PC e console, trasformando l’esperienza di gioco in un ambiente aperto alla sperimentazione, dove è possibile testare script e osservare in tempo reale le reazioni del sistema.
La versione 3.3.0 introduce anche miglioramenti tecnici importanti, tra cui la correzione di un problema legato alla gestione persistente del dizionario interno _changed, che in precedenza poteva causare anomalie durante il caricamento dei salvataggi modificati.
Parallelamente, è stata resa più chiara e completa la documentazione, soprattutto per quanto riguarda la gestione dei save su PS5, un’operazione che richiede attenzione e strumenti adeguati per l’importazione e l’esportazione dei dati.
Giochi supportati
- A YEAR OF SPRINGS PS4 (CUSA30428, CUSA30429, CUSA30430, CUSA30431)
- Arcade Spirits: The New Challengers PS4 (CUSA32096, CUSA32097)
- Arcade Spirits: The New Challengers PS5 (PPSA06409, PPSA06410)
Come usare
Grazie a https://github.com/shahrilnet/remote_lua_loader/blob/main/SETUP.md per la base di questa guida.
Eseguire il “pickling” dei dati di salvataggio (può essere saltato se si scarica il file di salvataggio già pronto dalle release).
- Eseguire
python3 pack_savegame.pyper generare il filesave.zip.- È possibile utilizzare
updater.pyoppure Apollo Save Tool per applicare i dati di salvataggio.
- È possibile utilizzare
Creare un unico file di salvataggio (opzionale, se non è possibile copiare tutti i file).
Importante: È necessario eseguire prima pack_savegame.py per generare save.zip prima di questo passaggio.
- Eseguire
python3 pack_unzipper.pyper generare1-1-LT1_unzipper.save.- Rinominare
1-1-LT1_unzipper.savein1-1-LT1.savee copiarlo nella cartella dei dati di salvataggio sulla console.
- Rinominare
Avviso: Questa operazione cancellerà quasi certamente i dati di salvataggio esistenti per quel gioco. Assicurati di fare prima un backup!
Nota: La guida qui sotto presuppone che tu abbia già creato un file di salvataggio nel gioco che desideri modificare.
Nota: A causa del limite sul numero di file imposto da Discord, quando utilizzi il bot Discord per cifrare il salvataggio potresti non riuscire a caricare tutti i file. In questo caso, usa 1-1-LT1.save (rinominato da 1-1-LT1_unzipper.save se hai eseguito tu stesso il “pickling” tramite pack_unzipper.py) per creare un unico salvataggio che contenga tutti i file. Quando avvierai il gioco, i file verranno estratti automaticamente.
Modifica dei dati di salvataggio su PS4 / PS4 Slim / PS4 Pro
Jailbroken
- Scaricare ed estrarre il file
save.zipsul PC. - Utilizzare Apollo Save Tool per esportare i dati di salvataggio decriptati su una chiavetta USB tramite l’opzione “Copy save game to USB”.
- Andare nel percorso
/PS4/APOLLO/id_{TUO_GAME_CUSA_ID}_savedatae copiare tutti i contenuti dell’archiviosave.zipin quella cartella, sostituendo i file esistenti. - Utilizzare nuovamente Apollo Save Tool per importare i nuovi dati di salvataggio dalla USB con “Copy save game to HDD”.
- Avviare il gioco e verificare se il salvataggio è stato modificato (controllando l’immagine del save).
PSN (o fake)-Activated
- Scaricare ed estrarre il file
save.zipsul PC. - Assicurarsi di essere connessi con l’utente PSN (o fake) attivato.
- Collegare la chiavetta USB alla PS4 / PS4 Slim / PS4 Pro.
- Utilizzare il menu impostazioni della PS4 per esportare il salvataggio su USB (Impostazioni → Gestione dati salvati dell’applicazione → Dati salvati nella memoria di sistema → Copia su dispositivo di archiviazione USB → seleziona il gioco e copia).
- Dovreste trovare i file
SAVEDATA00eSAVEDATA00.binnel percorso/PS4/SAVEDATA/(hash)/CUSA(id gioco)/sulla USB. Utilizzare Save Wizard oppure un bot Discord per decriptare il salvataggio. - Accedere alla cartella del salvataggio decriptato e copiare al suo interno tutti i file di
save.zip, sostituendo quelli esistenti. - Ricifrare il salvataggio modificato utilizzando Save Wizard o il bot Discord.
- Reinserire i file
SAVEDATA00eSAVEDATA00.bincifrati nella stessa cartella sulla USB. - Collegare il dispositivo USB alla console.
- Importare il salvataggio modificato tramite il menu impostazioni (Impostazioni → Gestione dati salvati → Dati salvati su USB → Copia nella memoria di sistema → seleziona il gioco).
- Avviare il gioco e verificare le modifiche.
Modifica dei dati di salvataggio su PS5 / PS5 Slim / PS5 Pro
Jailbroken (funziona con giochi PS4 e PS5)
- Avviare il gioco almeno una volta e creare un salvataggio.
- Chiudere il gioco.
- Inviare garlic-savemgr all’elfldr.
- Aprire nel browser del PC l’indirizzo
http://<ps5-ip>:8082. - Andare nella scheda Browser e selezionare il gioco.
- Estrairre l’archivio
save.zipe trascinare tutti i file nella pagina di garlic. - Cliccare su “Unmount”.
- Avviare il gioco e controllare se il salvataggio è cambiato.
PSN (o fake)-Activated (solo giochi PS4)
- Recuperare l’ID account PSN dalla console (tramite impostazioni o siti dedicati).
- Convertire l’ID (circa 19 caratteri) in formato esadecimale attraverso questo sito web.
- Seguire la guida PS4 sopra fino al punto di esportazione su USB.
- Assicurarsi di essere connessi con l’utente PSN attivo.
- Collegare il dispositivo USB alla PS5.
- Importare il salvataggio cifrato tramite il menu (Dati salvati e impostazioni gioco/app → Dati salvati PS4 → Copia o elimina da USB → seleziona il gioco).
- Avviare il gioco e verificare le modifiche.
Eseguire codice personalizzato nel gioco
- Utilizzare un client TCP sul PC (ad esempio hermes-link o strumenti simili).
- Preparare uno script Python da eseguire.
- Inviare lo script alla console sulla porta 9025.
- Il codice verrà eseguito direttamente nel gioco.
Aggiornare Yarpe
- Scaricare l’archivio
save.zipsul PC. - Eseguire
updater.py(oppureupdater_for_up_to_2.x.x.pyper versioni precedenti) sulla console. - Inviare il file
save.zipalla console con lo stesso metodo utilizzato per il codice. - Premere
(o
) per uscire dal gioco quando richiesto.
Auto loader
Nota: Richiede la creazione di un salvataggio personalizzato tramite il metodo “pickling”.
- Modificare il file
yarpe_autoload/autoload.example.txtsecondo le proprie esigenze e salvarlo comeautoload.txt. - Copiare eventuali script, elf o bin necessari nella cartella
yarpe_autoload/. - Eseguire il “pickling” del salvataggio con
pack_savegame.py(epack_unzipper.pyse necessario). - Copiare il salvataggio generato sulla console con i metodi descritti sopra.
- Utilizzare
payloads/force_persistent.pyper caricare automaticamente il salvataggio all’avvio del gioco. - Per ignorare l’auto loader e accedere direttamente alla modalità socket, tenere premuto il tasto
durante il caricamento del salvataggio.
- Utilizzare
Python API
utils: Vari moduli utilityutils.ref: Funzioni per ottenere riferimenti a byte/oggetti bytearray.utils.ref.refbytes(data): Restituisce un puntatore al contenuto dei dati degli oggetti byte che può poi essere passato alle funzioni.utils.ref.refbytearray(data): Restituisce un puntatore al contenuto dei dati degli oggetti dell’array di bytearray che può poi essere passato alle funzioni.utils.ref.get_ref_addr(data): Restituisce l’indirizzo del contenuto dei dati degli oggetti byte/bytearray/str/Structure.
utils.pack: Funzioni per imballare/disimballare dati.utils.pack.p64(value_list): Impacchettavalue_listcome byte little-endian da 8 byte.utils.pack.p64a(*value): Il valore dei pacchetti è di 8 byte little-endian.utils.pack.p32(value_list): I pacchettivalue_listcome byte little-endian da 4 byte.utils.pack.p32a(*value): I pacchetti valgono come byte little-endian da 4 byte.utils.pack.p16(value_list): Impacchettavalue_listcome byte little-endian da 2 byte.utils.pack.p16a(*value): Il valore dei pacchetti è byte little-endian da 2 byte.utils.pack.unpack(data): Scarica i dati little-endian di 8 byte in intero.
utils.conversion: Funzioni per convertire tra diversi tipi di dati.utils.conversion.u64(value): Converte il valore in un intero non firmato a 64 bit.utils.conversion.u64_to_i64(valore): Converte il valore intero non segnato a 64 bit in intero a 64 bit con segno.utils.conversion.u32_to_i32(valore): Converte il valore intero non firmato a 32 bit in intero a 32 bit con segno.utils.conversion.get_cstring(data): Ottiene la stringa terminata nulla in stile C dai dati.
utils.etc: Funzioni di utilità varie.utils.etc.sizeof(data): Restituisce la dimensione dei dati byte/bytearray/Structure object.utils.etc.flat(list_of_data): Appiattisce una lista di oggetti in un’unica lista.utils.etc.addrof(data): restituisce l’indirizzo dei dati dell’oggetto.utils.etc.to_hex(data): Converte i dati in una stringa esadecimale.utils.etc.alloc(size): Alloca i byte di dimensione nella memoria del gioco e restituisce il bytearray.utils.etc.bytes(arr): Converte una lista di interi arr in oggetto bytes.
utils.unsafe: Funzioni di accesso alla memoria non sicure.utils.unsafe.readbuf(addr, length): Lettura byte di lunghezza da addr.utils.unsafe.writebuf(addr, data): Scrive i dati su addr.utils.unsafe.readuint(addr, size): Legge un intero senza segno di byte size da addr.utils.unsafe.writeuint(addr, value, size): Scrive il valore intero senza segno dei byte size in addr.utils.unsafe.fakeobj(addr): Restituisce un oggetto python falso in addr.
utils.rp: Accesso allo schermo usando le funzioni di Ren’Py.utils.rp.log(*args): Logs args allo schermo.utils.rp.log_exc(string): Registra la stringa come eccezione per lo screening.
utils.tcp: Funzioni del socket TCP.utils.tcp.ip_to_int(ip_string): Converte ip_string in intero.utils.tcp.htonl(value): Converte il valore in ordine dei byte di rete.utils.tcp.create_tcp_socket(): Crea un socket TCP e restituisce il suo descriptor del file.utils.tcp.get_socket_name(socket_fd): Ottiene l’IP del socket e la porta di socket_fd.utils.tcp.create_tcp_server(port, ip='0.0.0.0'): Crea un server TCP che ascolta su ip:port e restituisce il suo descrittore di file e sockaddr_in struct.utils.tcp.create_tcp_client(ip, porta): Crea un client TCP collegato a ip:port e restituisce il suo descrittore del file.utils.tcp.accept_client(socket_fd): Accetta una connessione client su socket_fd e restituisce il socket client fd e sockaddr_in struct.utils.tcp.read_from_socket(socket_fd, dimensione=4096): Legge fino a byte di dimensione da socket_fd e restituisce i dati.utils.tcp.read_all_from_socket(socket_fd): Legge tutti i dati disponibili da socket_fd finché non sono più dati disponibili e restituisce i dati.utils.tcp.write_to_socket(socket_fd, dati): Scrive dati per socket_fd.utils.tcp.close_socket(socket_fd): Chiude la presa socket_fd.
utils.fs: Funzioni del file system.utils.fs.stat_file(path): Recupera la struttura stat del file al percorso specificato.utils.fs.file_exists(percorso): Restituisce se il file al percorso esiste.utils.fs.read_file_data(path): Legge il file al path e restituisce i suoi dati.utils.fs.write_file_data(path, data): Scrive i dati nel file al percorso.
sc.sc: Istanza SploitCore- Ridotto
sc.scinSCper una lettura più facile. SC.MEM: bytearray che rappresenta la memoria del gioco.sc.functions: Funzioni note a cui puoi accedere come sc.functions.function_name(arg1, arg2, …). Gli argomenti verranno automaticamente convertiti in interi usando get_ref_addr().sc.syscalls: Chiamate di sistema note a cui puoi accedere come sc.syscalls.syscall_name(arg1, arg2, …). Gli argomenti verranno automaticamente convertiti in interi usando get_ref_addr().sc.errno: Ultimo numero di errore.sc.exec_addr: Indirizzo base dell’eseguibile del gioco in memoria.sc.libc_addr: Indirizzo base di libc nella memoria del gioco.sc.libkernel_addr: Indirizzo base di libkernel nella memoria del gioco.sc.platform: La piattaforma console (non dipende dall’edizione del gioco) (ad esempio, ‘ps4’, ‘ps5’).- Nota che sono in minuscolo.
sc.version: La versione firmware della console (ad esempio, ‘9.00’, ‘10.03’).sc.is_jailbroken: Restituisce se la console è jailbreakata.sc.make_function_if_needed(name, addr): Crea una voce di funzione in sc.functions se non esiste già, e la restituisce.sc.make_syscall_if_needed(nome, num): Crea una voce syscall in sc.syscalls se non esiste già, e la restituisce.sc.send_notification(messaggio): Invia una notifica alla PS4/PS5.sc.get_sysctl_int(nome): Ottiene il valore intero del nome della variabile sysctl.sc.set_sysctl_int(nome, valore): Imposta il valore intero del nome della variabile sysctl in valore.sc.kill_game(): Uccide il processo di gioco attuale.
- Ridotto
ropchain: ROPChain modulocatena di corda. ROPChain(sc, dimensione=variable_per_console): Crea un costruttore di catene ROP.chain.chain: L’array di bytearray che rappresenta la catena ROP.chain.index: Indice corrente nella catena ROP.chain.return_value:- Se è stato usato push_get_return_value(), questo conterrà il valore di ritorno della chiamata alla funzione dopo l’esecuzione.
chain.errno:- Se è stato usato push_get_errno(), questo conterrà il valore errno dopo l’esecuzione.
chain.addr: L’indirizzo della catena ROP in memoria.chain.reset(): Resetta la catena ROP a vuoto.chain.append(value): Aggiunge il valore di 8 byte alla catena ROP.chain.extend(buf): Estende la catena ROP con i byte in buf.chain.push_gadget(gadget_name): Aggiunge il gadget con il nome gadget_name alla catena ROP.chain.push_value(valore): Uguale ad appendere (valore).chain.push_syscall(syscall_number, arg1, arg2, ...): Aggiunge la syscall con numero syscall_number e i suoi argomenti alla catena ROP. Gli argomenti verranno automaticamente convertiti in interi usando get_ref_addr().chain.push_call(addr, arg1, arg2, ...): Aggiunge la chiamata alla funzione a addr con i suoi argomenti alla catena ROP. Gli argomenti verranno automaticamente convertiti in interi usando get_ref_addr().chain.push_get_return_value(): Aggiunge i gadget necessari per ottenere il valore di ritorno dell’ultima funzione/chiamata di sistema chiamata.chain.push_get_errno(): Aggiunge i gadget necessari per ottenere il valore errno dopo l’ultima funzione/syscall chiamata.chain.push_write_into_memory(addr, data): Aggiunge i gadget necessari per scrivere i dati in memoria a addr.chain.push_store_rax_into_memory(addr): Aggiunge i gadget necessari per memorizzare il valore in RAX in memoria all’addr.chain.push_store_rdx_into_memory(addr): Aggiunge i gadget necessari per memorizzare il valore in RDX in memoria all’addr.
- catena di corda. Executable(sc, size=variable_per_console): Crea una regione di memoria eseguibile.
- Quando crei un’istanza eseguibile, devi creare 4 catene ROP:
- Front chain.
- Call/syscall chain.
- Post chain.
- Back chain.
executable.chain: L’istanza ROPChain che rappresenta il codice eseguibile.executable.errno: Il valore errno dopo l’esecuzione.executable.setup_front_chain(): Prepara la catena frontale per l’esecuzione.executable.setup_call_chain(func_addr, arg1, arg2, ...): Imposta la catena di chiamate per chiamare func_addr con i suoi argomenti. Gli argomenti verranno automaticamente convertiti in interi usandoget_ref_addr().executable.setup_syscall_chain(syscall_number, arg1, arg2, ...): Imposta la catena di syscall per chiamare syscall_number con i suoi argomenti. Gli argomenti verranno automaticamente convertiti in interi usando get_ref_addr().executable.setup_post_chain(): Prepara la catena di post-esecuzione.executable.setup_back_chain(): Prepara la catena posteriore per l’esecuzione.executable.execute(): Esegue il codice nella regione di memoria eseguibile.
- Quando crei un’istanza eseguibile, devi creare 4 catene ROP:
structure: Modulo strutturastructure.Structure(structure_pair): Crea una definizione di struttura a partire dastructure_pair.structure_pair = [(field_name1, field_size1), (field_name2, field_size2), ...]struct.size: Dimensione totale della struttura in byte.struct.offsets: Un dizionario che mappa i nomi dei campi ai loro offset nella struttura.struct.create(defaults=None): Crea un’istanza della struttura con defaults opzionali(defaults[field] = value).struct.from_bytes(dati): Crea un’istanza della struttura dai dati dati in byte.- Nota che i dati verranno copiati in un nuovo bytearray, quindi modificare l’istanza non modificherà i dati.
struct.from_bytearray(data): Crea un’istanza della struttura a partire dai dati dati dell’array di byte.- Tenere presente che modificare l’istanza modificherà anche i dati.
struct.from_address(addr): Crea un’istanza della struttura dalla memoria inaddr.- Nota che modificare l’istanza modificherà anche la memoria in
addr.
- Nota che modificare l’istanza modificherà anche la memoria in
structure.StructureInstance(structure, defaults=None): Crea un’istanza distructure.- Puoi fornire predefiniti opzionali (
defaults[field] = value) per inizializzare i campi. - Quando accedi ai campi come attributi (ad esempio,
instance.field_name), riceve/imposta automaticamente il valore corrispondente del campo. instance.structure: La definizione di struttura usata per creare questa istanza.instance.buf: L’array di byte che rappresenta i dati della struttura.instance.addr: L’indirizzo dei dati della struttura in memoria.instance.get_field(field_name): Ottiene il valore del campo field_name.instance.set_field(field_name, valore): Imposta il valore del campo field_name a valore.instance.get_field_raw(field_name, dimensione): Ottiene i byte grezzi del campo field_name con la dimensione della lunghezza.instance.set_field_raw(field_name, dati): Imposta i byte grezzi del campo field_name a dati.instance.reset(): Azzera tutti i campi.
- Puoi fornire predefiniti opzionali (
offset: modulo Offset listoffsets.GADGET_OFFSETS: Un dizionario contenente offset di gadget noti che possono essere utilizzati nelle catene ROP.- Esempio:
GADGET_OFFSETS[game_name][console_variation][gadget_name] = offset
- Esempio:
offsets.LIBC_GADGETS: Una lista che indica quali gadget provengono da libc.- Ad esempio, se imposti pop rax; Gadget RET come gadget libc, verrà risolto usando sc.libc_addr + offset invece di sc.exec_addr + offset.
offsets.LIBC_OFFSETS: Un dizionario contenente offset di funzione libc noti che può essere usato per creare voci di funzione in sc.functions.- Esempio:
LIBC_OFFSETS[game_name][console_variation][function_name] = offset
- Esempio:
offsets.EXEC_OFFSETS: Un dizionario contenente gli offset noti delle funzioni eseguibili che possono essere utilizzati per creare voci di funzione insc.functions.- Esempio:
EXEC_OFFSETS[game_name][console_variation][function_name] = offset
- Esempio:
costanti: modulo delle costantiVERSION: La versione di yarpe.- Se hai costruito Yarpe dalla fonte, questo sarà “custom build”.
CONSOLE_KIND: Edizione attuale per console di gioco (ad esempio, ‘PS4’, ‘PS5’) (non dipende dal modello della console stessa).- Nota che sono in maiuscolo.
SELECTED_GADGETS: Il set di gadget selezionato per il gioco e la console attuali.SELECTED_LIBC: Gli offset libc selezionati per il gioco e la console attuali.SELECTED_EXEC: Gli offset eseguibili selezionati per il gioco e la console attuali.SYSCALL: Un dizionario contenente numeri di syscall noti che può essere utilizzato per creare voci di syscall in sc.syscalls.- Esempio:
SYSCALL[syscall_name] = numero
- Esempio:
nogc: Una lista che contiene riferimenti a oggetti che non dovrebbero essere raccolti con spazzatura.RP: variabile Renpy che può essere usata per accedere alle funzioni Ren’Py.SHARED_VARS: Un dizionario che può essere utilizzato per condividere dati tra più payload.
Changelog
1-1-LT1.save: contiene un unzipper unificato che estrae automaticamente tutti i file.save.zip: contiene tutti i file singoli.
Download: yarpe v3.3.0 (1-1-LT1.save)
Download: yarpe v3.3.0 (save.zip)
Download: Source code yarpe v3.3.0
Alcune parti di questo articolo sono state generate con l’aiuto dell’intelligenza artificiale. Questo articolo contiene link affiliati a Amazon. Se acquisti tramite questi link, potrei guadagnare una commissione senza costi aggiuntivi per te.🔥 Prodotti in promozione e articoli più venduti: PS4
Vedi altri prodotti PS4
Ultimo aggiornamento 2026-06-16 / Link di affiliazione / Immagini da Amazon Product Advertising API





