#ios #tweak

How I Used Obfuscated Strings to Protect My iOS Tweaks

Published Mar 16, 2021 by Logan O'Connell


Why Bother With Tweak Security?

For a while in high school I would spend most of my time making “tweaks” for iOS, which was the common word used for what were essentially jailbroken add-ons. These tweaks were written in a flavor of Objective-C called Logos, and they were then packaged up and distributed on Cydia. The tweaks were packaged as .deb files, and when extracted would expand to a small filesystem including a .dylib file. The .dylib file would be injected into iOS at runtime, and my code would be able to run on top of iOS through method swizzling.

Cydia allowed for people to add custom repositories for tweaks. This was a great feature, and I even created my own, but some of these repositories would simply change the bundle identifier of paid tweaks and make them free to install.

This was tough when I was attempting to make money off of paid tweaks of my own. Tweaks usually had the best-selling days immediately following their launch, so the first few days after a tweak came out were the most important when it came to security. Luckily, I was able to find DRM (Digital Rights Management) that used UAObfuscatedString by Urban Apps, which proved to be just strong enough to protect the tweak for a few days.

How UAObfuscatedString Works

It was easy to find constrant strings in the .dylib binaries, so checking against a file’s existance or some other condition was meaningless if an adversary could simply create the file that your string constant points to or change the constant all together.

This is where UAObfuscatedString solved such a problem. The string class is an extension on NSMutableString that can be seen in part in the header of this post. An example of its use is when the method i() is called on the string “h”, the result from the method call will be the string “hi”.

A UAObfuscatedString’s creation is started with the Obfuscate keyword. In my tweak, I used the library to obfuscate the string “/var/lib/dpkg/info/org.thebigboss.3dapplock.list” with a string of method calls: Obfuscate.forward_slash.v.a.r.forward_slash.l.i.b.forward_slash.d.p.k.g.forward_slash.i.n.f.o.forward_slash.o.r.g.dot.t.h.e.b.i.g.b.o.s.s.dot._3.d.a.p.p.l.o.c.k.dot.l.i.s.t. This string is the location of a file that was written when my tweak is installed through the correct source.

Yeah, it looks pretty gross on the eyes. But hey, it works! A string constant can no longer be found in the binary, and the binary is much harder to investigate with a disassembler because of the mass of method calls to create this string. In addition, the choice of this specific file poses a problem for adversaries because it involves the bundle identifier of my tweak, and if a pirated repository tries to create a tweak with the same identifier to circumvent the DRM, dpkg will throw annoying errors to users about duplicated tweaks in separate repositories.

But All Things Must End

Usually, this DRM was broken in a few days. However, as said before, these days were the most important so it got the job done.

And on a last, unrelated note, I hope to get back into tweak development soon!