The MobileSafari comes with iPhone doesn’t allow to open local file, you’ll get the following error when you try to enter a file:/// URL:
Safari can't open the page because it is a local file.
This can be easily patched. This article describes how to patch MobileSafari to make it open local files (e.g. PDF). I’ll use the 1.1.3’s MobileSafari as an example and try to explain how to patch it.
If you don’t want to know the technical details, then just download the following patched file:
Copy it over your current MobileSafari at /Applications/MobileSafari.app/ (backup the old one in case something’s wrong), and you can now open the local file in MobileSafari like this:

Where to Start
First, fire up the IDA Pro and load in the MobileSafari, now think about the NSURL class, there’s a method named isFileURL which is the common method to check if a URL refers to a local file, so let’s look for it in the Strings subview, then open the Chart of xrefs to graph in IDA Pro, as shown below:

From the chart we know there’re two methods refering to this string, so there may be two places need to be patched. Record the method names: sub_23060 and sub_22EE4.
Examine the First Method
Now let’s start from the first method: sub_23060. By checking the string in instance method (labeled as __inst_meth), we know this method’s realname is:
_decidePolicyForAction:request:frame:newFrameName:decisionListener:
We don’t need to understand the whole method at this time, as we just need to know how and where it checks the URL. So let’s find it out, it’s at offset 0×00231D4. With a few examination we can know it’s algorithm is like this (I add some labels and comments):

From the checking algorithm, we know if we change the BEQ go_on to B go_on, it will allow any URL, and this is exactly what we need. So we need to change byte at offset 0×000231EB from 0×0A to 0xEB 0xEA (sorry, typo).
Notice the instruction MOV R0, R8, how do we know what is in R8? Well, it’s from the previous function call, roll back some lines, it’s at the very beginning of the method, as shown below:

Examine the Second Method
Now let’s go to the second method sub_22EE4, again we follow the references to it and will soon find its real name is:
webView:resource:willSendRequest:redirectResponse:fromDataSource
This method is short, so I give the complete disassembly here (with some customized labels and comments):

Then we look for the the location that refers to the isFileURL string, we’ll find it at offset 0×00022F2C. The algorithm is also simple:
If a file URL is found, return null, otherwise return the request
So we just need to NOP that MOVNE R4, 0 and it will always return the request pointer, change the four bytes (00 40 A0 13) at offset 0×00022F3C to all 0’s does the trick here.
Summary
From the above examination, we know we need to patch two methods, actually two instructions. The final patch is shown here:
Search for differences 1. G:\iPhone Stuffs\MobileSafari\1.1.3\Original\MobileSafari: 454,436 bytes 2. G:\iPhone Stuffs\MobileSafari\1.1.3\Patched\MobileSafari: 454,436 bytes Offsets: hexadec. 21F3D: 40 00 21F3E: A0 00 21F3F: 13 00 221EB: 0A EA 4 difference(s) found.
And this ends our MobileSafari patch.
NOTICE: sometimes IDA Pro can’t successfully detect all cross-references, in such a case, we have to take more time finding out all the cross-references manually. Fortunately, in our example, this does not happen :)

12 Comments
Excellent guide George, following your instructions I found the
required places to patch MobileSafari for version 1.1.2, cheers.
Comparing files MobileSafari and MobileSafari.patched
00021621: 40 00
00021622: A0 00
00021623: 13 00
000218CF: 0A EB
Hi User, can you share your patched version of 1.1.2 Safari? thanks in advance.
Thank for your guide.
Brilliant!
What about the user agent string? I think it’s hardcoded in the WebKit framework, but I wonder if there is an option to use an alternate, e.g. if a certain key exists in the preferences file…
Done patching 1.1.2 version, thanks!
Hello George. I am very interested in the hex editing that you are doing with the iPhone, but I am new to Assembly, IDA Pro, and the like. If you don’t mind could you explain in lay mens terms, for example, why 0A would turn to EA? What does EA mean? Thank you in advance, I look forward to your response.
You need to read the ARM reference manuals. Basically, what you’re looking for is a way to convert Assembly Language instruction into Machine Language opcode/operands (normally assembler does this conversion), and the reference manual is the document you need to do this conversion manually.
Beautiful!
I just fixed my mobilesafari 1.1.2 with your instructions and it works with local files. All I did was open mobilesafari with a hex editor and changed the values as shown above by User: like this
00021621: 40 00
00021622: A0 00
00021623: 13 00
000218CF: 0A EB
Hi,
This patch was so helpfull for 1.1.4 … and i’m missing it every day since the upgrade to 2.0. Does anybody know if there’s a patch for 2.0 available. That would be really great. Many thanks!
I’m a noob, can you please ModiFy my safari version (2.0):
I’ve jailbreaked it, but there’s not yet a patch for firmware version 2.0, can you try it for me?
My executable is:
http://rapidshare.com/files/136003337/MobileSafari.zip.html
Thanks!
I managed to get this working on the 2.0 SDK (I haven’t downloaded 2.01 yet).
Procedure was quite similar, although IDA coulnd’t find isFileURL so I looked differently.
Anyway:
fc /b MobileSafari MobileSafari.orig
Comparing files MobileSafari and MOBILESAFARI.ORIG
000246D7: EA 1A
000249F3: EA 0A
Just two bytes to change!
Don’t forget to run ldid to re-sign MobileSafari after uploading the new version onto the iPhone:
apt-get install ldid
ldid -S MobileSafari
Note that I had to temporary move MobileSafari onto /var/root in order to run ldid - it would crash if I tried to run it directly from /Applications/MobileSafari.app. Probably because it ran out of space?
Anyway, do this at your own risk, and make a backup of the original version before making any change!
If Safari exits as soon as it opens a URL, it’s a sure sign you didn’t sign it…
enoHp1