User:Orangebananaspy

6 editsJoined 31 January 2015
Revision as of 16:51, 31 January 2015 by Orangebananaspy (talk | contribs)

DRM For Cydia Tweaks


File Check


This type of protection uses NSFileManager to check for a file usually unique to the system when your package is installed on a device. A protection like this is usually not the strongest against crackers as the only thing they would need to do is change your path as seen in the binary.

 /var/lib/dpkg/info/com.example.packagename.list     -->    /var/lib/dpkg/info///////////////////cydia.list

On the left is an classic example seen in countless binaries to protect the tweak. The one on the right is how a cracker would change the string, making the tweak check for Cydia rather than checking the files you had given it to check. Now an easy way to protect this file path from getting changed is a little term called Obfuscation, in which you hide the string in the binary making it not editable. This type of protection even with Obfuscation is bit still too easy for a cracker to crack as the cracker could eventually find the hidden string.

if ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/com.example.packagename.list"])
{
//Do if the file exists
}
else
{
//Do if file doesn't exist
}


DPKG Status Check


This is bit of a tricky process as of iOS 8 the system() function was depreciated by apple. DPKG has a simple function where it will tell you the status of the package.

Package: dpkg
Status: install ok installed
Priority: required
Section: Packaging
Installed-Size: 828
Maintainer: Jay Freeman (saurik) <[email protected]>
Architecture: iphoneos-arm
Version: 1.14.25-9
Depends: bash, bzip2, coreutils-bin, diffutils, findutils, gzip, lzma, ncurses, tar
Description: package maintainance tools from Debian
Name: Debian Packager
Homepage: http://wiki.debian.org/Teams/Dpkg

This is the status you get for dpkg itself. There are many ways you can implement this in your tweak, some developers end up directly going to the path of the status file and searching that, but as you would have already guessed it could be cracked by simply changing the path of the file. Another method is to use a call like system() to run a bash command and getting its response, and than comparing with the string. This can also be cracked as you can't really encrypt a bash command string, so someone can change "dpkg -s packageName" to whatever bash command "craK -s packageName", which would basically run the made up bash of a person cracking it. The bash command for this is:

dpkg -s packageName


Server Checks


I personally think this is the most effective of all protections. Luckily for you theres not much of a work you will need to do except for finding a way to actually getting a device's UDID from the device and to the server where the UDID will be checked with Cydia. Here is the php code that Cydia has provided to developers

<?php
   $vendor = "vendorID";
   $secret_key = "secretKey";
   $udid = $_GET['UDID']); //the udid sent from device
   function urlsafe_b64encode($string) {
       return str_replace(array('+','/','='), array('-','_',), base64_encode($string));
   }
   
   function cydia_($url, $dict, $key) {
       ksort($dict);
       $query = http_build_query($dict);
       $response = file_get_contents("$url?$query&signature=" . urlsafe_b64encode(hash_hmac("sha1", $query, $key, true)));
       $values = array();
       parse_str($response, $values);
       return $values;
   }
   
   function cydia_check($vendor, $package, $version, $device, $host, $mode, $key) {
       return cydia_("http://cydia.saurik.com/api/check", array('device' => $device, 'package' => $package, 'vendor' => $vendor, 'version' => $version, 'mode' => $mode, 'host' => $host, 'nonce' => uniqid(), 'timestamp' => time()), $key);
   }
   
   if (!isset($udid)
   {
       header("Status: 403 Unique device identifier not provided");
   }
   else
   {
       $response = cydia_check($vendor, 'com.example.packageName', 'PackageVersion', $udid, $_SERVER['REMOTE_ADDR'], 'local', $secret_key); //make sure this is correct
       
       if (!isset($response['state']) or $response['state'] != 'completed')
       {
           echo "UDID has not purchased such package and this string will be returned";
       }
       else
       {
           echo "UDID has purchased this and this string will be returned";
       }
   }
  ?>

These types of DRM's are amazing. You can encrypt an unique string being sent to the device and than check it with the device if the string is what you had assumed it would be. Now make sure not to make it too easy for someone cracking it to see what the string is you're checking with, or the response from the server is encrypted and only accessible by your tweak using .htaccess

NSError* error = nil;
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com/server/protection.php?1=%@", UDID]] options:NSDataReadingUncached error:&error];
if (error) {
    NSLog(@"%@", [error localizedDescription]);//device not connected to wifi, usually...
} else {
    NSLog(@"Data has loaded successfully.");//data returned with your response from server, this is where you will be checking the return value
}

Its always good to encrypt the URL string so it can't be edited by the cracker even if he finds out your returning response, and just makes it harder.