Develop A Cydia Tweak

Today I am going to talk about how to start with Cydia Tweak development. It is not that hard to start with it. Steps are

  • Get Theos
  • Fix installation errors
  • Develop

Get Theos

Easiest way to get Theos Follow the WIKI page Since I use macOS, I installed with the help of Wiki and it mostly worked. For macOS steps are

  • Install Xcode (AppStore)
  • Install Homebrew
  • Install necessary packages
brew install dpkg ldid
brew install --HEAD hbang/repo/deviceconsole  # (not required, but very useful)
  • Install Theos Refer to WIKI for detailed instuctions.

Fix installation errors

If you are using macOS, after installation you may see following error

dpkg-deb: error: obsolete compression type 'lzma'; use xz instead

Type dpkg-deb --help for help about manipulating *.deb files;
Type dpkg --help for help about installing and deinstalling packages.
make: *** [internal-package] Error 2

In order to fix this error,

brew remove dpkg
brew install --force-bottle https://raw.githubusercontent.com/Homebrew/homebrew-core/7a4dabfc1a2acd9f01a1670fde4f0094c4fb6ffa/Formula/dpkg.rb

Develop

For this exercise I am going to develop a tweak for an app to disable its ads. I am not going to name the app but this app has banner ads, interstitial ads and interstitial video ads whenever you click on something.

Purpose of our tweak is to prevent any ad showing up and remove any views or hide it afterwards. In order to write such tweak, we must decrypt binary, find out classes and develop a plan to disable or remove ad showing functions from those classes.

Decrypt Binary

You can use Clutch or to dumpdecrypted.dylib to dump the binary

Class Dump

You can use classdump  to dump the classes

Planning

I have checked class names for ad,banner and found couple of candidates

@interface AdBannerView : DFPBannerView
{
}

- (void)loadRequest:(id)arg1;
- (id)initWithAdSize:(struct GADAdSize)arg1;
- (id)initWithFrame:(struct CGRect)arg1;

@end

This class is responsible for creating a view for an add. We can actually return nil from initializers but this app crashes if it can’t init the view. Therefore I will disable loadRequest function.

So after analyzing classes of the app, I came up with following list

Class Function
AdBannerView – (void)loadRequest:(id)arg1
MainMenuBase – (void)loadInterstitial
PhoneScreenTeam – (void)showInterstitial
PhoneScreenTeam – (void)loadInterstitial
PhoneScreenOrganization – (void)showInterstitial
PhoneScreenOrganization – (void)loadInterstitial
KrVideoPlayerController – (void)requestAds
KrVideoPlayerController – (void)adsLoader:(id)arg1 adsLoadedWithData:(id)arg2
KrVideoPlayerController – (void)setupAdsLoader

This classes and their functions are responsible for showing ads on the screen such as banner ads or interstitial ads. Basically we want to disable running these functions. If functions is not returning anything, (void) you can generally skip that function. Because function tells that I am not returning anything.

Developing Tweak

Preparation

We are going to use Theos to develop our tweak. Go to any folder of your choice and run following commands

nic.pl

If you get an error it means either you didn’t install the Theos or you didn’t add Theos folder to your path. Please follow WIKI to fix it.

You should see following screen

NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/activator_event
  [2.] iphone/application_modern
  [3.] iphone/cydget
  [4.] iphone/flipswitch_switch
  [5.] iphone/framework
  [6.] iphone/ios7_notification_center_widget
  [7.] iphone/library
  [8.] iphone/notification_center_widget
  [9.] iphone/preference_bundle_modern
  [10.] iphone/tool
  [11.] iphone/tweak
  [12.] iphone/xpc_service
Choose a Template (required): 

Since we are going to develop Tweak we will select 11 Give a project name(My Cool Project), Package name(com.whateveryouwant.mycoolproject), Username. For MobileSubstrate Bundle filter you must write the bundle id of app you write your tweak against. Open Info.plist of your app on your device and find the bundleid of your app. This is very important. Tweak will be only activated for the bundle id you set. You can just hit Enter for other options if you are happy with the defaults.

If everything is made correctly you should have a folder with your Tweak source Tweak.xm and couple of other files and folders inside. Open your terminal and go to that directory and write below

make package

If you don’t get an error, you are ready for actually writing the tweak. If you get an error, please read the beginning of this tutorial to fix possible errors.

Successful compilation will give you a deb file in packages folder.

Writing Code for Tweak

Open Tweak.xm with your editor and write the code for disabling ad functions.

If you read the generated Tweak.xm you can see how to disable functions or how to call original functions from the app. In order to hook a class and you must write block of code something like below

%hook Nameoftheclass

//functions you want to hook

%end

Let’s disable our first add

%hook AdBannerView

- (void)loadRequest:(id)arg1 {

}

%end

So I am hooking AdBannerView class and I basically disable the function by doing nothing at all. Since this is a void function I don’t need to return anything. However some functions may need to return something. For example, after I disabled AdBannerView, tableview had some white cells due to AdBannerView. You can actually be hardcore and find TableDataSource and fix the problem or just hide the cell by setting height to 0. In TableViews, cell’s height is decided by following function

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath;

As you see this function is returning CGFloat as the height of the cell. If we return 0 from this function, we will basically hide the cell.

PhoneScreenOrganization has the banners so our hook function will we something like this

%hook PhoneScreenOrganization
- (void)showInterstitial {

}
- (void)loadInterstitial {

}


- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
    CGFloat height = %orig;
    if (height == 50) {
        return 0;
    }
}

%end

If you check the function, first I call original function with %orig; This will call original function will all of its arguments. You can also do something like %orig(arg1,arg2….) with its arguments.

First I get height by asking app to calculate for me. I checked the size of the banner and found out that it is 50. Therefore if calculated height is 50 I am returning 0 to hide it otherwise I am returning the original height.

After you make your package with make package Upload to your device and install the package with Filza or any other way you like. In order to facilitate easy debugging, Theos increases build number and adds debug configuration each time you make a package. When you decide everything is working as expected, you can easily disable the debug mode. Open Makefile and add

FINALPACKAGE=1 to the top of the file.

Tip: You can debug your tweak by adding some NSLog() functions and using deviceconsole.

That is all I guess. I hope this tutorial helps you to get started with Tweak development.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s