Saturday, March 30, 2019

Yet another peril of off the shelf copy protection

A friend contacted me to "help him with a program".  That can only mean one thing, "can you fix this for me?".  He sends it along, I install it, and start looking at the files that I get.  Right away I notice something suspicious.  There's a .dll in here named "KEYLIB32.DLL".  Could you be any more obvious?  A quick check of the version info confirms that it's from a different company from the target, and a quick Google points me at them.  I toss the main app into IDA, and when the disassembly is done, I look at the imports to see that all the functions called from keylib32 are things that just SOUND like copy protection.  I save the disassembly, and toss keylib32 into IDA.  "Import section destroyed" (or something similar).  Huh, is this PACKED?  I fire up some "protection and packer identifier" apps, and see that it IS packed.  With a packer made by the same company that makes keylib32 itself.  NICE!  At this point I'm thinking "This could be hairy if they really know what they're doing".  (But how many people truly do?)

I run the app for the first time, get presented with the typical "You don't have a license, what do you want to do?" style dialog, I choose "activate" of course, and then "activate by phone" so that it won't attempt to connect to anyone over the internet.  It provided 2 numbers for me, and asked for 2 numbers FROM me.  I enter some BS as I normally do, and press "Next", and it pops up a nice messagebox telling me that code 1 was incorrect.  That's almost ALWAYS helpful.  I flip over to IDA, and search for that string.  What do you MEAN not found?  I search for smaller parts, nothing!  I fire up hexworkshop and search the .exe for the string in either ascii or unicode.  Not there.  Huh.  I've seen this before!  Some authors of apps will put all their strings in an external .DLL to make the app easier to port to other languages.  They just recreate the app with the translated strings and the correct "resource IDs", and boom.  It's done.  So now, the search is on for the .DLL.  It's not hard to find, and a few minutes with Resource Hacker and I have the resource IDs for the dialog box, and the error strings for when things go bad.  A quick search for the dialogs resource ID, and I discover that there are WAYY too many instances of this value in the program.  I need a new tact.  So, instead, I search for CDialog::CD, and this walks right through the app, pointing out every place that a dialog is created, or DoModal is called to handle it.  A minute or so of this searching takes me right to the code that creates, and calls the dialog.  A quick look at the code before it shows what must be the "Do you have a license file?" code.  A quick 5 byte change, and the jnz is now a jmp, and we can skip the "You don't have a license, what do you want to do?" dialog, and use the program.  I give this patch to my bud, as he was in a bit of a crunch, and now with the pressure off, I had some time to do a deeper dive into this protection.

I went looking for an automated unpacker that would unpack that .DLL, and let me look at the guts of the functions.  No go.  So, I turned to Google.  There was no "pirate chatter" about the protection, but there was something better.  A website with the full SDK documentation for it.  The same stuff you'd get if you were Johnny shareware author and you'd just wasted your money on this crap.  A few minutes of reading what the individual APIs did, and it seemed simple enough.  I went back to IDA's imports tab, and found the especially interesting sounding ones that got called, and looked them up.  Hmm.  This one is interesting!  pp_eztrig1ex().  This appears to be the function that gets called when you press "Next" on the button I mentioned above.  This is the muscle that does the actual comparison of what you typed in, vs. what was expected.  This could be useful!  I jumped to where the stub was in the app, and saw that there was *1* reference to this function.  That's handy!  I went to that location, and fired up HexRays to give me a shortcut peek into what I was dealing with.  Lots of functions, lots of compares, and best of all, references to those error strings I found in the resources earlier!  We're definitely close!  I found the compare for the return value from the the checker function, and forced it to pass.  (Sometimes this will cause the app to generate a valid license and save it for you, effectively self-registering, and that's the end).  In this case though, it wasn't to be.  I got the "Congrats, your shit is registered" dialog box, but I also got a "This is an unregistered eval copy" message at the bottom of the app.  Well THAT'S no good!  I figured I should take a closer look at this protection, and see if I could find any hints.

My first thought was that I could read the documentation, and see if they showed how you were supposed to write your own key generator.  As it turns out, you DON'T.  They HAVE one.  It comes with the SDK.  To their benefit, they didn't have a "Here, please download our SDK!" link in sight.  This would have been almost too embarrassing for words.  Another quick Google search, and I have a link to TFEdit.  The generic keygen app for people using this protection.  I fire it up, and some idiot has left their info in it.  So, I could generate licenses for their apps all day.  (shakes head).  I then go BACK to the online documentation, and research how to set up a new application.  It turns out that as a developer, the ONLY things that differentiate YOUR codes from MY codes are 2 keys.  We'll call them seed1, and seed2.  (As that's more or less what THEY call them).  I tinker around, and find out that seed2 has to be between 1-254.  Now that's REAL security right there!  seed1 appears that it COULD be larger.  So there we have it, we need to know the seeds that are used to generate these licenses.  I could brute force this, but that would take longer than I was willing to invest in this crap.  So, I went back to the documentation for our friend pp_eztrig1ex, and it reveals:

LONG pp_eztrig1ex(PPLFHANDLE handle, LONG regkey1, LONG regkey2, LONG flags, LONG usercode1, LONG usercode2, LONG tcseed, LONG regkey2seed, LPLONG tcvalue, LPLONG tcdata)

Arguments:

handle is the handle to the License File given by pp_lfopen()

regkey1 is the value of Reg Key 1 entered by user

regkey2 is the value of Reg Key 2 entered by user

flags is reserved; set to 0 always

usercode1 was used as User Code 1 or Session Code

usercode2 was used as User Code 2 or Computer ID

tcseed is the Trigger Code seed used to randomize the algorithm

regkey2seed is the Trigger Code Event Data seed

tcvalue is a buffer to place the Trigger Code number. Use 0 to ignore this parameter.

tcdata is a buffer to place the Trigger Code Event Data. Use 0 to ignore this parameter.

Yes, that's right.  The call to the function passes BOTH seed values as parameters.  I load up our old friend Olly, go to the location of that function call and set a breakpoint.  Run the app, enter some crap, and press "Next", and we break.  Huh, seed2 is, as expected, 1 byte.  And seed1, the super secure one, is 2 bytes.  I plug these values into my "new product setup" in TFEdit, and generate myself a license.  The target app takes it, and says I'm registered.  I exit it, and relaunch it, and it runs, but pops up a messagebox telling me that my support has expired, and that I *MUST* renew it.  Huh, what is this?  Well, it turns out that the license has 2 parts.  1 just unlocks that app, and the other specifies the number of days left on your support contract.  (seed2 is used to "protect" those days).  I run it again, re-enter the license details into the app, and this time specify the "extra data" as the max, 53 years of support, and generate the license.  The target gobbles it down, and a restart reveals that I now have support as well. 

So, you pay $700 I think it is, for this protection package, and your only protection is 24 bits of data.  And to make matters WORSE, they must be included in your app where any hacker can just extract them, and then use the license generator to make licenses.  SAD, just SAD.