19.11.2016 Views

Technical Analysis of the Pegasus Exploits on iOS

eNQc3Ry

eNQc3Ry

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

structure and <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel address space. This value is <str<strong>on</strong>g>the</str<strong>on</strong>g>n stored in a global variable for use by<br />

functi<strong>on</strong>s that must access kernel memory for <str<strong>on</strong>g>the</str<strong>on</strong>g> purposes <str<strong>on</strong>g>of</str<strong>on</strong>g> code executi<strong>on</strong>.<br />

Whenever 32Stage2 wants to execute code within <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel, <str<strong>on</strong>g>the</str<strong>on</strong>g> following data structure is<br />

written to <str<strong>on</strong>g>the</str<strong>on</strong>g> write pipe <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> generated pipe set:<br />

[00] argument 1<br />

[04] argument 2<br />

[08] address <str<strong>on</strong>g>of</str<strong>on</strong>g> code to execute<br />

In order to call <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong> specified in <str<strong>on</strong>g>of</str<strong>on</strong>g>fset 8 <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> data structure, ano<str<strong>on</strong>g>the</str<strong>on</strong>g>r DWORD is<br />

prepended to <str<strong>on</strong>g>the</str<strong>on</strong>g> structure and passed to <str<strong>on</strong>g>the</str<strong>on</strong>g> real-time clock’s getattr handler (accessed via<br />

OSSerializer::serialize), which places argument 1 into R3 and argument 2 into R1<br />

before calling <str<strong>on</strong>g>the</str<strong>on</strong>g> address specified for <str<strong>on</strong>g>the</str<strong>on</strong>g> functi<strong>on</strong> to execute. By prepending <str<strong>on</strong>g>the</str<strong>on</strong>g> unused<br />

DWORD to <str<strong>on</strong>g>the</str<strong>on</strong>g> data structure, <str<strong>on</strong>g>the</str<strong>on</strong>g> data structure becomes <str<strong>on</strong>g>the</str<strong>on</strong>g> vtable replacement for<br />

OSSerializer. This technique is used in two different functi<strong>on</strong>s within 32Stage2. One functi<strong>on</strong><br />

allows arbitrary kernel functi<strong>on</strong> calls and <str<strong>on</strong>g>the</str<strong>on</strong>g> o<str<strong>on</strong>g>the</str<strong>on</strong>g>r is used to write DWORD values into <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

kernel address space.<br />

Patching <str<strong>on</strong>g>the</str<strong>on</strong>g> Kernel to Allow Kernel Port Access<br />

With <str<strong>on</strong>g>the</str<strong>on</strong>g> ability to read, write, and execute arbitrary locati<strong>on</strong>s within <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel address space,<br />

<str<strong>on</strong>g>the</str<strong>on</strong>g> next step involves gaining more direct access to <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel through <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel port. The<br />

functi<strong>on</strong> task_for_pid will return an error if called with <str<strong>on</strong>g>the</str<strong>on</strong>g> PID value <str<strong>on</strong>g>of</str<strong>on</strong>g> 0. In order to bypass<br />

this protecti<strong>on</strong>, Stage 2 modifies four different locati<strong>on</strong>s within <str<strong>on</strong>g>the</str<strong>on</strong>g> task_for_pid functi<strong>on</strong>.<br />

Before <str<strong>on</strong>g>the</str<strong>on</strong>g> patching <str<strong>on</strong>g>of</str<strong>on</strong>g> task_for_pid begins, Stage 2 determines if <str<strong>on</strong>g>the</str<strong>on</strong>g> area requiring <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

patch is within a regi<strong>on</strong> <str<strong>on</strong>g>of</str<strong>on</strong>g> memory that is read/execute. If <str<strong>on</strong>g>the</str<strong>on</strong>g> memory is n<strong>on</strong>-writable, Stage 2<br />

will directly modify <str<strong>on</strong>g>the</str<strong>on</strong>g> permissi<strong>on</strong>s <str<strong>on</strong>g>of</str<strong>on</strong>g> <str<strong>on</strong>g>the</str<strong>on</strong>g> memory regi<strong>on</strong> to allow for write access and <str<strong>on</strong>g>the</str<strong>on</strong>g>n<br />

invalidate <str<strong>on</strong>g>the</str<strong>on</strong>g> dcache and flush <str<strong>on</strong>g>the</str<strong>on</strong>g> data and instructi<strong>on</strong> TLBs in order to ensure that <str<strong>on</strong>g>the</str<strong>on</strong>g><br />

memory regi<strong>on</strong> is updated with <str<strong>on</strong>g>the</str<strong>on</strong>g> new permissi<strong>on</strong>s.<br />

After patching <str<strong>on</strong>g>the</str<strong>on</strong>g> task_for_pid functi<strong>on</strong> to allow <str<strong>on</strong>g>the</str<strong>on</strong>g> caller to gain a port to <str<strong>on</strong>g>the</str<strong>on</strong>g> kernel, Stage<br />

2 will attempt to get a kernel port by calling task_for_pid(mach_task_self, 0, &port)<br />

up to five times with a 100 mllisec<strong>on</strong>d delay between each attempt before calling <str<strong>on</strong>g>the</str<strong>on</strong>g> assert<br />

callback and exiting.<br />

Page 31

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!