Wednesday, March 25, 2009

Cracking Signed ActiveX Controls

Ever come across an ActiveX control you can't afford to buy but wish to use for your own little pet project? Especially those readily available for download, but annoys the hell out of you when you try to use it as it keeps painting "Evaluation Version" all over itself?

Well, from time to time, I develop pet projects to keep myself entertained. Being a perfectionist, I just can't stand to see the "Eval Version" message appearing on my applications. Yes, the sole purpose of these apps are just so I could marvel at myself when I finish them, but how would I be able to do that if I leave the "Eval Version" message lying around? I want that newly polished, super shiny feeling you get when you finish something you can be proud of.

So I set out with a mission - to crack the ActiveX control that is sprinkling all those "Eval Version" on itself.

Surprisingly, cracking the several ActiveX controls I've used isn't all that hard - so long as you know a little x86 ASM and have the right tools (such as the W32Dasm for Windows). Most ActiveX controls are smart enough to prevent simple cracks such as looking up the "Eval Version" message and skipping them via a jmp, but in order to draw the text on the screen, the message would still have to be decrypted somehow and placed in the memory. And, THAT is usually the weakest link. What I usually do is, I'd change the opcodes directly in the memory while I step through the ASM in an IDE (I use CodeGear RAD Studio 2007) so I could see the effects immediately. If things go wrong, I'd simply break out of the debug session and restart.

Once you have cracked it, use a hex editor to change the bytes you've changed in the IDE - you'll have to note down a few instructions before and after the ones you're about to change when you were debugging in the IDE, as there may be more than one occurrence of the bytes you search for. For example, there could be numerous occurrences of "33C9" hex, which translates to "xor ecx,ecx".

For normal exe / dll files, patching the file and then doing a final test would've been the end of it. With a signed ActiveX file, however, you'd find that if you try to use the ActiveX in your IDE, it'll complain that the ActiveX cannot be loaded. That simply means that the hash (usually SHA1) in the ActiveX no longer matches the file - and rightly so! This is easily circumvented though - all you need to do is re-sign the file, and then re-import that into your IDE.

Lucky for us, there's no need to un-sign the ActiveX file before re-signing it with our own cert. Here's a link with step-by-step guide for signing an ActiveX file - http://www.pantaray.com/signcode.html

In the next installment, I'd probably blog about cracking signed .NET assemblies, if responses are good for this one.

Wednesday, March 18, 2009

WinAPI functions and GetLastError / WSAGetLastError

Having been using WinAPI for more than a decade, I was surprised with myself for not being more careful with the return value and GetLastError's error code following a WinAPI call. Granted the bug I was facing was not easy to root cause, but that was no excuse as I should've been more careful when coding. We all make mistakes but the difference between a good and bad programmer is that the former is constantly alert of the pitfalls when coding (read: edging toward paranoia) while the latter simply hacks away hoping things will work out fine.

The thing to keep in mind is WinAPI functions don't set Last Error Code unless the function's return value is FALSE (zero) even if GetLastError sometimes returns ERROR_SUCCESS (e.g. TlsGetValue) - it does NOT mean that WinAPI functions will set Last Error Code to ERROR_SUCCESS regardless. If you've made the assumption that all WinAPI function calls will reset Last Error Code to ERROR_SUCCESS (or NO_ERROR) following a call, then chances are your code will work fine so long as the function has not encountered an error, but will fail as soon as it does, because subsequent calls to the function will appear like an error if you rely on just GetLastError for the result. You should ALWAYS read the documentation of each function as their Return Value varies and remember that there will be one scenario where Last Error Code won't be set.