The solutions to the crackmes in this blog would not have been possible without finding a solution to a common problem: If I have a NSString pointer in a register (let’s assume $eax), is there a way to find the location in memory to the string characters in a certain encoding ? This was a problem because many times in the crackmes we have a trivial [isEqualToString:] operation going on, and we want to know what strings it is actually comparing. While digging around I found a solution, although it does not always work. Let’s take an example from the Fox crackme:
In this example, isEqualToString will compare the result of the previous method (uppercaseString) with the NSString we have inserted in the license. A good spot to intervene is 0x274d. Usually (and this is the case) the result of the call to the method is put in $eax. $eax now contains a pointer to an NSString object. If we try to display the contents of memory at that address, we will see apparently meaningless bytes of information. What I have tried is the following: I have created a simple Xcode project that creates a NSString literal and calls:
|
|
At that point, I wrote down the address of temp, and I went back to the address of the NSString in memory (with the Xcode debugger). After some looking around, I succeeded in finding the address in temp starting from the 8th byte (in 32-bit) or from the 16th byte (in 64bit). Of course, the address is in little-endian format, so actually its byte order is reversed. Of course, the address is 4 bytes long in 32bit and 8 bytes long in 64bit applications. Continuing from the Fox crackme, this is the memory, in Hopper Disassembler, starting at the address in $eax :
Starting from the 8th byte, we have 0x208C3D00. If we display memory at that address reversed, that is 0x003D8C20, we find the string, apparently as UTF8 characters:
Voilà, we found the readable characters ! unfortunately this does not work at all cases but really helps. You can see, strangely enough, that the string is stored as a Pascal string, that is with the prefix value being the length of the string. In this case it is 0x28 = 40 characters. I have written a small c snippet that demonstrates the above theory:
|
|
This is a test with 100.000 iterations and the calculated address is never different from the one that [UTF8String] returns.