Ps5_kldload

buzzer-re buzzer-re
Dépôt créer le : 30/03/2025
Forks: 9 Watcher: 0 56
Choisir une liste...
FR

PS5 kldload

Il s'agit d'un chargeur de module noyau pour la PlayStation 5 qui vise à fournir une compréhension plus approfondie des internes du système et à aider dans mes recherches sur ses internes.

L'hyperviseur reste actif et intact, mais les modules du noyau fonctionnent normalement et en harmonie avec lui.

Comment ça marche

Sur les systèmes PlayStation 4, les développeurs ont pu corriger le noyau en cours d'exécution pour le forcer à toujours attribuer des zones de mémoire lisibles-exécutables dans la fonction kmem alloc. Sur la PlayStation 5, les choses sont un peu différentes, avec quelques mises en garde, comme l'Hypervisor, qui empêchent l'accès à la lecture/écriture de texte en raison de XOM et l'hypothèse que GMET est activé.

GMET (Guest Mode Execute) est une technologie AMD utilisée par son hyperviseur pour contrôler spécifiquement quelles pages peuvent être exécutées au niveau des invités. Lorsqu'il est activé et correctement configuré, l'invité ne peut pas demander des pages exécutables ou exécuter du code en dehors de la zone autorisée. La PlayStation 5 manque cette configuration jusqu'au firmware 6.50. kldload fonctionne en demandant de telles pages, en écrivant du code en utilisant les primitives du noyau, et en l'exécutant comme un vrai kthread, permettant ainsi l'exécution de code au niveau du noyau réel sur le périphérique.

Pour appeler les fonctions et ainsi de suite, on peut utiliser r0gdb ou kstuff. Cependant, ni l'un ni l'autre ne patche le noyau. Au lieu de cela, ils utilisent des primitives du noyau read/write (RW) pour s'enregistrer dans la Table de Descripteur Interrupt (IDT) pour capturer les défauts de protection générale (int13) et les pièges de débogue (int1). Avec les gadgets nécessaires, ils peuvent également lire et écrire aux registres de débogage.

Utiliser kstuff pour demander des pages du noyau RWX implique de définir des points d'arrêt spécifiques dans le noyau. kmem_alloc fonction puis, avant l'attribution, changer les permissions RW par défaut en RWX. Ceci est similaire à la façon dont les correctifs importants tels que le patch mprotect (qui permet PROT_EXEC protection dans le pays utilisateur) ont été appliquées.

Utilisation r0gdb l'implémentation est différente : un traceur est configuré lors de l'appel de kmem alloc, et il retracera un État qui se produit avant l'attribution de la page, puis il le changera en RWX Exécutable.

r0gdb est la principale méthode supportée de ce projet, car elle est plus simple et ne nécessite pas de forcer le système à déclencher une #GP à chaque tentative. La seule mise en garde en ce moment est que les chargeurs tels que elfldr peut connaître un comportement non défini ; c'est actuellement sur l'arriéré de débogage/fixation. Néanmoins, si kstuff est chargé dans le système avant kldload, il vérifiera si les kekcalls nécessaires sont mis en œuvre. S'ils le sont, il utilisera le module kstuff actuellement en cours d'exécution sur le r0gdb.

Firmware soutenu

firmware actuellement pris en charge:

  • 3,0
  • 3.10
  • 3.20
  • 3.21
  • 4.03
  • 4,51
  • 5,0
  • 5.02
  • 5.10
  • 5,50
  • 6.0
  • 6.02
  • 6,50

Construction et utilisation

Assurez-vous d'avoir la dernière version du SDK installé.

Cloner le dépôt de façon récursive:

git clone --recursive https://github.com/buzzer-re/PS5 kldload.git

Ensuite, vous pouvez construire et exécuter l'outil avec:

faire propre && faire & & faire test

Il écoutera sur le port 9022 et lancera toutes les charges utiles du noyau en mode noyau.

Exemple

Les charges utiles du noyau peuvent être écrites de la même manière que pour la PlayStation 4. À l'avenir, un SDK pourrait être élaboré pour y contribuer. Voici un simple Bonjour monde exemple qui lit le MSR_LSTAR valeur. Le code source complet peut être trouvé ici.

#include "../include/firmware/offsets.h"

#define MSR_LSTAR 0xC0000082
typedef unsigned long uint64_t;
typedef unsigned int uint32_t;

inline uint64_t __readmsr(uint32_t msr) // wrapper for the rdmsr instruction
{
    uint32_t low, high;
    __asm__("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
    return (low | ((uint64_t) high << 32));
}

typedef struct __kproc_args
{
    uint64_t kdata_base;
} kproc_args;

void (*kprintf)(char* fmt, ...);
uint64_t kdata_address;

void init_kernel()
{
    kprintf = (void (*)(char*, ...)) (kdata_address + kprintf_offset);
}

int module_start(kproc_args* args)
{
    kdata_address = args->kdata_base;
    init_kernel();

    kprintf("Hello from kernel land! Let's check the MSR_LSTAR value!\n");
    kprintf("MSR_LSTAR => %#02lx\n", __readmsr(MSR_LSTAR));

    return 1;
}

Envoie-le avec socat -t 99999999 - TCP:PS5_IP:9022 < hello_world.bin alors vous pouvez vérifier klogs:

Travaux futurs

Voici quelques choses que je travaille actuellement et qui ont besoin d'aide pour quiconque veut aider avec:

  • Chargeur SDK et ELF pour KLD
    • Similaire sur la façon dont FreeBSD fait déjà, il est bon d'avoir un format bien défini et charger similaire à ceux actuels
  • Définition de l'acquisition et de la fonction des offsets
    • Il y a beaucoup de compensations déjà définies sur le décaissements.c, certains d'entre eux ont besoin d'une définition de fonction à utiliser

Contributeurs GitHub

buzzer-re
buzzer-re
8 contributions