Text: tickle.dr
Purpose: Tutorial on cracking Tickle.exe using hmemcpy and memory breakpoints
Program: Tickle.exe - Keeps your ISP connection alive
By: drLAN, mexelite


Let's get started cracking this baby...

Run the program and select:
  - Tickle
    - Register

Now type in any name and code, but don't press enter yet.  First pop over
in to SoftICE by pressing Ctrl-D.  Let's set a breakpoint on hmemcpy.  This
routine is often used to manipulate strings in memory.  To set the breakpoint
type: bpx hmemcpy.  Make sure you get your name and code typed in before you
set the hmemcpy breakpoint, or sICE will break for each character you type.

Now toggle back to the program with Ctrl-D and press Enter or click OK.  As
soon as you hit Enter, sICE pops, at your hmemcpy breakpoint.

Now let's scan memory for the reg code we entered.  I entered the following:

Name: drLAN
Code: 006969

So my search looks like: s 0 l ffffffff '006969'

sICE should find an echo of this string setting in memory.  It found mine
at 013F:0076177C.  Your actual segment:offset will probably vary.  Ok, so
now we found a copy of our string in memory, now what.  Well, let's set a
breakpoint on this memory location.  There are many ways to do this and you
may need to use differemt approaches depending on the program you are working
on.  Some common approaches are to breakpoint on a memory location (BPM).
Any reads/writes at that location will trigger the breakpoint.  Another
approach is to set the breakpoint on a memory range, from the first char of
your reg code to the last.  Or, if you know a little about the proggie you
might want to break on a single byte (BPMB), a word (BPMW), or a double word
(BPMD).  Each of these approaches has its merrits depending on what you're
looking for.  I commonly use BPM and BPMB.

So based on where it found my string, here are the BPM and BPR approaches.
NOTE: Only use one of the two.  I used approach #1.

#1: Breakpoint on memory location:
bpm 013f:0076177c                       <== this is the one I set

#2: Breakpoint on memory range:
bpr 013f:0076177c 013f:00761781 RW

Note the last two digits changed on the ending range.  That's because it is
pointing to the memory location containing the last character of our string.
First character is at 013f:0076177c.  String length is 6.  So the last char
is at 013f:0076177c+(6-1), or 013f:00761781.

Usually the program will create another copy of the string in memory before
doing its final comparison(s).  So, it's often this second copy we need to
scan for.  We could single step through the program for a while, using F10.
After each CALL, do the scan again to see if it has made a second copy.  If
so, set a memory breakpoint at that address, too.  Don't clear the first one
unless that memory segment is completely overwritten with something different
that the code you typed.

If you don't feel like stepping through the code for the rest of your life,
you can press Ctrl-D a second time from within sICE and you'll break at
another hmemcpy.  If you break on the first memory address, just press Ctrl-D
again until you hit the second hmemcpy.  Now scan again and see if there is a
second copy of the string in memory.  If so, set your memory breakpoint here.
If not, F10 a few times to step through some code.  Do your scan after any
CALL routine.  Do the scan periodically anyway.  If you type S, then up arrow
it should fill out the rest of your scan command from the buffer, so you don't
have to retype the whole thing each time.

Eventually you will find the second copy of the string in memory.  This will
turn out to be the copy we're interested in.  Set your memory breakpoint (BPM)
here.

Then press Ctrl-D again.  Now you should be sitting one instruction before
the good-guy/bad-guy compare routine.  The code should look something like
this:

MOV     CL,DL
CMP     DL,BL
JNZ     78005DAC        ; bad-guy, jump to sorry sucker
TEST    CL,CL
JZ      78005DB6        ; good-guy, jump to thanks for registering

Now, if you scroll up through your data window using your mouse, or change
focus to that window and use Ctrl-Up Arrow, you will see the code that points
these registers at memory locations for the compare routine.  You should
see DL being pointed to [EAX] (the good code) and BL being pointed to [ESI]
(our code/the bad guy code).  You can verify this with D EAX, and D ESI.  If
you scrool up the code you find should look like this:

MOV     ESI,[ESP+18]
MOV     EAX,[ESP+14]
MOV     DL,[EAX]        ; points DL to the memory location of good-guy code
MOV     BL,[ESI]        ; points BL to the memory location of bad-guy code

Then we hit the code above...

D ESI   ; bad-guy code (the one we entered)
D EAX   ; good-guy code (you know what to do with this one)

Beautiful, there's your good-guy code.  Clear your breakpoints and register
this baby!