Gunlock

From The iPhone Wiki
Jump to: navigation, search

It was the first implementation of the Minus 0x20000 with Back Extend Erase exploit. In the first version of this unlock, Airplane Mode had to be switched on. If it was not, your phone would enter a boot loop upon updating to 1.1.3.

Credit

geohot

Instructions

  1. Download gunlock and the secpack from http://iphonejtag.blogspot.com/, and the 4.02.13 fls from http://george.zjlotto.com/index.php/baseband/
  2. Downgrade your phone to 1.0.2. See all the great tutorials online to do this. Your baseband won't be downgraded, this is normal. This will probably work on other versions too, but 1.0.2 doesn't lose wifi on bb access.
  3. Kill CommCenter and run "gunlock secpack ICE04.02.13_G.fls"
  4. Reload CommCenter. For some reason my phone was in brick mode. Use the elite team bricktool to get out.
  5. Enjoy your 1.1.2 OTB unlocked iPhone

if you dont want to downgrade to 1.0.2 try

  1. unlock and the secpack from http://iphonejtag.blogspot.com/ or the blog and the 4.02.13 fls from http://george.zjlotto.com/index.php/baseband/
  2. Upgrade to 1.1.2 and jailbreak ( must not be on 1.1.3 )
  3. install ssh
  4. upload all downloaded files to /usr/bin and set all permissions to 755
  5. chmod +x gunlock
  6. chmod +x gunlock.c
  7. Log to your phone trough terminal and follow this commands one by one:
  8. ssh root@iPhone ip address
  9. password: alpine
  10. launchctl unload /System/Library/LaunchDaemons/com.apple.CommCenter.plist
  11. cd /usr/bin
  12. /gunlock secpack ICE04.02.13_G.fls
  13. launchctl load /System/Library/LaunchDaemons/com.apple.CommCenter.plist

version info

1.1.2 [1]

1.1.3 [2]

the exploit was updated for 1.1.4 ( removed the need for a new secpack ) [3] or [4]

Road blocks

  • Send the 1.1.3 secpack to erase 1.1.2
  • Second exploit, the fake secpack erase range
    • If a valid secpack is present in 0x3C0000, the phone won't boot. And since endpack doesn't work, I needed to find another way.

source code

//geohot's 112 otb unlocker
//this code is GPLed
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <IOKit/IOKitLib.h>
#include <sys/ioctl.h>
#include <strings.h>
#include <errno.h>
#include <mach/mach_time.h>
struct termios term;
int hlen,t,u,fp;
unsigned char *data, *secpack;
FILE *f;
int adrcount;
int openport(int speed)
{
 int fd = open("/dev/tty.baseband", O_RDWR | 0x20000 | O_NOCTTY);
 unsigned int blahnull = 0;
 unsigned int handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
 if(fd == -1)
 {
   fprintf(stderr, "%i(%s)\n", errno, strerror(errno));
   exit(1);
 }
 ioctl(fd, 0x2000740D);
 fcntl(fd, 4, 0);
 tcgetattr(fd, &term);
 ioctl(fd, 0x8004540A, &blahnull);
 cfsetspeed(&term, speed);
 cfmakeraw(&term);
 term.c_cc[VMIN] = 0;
 term.c_cc[VTIME] = 5;
 term.c_iflag = (term.c_iflag & 0xFFFFF0CD) | 5;
 term.c_oflag =  term.c_oflag & 0xFFFFFFFE;
 term.c_cflag = (term.c_cflag & 0xFFFC6CFF) | 0x3CB00;
 term.c_lflag =  term.c_lflag & 0xFFFFFA77;
 term.c_cflag = (term.c_cflag & ~CSIZE) | CS8;
 term.c_cflag &= ~PARENB;
 term.c_lflag &= ~ECHO;
 tcsetattr(fd, TCSANOW, &term);
 ioctl(fd, TIOCSDTR);
 ioctl(fd, TIOCCDTR);
 ioctl(fd, TIOCMSET, &handshake);
 return fd;
}
void resetbaseband()
{
 kern_return_t   result;
 mach_port_t     masterPort;
 result = IOMasterPort(MACH_PORT_NULL, &masterPort);
 CFMutableDictionaryRef matchingDict = IOServiceMatching("AppleBaseband");  
 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
 io_connect_t conn;
 result = IOServiceOpen(service, mach_task_self(), 0, &conn);
 result = IOConnectCallScalarMethod(conn, 0, 0, 0, 0, 0);
 IOServiceClose(conn);
}
void getheader(unsigned int timeout)
{
fd_set nfp;
FD_ZERO(&nfp);
FD_SET(fp, &nfp);
struct timeval tv;
tv.tv_sec=0;
tv.tv_usec=timeout*1000;
hlen=0;
while(select(fp+1,&nfp,0,0,&tv)>0)
{
hlen+=read(fp,data+hlen, 0x10064-hlen);
//printf("Attempting to read[%d]...%x %x\n",hlen,data[0],data[1]);
}
}
void getcommand()	//will return when done
{
int maxlength=6;
hlen=0;
while(hlen<maxlength)
{
hlen+=read(fp,data+hlen, 6);
}
maxlength+=data[5]*0x100+data[4]+4;	//2 for checksum and 2 for end
while(hlen<maxlength)
{
hlen+=read(fp,data+hlen, 0x10064-hlen);
}
}
struct termios options;
void openbaseband()
{
int t1=0;
int t2=0x126;
fp=open("/dev/tty.baseband",0x20002);
ioctl(fp,0x2000740D);
fcntl(fp,4,0);
tcgetattr(fp,&options);
ioctl(fp,0x8004540A,&t1);
cfsetspeed(&options,115200);
cfmakeraw(&options);
options.c_cc[16]=0;
options.c_cc[17]=5;
options.c_iflag=(options.c_iflag | 0x5) & 0xFFFFF0CD;
options.c_oflag=options.c_oflag & 0xFFFFFFFE;
options.c_cflag=(options.c_cflag | 0x3CB00) & 0xFFFFEFFF;
options.c_lflag=options.c_lflag & 0xFFFFFA77;
tcsetattr(fp,0,&options);
ioctl(fp,0x20007479);
ioctl(fp,0x20007478);
ioctl(fp,0x8004746D,&t2);
printf("Opened: /dev/tty.baseband\n");
}
void printbuffer()
{
for(t=0;t<hlen;t++)
{
if(t!=0&&t%16==0) printf("\n");
printf("%2.2X ", data[t]);
}
if(hlen>0)
printf("\n");
}
struct cmd_pkt{
unsigned short int w02;
unsigned short int cmd;
unsigned short int data_size;
};
struct cmd_pkt_end{
unsigned short int checksum;
unsigned short int w03;
};
struct cmd_pkt mycmdpkt;
struct cmd_pkt_end mycmdpktend;
void cmd_write()
{
mycmdpkt.w02=2;
mycmdpktend.w03=3;
mycmdpktend.checksum=0;
for(t=0;t<mycmdpkt.data_size;t++)
{
mycmdpktend.checksum+=data[t];
}
mycmdpktend.checksum+=mycmdpkt.cmd+mycmdpkt.data_size;
write(fp,&mycmdpkt,6);
write(fp,data,mycmdpkt.data_size);
write(fp,&mycmdpktend,4);
}
void usage()
{
printf("geohot's 112 otb unlocker...\n");
}
int enterinteractive()
{
tcgetattr(fp,&options);			//baud rate upped
cfsetspeed(&options,115200);
tcsetattr(fp,0,&options);
printf("Waiting for data...\n");
do
{
data[0]=0x60; data[1]=0x0D;
if(write(fp,data,2)==-1)
 {
printf("Can't write\n");
return -1;
}
printf("Attempt...\n");
getheader(500);
} while(hlen==0||data[0]!=0xb);
printf("Got Header: %d %2.2x %2.2x\n",hlen, data[0], data[1]);
return 0;
}
void increasebaudrate()
{
printf("Increasing baud rate...\n");
mycmdpkt.cmd=0x82;
mycmdpkt.data_size=4;
data[0]=0x00; data[1]=0x10; data[2]=0x0E; data[3]=0x00;		//115200 bps
cmd_write();
getcommand();
printbuffer();
tcgetattr(fp,&options);			//baud rate upped
cfsetspeed(&options,921600);
tcsetattr(fp,0,&options);
}
void getflashid()
{
printf("Get flash ID\n");
mycmdpkt.cmd=0x801;
mycmdpkt.data_size=0;
cmd_write();
getcommand();
//printbuffer();
}
void cfistage1()
{
printf("CFI Stage 1\n");
mycmdpkt.cmd=0x84;
mycmdpkt.data_size=2;
data[0]=0; data[1]=0;
cmd_write();
getcommand();
//printbuffer();
}
void cfistage2()
{
printf("CFI Stage 2\n");
mycmdpkt.cmd=0x85;
mycmdpkt.data_size=0;
cmd_write();
getcommand();
//printbuffer();
}
void address(unsigned int addr, int print)
{
adrcount=addr;
if(print==0) printf("Address to 0x%X  ",addr);
mycmdpkt.cmd=0x802;
mycmdpkt.data_size=4;
memcpy(data,&addr,4);
cmd_write();
getcommand();
if(print==0) printbuffer();
}
void sendsecpack(char *secpack)
{
printf("Sending secpack... ");
mycmdpkt.cmd=0x204;
mycmdpkt.data_size=0x800;
memcpy(data,secpack,0x800);
cmd_write();
getcommand();
printbuffer();
}
void bbread(short int len)
{
mycmdpkt.cmd=0x803;
mycmdpkt.data_size=2;
memcpy(data,&len,2);
cmd_write();
getcommand();
printbuffer();
}
void bbwrite(unsigned int size, int print)	//put crap in data already
{
if(print==0) printf("Writing: 0x%X  ",adrcount);
mycmdpkt.cmd=0x804;
mycmdpkt.data_size=size;
cmd_write();
getcommand();
if(print==0) printbuffer();
adrcount+=size;
}
int erase(unsigned int start, unsigned int end, int debug)
{
printf("Erasing: 0x%X-0x%X  ",start, end);
mycmdpkt.cmd=0x805;
mycmdpkt.data_size=8;
memcpy(data,&start,0x4);
memcpy(&data[4],&end,0x4);
cmd_write();
getcommand();
printbuffer();
printf("Waiting for erase to finish...\n");
do{
mycmdpkt.cmd=0x806;
mycmdpkt.data_size=2;
data[0]=0; data[1]=0;
cmd_write();
getcommand();
if(debug==0) printbuffer();
usleep(100000);
}while(data[6]==0);
if(debug!=0) printbuffer();
if(data[9]!=0x31) 
{
//printf("Erase failed!\n");
return -1;
}
return 0;
}
void endsecpack()
{
printf("End Secpack  ");
mycmdpkt.cmd=0x205;
mycmdpkt.data_size=2;
data[0]=0; data[1]=0;
cmd_write();
getcommand();
printbuffer();
}
void readmem(unsigned int addr)		//you need a patched bootloader :)
{
//printf("procx102\n");
unsigned int memdata;
mycmdpkt.cmd=0x102;
mycmdpkt.data_size=4;
memcpy(data,&addr,0x4);
cmd_write();
getcommand();
memcpy(&memdata,&data[6],0x4);
printf("[0x%X]=0x%X\n",addr,memdata);
//printbuffer();
}
#define patchloc 0x2359d4	//this is for 4.02.13
int main(int argc, char *argv[])
{
usage();
if(argc<3) { printf("usage: %s <113secpack> <112fls>\n",argv[0]); return -1;}
resetbaseband();
fp = openport(115200);
//FILE *secpack=fopen(argv[1],"rb");
data=(unsigned char *)malloc(70000);
if(enterinteractive()==-1) return -1;
printf("Bootloader version: %s\n",&data[0xD]);
if(data[5]!=4)
{
printf("Incorrect bootloader version\n");
return -1;
}
increasebaudrate();
cfistage1();
cfistage2();
char *rsecpack=(char *)malloc(0x800);
FILE *secpack=fopen(argv[1],"rb");
fread(rsecpack,1,0x800,secpack);
fclose(secpack);
//Send the 1.1.3 secpack to erase 1.1.2
sendsecpack(rsecpack);
if(erase(0xA0020000, 0xA03BFFFE,1)==-1) {
printf("Erase failed\n");
printf("Hang on...we can fix that\n");
const char efakesec[]={0x00,0x00,0x02,0xA0,0x00,0x00,0x3D,0x00,0x00,0x00,0x3D,0x00,0x00,0x00,0x00,0x00};	//full range including main fw...
//2nd exploit variant for >=1.1.3
memcpy(&rsecpack[0x780],efakesec,0x10);
sendsecpack(rsecpack);
endsecpack();
erase(0xA03D0000,0xA03F0000,1);	//the only secpack free allowed erase :)
printf("Okay, lets try that again...\n");
secpack=fopen(argv[1],"rb");	//reread
fread(rsecpack,1,0x800,secpack);
fclose(secpack);
sendsecpack(rsecpack);
if(erase(0xA0020000, 0xA03BFFFE,1)==-1) {
printf("Hmm...what did you do?");
return -1;
}
}
//First exploit, the -0x20000 exploit
//This writes the firmware, in all its unsigned glory
//I guess Apple figured -0x400 was simple, -0x20000 is *much* harder
address(0xA0000000,0);		//-0x20000, like i said :)
FILE *bb=fopen(argv[2],"rb");
fseek(bb,0x9a4,SEEK_SET);		//skip bbupdater data and secpack
int a,rc=0;
do{
a=fread(data,1,0x800,bb);
if(rc<patchloc&&patchloc<(rc+a))	//patch the firmware
{
printf("Patching...\n");
data[patchloc-rc+3] = 0xe3;
data[patchloc-rc+2] = 0xa0;
data[patchloc-rc+1] = 0x00;
data[patchloc-rc]   = 0x01; 
}
if(rc%0x10000==0||a!=0x800) printf("Wrote: 0x%x 0x%x\n",a,rc);
if(a>0)
bbwrite(a,1);		//write like hell
rc+=a;
}while(a>0);
//Second exploit, the fake secpack erase range
//If a valid secpack is present in 0x3C0000, the phone won't boot
//And since endpack doesn't work, I needed to find another way
const char fakesec[]={0x00,0x00,0x3C,0xA0,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00};	//not 0xA03D0000
memcpy(&rsecpack[0x780],fakesec,0x10);
sendsecpack(rsecpack);
endsecpack();
erase(0xA03D0000,0xA03F0000,1);	//the only secpack free allowed erase :)
close(fp);
resetbaseband();
printf("Enjoy your unlocked iPhone...\n");
return 0;
}