Wednesday, August 12, 2020

All the platforms I've cracked for/on

 I saw a request for someone to remove a doc check in a Mac Classic app today, to which I volunteered.  This made me think back to the amount of things I've cracked code on.  I thought I should document that list somewhere, and maybe a story or two.


  • As explained elsewhere on this blog, I started cracking on the Commodore 64.  
  • Then cracked a couple of games on TRSDOS on the Radio Shack TRS-80 Model 3/4.  
  • Then, I sold my C-64 stuff, and bought an Amiga.  I cracked a few games there.  
  • While at work one day, I got the opportunity to crack Empire! for my boss on DOS.  
  • I cracked games on Windows.
  • I cracked an NLM module on Novell Netware once
  • I cracked an app for the Palm Pilot, so Palm OS
  • I've cracked Macintosh apps on 68k, PPC, and X86.
  • I cracked a "Pay to use" sound driver for Linux.  (10k1 sound driver IIRC).
  • I "cracked" Super Star Wars on the SNES, as it wouldn't run on the Magicom
  • I cracked/keygened a Verifone Tranz 380x2
I *BELIEVE* that's the complete list.  Should anything else pop into my head, I'll be sure to come back and add them here. 

There would be another, but I was thwarted by a hash of the data on the card.  I rented a Mercedes C300 for a trip once, and when I tried to use the navigation, it told me that I needed to purchase a license for it.  I also found that there was an SD card in the car with the navigation software on it.  So, I took it out, WRITE PROTECTED IT, and copied the contents off to my PC.  I then put the card back in the car, and returned it to the rental agency.  When I got home, I looked at the navigation program that I had gotten from the card, and I was quite shocked to see that it was Windows CE based, and the registration stuff was in a .DLL.  I tossed it into IDA, and finding the registration code, and finding the specific place to cause it to not CARE that it wasn't licensed, was pretty easy.  I went online, and looked around, and there was, at the time, a message board dedicated to people that owned the C class, and there was a topic in it talking about the navigation, and having to buy a license.  I asked if anyone would be willing to try my "modified" version, and a couple of people offered to give it a shot.  I patched the .DLL, and posted a link on this board, people grabbed it, and told me that when they put it on the card, the car refused to even admit that there was anything in the card reader.  So, I assume it was hashed somewhere or something.  (That's how *I* would do it if I were trying to protect it).  So, not having access to a head unit to pull the code from, that was the end of that investigation.

I've long been fascinated with automotive head units, and the code that runs on them.  I had a rental Genesis G80 once as well, and I did the same thing.  Pulled the SD Card, and copied the code from it for examination.  This was much better, as it's x86 Linux running QT apps.  So, something that I wanted to know.  This car featured Sirius XM radio, and I wanted to see where in the code it was handled.  So, I went looking, only to find that the head unit code only handled status messages sent over the DBUS interface, from what I can only assume, is a self-contained module in the head unit.  So, no code to look at there.  And that's a shame, as Hyundai, or whomever makes the units, didn't strip the executables, so I got function names, and some variable names as well.  It was easy to disassemble, read, and understand.


Sunday, January 19, 2020

For the last(??) time, .NET code isn't safe!

Recently a friend asked me to have a look at an application that he uses.  So I downloaded and installed it, and set about having a look.  A quick glance at the file listing shows a likely candidate, "Common.Licensing.dll".  Could you be any more obvious?  And the filesize?  30kb.  (closes eyes, shakes head).  I toss it into IDA Pro, and discover that it's a .NET assembly.  So, I exit IDA, and toss it into dnspy.  (If you've not yet seen the power of dnspy, I HIGHLY recommend it.  This applies not only to us reversers, but to anyone who ships a protected product using .NET.  Have a look at what I can see about your product!)

For instance, if you have a licensing object, and associated fields, I might see something like this:

        public int TrialDays { get; set; }

        public bool IsTrial { get; set; }

This means that I can simply replace the accessor functions to always say that this ISN'T a trial by returning FALSE on the get, and just ignoring what happens in the set.  Or, if I'm feeling especially funny, I'll change the TrialDays get to return "69", or "420" or some other funny number.  Or if you store the code that the user enters when trying to register your application in an obvious place, I might see something like this:
public string ActivationCode
        {
            get
            {
                return this._settings.ActivationCode;
            }
        }

So now I can just look through the rest of the code for references to ActivationCode, and find all sorts of things.  Like, I could find out that you compute this activation code via MD5:
public string GetHash(string activationCode, string email, bool isExtended)
        {
            return LicenseChecker.GetMd5Hash(CryptHelper.Encrypt(this.GetHwId(isExtended), this.Aggregate(new string[]
            {
                activationCode,
                email,
                this._md5HashKey
            }, "")));
        } But, you think that's OK, because you encrypt it before you store it, right?  Like this:  
public Func<string, string> Encrypt
        {
            get
            {
                return (string value) => CryptHelper.Encrypt(value, this._md5HashKey);
            }
        }

I heard that! You said "Big deal, you know it's MD5, but you don't know the hash key! Ahem: public readonly string _md5HashKey = "kPW6ib49Q1mUaPJBmD2OKaXLo9B7eKCf";

But, it's not all bad news! (I lied, it's all bad). Even your idea that "it's OK to include the code to compute the activation code locally, as you plan to VALIDATE it online, and THAT will certainly stop me" is a bad one. As you included all of THAT code in the same file, so it became this:
public bool CheckOnline(UserSettings settings, Action onOnlineReCheckFailed = null, bool waitResult = false)
{
    return true;
}
And that's just not very useful is it? You also started some threads that should, in theory, validate the activation from time to time right?
        public async Task<SerialValidationResultEnum> CheckOnlineAsync(UserSettings settings)
        {
            TaskAwaiter<bool> taskAwaiter = this.IsOnline().GetAwaiter();
            if (!taskAwaiter.IsCompleted)
            {
                await taskAwaiter;
                TaskAwaiter<bool> taskAwaiter2;
                taskAwaiter = taskAwaiter2;
                taskAwaiter2 = default(TaskAwaiter<bool>);
            }
            SerialValidationResultEnum result;
            if (!taskAwaiter.GetResult())
            {
                result = SerialValidationResultEnum.ConnectionToServerFailed;
            }
            else
            {
                string url = (!settings.IsValid()) ? this._registrationURL : this._checkURL;
                string requestData = this.GetRequestData(settings);
                result = await this.GetServerResult(url, requestData, false);
            }
            return result;
        }
Well, I see from this that you return an enum. And, you include that in the source, so this whole function becomes:
       public async Task<SerialValidationResultEnum> CheckOnlineAsync(UserSettings settings)
        {
            return SerialValidationResultEnum.SuccessfullyValidated;
        }
And you included, as strings! The server URLs that you plan to try to contact, have all been changed. This is what they look like now:
        public readonly string _registrationURL = "localhost";
        public readonly string _checkURL = "localhost";
        public readonly string _trialURL = "localhost";

So, good luck getting any data out that way either. And last but not least, all those other "background tasks" that you run that will validate things, and update member variables of the class should something not look right? Yeah, they don't do much anymore:
        public async Task<SerialValidationResultEnum> CheckTrial()
        {
            return SerialValidationResultEnum.SuccessfullyValidated;
        }

        public async Task<SerialValidationResultEnum> CheckAsync(string activationCode, string email)
        {
            return SerialValidationResultEnum.SuccessfullyValidated;
        }

        public async Task<SerialValidationResultEnum> CheckAsync(UserSettings settings)
        {
            return SerialValidationResultEnum.SuccessfullyValidated;
        }

        public async Task<SerialValidationResultEnum> GetServerResult(string url, string requestData, bool isTrialResponse = false)
        {
            return SerialValidationResultEnum.SuccessfullyValidated;
        }

        public async Task<bool> IsOnline()
        {
            return false;
        }

        public async Task<bool> SendAnalytics(AnalyticsEventsEnum analyticsEvent)
        {
            return true;
        }
And, as the cherry on this sundae of fail, I couldn't resist a little graffiti.

        public string ActivationCode
        {
            get
            {
                return "The Humble Guys!";
            }
        }
This shows up when you do Help|About. 

So, in closing, be aware of your surroundings.  If you plan to write an app in .NET be aware that there are some KICKASS tools out there for decompiling your code, and in the case of dnspy, it even allowed me to make all those changes you see above in a "Visual Studio feeling" editor, and one click later, it had compiled all my changes, and had written them to MY version of Common.Licensing.dll.  So, no hex-editing required.