iPhone Piracy 101: Steps to Prevent it
>> Sunday, September 06, 2009
**This is a guest article by Will Strafach. Unlike you, this person got off his ass and earned some $$ writing about what he loves. He has accomplished something with his life, he has written for MrCracker.com . What have you done? Click Here to start.**
Now that you know how iPhone piracy works, (if not, click here to read previous article), you probably want to know how you can prevent it. This article will tell you that, but please note this. This is getting published for all to see, including the people that want to crack your application. If I provide you with code or a method to do a certain check in here, do not just copy it verbatim, tweak it a little so that the crackers don’t know exactly what to look for.
Since we know that crackers are going to crack your app anyway, we do not want to look at this in a “we need to stop them” way. You must know that it will happen. We need to think of this in a “hold them off as long as possible” way. The first step would be obfuscation, to confuse them. Save the code attached to the end of this post and save it In a file called “iPhoneOS_swi.S”. Include it in one of your projects and, for example, you want a discrete exit(), simply call swi_exit(); from your code. Crackers will soon catch on to this, but it is at least better then flat out and obviously calling exit(). This will at least cause some confusion. If you want to try further obfuscation, use swi_exit_obfuscated(), but change it around a bit so people can’t do a simple byte search to patch it. I have not tested that one yet, but in theory it should change the “NOP” to “SWI 0×11” in memory. Usually, kernel restrictions block this type of obfuscation, but funnily enough the patch that is needed for WinterBoard and such to work, is what allows this trick to work, in theory. Another less obvious thing you can check is if the app is running as root, which it normally should not be unless a cracker was running it in GDB via SSH like they normally do. So use something like the swi_getgid() to check if it is running as 0, which is root, and if so swi_exit(). Again, I must stress to play with this a bit, because if you do it exactly then it will be obvious for the crackers, as I can safely say they will read this article.
Now, above I am talking about how to exit the app without the cracker seeing the call directly in IDA, but you are probably thinking, “But chronic, in what cases would I actually need to exit the application? What kind of checks can I do?”. This is where things get a little shady. If I specifically give out checks to use, they are useless since they are public and they will be looked for. Instead, I will give you some tips…
- stringWithFormat: is your friend. Use it to construct a string in a buffer letter by letter instead of having the whole string there in your code, easily searchable in IDA Pro. It is comparable to the sprintf(); of Objective-C, you could almost say.
- Excessively use stringWithFormat: to “obfuscate” strings that do other things in your application, even the text of an AlertView or something. The goal would be to annoy the cracker when looking for all of the calls to stringWithFormat:, maybe even to the point where he would not try to take that shortcut if you use it enough times for legitimate strings.
- Keep in mind that Info.plist is modified. You can check the size, the existence of the “SignerIdentity” key…use your imagination. The crackers /need/ to modify this file, so use that to your advantage.
01.
/*
02.
* iPhoneOS_swi.S
03.
*
04.
* Created by Will Strafach on 5/23/09
05.
* Copyright 2009 Chronic Dev. All rights reserved.
06.
*
07.
* Mini-License: Keep this header here, do not modify it or anything,
08.
* and you can use this in your projects. Also, I grant MrCracker.com
09.
* permission to use this in their "iPhone Piracy 101" article.
10.
*/
11.
12.
.global _swi_exit
13.
.global _swi_exit_obfuscated
14.
.global _syscall_exit
15.
.global _syscall_chmod
16.
.global _syscall_chown
17.
.global _syscall_getpid
18.
.global _syscall_getuid
19.
.global _syscall_geteuid
20.
.global _syscall_access
21.
.global _syscall_getegid
22.
.global _syscall_getgid
23.
24.
_swi_exit:
25.
SWI 0x11
26.
BX LR
27.
28.
_swi_exit_obfuscated:
29.
MOV R0, #0x11
30.
STRB R0, [PC,#0x10]
31.
MOV R0, #0x00
32.
STRB R0, [PC,#0x8]
33.
STRB R0, [PC,#0x4]
34.
MOV R0, #0xEF
35.
STRB R0, [PC,#-0x4]
36.
NOP
37.
BX LR
38.
39.
_syscall_exit:
40.
MOV R12, #1
41.
SWI 0x80
42.
BX LR
43.
44.
_syscall_chmod:
45.
MOV R12, #15
46.
SWI 0x80
47.
BX LR
48.
49.
_syscall_chown:
50.
MOV R12, #16
51.
SWI 0x80
52.
BX LR
53.
54.
_syscall_getpid:
55.
MOV R12, #20
56.
SWI 0x80
57.
BX LR
58.
59.
_syscall_getuid:
60.
MOV R12, #24
61.
SWI 0x80
62.
BX LR
63.
64.
_syscall_geteuid:
65.
MOV R12, #25
66.
SWI 0x80
67.
BX LR
68.
69.
_syscall_access:
70.
MOV R12, #33
71.
SWI 0x80
72.
BX LR
73.
74.
_syscall_getegid:
75.
MOV R12, #43
76.
SWI 0x80
77.
BX LR
78.
79.
_syscall_getgid:
80.
MOV R12, #47
81.
SWI 0x80
82.
BX LR