The iPhone Wiki is no longer updated. Visit this article on The Apple Wiki for current information. |
Difference between revisions of "JerrySIM"
ChronicDev (talk | contribs) |
ChronicDev (talk | contribs) |
||
Line 10: | Line 10: | ||
[http://code.google.com/p/iphone-elite/wiki/JerrySim the elite wiki's page on the topic] |
[http://code.google.com/p/iphone-elite/wiki/JerrySim the elite wiki's page on the topic] |
||
+ | ==Leaked Source== |
||
+ | Zibri removed it from the Google Code page, but the source is still easily available via google cache, or the fact that Google Code wiki pages are svn based and you can easily just look at an earlier rev :) |
||
+ | |||
+ | On the page before the source got deleted, Zibri referred to itas C source, although by the looks of it he may have failed to realize that it looks like something that should be run off of a TurboSIM |
||
+ | <pre> |
||
+ | /* |
||
+ | Usage : send the exploit from OS level, using tty.debug/tty.baseband |
||
+ | 1) Select SMS file |
||
+ | AT+CSIM=7,"A0A40000027F10" |
||
+ | AT+CSIM=7,"A0A40000026F3C" |
||
+ | 2) Upload start registers if necessary |
||
+ | R4, R5, R6, R7, PC swapped |
||
+ | default R4=4, R5=5, R6=6, R7=7, PC=0xB00AC67C |
||
+ | AT+CSIM=28,"A0DC0104174A5300..." |
||
+ | 3) Upload the exploit |
||
+ | AT+CSIM=XX,"A0DC0104XXA53001..." |
||
+ | 4) Run (fixme stk call from tty) |
||
+ | 5) Grab the crash result |
||
+ | AT+XLOG=0 |
||
+ | */ |
||
+ | |||
+ | |||
+ | #include <config.h> |
||
+ | #include <turbo/turbo.h> |
||
+ | |||
+ | #include <stdlib.h> |
||
+ | #include <string.h> |
||
+ | |||
+ | #define VERSION "0.1" |
||
+ | |||
+ | #define REGS_SIZE 20 |
||
+ | #define MAX_PAYLOAD_SIZE 255 |
||
+ | #define MAX_BLOCK_SIZE 50 |
||
+ | |||
+ | u8 PROGMEM ef_sms_path[] = { 0x3f, 0x00, 0x7f, 0x10, 0x6f, 0x3c }; |
||
+ | |||
+ | u8 PROGMEM ABOUT_1[] = "JerrySIM version "; |
||
+ | u8 PROGMEM ABOUT_2[] = "\r\niPhone Dev Team/Elite Team internal release\r\nDO NOT LEAK"; |
||
+ | u8 PROGMEM ABOUT_3[] = "\r\nWe still have to find a way to make money out of this!"; |
||
+ | |||
+ | u8 PROGMEM DEFAULT_REGS[] = { 0x00, 0x04, 0x00, 0x00, |
||
+ | 0x00, 0x05, 0x00, 0x00, |
||
+ | 0x00, 0x06, 0x00, 0x00, |
||
+ | 0x00, 0x07, 0x00, 0x00, |
||
+ | 0xC6, 0x7C, 0xB0, 0x0A }; |
||
+ | |||
+ | #define DEFAULT_OVERFLOW_TAG_SIZE 0xC0 |
||
+ | |||
+ | static lc_char PROGMEM lc_JerrySIM[]={ |
||
+ | LC_EN("JerrySIM") |
||
+ | LC_END |
||
+ | }; |
||
+ | |||
+ | static lc_char PROGMEM lc_Run[]={ |
||
+ | LC_EN("Run") |
||
+ | LC_END |
||
+ | }; |
||
+ | |||
+ | static lc_char PROGMEM lc_Debug[]={ |
||
+ | LC_EN("Debug") |
||
+ | LC_END |
||
+ | }; |
||
+ | |||
+ | static lc_char PROGMEM lc_About[]={ |
||
+ | LC_EN("About") |
||
+ | LC_END |
||
+ | }; |
||
+ | |||
+ | typedef struct exploitDataStruct { |
||
+ | u8 *regs; /* r4 r5 r6 r7 PC */ |
||
+ | u8 *payload; |
||
+ | u8 payloadSize; |
||
+ | u8 padSize; |
||
+ | } exploitDataStruct; |
||
+ | |||
+ | |||
+ | exploitDataStruct *exploitData; |
||
+ | u8 *preparedData; |
||
+ | |||
+ | void display_hex(u8 *data, u8 dataSize) { |
||
+ | u8 i; |
||
+ | while (dataSize) { |
||
+ | u8 *r = buf_B(); |
||
+ | u8 blockSize = (dataSize < MAX_BLOCK_SIZE ? dataSize : MAX_BLOCK_SIZE); |
||
+ | for (i=0; i<blockSize; i++) { |
||
+ | u8 x = (data[i] >> 4) & 0x0f; |
||
+ | if (x <= 9) { |
||
+ | *r++ = x + '0'; |
||
+ | } |
||
+ | else { |
||
+ | *r++ = x - 0xa + 'a'; |
||
+ | } |
||
+ | x = (data[i] & 0x0f); |
||
+ | if (x <= 9) { |
||
+ | *r++ = x + '0'; |
||
+ | } |
||
+ | else { |
||
+ | *r++ = x - 0xa + 'a'; |
||
+ | } |
||
+ | } |
||
+ | *r = '\0'; |
||
+ | dataSize -= blockSize; |
||
+ | data += blockSize; |
||
+ | display_text_raw(buf_B(), Q_DISPLAY_TEXT_USER_CLEAR); |
||
+ | } |
||
+ | } |
||
+ | |||
+ | u8 prepareData(); |
||
+ | |||
+ | void go_payload(void *param) { |
||
+ | u8 dataSize; |
||
+ | dataSize = prepareData(); |
||
+ | if (dataSize != 0) { |
||
+ | stk_cmd(0x01, 0x01, 0x82, dataSize); |
||
+ | } |
||
+ | } |
||
+ | |||
+ | |||
+ | void process_sms_file(File_apdu_data *fa) { |
||
+ | if (fa->ins == ME_CMD_UPDATE_RECORD && fa->data[0] == 'J' && fa->data[1] == 'S' && |
||
+ | (fa->data[2] == 0x00 || fa->data[2] == 0x01 || fa->data[2] == 0x02 || fa->data[2] == 0x03)) { |
||
+ | switch(fa->data[2]) { |
||
+ | case 0x00: |
||
+ | /* Update registers */ |
||
+ | if (fa->p3 != REGS_SIZE - 3) { |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0xF0; |
||
+ | } |
||
+ | else { |
||
+ | memcpy(exploitData->regs, fa->data + 3, REGS_SIZE - 3); |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0x90; |
||
+ | } |
||
+ | break; |
||
+ | case 0x01: |
||
+ | /* Update payload */ |
||
+ | if ((fa->p3 - 3 + 1 + 0x1C + REGS_SIZE) > exploitData->padSize) { |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0xF1; |
||
+ | } |
||
+ | else { |
||
+ | exploitData->payloadSize = fa->p3 - 3; |
||
+ | memcpy(exploitData->payload, fa->data + 3, exploitData->payloadSize); |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0x91; |
||
+ | } |
||
+ | break; |
||
+ | case 0x02: |
||
+ | /* Upload padding */ |
||
+ | if (fa->p3 != 1 + 3) { |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0xF2; |
||
+ | } |
||
+ | else { |
||
+ | exploitData->padSize = fa->data[3]; |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[1] = 0x92; |
||
+ | } |
||
+ | break; |
||
+ | /* To be tested ! */ |
||
+ | case 0x03: |
||
+ | /* Go */ |
||
+ | stk_thread(go_payload, NULL); |
||
+ | fa->data[0] = 0x6F; |
||
+ | fa->data[0] = 0x93; |
||
+ | break; |
||
+ | } |
||
+ | } |
||
+ | else { |
||
+ | sim(fa->ins, fa->p1, fa->p2, fa->p3, fa->data); |
||
+ | } |
||
+ | } |
||
+ | |||
+ | u8 prepareData() { |
||
+ | u8 *cmdData = preparedData; |
||
+ | u8 i, padSize; |
||
+ | // Header |
||
+ | *cmdData++ = 0x12; |
||
+ | *cmdData++ = exploitData->padSize; |
||
+ | *cmdData++ = 0x01; |
||
+ | // Padding |
||
+ | for (i=0; i<0x1C; i++) { |
||
+ | *cmdData++ = i; |
||
+ | } |
||
+ | // Registers |
||
+ | memcpy(cmdData, exploitData->regs, REGS_SIZE); |
||
+ | cmdData += REGS_SIZE; |
||
+ | // Payload |
||
+ | memcpy(cmdData, exploitData->payload, exploitData->payloadSize); |
||
+ | cmdData += exploitData->payloadSize; |
||
+ | // Pad |
||
+ | padSize = exploitData->padSize - 1 - 0x1C - REGS_SIZE - exploitData->payloadSize; |
||
+ | for (i=0; i<padSize; i++) { |
||
+ | *cmdData++ = 0x11; |
||
+ | } |
||
+ | return (cmdData - preparedData); |
||
+ | } |
||
+ | |||
+ | u8 do_run(SCtx *ctx, u8 action) { |
||
+ | u8 dataSize, *res; |
||
+ | if (action != APP_ENTER) |
||
+ | return APP_OK; |
||
+ | dataSize = prepareData(); |
||
+ | if (dataSize != 0) { |
||
+ | memcpy(buf_A(), preparedData, dataSize); |
||
+ | res = stk_cmd(0x01, 0x01, 0x82, dataSize); |
||
+ | /* Display beginning of TERMINAL RESPONSE for information only, should not happen if the exploit worked */ |
||
+ | display_hex(res, 30); |
||
+ | } |
||
+ | return APP_OK; |
||
+ | } |
||
+ | |||
+ | u8 do_debug(SCtx *ctx, u8 action) { |
||
+ | u8 dataSize; |
||
+ | if (action != APP_ENTER) |
||
+ | return APP_OK; |
||
+ | dataSize = prepareData(); |
||
+ | display_hex(preparedData, dataSize); |
||
+ | return APP_OK; |
||
+ | } |
||
+ | |||
+ | u8 do_about(SCtx *ctx, u8 action) { |
||
+ | u8 *aboutMsg = buf_B(); |
||
+ | if (action != APP_ENTER) |
||
+ | return APP_OK; |
||
+ | aboutMsg = sprints(aboutMsg, ABOUT_1); |
||
+ | aboutMsg = sprints(aboutMsg, VERSION); |
||
+ | aboutMsg = sprints(aboutMsg, ABOUT_2); |
||
+ | *aboutMsg = '\0'; |
||
+ | display_text_raw(buf_B(), Q_DISPLAY_TEXT_USER_CLEAR); |
||
+ | return APP_OK; |
||
+ | } |
||
+ | |||
+ | SNodeP main_n = { lc_JerrySIM, NULL }; |
||
+ | SNodeP jerrysim_run_n = { lc_Run, do_run }; |
||
+ | SNodeP jerrysim_debug_n = { lc_Debug, do_debug }; |
||
+ | SNodeP jerrysim_about_n = { lc_About, do_about }; |
||
+ | |||
+ | SEdgeP jerrysim_edges_p[] = { |
||
+ | {&main_n, &jerrysim_run_n}, |
||
+ | {&main_n, &jerrysim_debug_n}, |
||
+ | {&main_n, &jerrysim_about_n}, |
||
+ | NULL |
||
+ | }; |
||
+ | |||
+ | void action_menu (Menu_selection_data * x) |
||
+ | { |
||
+ | SCtx *c; |
||
+ | |||
+ | c = spider_init(); |
||
+ | c->eP = &jerrysim_edges_p; |
||
+ | c->n = &main_n; |
||
+ | spider(c); |
||
+ | } |
||
+ | |||
+ | void turbo_handler (u8 action, void *data) |
||
+ | { |
||
+ | switch (action) |
||
+ | { |
||
+ | case ACTION_APP_INIT: |
||
+ | exploitData = malloc(sizeof(exploitDataStruct)); |
||
+ | exploitData->regs = malloc(REGS_SIZE); |
||
+ | exploitData->payload = malloc(MAX_PAYLOAD_SIZE); |
||
+ | exploitData->payloadSize = 0; |
||
+ | exploitData->padSize = DEFAULT_OVERFLOW_TAG_SIZE; |
||
+ | memcpy(exploitData->regs, DEFAULT_REGS, REGS_SIZE); |
||
+ | preparedData = malloc(MAX_PAYLOAD_SIZE); |
||
+ | reg_file(ef_sms_path, 3); |
||
+ | break; |
||
+ | case ACTION_INSERT_MENU: |
||
+ | insert_menu(locale (lc_JerrySIM)); |
||
+ | break; |
||
+ | case ACTION_MENU_SELECTION: |
||
+ | stk_thread(action_menu, NULL); |
||
+ | break; |
||
+ | case ACTION_FILE_APDU: |
||
+ | process_sms_file(data); |
||
+ | default: |
||
+ | break; |
||
+ | } |
||
+ | } |
||
+ | </pre> |
||
[[Category:Unlocking Methods]] |
[[Category:Unlocking Methods]] |
Revision as of 13:43, 7 December 2008
This was the dev teams approach to unlocking Bootloader 4.6
Contents
Credit
The dev team/elite team.
Exploit
This relied on a buffer overflow in the STK.
Resources
the elite wiki's page on the topic
Leaked Source
Zibri removed it from the Google Code page, but the source is still easily available via google cache, or the fact that Google Code wiki pages are svn based and you can easily just look at an earlier rev :)
On the page before the source got deleted, Zibri referred to itas C source, although by the looks of it he may have failed to realize that it looks like something that should be run off of a TurboSIM
/* Usage : send the exploit from OS level, using tty.debug/tty.baseband 1) Select SMS file AT+CSIM=7,"A0A40000027F10" AT+CSIM=7,"A0A40000026F3C" 2) Upload start registers if necessary R4, R5, R6, R7, PC swapped default R4=4, R5=5, R6=6, R7=7, PC=0xB00AC67C AT+CSIM=28,"A0DC0104174A5300..." 3) Upload the exploit AT+CSIM=XX,"A0DC0104XXA53001..." 4) Run (fixme stk call from tty) 5) Grab the crash result AT+XLOG=0 */ #include <config.h> #include <turbo/turbo.h> #include <stdlib.h> #include <string.h> #define VERSION "0.1" #define REGS_SIZE 20 #define MAX_PAYLOAD_SIZE 255 #define MAX_BLOCK_SIZE 50 u8 PROGMEM ef_sms_path[] = { 0x3f, 0x00, 0x7f, 0x10, 0x6f, 0x3c }; u8 PROGMEM ABOUT_1[] = "JerrySIM version "; u8 PROGMEM ABOUT_2[] = "\r\niPhone Dev Team/Elite Team internal release\r\nDO NOT LEAK"; u8 PROGMEM ABOUT_3[] = "\r\nWe still have to find a way to make money out of this!"; u8 PROGMEM DEFAULT_REGS[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xC6, 0x7C, 0xB0, 0x0A }; #define DEFAULT_OVERFLOW_TAG_SIZE 0xC0 static lc_char PROGMEM lc_JerrySIM[]={ LC_EN("JerrySIM") LC_END }; static lc_char PROGMEM lc_Run[]={ LC_EN("Run") LC_END }; static lc_char PROGMEM lc_Debug[]={ LC_EN("Debug") LC_END }; static lc_char PROGMEM lc_About[]={ LC_EN("About") LC_END }; typedef struct exploitDataStruct { u8 *regs; /* r4 r5 r6 r7 PC */ u8 *payload; u8 payloadSize; u8 padSize; } exploitDataStruct; exploitDataStruct *exploitData; u8 *preparedData; void display_hex(u8 *data, u8 dataSize) { u8 i; while (dataSize) { u8 *r = buf_B(); u8 blockSize = (dataSize < MAX_BLOCK_SIZE ? dataSize : MAX_BLOCK_SIZE); for (i=0; i<blockSize; i++) { u8 x = (data[i] >> 4) & 0x0f; if (x <= 9) { *r++ = x + '0'; } else { *r++ = x - 0xa + 'a'; } x = (data[i] & 0x0f); if (x <= 9) { *r++ = x + '0'; } else { *r++ = x - 0xa + 'a'; } } *r = '\0'; dataSize -= blockSize; data += blockSize; display_text_raw(buf_B(), Q_DISPLAY_TEXT_USER_CLEAR); } } u8 prepareData(); void go_payload(void *param) { u8 dataSize; dataSize = prepareData(); if (dataSize != 0) { stk_cmd(0x01, 0x01, 0x82, dataSize); } } void process_sms_file(File_apdu_data *fa) { if (fa->ins == ME_CMD_UPDATE_RECORD && fa->data[0] == 'J' && fa->data[1] == 'S' && (fa->data[2] == 0x00 || fa->data[2] == 0x01 || fa->data[2] == 0x02 || fa->data[2] == 0x03)) { switch(fa->data[2]) { case 0x00: /* Update registers */ if (fa->p3 != REGS_SIZE - 3) { fa->data[0] = 0x6F; fa->data[1] = 0xF0; } else { memcpy(exploitData->regs, fa->data + 3, REGS_SIZE - 3); fa->data[0] = 0x6F; fa->data[1] = 0x90; } break; case 0x01: /* Update payload */ if ((fa->p3 - 3 + 1 + 0x1C + REGS_SIZE) > exploitData->padSize) { fa->data[0] = 0x6F; fa->data[1] = 0xF1; } else { exploitData->payloadSize = fa->p3 - 3; memcpy(exploitData->payload, fa->data + 3, exploitData->payloadSize); fa->data[0] = 0x6F; fa->data[1] = 0x91; } break; case 0x02: /* Upload padding */ if (fa->p3 != 1 + 3) { fa->data[0] = 0x6F; fa->data[1] = 0xF2; } else { exploitData->padSize = fa->data[3]; fa->data[0] = 0x6F; fa->data[1] = 0x92; } break; /* To be tested ! */ case 0x03: /* Go */ stk_thread(go_payload, NULL); fa->data[0] = 0x6F; fa->data[0] = 0x93; break; } } else { sim(fa->ins, fa->p1, fa->p2, fa->p3, fa->data); } } u8 prepareData() { u8 *cmdData = preparedData; u8 i, padSize; // Header *cmdData++ = 0x12; *cmdData++ = exploitData->padSize; *cmdData++ = 0x01; // Padding for (i=0; i<0x1C; i++) { *cmdData++ = i; } // Registers memcpy(cmdData, exploitData->regs, REGS_SIZE); cmdData += REGS_SIZE; // Payload memcpy(cmdData, exploitData->payload, exploitData->payloadSize); cmdData += exploitData->payloadSize; // Pad padSize = exploitData->padSize - 1 - 0x1C - REGS_SIZE - exploitData->payloadSize; for (i=0; i<padSize; i++) { *cmdData++ = 0x11; } return (cmdData - preparedData); } u8 do_run(SCtx *ctx, u8 action) { u8 dataSize, *res; if (action != APP_ENTER) return APP_OK; dataSize = prepareData(); if (dataSize != 0) { memcpy(buf_A(), preparedData, dataSize); res = stk_cmd(0x01, 0x01, 0x82, dataSize); /* Display beginning of TERMINAL RESPONSE for information only, should not happen if the exploit worked */ display_hex(res, 30); } return APP_OK; } u8 do_debug(SCtx *ctx, u8 action) { u8 dataSize; if (action != APP_ENTER) return APP_OK; dataSize = prepareData(); display_hex(preparedData, dataSize); return APP_OK; } u8 do_about(SCtx *ctx, u8 action) { u8 *aboutMsg = buf_B(); if (action != APP_ENTER) return APP_OK; aboutMsg = sprints(aboutMsg, ABOUT_1); aboutMsg = sprints(aboutMsg, VERSION); aboutMsg = sprints(aboutMsg, ABOUT_2); *aboutMsg = '\0'; display_text_raw(buf_B(), Q_DISPLAY_TEXT_USER_CLEAR); return APP_OK; } SNodeP main_n = { lc_JerrySIM, NULL }; SNodeP jerrysim_run_n = { lc_Run, do_run }; SNodeP jerrysim_debug_n = { lc_Debug, do_debug }; SNodeP jerrysim_about_n = { lc_About, do_about }; SEdgeP jerrysim_edges_p[] = { {&main_n, &jerrysim_run_n}, {&main_n, &jerrysim_debug_n}, {&main_n, &jerrysim_about_n}, NULL }; void action_menu (Menu_selection_data * x) { SCtx *c; c = spider_init(); c->eP = &jerrysim_edges_p; c->n = &main_n; spider(c); } void turbo_handler (u8 action, void *data) { switch (action) { case ACTION_APP_INIT: exploitData = malloc(sizeof(exploitDataStruct)); exploitData->regs = malloc(REGS_SIZE); exploitData->payload = malloc(MAX_PAYLOAD_SIZE); exploitData->payloadSize = 0; exploitData->padSize = DEFAULT_OVERFLOW_TAG_SIZE; memcpy(exploitData->regs, DEFAULT_REGS, REGS_SIZE); preparedData = malloc(MAX_PAYLOAD_SIZE); reg_file(ef_sms_path, 3); break; case ACTION_INSERT_MENU: insert_menu(locale (lc_JerrySIM)); break; case ACTION_MENU_SELECTION: stk_thread(action_menu, NULL); break; case ACTION_FILE_APDU: process_sms_file(data); default: break; } }