Crack prevention: Difference between revisions

From iPhone Development Wiki
(→‎PT_DENY_ATTACH: Someone did this earlier, so figured it'd be worth noting.)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
''Note: This article was mostly written in 2009; if you know something about the topic, please review it and update it! It'd be helpful for the article to be clear about which sections apply only to App Store apps and which sections apply to both App Store apps and extensions for jailbroken iOS.''
Crack Prevention is a series of steps taken by some developers to prevent 'cracked' applications executing. Many developers and businesses see DRM as a malicious feature that only hurts legitimate users, as once broken it serves no purpose in defeating illegitmate use, but does use up developer time and can effect user's stability. All methods detailed here are easy to bypass - do not use them as protection.


= How cracking works =
== App Store ==
App Store binaries are signed by both their developer and Apple. This encrypts the binary so that decryption keys are needed in order to make the binary readable. When iOS executes the binary, the decryption keys are used to decrypt the binary into a readable state where it is then loaded into memory and executed. iOS can tell the encryption status of a binary via the cryptid struture member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero value then the binary in encrypted.


== Redistribution ==
'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into a new binary file, resigning, and repackaging. This will only work on jailbroken devices as codesignature validation has been removed. Resigning takes place because while the codesignature doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have AppSync or similar to disable codesignature checks.
The first step of crackers is to get the redistributable files. Crackulous and AppCrack are the notorious examples of cracking the DRMs and get the redistributable IPAs for installation on unauthorized devices.


=== AppStore ===
AppStore apps are all encrypted when downloaded, to prevent reverse engineering, and ensure every account can only run their own copy. The CPU, however, is unable to run encrypted instructions. Everything must be decrypted by the time it is loaded into the RAM. Crackers exploit this fact, and uses GDB to dump the decrypted data, so that these apps can be run anywhere.
In detail, every protected app has an <tt>LC_ENCRYPTION_INFO</tt> load command. This load command looks like:
<source lang="c">
<source lang="c">
#define LC_ENCRYPTION_INFO 0x21
/* Declared in mach-o/loader.h */
struct encryption_info_command {
struct encryption_info_command {
  uint32_t cmd;
  uint32_t cmd;   /* LC_ENCRYPTION_INFO */
  uint32_t cmdsize;
  uint32_t cmdsize; /* sizeof(struct encryption_info_command) */
  uint32_t cryptoff;   // file offset of first encrypted byte
  uint32_t cryptoff; /* file offset of encrypted range */
  uint32_t cryptsize;  // file size of encrypted data
  uint32_t cryptsize;  /* file size of encrypted range */
  uint32_t cryptid;   // method of encryption
  uint32_t cryptid; /* which enryption system,
          0 means not-encrypted yet */
};
};
</source>
</source>
when the binary is encrypted, this load command must exist, and all the 3 <tt>crypt***</tt> fields are nonzero. For deCrypt, xCrack and alike, the GDB command to get the dump is like this:
set sharedlibrary load-rules ".*" ".*" none <span style="color:gray;"># Don't load any symbols and libraries automatically</span>
set inferior-auto-start-dyld off
set sharedlibrary preload-libraries off
set sharedlibrary load-dyld-symbols off
handle all nostop                          <span style="color:gray;"># Ignore all terminating signals.</span>
rb doModInitFunctions                      <span style="color:gray;"># Breaks when dyld starts.</span>
command 1                                  <span style="color:gray;"># When the breakpoint is reached, dump the encrypted content and quit.</span>
  dump memory ''output.bin'' 0x2000 (''cryptsize'' + 0x2000)
  kill
  quit
end
start
This script will execute ''before'' the app's user code comes into play, and therefore you have no chance to deploy a working prevention against it ([[#PT_DENY_ATTACH|PT_DENY_ATTACH]] won't work).


=== CydiaStore and RockApp ===
Cracking has legitimate uses in the Application Security industry, as well as for user's who wish to back up DRM-free copies of software they own, however the act of stripping DRM does allow the binary to be easily shared.
CydiaStore and RockApp, in a nutshell, are just repositories with a secure, authenticated connection on top of the usual APT/DPKG system. Unlike AppStore there isn't additional encryption/DRM. Therefore all the crackers need is to obtain the download .deb file.  
 
=== Tools ===
The majority of cracking tools started out as bash scripts that used gdb to dump the decrypted data; xCrack, CrackTM, PCM etc. Methods have now moved away from bash and gdb to manually forking the binary, dumping and patching as needed. The most popular tool at the moment is Clutch.  


= Crack prevention =
== Cydia ==
Cydia in a nutshell is just repositories with a secure, authenticated connection on top of the usual APT/DPKG system. Unlike the App Store there isn't additional encryption/DRM. Therefore all the crackers need is to obtain the download .deb file. Some developers have attempted to write their own DRM - for example CoolStarDRM, although this was [http://qwupz.me/KJC-BPD.nfo soon broken].


== General techniques ==
== General Crack Protection ==
All anti-piracy checking won't 100% prevent crackers because they have total access to your code. But they can delay the cracks from appearing early and hurt legitimate sales.
All Crack Protections are generally rendered useless by either Clutch or Overdrive, these methods remain purely as interesting tidbits. They will not stop your application from being cracked. All anti-piracy checking is fairly useless as attackers have complete access to your binary and can patch them with relative ease.  


=== Multi-pass check ===
=== Multi-pass check ===
To make crackers a hard day a simple method is to have multitudes of checks at ''different'' locations. A convenient method is to define an always inline function, e.g.
''This method only works as a delay - it is easy to patch.''
 
A simple method is to have multitudes of checks at ''different'' locations. A convenient method is to define an always inline function. The key point here is ''always_inline''. Without inlining, the cracker could simply patch the check_crack() function to do nothing and your anti-crack will fail immediately. Do not make the check computationally too expensive, otherwise legitimate users will be affected too.
 
<source lang="c">
<source lang="c">
__attribute__((always_inline)) void check_crack(symbol, length, result) {
__attribute__((always_inline)) void check_crack(symbol, length, result) {
Line 57: Line 46:
...
...
</source>
</source>
The key point here is ''always_inline''. Without inlining, the cracker could simply patch the check_crack() function to do nothing and your anti-crack will fail immediately.


Do not make the check computationally too expensive, otherwise legitimate users will be affected too.
=== Malformed Mach-O Binaries ===
Many reverse engineering tools, including <tt>otool</tt>, <tt>gdb</tt>, <tt>class-dump</tt>, etc. will blindly trust the Mach-O file to be well-formed. If a Mach-O file is malformed these tools will fail to work. On the other hand, the kernel is more resistant to these corruptions, making it viable to be run.


== Anti-redistribution ==
One proved method is to set a wrong value to the number of sections in a segment command. Unfortunately, both <tt>ldid</tt> and <tt>dyld</tt> cannot recover from this kind of error, making such binaries not runnable nor linkable. But you can do the following to get your dylib/executable working: <tt>ldid -S</tt> the binary, modify nsects and then recreate the SHA with <tt>ldid -s</tt>. After that the binary is fully usable on an iOS device.
These are methods which can delay the time the first redistributable copy appear.  


<!--
Crackers can simply fix the count to perform their analysis.
=== <tt>grep</tt> confusion ===
 
Most AppStore "cracking" tools are based on shell scripts <tt>grep</tt>ping info from <tt>otool</tt>, so it should be able to confuse these tools with these 3 lines of code:
== Obfuscation ==
<source lang="c">
Obfusification is the method of making code or instructions harder to read - this makes it slightly harder for a patcher to figure out what is happening in a routine but is in no way a bullet-proof solution.
__attribute__((section("__DATA,cryptsize"),used)) static int x;
__attribute__((section("__DATA,cryptoff"),used)) static int y;
__attribute__((section("__DATA,cryptid"),used)) static int z;
</source>
or having a weak link to libraries named <tt>cryptsize.dylib</tt>, and so on.


These only works against dump grep-based scripts. A properly written tool and human inspector can avoid these easily.
=== Strip symbols ===
-->
[http://en.wikipedia.org/wiki/Strip_(Unix) Stripping] symbols makes it hard to guess the purpose of a routine.  


== Anti-analysis ==
=== Minimize use of Objective-C ===
Avoids your binary being analyzed.
To support the runtime features, Objective-C-based binaries need to retain a lot of class information, which is enough to rebuild the class interface. This information cannot be stripped away, therefore, all essential implementations should be done using C or C++.


=== Malformed Mach-O Binaries ===
=== Generate strings dynamically ===
Many reverse engineering tools, including <tt>otool</tt>, <tt>gdb</tt>, <tt>class-dump</tt>, etc. will blindly trust the Mach-O file to be well-formed. If a Mach-O file is malformed these tools will fail to work. On the other hand, the kernel is more resistant to these corruptions, making it viable to be run.
Even if you have stripped the binary, chances are there still is a constant string pool. If you use some visual technique to inform the user they're using a cracked version, the crackers can quickly track down where the view is generated with <tt>strings</tt> and disable your check.


One proved method is to set a wrong value to the number of sections in a segment command. Unfortunately, both <tt>ldid</tt> and <tt>dyld</tt> cannot recover from this kind of error, making such binaries not runnable nor linkable. But you can do the following to get your dylib/executable working: <tt>ldid -S</tt> the binary, modify nsects and then recreate the SHA with <tt>ldid -s</tt>. After that the binary is fully usable on the iDevice.
== Deprecated or not working methods ==
=== Kali Anti-Piracy ===
[http://kaliap.com/ Kali Anti-Piracy], developed by RiP-Dev, was the first generic AppStore crack prevention mechanism announced. Since RiP-Dev has been closed down, Kali's status is doubtful enough to be considered obsoleted.


Crackers can simply fix the count to perform their analysis.
Kali has 3 levels of protection<ref>http://www.iclarified.com/entry/index.php?enid=3058</ref>:
* Anti-debugging
* Anti-dumping
* Integrity check and dynamic code generation.


=== PT_DENY_ATTACH ===
=== PT_DENY_ATTACH ===
''This method is now bypassed by tools automatically'' 
'''Do not do this in a tweak. This will prevent other developers from being able to work on their own projects with your tweak installed.'''
PT_DENY_ATTACH<ref>http://developer.apple.com/Mac/library/documentation/Darwin/Reference/ManPages/man2/ptrace.2.html</ref> is an Apple-specific constant that can prevent debuggers (gdb, DTrace, etc.) from debugging your binary in kernel-level. Calling
PT_DENY_ATTACH<ref>http://developer.apple.com/Mac/library/documentation/Darwin/Reference/ManPages/man2/ptrace.2.html</ref> is an Apple-specific constant that can prevent debuggers (gdb, DTrace, etc.) from debugging your binary in kernel-level. Calling
<source lang="c">ptrace(PT_DENY_ATTACH, 0, 0, 0);</source>
<source lang="c">ptrace(PT_DENY_ATTACH, 0, 0, 0);</source>
Line 96: Line 88:
     continue
     continue
  end
  end
Nevertheless, since the <tt>ptrace</tt> is built inside the kernel, which the userspace interface only performs syscall 26<ref>http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/kern/syscalls.master</ref>, as long as your ''assembly'' code resembles
Nevertheless, since the <tt>ptrace</tt> is built inside the kernel, which the userspace interface only performs syscall 26<ref>http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/kern/syscalls.master</ref>, as long as your ''assembly'' code resembles
  mov r0, #31
  mov r0, #31
Line 105: Line 98:
the PT_DENY_ATTACH will be installed and there is no way GDB can workaround it. The cracker can still use patching techniques to <tt>nop</tt> out the <tt>svc #0x80</tt> instructions, but checksumming would help in these cases. Also make sure you don't compile your binary in thumb, cause the compiler will fail due to limited availability of registers in thumb mode.
the PT_DENY_ATTACH will be installed and there is no way GDB can workaround it. The cracker can still use patching techniques to <tt>nop</tt> out the <tt>svc #0x80</tt> instructions, but checksumming would help in these cases. Also make sure you don't compile your binary in thumb, cause the compiler will fail due to limited availability of registers in thumb mode.


== Obfuscation ==
=== Check if encryption is intact ===
=== Strip symbols ===
''This is automatically patched by most tools''
[http://en.wikipedia.org/wiki/Strip_(Unix) Stripping] symbols makes it hard to guess the purpose of a routine.
=== Minimize use of Objective-C ===
To support the runtime features, Objective-C-based binaries need to retain a lot of class information, which is enough to rebuild the class interface. This information cannot be stripped away, therefore, all essential implementations should be done using C or C++.
 
=== Generate strings dynamically ===
Even if you have stripped the binary, chances are there still is a constant string pool. If you use some visual technique to inform the user they're using a cracked version, the crackers can quickly track down where the view is generated with <tt>strings</tt> and disable your check.


== Legitimacy check ==
=== Check if encryption is intact ===
This is only meaningful for AppStore apps. If the binary is not yet decrypted, the LC_ENCRYPTION_INFO load command should still exist and all its fields are nonzero. There is a sample code in http://landonf.bikemonkey.org/2009/02/index.html showing how to check this.
This is only meaningful for AppStore apps. If the binary is not yet decrypted, the LC_ENCRYPTION_INFO load command should still exist and all its fields are nonzero. There is a sample code in http://landonf.bikemonkey.org/2009/02/index.html showing how to check this.
== Deprecated or not working methods ==
=== Kali Anti-Piracy ===
[http://kaliap.com/ Kali Anti-Piracy], developed by RiP-Dev, was the first generic AppStore crack prevention mechanism announced. Since RiP-Dev has been closed down, Kali's status is doubtful enough to be considered obsoleted.
Kali has 3 levels of protection<ref>http://www.iclarified.com/entry/index.php?enid=3058</ref>:
* Anti-debugging
* Anti-dumping
* Integrity check and dynamic code generation.


== References ==
== References ==
<references />
<references />

Latest revision as of 16:42, 30 July 2020

Crack Prevention is a series of steps taken by some developers to prevent 'cracked' applications executing. Many developers and businesses see DRM as a malicious feature that only hurts legitimate users, as once broken it serves no purpose in defeating illegitmate use, but does use up developer time and can effect user's stability. All methods detailed here are easy to bypass - do not use them as protection.

App Store

App Store binaries are signed by both their developer and Apple. This encrypts the binary so that decryption keys are needed in order to make the binary readable. When iOS executes the binary, the decryption keys are used to decrypt the binary into a readable state where it is then loaded into memory and executed. iOS can tell the encryption status of a binary via the cryptid struture member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero value then the binary in encrypted.

'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into a new binary file, resigning, and repackaging. This will only work on jailbroken devices as codesignature validation has been removed. Resigning takes place because while the codesignature doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have AppSync or similar to disable codesignature checks.

/* Declared in mach-o/loader.h */
struct encryption_info_command {
   uint32_t cmd;    /* LC_ENCRYPTION_INFO */
   uint32_t cmdsize;  /* sizeof(struct encryption_info_command) */
   uint32_t cryptoff; /* file offset of encrypted range */
   uint32_t cryptsize;  /* file size of encrypted range */
   uint32_t cryptid;  /* which enryption system,
           0 means not-encrypted yet */
};

Cracking has legitimate uses in the Application Security industry, as well as for user's who wish to back up DRM-free copies of software they own, however the act of stripping DRM does allow the binary to be easily shared.

Tools

The majority of cracking tools started out as bash scripts that used gdb to dump the decrypted data; xCrack, CrackTM, PCM etc. Methods have now moved away from bash and gdb to manually forking the binary, dumping and patching as needed. The most popular tool at the moment is Clutch.

Cydia

Cydia in a nutshell is just repositories with a secure, authenticated connection on top of the usual APT/DPKG system. Unlike the App Store there isn't additional encryption/DRM. Therefore all the crackers need is to obtain the download .deb file. Some developers have attempted to write their own DRM - for example CoolStarDRM, although this was soon broken.

General Crack Protection

All Crack Protections are generally rendered useless by either Clutch or Overdrive, these methods remain purely as interesting tidbits. They will not stop your application from being cracked. All anti-piracy checking is fairly useless as attackers have complete access to your binary and can patch them with relative ease.

Multi-pass check

This method only works as a delay - it is easy to patch.

A simple method is to have multitudes of checks at different locations. A convenient method is to define an always inline function. The key point here is always_inline. Without inlining, the cracker could simply patch the check_crack() function to do nothing and your anti-crack will fail immediately. Do not make the check computationally too expensive, otherwise legitimate users will be affected too.

__attribute__((always_inline)) void check_crack(symbol, length, result) {
  if (checksum(symbol, length) != result)
    exit(0);
}
...
check_crack(my_inline_uuid_check, 0x200, 0x12345678);
register int res = my_inline_uuid_check();
...
check_crack(my_inline_serial_number_check, 0x200, 0x87654321);
...

Malformed Mach-O Binaries

Many reverse engineering tools, including otool, gdb, class-dump, etc. will blindly trust the Mach-O file to be well-formed. If a Mach-O file is malformed these tools will fail to work. On the other hand, the kernel is more resistant to these corruptions, making it viable to be run.

One proved method is to set a wrong value to the number of sections in a segment command. Unfortunately, both ldid and dyld cannot recover from this kind of error, making such binaries not runnable nor linkable. But you can do the following to get your dylib/executable working: ldid -S the binary, modify nsects and then recreate the SHA with ldid -s. After that the binary is fully usable on an iOS device.

Crackers can simply fix the count to perform their analysis.

Obfuscation

Obfusification is the method of making code or instructions harder to read - this makes it slightly harder for a patcher to figure out what is happening in a routine but is in no way a bullet-proof solution.

Strip symbols

Stripping symbols makes it hard to guess the purpose of a routine.

Minimize use of Objective-C

To support the runtime features, Objective-C-based binaries need to retain a lot of class information, which is enough to rebuild the class interface. This information cannot be stripped away, therefore, all essential implementations should be done using C or C++.

Generate strings dynamically

Even if you have stripped the binary, chances are there still is a constant string pool. If you use some visual technique to inform the user they're using a cracked version, the crackers can quickly track down where the view is generated with strings and disable your check.

Deprecated or not working methods

Kali Anti-Piracy

Kali Anti-Piracy, developed by RiP-Dev, was the first generic AppStore crack prevention mechanism announced. Since RiP-Dev has been closed down, Kali's status is doubtful enough to be considered obsoleted.

Kali has 3 levels of protection[1]:

  • Anti-debugging
  • Anti-dumping
  • Integrity check and dynamic code generation.

PT_DENY_ATTACH

This method is now bypassed by tools automatically

Do not do this in a tweak. This will prevent other developers from being able to work on their own projects with your tweak installed.

PT_DENY_ATTACH[2] is an Apple-specific constant that can prevent debuggers (gdb, DTrace, etc.) from debugging your binary in kernel-level. Calling

ptrace(PT_DENY_ATTACH, 0, 0, 0);

will send a SEGFAULT to its tracing parent. Nevertheless, since ptrace has a well-defined address, a simple GDB macro is enough to break this[3]:

break ptrace
commands 1
   return
   continue
end

Nevertheless, since the ptrace is built inside the kernel, which the userspace interface only performs syscall 26[4], as long as your assembly code resembles

mov r0, #31
mov r1, #0
mov r2, #0
mov r3, #0
mov ip, #26
svc #0x80

the PT_DENY_ATTACH will be installed and there is no way GDB can workaround it. The cracker can still use patching techniques to nop out the svc #0x80 instructions, but checksumming would help in these cases. Also make sure you don't compile your binary in thumb, cause the compiler will fail due to limited availability of registers in thumb mode.

Check if encryption is intact

This is automatically patched by most tools

This is only meaningful for AppStore apps. If the binary is not yet decrypted, the LC_ENCRYPTION_INFO load command should still exist and all its fields are nonzero. There is a sample code in http://landonf.bikemonkey.org/2009/02/index.html showing how to check this.

References