You might be curious on how people actually do it, or you work with securing software and want to know what methods the other side use so you can better figure out how to protect you software. If so, read on.
I am by now means an expert in the area, but I recently did crack a piece of software to learn about it.
To learn about this I suggest you find a small shareware application or similar to practice on. They usually have copy protection that is weak enough to be cracked by a novice.
To be able to crack you need a number of different tools. Most of them will already be installed if you have installed Apple’s development tools.
- Interface Builder. You will use this application to poke around in the user interface of the program you wish to crack.
- otool. With this command line tool you can disassemble a file, or print
out other useful information about the executable. For instance you can use it to find out where in memory your program will be loaded.
- class-dump. Command line utility you have to download. It has some of the same functionality as otool, but allows you to see Objective-C class definitions as they normally appear in the header file.
- gdb. This is our most important tool. The GNU Debugger. You will use it to trace through the program you wish to crack to find where int he code the copy protection resides
- HexEditor. To be able to patch your changes into an executable you need an editor that can edit the raw data on a file.
Before you can learn and do cracking you have to know some basics first.
- Objective-C. You do not need to be a wiz, but some basic knowledge of Objective-C is needed to crack a OS X program since most are written using it. At least most of the little shareware programs you find
- Interface Builder. You should have basic knowledge about how to work with interface builder.
- Assembly programming. Again no need to be great at it, or know PowerPC assembly. But you will need to get a reference over the instruction set. IBM also has a nice intro about PPC assembly.
- Know about the Mac OS X binary application interface (ABI). This you can read about in the Apple developer documentation. Info about the format of OS X executable can be found here and here.
- Most important though is to make yourself familiar with calling conventions for functions on OS X. This will tell you what the different registers are typically used for, which helps reading and understanding assembly code.
GDB crash course
To run a program through the gdb debugger. write:
The program has now been loaded into memory.
Commands in GDB
gdb has a lot of commands and they all have long descriptive names. You can get help about a command by writing
help commandname. However to save you typing, gdb allows you to write abbrivations for the names. You can write the first letter and gdb will choose the first command that match these letters. E.g. instead of writing
A lot of the commands will take a line number, function name, or address in memory as argument. Usually you just write the function name as it is. gdb supports command completion with tab if you don’t remember exact name. Line number can also be written directly. If you write an address you have to prefix it with
runStarts running the loaded program
info funGets information about a given function. Address it is located at etc.
info symDumps information about which segment and function the address or symbol is in. Example:
| (gdb) info sym 0x50fd0 | [StateController validState] in section LC_SEGMENT.__TEXT.__text
Says that address 0×50fd0 is in segment __TEXT and section __text.
breakSet a breakpoint at given function, line number or address.Short hand
rbreakSet breakpoint at all functions with matching regular expression
deleteDelete all breakpoints or breakpoint given by an index number
disassembleDisassemble code in current function
backtraceShow a stack backtrace of all functions that were called up to current function.
stepiStep one instruction at a time in code. Short hand
wherePrint out current location in code. Where the program counter is.
poInterpret expression as the address of a Objective-C object and print out result one would get from asString. This is used to e.g. print Objective-C strings. Since print does not allow you to do that.
xExamine memory by giving and address or register.
dispSet expression to display each time program is stopped. For instance after each break or step instruction. Use it to display registers or memory you want to follow the changes in.
You can look up more detailed explanation of each command in the gdb online help. One thing that is useful to know though is that most command that give information about memory or registers let you choose format. E.g.
x/x *0x00fb dumps content of address
0x00fb as hexadecimal number.
x/s *0x00fb dumps contents as a c string.
Supported format types:
iinstruction. Lets you interpret location in memory as PowerPC assembly instructions
Showing contenst of registers:
The PowerPC CPU has a lot of register. The most used general purpose registers are numbered from 0 to 31. To show contents of register you specify a register by writing
$ and then its name. E.g.
$r1 denotes the second general purpose register.
$pc is the program counter.
info register $r3 Dumps contents of register 3 and contents of memory it points to.
p $r3 Dump contents of memory pointed to by register 3.
x/x $r3 Dump contents of memory pointed to by register 3. as hexadecimal format.
Setting value of register:
You can set the value of a register using
set command. E.g.
As with gdb you have to specify the path to the executable. E.g.
otool -l nameOfProgram.app/Contents/MacOS/nameOfProgram. otool has several options, you can read about them all by writing
man otool in Termina.app. However there are a few options that are of most use to us.
-lDisplay load commands. This will give you information about where the different segments in the code get loaded into memory. And at which offset in your executable this segment can be found. E.g. if you look at the output you will see e.g.:
Section sectname __text segname __TEXT addr 0x00002884 size 0x0009149c offset 6276 align 2^2 (4) reloff 0 nreloc 0 flags 0x80000400 reserved1 0 reserved2 0
This tells us that this section can be found at offset (decimal) 6276 in executable. When this program is loaded into memory that section is placed at address (in hex) 0×00002884.
-tVvDisassembles the give executable and dumps to standard output.
This is easy to use just type
class-dump nameOfProgram.app/Contents/MacOS/nameOfProgram to dump out definition of Objective-C classes in executable. When you download the file though it doesn’t come with an installer so you need to put it in your search path. E.g. I copied it directly to
/usr/bin but you have to be root user to do that. So do a
sudo cp class-dump /usr/bin e.g.
Lets get started
First thing to do is to go into the application bundle by right clicking and select Show Package Contents. Then you navigate to e.g
Contens/Resources/English.lproj. Here there will be .nib files for the user interface. I opened
MainMenu.nib. Here I found the registration sheet. I selected the register… button. Pressing
shift+apple+i brings up the inspector panel. Here I looked at the
target attribute. It shows which method the button click is connected to. Say it is called
registerAction: and exist in the
AppController. Try looking for something similar. Then you will have a starting point to start looking for the registration code.
An alternative is to use
class-dump on the executable and search for method names called something with register, serial number etc or a class nammed RegHandler, Reg or something similar. E.g.
class-dump executable | grep register.
Now that we found a method to inspect, load the executable in gdb. Type
break registerA and hit tab to complete our method. Then we have set a break point. Type
run and out application should start running and then stop executing when it reaches our breakpoint.
When you trace through the code using
stepi you will often see lines like this:
00010070 bl 0x12e10 ; symbol stub for: _objc_msgSend
What this is a dispatching of a message to an Objective-C object. This is how methods are called in Objective-C. r3 contains pointer to object that will receive message. You can find out what kind of object it is by typing
po $r3, this will give a description of object. If object is a
NSString it will display the string. r4 contains the message selector. This basically says which method to call. The good thing about this is that the message selector also happens to be a pointer to the c string name of the method. So by typing
x/s $r4 you can find out what the name is of the objective-c method being called. r5, r6.. contains the first, second… arguments of the method call. The result of the method call is returned in r3.
r1 and r30 typically points to the start of the stack. So
lwz using these registers usually access local variables in the method.
How copy protection works
Copy protection can work in many ways. But the way it worked in my case is that I register the product with a name. I then get back a serial number for that registration name from the application maker. So say I register the application on “Erik” then there will be a unique serial number associated with that name.
When the program loads it reads my registered name from a file and then performs a calculation on it. This will produce a serial number or seed that is compared with the serial number I have put into my application.
What I managed to do was to eventually locate the method that did generation of serial number or seed. I then put a break at that method and rerun the application. Then I did a
backtrace to find out which method called the serial number generator at startup.
From there on I was able to find the place where the serial number method was called and the code that compared the results afterwards.
What the code did was doing a comparison with a fixed number against the returned seed (the registered code and provided serial number are used together to produce some unique seed numbers).
In the debugger I used
set to set the registered that were compared to the exact same number they were compared against. Then I typed
continue to continue execution of code. The program now ran as registered. So it worked.
The last step to do when you have found out how to circumvent the copy protection is to change the executable (patch it). This you can do with HexEdit. The problem is to find out where in the file to make changes.
There are a number of things that are handy to know when doing this:
- Since PowerPC is a RISC processor every instruction has the same length, which is 32 bits (4 bytes). Thus you can easily calculate the number of bytes a chunk of code takes. Just multiply number of instructions with 4. This also means you can easily jump over an instruction when tracing by writing
- As described before you can use
otool -lto get information about code or data segments. Using this information you can find the location of an address in memory in the file as follows:
location_in_file = location_in_memory - segment_address - segment_offset
So to find the location in the executable to change, you use
info sym as mentioned before to figure out in which segment and section it is in. Then use
otool -l to find the coresponding segment and section. Then read of the offset and address to calculate location of code in the executable.
To find out what hex codes corresponds to instructions you can write a simple assembly program as below. You can just fill in the instructions you need the hex codes for.
Name the file with the filename extension
.s. The file can then be compiled with e.g.:
gcc newfunc.s -o temp if your file is named newfunc.s.
You can now load your app into gdb and look at the hex code for your application by writing
x/24xb main. Which will list the 24 first bytes starting from main as hex values. 24 bytes corresponds to 24/4 = 6 instructions.
If you have any questions or comments please let me know. I will update this post later.