Bogus Serial Choosing (MisterE) with addendum by Suby
When you crack programs that needed a Serial #, I recommend to use always the same
one, so that you know, what your serial looks like in hexdecimal.
Suby:
I suggest using a serial with different chars like "1234567890" (the one I
use) because if the program doesn't check the chars from the first to the last but it
checks the third and the second then the last etc. you can easily know which one is checked.
If you use "1122334455" and it'll take the "1" you don't know if it
takes the first or the second instead if you use "1234567890" and it takes "2"
you're sure it'll check the second char of the serial.
|
CALLs (CrackZ)
Whenever you elect to step over a CALL in a protection, check the contents of any
registers which have changed, you may find the Serial # there, alternativly when
you have exhausted all posibilities, re-trace your steps and examine functions.
|
How a Cracker/Programmer thinks (rudeboy)
Programmers are taught that whenever you have a task that is going to be done more that
once, you should create a function to do that task, and just call the function when you
need to perform the task. Now, most programs that use a name/serial # combination check
the code at least twice, once when you enter the code, and once when the program starts
up. Because of this the programmer will usually call a function to test your reg code.
And usually, this function will be called every time the code is checked. At this point
you should probably see where I am going with this. If you patch the function that is
called to test the reg code, it will show up as valid whenever the program does it's
check.
The techniques employed here do not only apply to cracking programs with name/reg code
routines. Do not limit yourself by thinking "Inside the Box", these techniques can be
used with many other types of protections as well (for example, many times a date
check and a nag screen are done by one function).
|
INT 3 Using (josephCo)
In case you haven't heard already, INT 3 was set for debugging purposes. So if you want
to break at a specified routine, you can use this instruction. You can just "patch"
(the op code for INT 3 is just CC) a COPY of the file. Try to replace a single byte
op code with CC. If you can't find one, you've to put it inside a full instruction: don't
forget to "NOP" (the op code for NOP is just 90) out the remaining bytes.
Then you can use SoftICE to break on INT 3. Don't forget to note down the original data,
because you need it when SoftICE breaks at this location. When you're there (before the
INT 3 is executed), type A and then enter the commands you note down - if you don't do
this, you'll cause a General Protection Fault. Just continue like you want to ...
|
Return Values
When a function returns a value to see if a check has been successful mostly 1 (or
sometimes 0) will indicate success. -1 is normally used to indicate NO SUCCESS!
|
SoftICE conditional breakpoints (Rhayader)
In my early cracking experience, I usually set a BPX for GetDlgItemTextA and GetWindowTextA
inside SoftICE, whenever I found a program that ask for serial. Entering dummy code, and
'hoping' that SoftICE would pop up. Most of the time it works. Problem is, after I hit F12
(P RET), I usually get lost inside the code. Wondering where's that bloody text
buffer that I can set a BPR with.
After digging into SoftICE docs, I finally found a better way to do it (it's in Chapter
7 of the User Guide). IMHO, you should read it too. Some of the terms there might be
hard to understand if you were just started. But, hey, that's what The Forum is for, isn't
it?
:)
My aim here is to get SoftICE show us the text buffer for the two Win32 APIs mentioned
above. I'll use breakpoint "action" to do that.
Let's take a look at GetWindowTextA first. It's declared as:
int GetWindowText(HWND hWnd, LPTSTR lpString, int nMaxCount);
GetWindowText use stdcall calling convention. That means that argument will be pushed
right to left. Since SoftIce pop up before the prologue code is executed, the EBP stack
frame isn't set up yet. So we had to use ESP to adressed the argument. Here's how the
stack will look like when SoftIce pop up:
...
[ESP+0Ch] - nMaxCount
[ESP+08h] - lpString
[ESP+04h] - hwnd
[ESP+00h] - return EIP
When the function return, GetWindowTextA will put the text it retrieved to the location
pointed to by lpString (LPTSTR is a long pointer to a null terminated string). Thus,
we had to use SoftICE's indirection operator (it's the * character, same as C language,
see Chapter 8 ;). For example, the command:
D *(esp+8)
means, "show in data window, the location pointed to by the content of esp+8".
Since, this is a very common operation, SoftICE had a shorthand for it: esp->8. Allright
then, now we can set the breakpoint such as this:
BPX GetWindowTextA DO "D esp->8;"
And when we hit F12, we return to the caller and the text we entered will sit nicely at the
top of the data window, waiting for us to set up a BPR with it :) Why don't we do a return
to the caller automatically? Well, in my case, the screen flashes, and I hate it.
But, if you want to try, you can set the breakpoint as:
BPX GetWindowTextA DO "D esp->8;P RET;"
Now, let's take a look at GetDlgItemTextA. It is declared as:
UINT GetDlgItemText(HWND hDlg, int nIDDlgItem, LPTSTR lpString, int nMaxCount);
The only difference is nIDDlgItem, which is the ID of the control to get the text from. The
stack will look like this:
...
[ESP+10h] - nMaxCount
[ESP+0Ch] - lpString << here it is
[ESP+08h] - nIDDlgItem
[ESP+04h] - hwnd
[ESP+00h] - return EIP
And the breakpoint to set (I had a feeling that you already find out ;)
BPX GetDlgItemTextA DO "D esp->C;"
Well, that's all my friends. If you didn't want to type it everytime you want to use it,
then you had to set up a macro for it. Read chapter 11 :D I'd like to tell you, but this
became a looong post already. See ya...
|
Tip for NEW Reverse Engineerers (CrackZ)
When starting to reverse engineer a target it can be very tempting to immediately use a
variety of intrusive techniques, I for one am all to keen to fire SoftICE and start
tracing. In most cases this approach will work, but in order to reverse at a higher
level you should perhaps undertake an analysis of the code prior to using SoftICE -
you would do well to feel the code before entering SoftICE and attempting to study
the protection in detail. Using WDasm32 you'll easily locate some interesting String
References. By simple back tracing you could easily locate a deciding check.
|
Unregistred? (CbD)
If you crack a program and it says unregistred, you did most change a jmp here and there
and make the program take you an invalid code as a real one but the program wrote your
code to the registry or an ini file when you restarted it, the read the number or key and
it was an invalid one, so you must find where the program looks for a registration entry
(RegQueryValueEx[A] or a GetPrivateProfile[A]) and force the program to validate
any key that it sees. This can be a very difficult process so be prepared for a lot of
hell for this one. But the best idea is to use W32DASM to disassemble the target then
look in the import functions to find the functions above, then trace each one of them
(will be many) then after you trace the code and find the right one it will most
likely be a matter of changing a jnz to jz or something simple like that. If you still
can't do it seek help from a wise cracker.
|
Watches (Mammon)
Watches allow you track a variable while you are debugging a program; needless to say,
this is a very important function for cracking and reverse engineering. To open the
watch window, type ww at the Soft-Ice command line; typing watch followed by an
variable name (eg watch user_id) adds that variable (and its value) to the watch
window. Registers and stack offsets (not to mention memory values) can be watched
by using them in place of the variable name, such as watch es:di and watch [ebp 18]. In
addition, since many registers and stack offsets merely point to address where the real
variables are stored, you can watch the value referenced by the register or stack offset
by typing a * before the name of the register/offset (eg, watch *es:di). Good variables
to watch are es:di, *es:di, eax, and any [esp ?] or [ebp ?] that references input by a
user.
|
|