TAG | Reverse Engineering
Now it’s time for some poorly-written, lengthy sentences. I’m going to go ahead and explain a basic overview of how most simple apps are cracked on OS X. You most likely won’t walk away with knowledge of how to crack applications yourself, but if you’ve understood everything so far, you can probably teach yourself. Before I go any further, I would like to firmly state that this information is for educational purposes only and should not be redistributed or used to do anything illegal/unethical. I enjoy cracking applications because it gives me a better understand of what my computer is really doing, and I hope to share the joy of understanding with you. I do not condone piracy. If I like software, I buy it (and so should you). Now time for the good stuff.
The start of nearly every Mac OS X crack begins by examining the code contained within an application. You probably don’t have access to the source code of the application you are looking to crack, so you have to yank that information out of the app itself. This is both possible and easy thanks to our friend otool. With the right arguments, otool will dump out the code contained in an app. Gathering the correct arguments and digging through code to match up Objective-C method names can be a pain even after you’ve used otool, and that’s why otx is a lifesaver. otx is a GUI app that makes life easy by dumping a prettified otool output and more into a text file.
Running otx on an application’s executable (located at MyAppName.app/Contents/MacOS/MyAppName) for x86 will yield a beautiful mess of output that looks a bit like this (from Apple’s Calculator):
-(void)[LCDController setPrecision:]
+0 00003595 55 pushl %ebp
+1 00003596 89e5 movl %esp,%ebp
+3 00003598 8b4508 movl 0x08(%ebp),%eax
+6 0000359b 8b5510 movl 0x10(%ebp),%edx
+9 0000359e 895058 movl %edx,0x58(%eax) (int)__Precision
+12 000035a1 8b1578550100 movl 0x00015578,%edx showValue
+18 000035a7 89550c movl %edx,0x0c(%ebp)
+21 000035aa 894508 movl %eax,0x08(%ebp)
+24 000035ad c9 leave
+25 000035ae e9cbc80000 jmpl 0x0000fe7e
So you’re probably wondering what all of that means, right? I’ll go ahead and explain it a bit. The first line (with the brackets around it) is a method name. The fact that we can read these is important because it often gives clues as to what the app is doing when it calls that method- for instance, in this case the App (calculator) is setting its precision.
The first column you see is a local offset, or the offset within that method. It basically gives you an idea of how far into a particular method you are. The next column is the actual offset of the code- this is important to note because it is where the code you are viewing resides within the executable file. If you wanted to patch a piece of code, you could skip right to its offset in the binary. The next column is the opcode for the current instruction. This is the part that tells the computer what to do, and it’s the part you generally end up modifying in an executable. The last few columns are the assembly language instructions for what is going on.
Now that you have a clearer idea of what you are looking at, I’ll talk about the most simple reverse engineering technique. When you are trying to crack an application, you are generally looking to circumvent some sort of registration or trial restriction on the program. Most of the time, this means finding the location of the relevant code and patching the binary to ignore it. To find the necessary code, you can search through the otx dump for key words like “Register”, “Nag”, “Trial”, “Expire”, and more. You have to use your brain and take a look at what the methods are named and where they are being called. Try to get an understanding of what the program is doing and when. Most hackers use a debugger like GDB to actually follow the flow of the program, but this is a vast over-simplification based on guesswork.
The majority of the time, a crack comes down to modifying one single line of code, and that is the conditional check for a registration (where the program is checking whether or not you have a registered copy). In Objective-C, these checks tend to follow a pattern. Below is a snippet from an otx dump that is key to a crack:
+2351 00004481 e8f8b90000 calll 0x0000fe7e -[(%esp,1) isRegistered:]
+2356 00004486 84c0 testb %al,%al
+2358 00004488 752f jne 0x000044b9
What’s going on here (skipping a lot of essential code that comes before an simplifying what’s going on) is pretty easy to understand! The program is calling (see calll?) the method isRegistered: and is then testing (see testb?) the result. What usually follows is one of two instructions: jel or in this case, jne.
What do these instructions mean? Easy. jel means “jump if equal” and jne means “jump if not equal”. Jump just means to skip to a different part of the code. In this case, if you are not registered, it is going to skip to the part of the code that kicks you out. So 99% of cracks come down to reversing or ignoring one of these instructions.
In the pasted code, the program is checking if it is registered, testing the result, and jumping if the result is not equal (if this sounds funny go learn assembly or just accept that it’s not extremely important). Since the program is going to continue jumping to kick us out as long as we’re not registered, we want to remove or ignore the jne instruction and let the program continue on as if we were in fact registered.
If you’ve read my earlier posts, you probably know where I am going, and that is to nop. nop (opcode 90) is the “do nothing” instruction in assembly language. All we want to do is replace our little jne with a nop. To do this, you simply open the app’s original executable in a hex editor, jump to the offset from the otx dump ( 0x4488 in this case) and replace the offending code (752f) with nops (9090).
Voila, our imaginary app is cracked. Sorry for the horrible writing, I’m doing this at 1:22 AM instead of stressing over homework. This probably wasn’t the most clear guide, and it certainly isn’t the most accurate (like I mentioned, almost every real cracking process involves using GDB). If you have any questions or would like my help, feel free to comment or shoot me an email.
There will be another informative (and easier to understand) post coming soon on packet sniffing in Mac OS X!
I’d like to take the opportunity to explain some things to those of you who actually go outdoors on a somewhat regular basis. A lot of the posts that you will see on this site may confuse you, and I would like to prevent that. I’d like to do a couple things: first I’ll write out a glossary of terms you will encounter frequently, and second (when I’m more awake) I will write a description of a basic reverse engineering process. The second part will be in another post. The first part will happen RIGHT NOW.
I’ll start off with a couple broad terms:
Hacking – making things do stuff that they weren’t originally intended to do (I’d really like to hear others’ opinions on this).
Reverse Engineering – in the context I use it, reverse engineering (or RE) is the process of taking apart and analyzing software. Sometimes this means prodding around to see how things work, sometimes it’s just a step toward a bigger goal.
And now some more technical stuff:
Assembly [Language] – Assembly language is often considered the lowest-level human-readable programming language. It’s still not very human-readable. It’s mostly hard-to-understand instructions telling the computer hardware/OS exactly what to do.
Hex Editor – A program used to alter the contents of binary files such as compiled programs.
Method – In Objective-C (the predominate language of Mac OS X), a method is (in basic terms) a specific, named task that a program performs. otool dumps method names next to the low-level code when possible, making it easy to find relevant pieces of code.
Offset – A hexadecimal number that refers to a specific location in a binary file. Almost (but not quite) like a line number for geeks.
Opcode – A little hard to explain. Assembly language can be written out in opcodes, which is what the instructions in compiled programs are made of.
otool – A utility built in to Mac OS X that displays the low-level (hard to understand) code contained in a program in a pretty format.
These are some basic terms. I’d appreciate any feedback/questions on what I’ve written or what I should have written. This list might grow and I might make it into its own page. Until later (probably tomorrow), look forward to BUT WHAT DOES IT ALL MEAN? (pt. 2).
Another fun “crack” working on the latest version (1.8.0). This one works by giving you an infinite number of “trial” zaps.
I ran through the usual process of dumping the binary with otool and grepping for interesting lines. I ended up finding a couple interesting methods, the first of which is titled -(void)[AZPreferencesController showNag:]. Within that method is a call to -(BOOL)[AZRegistrationController validateExistingRegistrationInformation]. nop’ing out that call prevented the registration nag dialog from showing when launching, but did not allow any extra functionality- I left it in anyway. To do this, open up the AppZapper excutable in your favorite hex editor and skip to offset 0x3bb1b. All you have to do is replace the opcodes for the method call (e883450100) with nops (9090909090). A nop (opcode 90) basically just means “do nothing” in assembly.
The next interesting method I came across was titled -(void)[AZAppController _finishProcessingApps:]. Sounds boring- I know- but it contains an important call to the method -(BOOL)[AZRegistrationController canZap]. This is the method that determines whether or not the application is allowed to zap. All I had to do was nop out the jel immediately after this call, and the app would allow me to zap indefinitely beyond “0 trial zaps remaining” (I think I’m at -17 now). All you have to do is nop out 0f848d010000 with the good ol’ 909090909090 at offset 0x35527.
NOTE: This only works on x86-32. If you aren’t running an Intel chip, buy a new computer already.
The “crack” here is pretty simple and appears to still work on the latest version of the app (2.0.6), though the offset has changed throughout the versions. After dumping the app with otool and grepping my way through the file, I stumbled upon quite a few interesting methods. The most important of which is +(BOOL)[LicenseController isTrial]. Within this method is a je instruction at offset 0x114ab. Changing this je (jump if equal) to a jne (jump if not equal) tricks the app into doing the opposite of what it should in detecting whether or not we are running a trial. If you have a valid license (I now do), it will kick you out; if you do not have a valid license, you can enjoy your “registered” copy! All that you need to do is fire up your favorite hex editor and change 0x114ab from 74 (opcode for je) to 75 (jne).
NOTE: This only works on x86-32. If you aren’t running an Intel chip, buy a new computer already.
I really like that OS X includes Screen Sharing, but I hate that Apple strips out a lot of important features in the free version (such as Full Screen support). I enabled (most of) the features of the full-fledged Apple Remote Desktop in the free, crippled Screen Sharing app. Apple used nearly the same executable for both and simply removed the functionality from the UI in Screen Sharing. Fixing this was a simple process: I opened up the nib inside the application bundle, added a new overlay window, created some buttons, and linked them to the already defined actions in the executable for features like full screen viewing.
It seems that Apple has prevented you from doing this in the latest version of OS X by compiling the nib files inside the application bundle. There might be a way around this, we’ll see!
