Something I Learned During iLiberty Development

I’ve been a lazy guy and love to use already-made tools but hate writing it myself. I’m fine with the CLI tools for quite a long time during iPhone hacking process, but there’s one thing that annoys me every now and then, each tool has very specific purpose and hard to extend, it’s not a problem for people that use their iPhone as ‘phone’. For me, it’s more a computer with an interesting operating system than a phone, and I often do some experiments on it, so I need a way to quickly re-install the phone to a given state, as I said in previous article, there’s no such a tool that fulfills my needs, and this triggered my iLiberty project.

Okay, now iLiberty initial revision has been released, and I have co-operated with AViegas to share the same core scripts between iPlus and iLiberty (We actually have co-operated for quite some time), the next revision will use iPlus core scripts.

Before I start to write iLiberty, there’re actually three implementation methods for me to choose:

1. Put everything into ramdisk, and do all the job through one boot
2. Ramdisk does some jobs but leaves the others in the next boot
3. Ramdisk does almost nothing and all jobs are done in the next boot

The first choice is great, as it does everything in one turn and needs no multiple boots, ZiPhone (developed by Zibri) uses this method. However, the restrictions are obvious: ramdisk size can not exceed 32MB, this includes the prepended bytes (the prepended data can be as few as 0×990000 bytes, the choice of 0xCC2000 is arbitrary, might be “an attempt at steganography” — quoted from pumpkin), so the maximum possible size is around 23MB. Due to the space restrictions, it’s usage is quite limited. So this method can only do very simple jobs, like jailbreak, activation, unlock some specific baseband version, etc. Besides the space limitation, there’s another severe potential problem, when booting with ramdisk, if too much memory is used, memory will be corrupted eventually (because of overlapping I guess) and thus halt the phone, this weird behavior was first found by AViegas, a normal system doesn’t have this problem. This can be easily replayed by trying to extract some very large files, from my experience, extracting three 20MB files guaranteed to halt the phone.

The second choice is my choice in iLiberty initial revision, the ramdisk does all those jobs that normally require a reboot, e.g. to add AFC2 (iPHUC/iBrickr requires it), Services.plist needs to be patched, then a reboot is required for it to work. This method minimizes the chance to reboot, and also offers the flexibility. However, the severe memory problem in method one also happens in this method, the phone will halt when memory are over used.

Now the third choice, in this method ramdisk basically does nothing (or very few jobs), it sets up a minimal BSD environment for scripts to run, then put a service on iPhone, when phone reboots, the service will be launched and then uses the minimal BSD tool set to finish the jobs. This method is by far the most reliable one, and can satify all the current needs in iphone hacking. No memory overlapping problem, not space restrictions. The only drawback is, for some works to be done, several additional reboots might be needed. iPlus (developed by AViegas) uses this method, and it does its job very well, there’re some minor issues though, but in general it’s a great tool.

After some chatting with AViegas, I’ve decided to modify iLiberty to be compatible with iPlus core scripts, thus we don’t have to waste time doing the same thing twice. The point in the implementation is using AFC calls to transfer files between iPhone and PC, and to put iPhone into specific state (normal, recovery, dfu). It took me some time to port from Visual C++ style codes to Borland C++ Builder codes. The most important part buries in the privateFunction.c, there’re four very important functions, they were discovered early by DevTeam. Among the four functions there’re some assembly codes, these codes sets the parameter in register and in stack, then calls iTunes’ internal functions. One of such code snippet is (in VC++ inline assembly syntax):

#if defined (WIN32)
asm("movl %3, %%esi\n\tpush %1\n\tcall *%0\n\tmovl %%eax, %2"
      :
      :"m"(priv_sendCommandToDevice),  "m"(cfs), "m"(retval), "m"(rdev)
      :);

The code can be converted to the following more user-friendly code in BCB inline assembly syntax:

asm {
    mov esi, rdev
    push cfs
    call priv_sendCommandToDevice
    mv retval, eax
}

Please notice the difference between operands order, VC++ reversed the operands order, so mov rdev, esi actually means “store rdev value into esi register”, but in BCB it has to be mov esi, rdev.

When porting the above code from VC++ to BCB, there’s a catch here. The VC++ and BCB defaults to different calling conventions, so they don’t have the same stack frame. To make long words short, the result is: same code in VC++ might have different result when porting to BCB. I didn’t realize this until the test program crashed at sendCommandToDevice, with the help of OllyDbg I finally found out the stack was not ok after priv_sendCommandToDevice returns. Knowing the crash reason, the solution is simple, increase stack pointer by 4, like showing below:

asm {
    mov esi, rdev
    push cfs
    call priv_sendCommandToDevice
    add sp, 4
}

Note the mov eax, retval was intentionally dropped, why? This is because of the differences between compilers. With VC++ compiler, it adds a mov retval, eax before function returns, so storing eax (return value from priv_sendCommandToDevice) into retval ensures the correct return value is in eax when function returns. But in BCB, the compiler doesn’t append such “smart” code , so there’s no need to save eax into retval (Which compiler would you like? Borland or Microsoft compiler ? :).

Another problem happens in AFC itself, it’s not very stable and might not always work, transfering many small files are not reliable, normally a disconnection then reconnection can solve it. To get the best result, it’s better to pack the small files into a single big archive, and let script extracting it on iPhone.

There’re some other traps/tricks in iLiberty development, I’m sort of tired now and might put them in other articles later.


6 Comments

  1. fgsch
    Posted March 13, 2008 at 9:37 pm | Permalink

    btw, the assembler reversal looks due to Intel vs AT&T syntax.

  2. Q
    Posted March 14, 2008 at 9:59 pm | Permalink

    Zibri’s 0xcc2000 offset seems to be completely arbitrary. I have been able to boot a custom ramdisk using any offset as long as it was at least 0×990000

  3. Posted March 16, 2008 at 11:31 am | Permalink

    very attractive I have to admit. Tho would have been nicer if your application supports xp x64.
    ziphone is fully functionable under my Windows XP x64 with correct AppleMobileDevice x64 driver installed. iLiberty, in another hand, failed when sending ramdisk to the iphone.

  4. Posted March 16, 2008 at 10:25 pm | Permalink

    Hey George, shoot me an e-mail at willstrafach@gmail.com. I have got something you may be very interested in. Please email me from your domain name, so I know that it is valid, as this is not something that just anyone is allowed to have.

  5. Posted March 17, 2008 at 2:03 am | Permalink

    the 0xcc2000 was an attempt at steganography, I guess. its decimal value is 13377536, which starts with leet and who knows what it ends with… leettseg? leetaseg? that’s the problem with using lossy text compression algorithms :P

  6. Posted March 17, 2008 at 11:21 am | Permalink

    Q & pumpkin,

    Yeah, you’re right, that 0xCC2000 is not the only choice, I like the idea of ‘an attemp at steganography” :D

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Site hosted by