PS4/PS5 Reverse engineering 101 – The basics of PS4 exploits
Some of the questions that are the most frequently asked when it comes to PS4 Jailbreaks include “how do these guys find these exploits in the first place?” and “how does one become a console hacker, where’s the course for that?”.
Although I don’t have the full answer to these questions (I’d argue nobody does), I’ve recently become frustrated with how difficult it can be to find explanations to somewhat “simple” questions on the PS4/PS5 scene. All the components to get started diving into the PS4’s code (and, more specifically, looking for exploits) are here, but it’s connecting the dots that I have found surprisingly hard. Maybe it’s just me.
After a deep dive into the scene’s tools and collective knowledge, I’m happy to present a PS4 Reverse engineering introduction, for noobs, by a noob. I hope it will be helpful to some of you!
0. Prerequisites
If you intend to get the most of this article, there are a few expectations. Generally speaking, you should be familiar with running exploits and payloads on your PS4 (it is therefore expected that you have a hacked PS4 in order to retrieve some of the files that you’ll be looking at).
You should also have some knowledge of C and X86 Assembly. How much knowledge you ask? I don’t really know. I want to say “basic” knowledge, but really to take things to the next level, you’ll need some pretty advanced skills, to the extent that pointers should be afraid of you, not the other way around. (Personally, I’m definitely not there yet FWIW)
1. Getting access to the PS4 Code (How to Decrypt and Dump the PS4 Kernel as well as SPRX/SELF files)
A typical answer if you ask “how are PS4 exploits found” is “go read that writeup by [Cool Guy #1], it goes in depth into [Cool Exploit that just got released]”. And it’s true, there are great writeups on PS4 exploits out there. For example, Fail0verflow‘s Adieu writeup on the 4.05 exploit (which is the main topic of this guide), Or SpecterDev‘s entire github repo dedicated to his PS4 exploit explanations.
Those writeups always state that there is a function “blah” in the PS4 Kernel that has a flaw which can be leveraged for privilege escalation. And, if you’re familiar with programming in general, and reverse engineering to some extent, you can understand that concept in theory. “Bug in the code leads to some potential overflow on the stack or the heap, gives us control to some execution pointer or whatnot”, but…wait…
Where is that code they’re talking about, how do I get my hands on it???
TLDR:
- The kernel and other PS4 binaries are encrypted on the device. They need to be decrypted before you can think of reverse engineering them
- Hackers have access to private exploits (hardware or software based) that lets them decrypt the most recent firmwares, and can extract the kernel binaries that way for further inspection
- For us normal people, we’ll just ask nicely to our (hacked) PS4 to dump the decrypted version of its binaries for us
Acquiring the binaries that constitute the PS4’s kernel, or its usermode executables, is either so secret, or so trivial, that it is left as an exercise to the reader in most PS4 exploit writeups. Fair enough, these hackers are not here to teach you the basics every single time, they’re here to talk about a specific exploit.
So how is that code acquired in the first place?
There is a chicken-egg scenario here in that in order to acquire the code that’s running on these machines, you probably need some kind of exploit. But to find the exploits it would be better to have access to the code…
In practice, there’s often a hardware exploit involved the “first” time, where hackers are able to dump the binaries through some specific hardware attack. This is what Fail0verflow explain, when they say:
We were able to get a dump of the ps4 firmware 1.01 kernel via a PCIe man-in-the-middle attack
I have 0 skills or knowledge when it comes to hardware, so I won’t dive into that. However, once the console’s been hacked once, and we the general public have access to software Jailbreaks, it becomes “easier”. If you are running a Jailbroken PS4, questions such as “how do I decrypt the PS4 Kernel?” or “how to convert encrypted/signed PS4 sprx to decrypted prx” have a simple answer: we ask nicely for the PS4 to do it for us.
The Kernel code, and other libraries and binaries used by the PS4, sit somewhere on the hard drive (or some flash memory), encrypted. But of course, when the PS4 needs to use them, it needs to decrypt them before loading them in memory. The hacking tools/payloads that “decrypt” a Kernel, or SPRX/SELF files, simply ask the PS4 to decrypt them, load them in memory, and then these scripts copy the modules from RAM into a file for you. (Note: The Kernel is already loaded in RAM at that point so of course we don’t have to ask the PS4 to load it before dumping it).
If you have a hacked PS4, here are examples of some tools that will decrypt (and copy to a usb drive) the PS4’s Kernel and most libraries (prix files) respectively:
- https://github.com/eversion/PS4-Kernel-Dumper/releases A Payload that will dump the PS4’s Kernel from RAM to a USB Key (an other version here supports up to firmware 7.02)
- https://github.com/VV1LD/DumpFile405 Will decrypt sprx/self files to prx and elf on the USB. This if for firmware 4.05, but of course versions exist for pretty much every exploitable firmware
Notes:
- You should know how to run a payload on your PS4… but as a reminder: run the exploit on your console, it should generally come with a bin loader waiting for the payload on a specific port. Send the payload with a tool such as NetCat Gui. Carefully read the Readme of all tools you’re using, it will avoid lots of headaches.
- I’ve found that using Mira+HEN, or just the simplest binloader usually integrated with any Jailbreak release, is the best way to get these payloads to run. GoldHEN in particular, even though it has a binloader, didn’t like some of these payloads. YMMV
- The Kernel is directly dumped from RAM, while the usermode libraries and binaries are loaded from disk into RAM, before being dumped.
- You will, in general, not find these decrypted binaries online, because they contain Intellectual Property from PlayStation. Which is why it is basically expected that you dump them yourself from your own console.
Running those tools on your hacked console should give you decrypted prx and elf files, as well as a huge .bin file for the kernel. These file are decrypted now, so you should be able to start digging into them for reverse engineering.
2. The basics of Reverse Engineering Decrypted PS4 Binaries and Libraries – objdump, IDA Pro, Ghidra,…
Once you have decrypted the content from your PS4 in the step above, you are ready to start digging into it. This part becomes much closer to “regular” reverse engineering, and I’m assuming that people familiar with X86 Assembly in general will probably have no need for this section. I, however, am a complete noob, so it took me a while to figure some of these things out. I’m hoping it can help others getting their feet wet, but this is in no way a full-fledged tutorial on how to reverse engineer production-level X86 code.
Basics – objdump
One of the most basic tools to get started with reverse engineering is the command line objdump. That tool gives you basic information on the headers of ELF files, can output executable portions in readable assembly (disassemble), etc…
Running it with the default options on the files we just acquired from the PS4 might however not yield much, because those files are generally stripped of a lot of useful data, due to how they were created and extracted.
Thankfully, the PS4 Dev wiki has a useful page on reverse engineering that tells us this is the way to use objdump on those PS4 files:
objdump -b binary -D -m i386:x86-64 file
And sure enough, that works.
Technically, this is enough to get us started, but of course most experienced hackers use slightly more advanced tools when it comes to reverse engineering massive codebases such as the PS4’s.
IDA Pro and Ghidra
A lot of reverse engineers in the PS4 scene use IDA Pro and Ghidra. They’re not the only tools out there of course, but they’re the ones I see being mentioned the most. Honestly, IDA Pro is probably the most convenient one, but it is a very expensive piece of software, that professional hackers probably can get their company to pay for. Ghidra, on the other hand, is free and open source, so that’s what I’ll use here.
PS4 Binaries are X86-64 binaries, so in theory you should be able to open them “as is” with a tool such as Ghidra. However, plugins have been developed by the PS4 community to ease the process. This might not be critical in the context of this guide, but I recommend you install the PS4 Plugin “Ghidra Orbis” by Astrelsky. This plugin, in particular, deobfuscates some of the function names in the binary. For example, a function named “ANmSWUiyyGQ” in the binary file will be translated to its real name “sceSaveDataGetProgress“, making it much more readable for us as we step through the code.
- Ghidra
- Ghidra Orbis (plugin to help withPS4 Binaries reverse engineering).
Now that I have Ghidra and the extension installed, I will load the PS4 Kernel into Ghidra. You could load one of the decrypted prx or elf files instead (they’re smaller and more digestible), but I wanted to walk through one of the exploits writeups to see if I was doing things right.
3. An example: looking at the 4.05 namedobj PS4 Kernel Exploit
At this point I’m just trying to see if I understood things right, and I think it’s an interesting exercise. I looked at the 4.05 PS4 Kernel Exploit, mostly because it’s fairly well documented, and also because when I initially started looking into this, my PS4 was on Firmware 4.05. (Since then, I updated to 5.05, and that’s a difference that is important later in this walkthrough).
The most detailed writeup on this exploit is the one by Fail0verflow, which can be found here: https://fail0verflow.com/blog/2017/ps4-namedobj-exploit/. (SpecterDev also has a summary here). I don’t intend to look into the whole exploit, however.
Fail0verflow describe a function named sys_namedobj_create in the PS4 Kernel, that they have reverse engineered.
The goal of this walkthrough is simple. Can I:
- Find that sys_namedobj_create function in my kernel dump
- Understand Fail0verflow’s reverse engineered code and how similar it is to the function in my kernel dump
- Find how the function has been patched (since I have firmware 5.05, it stands to reason that my function will be slightly different from the one they describe. The bug they found was patched in 4.06, so 5.05 should have the patch)
3.1 Finding the sys_namedobj_create function
Now that I have loaded my kernel dump into Ghidra, all I have to do is “search all” for sys_namedobj_create in my .bin file. This takes a while (it is a big file), but sure enough, I find it.
With a few comments added by myself as I walked through the code and Fail0verflow’s explanation, this is what it looks like
int sys_namedobj_create(long param_1,long *param_2) { ushort uVar1; undefined8 uVar2; long lVar3; int iVar4; //Return value - rv int iVar5; undefined8 uVar6; //aka char* name or char _name[32] undefined8 *puVar7; //namedObj undefined8 *in_GS_OFFSET; undefined8 local_40; long local_38; local_38 = DAT_ffffffff97c90010; if (*param_2 == 0) { iVar4 = 0x16; //EINVAL - see https://man.freebsd.org/cgi/man.cgi?errno } else { uVar2 = *(undefined8 *)(*(long *)(param_1 + 8) + 0xab0); //uVar2 (idt) is one element of the param1 (thread * td) struct. // Fail0Verflow refer to it as idt = td->td_proc->sce_idt; uVar1 = *(ushort *)(param_2 + 2); //malloc of 0x20 for uVar6, then copy param2 (userland string) into uVar6 (kernel data) uVar6 = FUN_ffffffff95586250(0x20,&PTR_PTR_ffffffff96926050,2); //malloc lVar3 = *param_2; FUN_ffffffff9588ac30(*in_GS_OFFSET,"copyinstr",0); // https://man.freebsd.org/cgi/man.cgi?query=copyinstr&sektion=9&n=1 iVar4 = FUN_ffffffff95662b40(lVar3,uVar6,0x20,0); if (iVar4 == 0) { //if string copy succesful, malloc a namedObject Structure puVar7 = (undefined8 *)FUN_ffffffff95586250(0x18,&PTR_PTR_ffffffff96926050,2); //malloc *puVar7 = uVar6; //namedObj->name receives the kernel string puVar7[1] = param_2[1]; //namedObj->object receives third argument to the function call iVar5 = FUN_ffffffff9584afe0(uVar2,&local_40); //F0F: handle = id_alloc(idt, &ide); if (iVar5 == -1) { //if id_alloc failed, free memory and return error FUN_ffffffff95586460(uVar6,&PTR_PTR_ffffffff96926050); //free FUN_ffffffff95586460(puVar7,&PTR_PTR_ffffffff96926050); //free iVar4 = 0x23; // EAGAIN } else { //id_set(ide, (IDT_TYPE)kind, no, name); FUN_ffffffff9584b5a0(local_40,uVar1 | 0x1000,puVar7,uVar6); FUN_ffffffff9584b670(local_40); iVar4 = 0; *(long *)(param_1 + 0x398) = (long)iVar5; //td->td_retval[0] = handle; } } else { //if string copy unsuccessful, free uVar6 FUN_ffffffff95586460(uVar6); //free } } if (DAT_ffffffff97c90010 != local_38) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return iVar4; }
3.2 Understand the Reverse engineered code and compare it to the one from the Writeup
I will skip quickly through the steps comparing the code I found, to the code as described by Fail0verflow. Bottom line is, it is pretty obvious after a bit of looking at the code, that this is indeed the same function. Probably obvious for people with a bit of experience, but for me this is the first real confirmation that I now have a basic idea of the “PS4 Exploit finding” process from scratch.
Reverse engineering this kind of code is a matter of both theoretical knowledge and experience. Ghidra is supposed to help a lot, by transforming the assembly code into C, but you will not escape the need to learn a lot, in a lot of domains. Not only on assembly code itself, but also things related to the stack, the heap, syscalls, FreeBSD, computer software and hardware architecture there’s a lot in there and this tiny article will of course not cover all of that. And of course, nobody can do anything about the “gaining experience” part except for yourself. (If you’re interested in learning or getting refreshed on x86 Assembly I do recommend this course. It’s free and very well made IMO).
Because I am lazy, I did a bit of research here and there, to confirm that I was roughly understanding each line, but I didn’t jump into every single function call (which Fail0verflow did, obviously, and at this point their writeup should make much more sense to you as well). FYI I used the following sources to walk through the code:
- https://fail0verflow.com/blog/2017/ps4-namedobj-exploit/ Fail0verflow’s writeup of course
- https://github.com/RPCSX/rpcsx/blob/0bbab3eae53d01afbcdb16e97043b58e26fb54bd/orbis-kernel/src/sys/sys_sce.cpp#L469 The RPCSX implementation of the same code. At the very least, it is interesting to see how the same code in Assembly can lead to pretty different C/C++ versions when reverse engineered
- https://man.freebsd.org/cgi/man.cgi?errno to confirm the error numbers that were assigned to iVar4
- https://man.freebsd.org/cgi/man.cgi?query=copyinstr&sektion=9&n=1 Details on copyinstr
3.3 Find how the sys_namedobj_create function has been patched
Fail0verflow mention that this is how the bug got patched in 4.06:
I didn’t find the patch in my code. This one is a bit puzzling to me and remains a mystery to me at this point. I do not see any reference to 0x4000 in the code from my Firmware 5.05, neither do I see any other “if” or comparison that would resemble what they describe as the patch. There are some comparison shenanigans going on with variable Local_38, but as I understand, this is Stack Smash Protection added by the compiler (and not something you would typically surface in finalized reverse engineered code), it is not related to the fix.
But at this point I’m getting tired and have achieved most of what I was trying to understand with this exercise, so I’ll leave it at that for now.
If anybody knows what I’m missing, please tell me in the comments and I’ll update the article!
4. Conclusion and additional thoughts
We’re now able to decrypt the necessary files for PS4 Reverse engineering, as well as follow an explanatory writeup about a known PS4 Kernel exploit. Although there’s a long (long!) way before you get to find your own PS4 exploits, these are the basics of how it’s done. So, what’s next? In no particular order, some thoughts that went through my mind as I was researching this article:
Firmware consideration
It’s worth mentioning that the firmware binary you will dump is the one your console is running on. In my case, I dumped firmware 5.05, so that is the Firmware I’m reverse engineering in my examples. If I were to find an exploit in there, it would technically be a 5.05 exploit. So how does one find an exploit for a Firmware that hasn’t been hacked yet? The Chicken-Egg is back! Well the two routes I can think of are 1) as I mentioned above, hackers have access to private exploits (software or hardware) that let them decrypt and investigate the latest firmware, or 2) (which is a variation of the first point, really), if you find a new exploit in, say, firmware 5.05, it is extremely likely that the exact same flaw still exists in the latest Firmware. Kernel changes between firmwares are actually limited, as you might imagine. (Sony wouldn’t want to introduce even more bugs, or incompatibilities.)
Where to look in the kernel for PS4 Exploits?
When looking at the specific example of the 4.05 exploit, it seems “obvious” to me after the fact, that Fail0verflow were looking into it specifically because of the presence of the copyinstr function call, which lets one copy data from user memory to kernel memory. It seems like an ideal way to help with privilege escalation attacks.
The PS4 Kernel is big, but I wouldn’t be surprised if the “daily activity” of hackers is to dig for such sensitive functions (copyinstr, but not only) in the code, reverse engineer the functions calling them, and look for vulnerabilities in those. In other words, narrowing the search scope to the “low hanging fruits”.
Additionally, the PS4 being built on top of FreeBSD 9, any FreeBSD critical vulnerability is worth looking into. Often, the PS4 will have the same vulnerable code. FreeBSD is another big chunk of knowledge that people willing to understand the PS4/PS5 will have to dive into.
How about the PS5?
There is a particularity with PS5 hacking, which is that the PS5 is extremely similar to the PS4. It uses X86, is based on FreeBSD,… as such, people who have knowledge in PS4 hacking have a huge head start when it comes to the PS5. In previous generations, the PS3, Vita, and PSP were vastly different from each other, using different architectures. There is a unique opportunity here for hackers to leverage PS4 knowledge and directly reuse it for the PS5. (Which is why a lot of the current PS5 hackers are people you’ve seen before in the PS4 scene, of course)
The PS5 however has additional security in place, and in particular it is not currently publicly possible to dump its kernel, because of things such as eXecute Only Memory (there is no way to read the code, even when it is decrypted, from RAM). Although all of the above probably applies to the PS5, these additional locks mean it is currently not possible to even acquire the Kernel code to reverse engineer. (However, at the time of writing, folks running in 4.03 have ways to decrypt and dump some usermode libraries and binaries. It is also clear that some hackers have privately access to the kernel binaries)
Game Modding
I am absolutely not familiar with Game Modding, but I have to assume that all of the above applies to PS4 Game Reverse engineering for the purpose of patches and mods. Except that instead of loading the PS4 Kernel Dump, you would load a Game Dump
AI and Reverse engineering
An anecdote to conclude: I’ve once wondered if AI could help with PS5/PS4 Hacking. Although that was just an article I wrote for fun, out of curiosity, I did run the Ghidra disassembled function through ChatGPT. Although its answer was not something that would ever compile, it did give me some insight for some of the functions. In particular it correctly commented about Stack smashing protection as well as userland/kernel memory interactions, and gave me hints about what the variables might be used for.
I hope this article was useful to some. I tried to be as accurate and clear as possible, but as always, if you find issues in there, please let me know in the comments.
amazing article…in today’s class!
If you want to use objdump on PS4 userspace binaries, you can use my script: https://github.com/sleirsgoevy/ps4jb-payloads/blob/master/gdb_stub/enhancer.py. This will resolve proper section addresses, function names, and symbols, and even decipher the NIDs if you give it a database of known NIDs.
Awesome, I will update my article, I didn’t know about your tool. Thanks!
Nice. I love a good RE article, especially on PS4/PS5. ️
Nice
thank you
Thank you, love this kind of articles !
Appreciate the positive feedback, it was a pretty significant amount of research 🙂
Fantastic article. A good read while I wait for an 9.03 jailbreak
Thanks!
reverse engineerd psvita-linux time …
isnt it time to have psvita linux reverse engineerd?
i mean enso-psvita-linux standalone boot
with xmb option ofc :p
x89
buildroot$ make -j8
Makefile.legacy:9: *** “You have legacy configuration in your .config! Please check your configuration.”. Stop.
make: *** [Makefile:82: _all] Error 2
reverse engineerd psvita-linux time … isnt it time to have psvita linux reverse engineerd? i mean enso-psvita-linux standalone boot with xmb option ofc :p x89
anybody knows howto build the buildroot config witch specific checkout and system vendor … greatly appreciated 😀
It’s not just you, there’s tons of stuff out there that’s really poorly documented.
Many times it’s hard to get a proper grasp on where to start, because everyone uses acronyms for everything.
And give you short instructions like “just do make blablabla”.
But then I have a slightly different setup and the annoying google hunt begins.
Exactly!
Does anybody know newser buildroot error /kernel specific ?
>>> toolchain-external-bootlin 2022.08-1 Configuring
Incorrect selection of kernel headers: expected 5.4.x, got 5.10.x