Beginner level essay follows.
-----
A CDRom check with a twist
(by grasshopper)
One of the most annoying things is to find out
that a software that you've purchased with your
hard-earned money refuses to work until you stick
its CDRom into the drive. Such was the case
with a (several hundred dollar) program I recently
purchased. At least with dongles you don't have to
reach out for the CD, remove the current one in the
drive, select drive, click, remove cd, insert the
previous CD you were working and continue with your
work. If the lame-o program crashes, it's back to
the 2 minute drill. Eject, insert, click, click,
eject, insert.
I've been out of the (cracking) scene ever since
I retired my Apple ][, a looong time ago. Having
been emboldened by fravia's pages, the past few
weeks, I decided to give it a whirl a get rid of
this annoyance.
The protection check was a "standard" CDRom check.
So, the "standard" sice, BPX on GetDriveAttributeA,
GetVolumeInformationA, GetFileAttributes, CreateFileA.
Step, step, step. After spending a few nights (I'm
out of shape) tracing through the protection routines,
I patch the tail end of the protection check changing
a jne to a relative jmp. Hardly anything worth writing
about until . . .
Fire up the program, it seems to work sometimes, but most
of the time not. Wierd. What is that you say? "zen."
After poking around sice a little bit more, I try
a different approach. I run the executable through
a disassembler and check the dead listing. As I page
through the listing, a wierd thing catches my eye. It
seems that when I hit pagedown, my editor is redisplaying
the same portion over and over. Right at the spot where
the protection code is. I trace calls into the routine
and find this little gem:
jmp dword ptr [4*eax+00419198] ; jump to one of n random checks
call 004841C0 ; where eax holds a random value
jmp 00418F17 ; from 1 to n
call 00484CF0
jmp 00418F17
call 00485820
jmp 00418F17
call 00489010
I check the reference to 00419198 and sure enough,
it's a jump table to the calls below. The program
was randomizing the call to the protection check.
So tracing through one and applying a patch to "fix"
the return value would only work if it happened to
randomly pick the location that's been patched. A
simple jmp around to the correct place fixed the
program so it's no longer annoying to start-up.
What threw me off was the fact that I was starting the
trace on the GetDriveTypeA call and stepping through
the code, setting bp's at later system calls. Changing
eax before the end of the protection worked for that
one instance of the protection check but not for the
others, so when I patched that piece, it only worked
if it hit that correct random location.
How could it have been improved?
1. Bias the randomization so that it goes to the same
location everyday. The 30-second crack would then
work as many times as needed for testing during that
day but fail on other days.
2. Spread out the checks to different parts of the code.
It's obvious that the check was a cut and paste job
to the same file.