Wednesday, June 9, 2010

Another thing to NOT do.

I just examined a protection system for folks who write apps in the Borland languages, and want to distribute demo versions. It's the "R & T Software Registration Control". I normally don't tell names of protection systems, but since their website is down, I assume they're out of business, and fair game.

The app that I was examining called 2 methods from their control. The first was to get the days remaining in the trial, and the 2nd was to get the "level" of your license key. (Evidently you can generate keys that are capable of enabling multiple items in an app.) The 1st function returned the number of days left in AX. Well, they populate AX with some huge number prior to the call, so the fix for that was to change the 1st byte of the function to a RETN. Now, when it returns, it checks the number of days left on the trial, and it's some astronomical number, and it doesn't bother to nag you about registering, and most importantly doesn't exit.

The 2nd call returned a value that was immediately and'ed with 3. (Evidently only 3 levels in this app.) Well, as fate would have it, they also passed in a huge value that had the lower 2 bits set, so I changed the 1st byte of that function to a RETN as well. It returned, and'ed off the rest of the bits, saw the 3, and said "Full access!".

Obviously this was more the fault of the main app itself, but it's completely possible that this control required those crazy values to be passed in in AX, and if that's the case, they were completely self defeating. I neutered their entire $99 protection system with a 2 byte change.

Tuesday, May 25, 2010

Fab tackles a Mac program.

While not technically my FIRST Mac app, this was an interesting diversion if nothing else. The first app was a Mac port of a protection system that I had conquered on the windows side YEARS before, and I knew it intimately. SO that didn't really count. Some of my friends used this app at the office, but would like to have a copy at home so as to become more proficient with it. So, out of sheer boredom, I decided to have a look at it. What I found excited me. If ALL Mac apps are this easy, I might have to start taking requests!

First a few notes about Mac apps in general. Most of the more modern apps are compiled for both x86 and PPC chips, and the resultant output files are stuffed into a single file together for distribution. So, I did both versions. Now, not being a PPC hacker, that took a few minutes, but the mistakes that they made in the x86 version were also present in the PPC version, so it was a lot easier than it should have been.

In this particular case, (and I hope all others!), the way that the Mac compiler generates executables, and probably the whole underlying architecture of OSX makes reversing MUCH simpler. It's almost like there's an API for everything! To wit, this code looks odd enough, nothing really to see here, right?

__text:000DB4CB mov eax, ds:off_1D2514
__text:000DB4D0 mov [esp], eax
__text:000DB4D3 call _objc_msgSend

If you checkout off_1D2514, you discover that it's a pointer to NSConditionLock. So, spend a few minutes labeling all these "pointers to message names", and the disassembly starts to look VERY different!

Of course, if the particular program that you're working on uses a license file protection technique, and offers a demo version, then it could be even easier. It could have a function like this:
char __cdecl _XXApplication_isDemo_()
{
return *pTrialByte == 3;
}

Variable name was supplied by me, function name was left in the executable by them. Don't get me wrong, I certainly APPRECIATE it! ;-)

So with this function telling me not only what variable in memory was responsible for determining the trial/registered status of the app, but also what the value was that was interpreted as being a trial, it allowed me to make a simple fix. Just locate all the places in memory where this memory location was set. I.E.

__text:000E0453 mov ds:TrialByte, 3

A little more tracing showed me that a value of "1" in TrialByte meant that the app was registered, and happy. So a simple search revealed 3 places where a value other than "1" was being placed in this location. A simple change of "2" to "1", and a couple of "3" to "1" changes, and we were done.

I heard that! You said "What about the PPC version?". Well, I found much the same code there:

__text:0000B470 __XXApplication_isDemo_:
__text:0000B470 lis %rtoc, ((pTrialByte+0x10000)@h)
__text:0000B474 lwz %rtoc, pTrialByte@l(%rtoc)
__text:0000B478 lwz %r3, 0(%rtoc)
__text:0000B47C xori %r3, %r3, 3
__text:0000B480 subfic %r0, %r3, 0
__text:0000B484 adde %r3, %r0, %r3
__text:0000B488 blr
__text:0000B488 # End of function __XXApplication_isDemo_

This is our handy function for locating the variable, and what do you know? A quick search shows that there are 3 places that need to be patched to make it work. The same as the x86 version.