"Resisting App Pirates" - by Peter D. Gray, co-founder of Ripe Apps Inc. Presented at iOSTO #3 in Toronto, at the Pilot on Jan. 11.
www.iosto.ca
www.ripeapps.com
2. Resisting App Piracy
Background
Your apps may be pirated!
• Google "appname.ipa", but also search Cydia and other darker areas
• Flurry and Game Center still work on pirated apps.
• Many bloggers have reported analytics pointing to high piracy rates; especially games.
This talk is about what to do about it...
3. Resisting App Piracy
Philosophy
My Attitude
• It's an arms race which ultimately can't be won.
• I have better and more interesting things to do... But we can make it harder.
• Fully automated "crackers" must be stopped, as a duty to society.
• Jailbroken phones are okay, as long as they pay for my app.
Concerns
• No help from Apple; prohibited in Mac AppStore, but open issue on iOS.
• False positives are huge PR disaster (paying customers affected).
• Detection is focus, then behave differently:
- do not: rm -rf /
- keep plausible deniability (oops, silly bug)
- be cute, it helps if you get it wrong
4. Resisting App Piracy
Methods
Weak Methods
• check running as root: ASSERT(getuid() != 0);
- false positive on jailbroken devices
- already worked-around, may be obsolete technique
• looking at the bundle contents:
- bundle is modified by apple after review, can't checksum before we submit
- simple presence checks easily worked-around
My Approach
• all crack methods involve decrypting the binary
• GDB is used in the 'cracking' process, deny them that tool.
• I like checksums on binary code. It’s old-school but it works.
5. Resisting App Piracy
isPirate() Steps
1) Deny them use of GDB.
2) Verify checksum of binary running in memory.
3) Verify binary running was encrypted when loaded.
But...
• repeat above at random times
• make "isPirated" global flag non-trivial to force (ie. not just a flag)
• check flag very often, but do checksum less often
6. Resisting App Piracy
Deny GDB
• call: ptrace(PT_DENY_ATTACH...
• but hide ptrace() call, since its purpose is obvious
• does not stop them from decrypting binary because they will put a breakpoint
on the first instruction of your program; text has been decrypted into
RAM already at that point.
• point at which GDB is disabled very clear, not hard to find and patch
Checksum
• find the location and length of text segment at run time
• important gotcha:
- load address is random in signed app, but fixed for development builds
- extern byte_t start __asm__("start");
• length easy to fetch from getsectbyname(), could also be approximated
• MD5, CRC32, SHA256, whatever
7. Resisting App Piracy
Checksum Pre-Knowledge
• We need to know what the checksum should be.
• Python script in XCode "Build Phase script" to calculate it
- dump the binary's text segment using: otool -tX
- write out a plist or other file which can be read at runtime
• Don't just write the correct value to a file!
- should be function of a shared secret between binary and build script
• Consider hiding checksum value in a resource like image file.
Check Encryption
• Read mach-O headers, looking for structure that says file's text segment is encrypted.
• Difficult to test, since only the appstore seems to encrypt the file
- perhaps uniquely for each buyer?
• Published code keyword: LC_ENCRYPTION_INFO
8. Resisting App Piracy
More Specifics
• All code must be inlined: __attribute__((always_inline))
• Sprinkle checks into lots of different spots, not just startup
• Carefully choose when to re-verify checksum
- it is relatively slow
- harder to find a check if on code path that only runs once/rarely
Expected Results
• Automated piracy tools will still work, but the binary they make should fail:
- code checksum is right, but
- we'll see that we're not running from an encrypted file.
(realistically, they will stop here for my apps, but if you're selling something they really want...)
• They need to use GDB to find each spot where we disable GDB; NOP that out.
• The checksum will fail at that point, because binary has changed.
• Disable the checksum code and/or the piracy flag check.
• ... but they will have to find each instance of that code.
9. Resisting App Piracy
Other thoughts
• When handling support issues, it often helps to ask a user to send a screen shot of
the problem. If we see anything non-standard in the status bar, we say "we don't support
jailbroken devices–end of discussion". It's very hard for jailbreakers to resist personaliza-
tion.
• One problem: need two checksums if your apps support 3G and earlier devices. Your
binary will be "fat", both armv6 and armv7.
• Next level would be 'modulate' the checking code so that it's instruction sequence is
different each time it is included in the binary.