
HAH Trial CrackMe v2.0
Visual Basic Cracking
Written by Sphinx
Introduction |
Tools required |
Target's URL |
http://www.vinaplus.com/~tnhuan
Essay |
Ok. As usual, as I start any of my cracking session, I snoop instead of
running it immediately. Dunno why though.
I guess it's just me :) Ok.
Ahhh, VB6-coded once again (ie. requiring MSVBVM60.DLL). But still, no
SmartCheck
here and SoftICE wasn't used at all :) Only ExDec,
a powerful tool for cracking P-Coded "programs". Anyway,
onward we go (as we should)...
- Run the CrackMe. Whooow! Nifty gfx :) Though I personally liked the first
one ;) Hmmm... a name field and hey!
Notice how it'll accept a
serial. Yep, via four (4) (horizontal) scroll bars! Remember, I didn't
use SoftICE here, so I
entirely relied on ExDec and (a lot of)
my own intuition :) Anyway, I entered Sphinx as name and made the
bars read
(ie. starting from the top) 1234. And wouldn't
you know it? It's wrong! Then my egoistic personality suddenly kicked in :)
I was focused on a goal. A goal that must be pursued by all
means. A goal.... yeah, whatever. I just wanted to crack it :)
So let's exit and start from scatch with ExDec.
- Run ExDec and disassemble the crackme, then exit. Now search for a [my.txt]
in the dir where you've disassembled it.
And NOTE! I won't
present here the entire dasm listing, since it's too long. And some
infos aren't really necessary for us.
I'll just present here
the important parts (and also, I've modified some lines and added some comments
to make it more
clear for you and (a lot for) me :)
The (important) code snippet starts here: (hexcodes were ripped!)
408F1A: FnLenStr ; get namelength
408F1B: LitI4: 0x5 5 (....) ; the "to-be-compared to"
408F20: LtI4
408F21: BranchF: 408F4D ; jump to :408F4D (calc_routine) if length
>= 5 chars.
408F24: LitVar_Missing
408F27: LitVar_Missing
408F2A: LitVar_Missing
408F2D: LitI4: 0x0 0 (....)
408F32: LitVarStr: ( local_00AC ) Name must >=5 charecter
408F37: FStVarCopyObj local_00BC
408F3A: FLdRfVar local_00BC
408F3D: ImpAdCallFPR4:
408F42: FFreeVar
See? We jumped OVER these routine if we passed the length check :)
Calculations begins... NOW!
408F4D: LitI2_Byte: 0x1 1 (.) ; push 1 onto stack to be the
initial_value of the "for" loop below.
408F4F: FLdRfVar local_0086
408F52: ILdRf local_0094
408F55: FnLenStr; get namelength to be the the final_value
408F56: CI2I4
408F57: Lead3/63 ForI2: (when done) 408FAD ; Now it begins...
Ok. The actual for loop starts from the above - ie.
for Count := 1 to Length(Name)
408F5D: LitVarI2: ( local_00BC ) 0x1 (1) ; push 1 for MID$()
408F62: FLdI2 local_0086
408F65: CI4UI1
408F66: FLdRfVar local_0094
408F69: CVarRef: ( local_00AC ) 4008
408F6E: FLdRfVar local_00DC
Maybe "FldRfVar" will load the variable for name, coz
we're starting to get the chars of name here!
408F71: ImpAdCallFPR4: rtcMidCharVar; yep, call MID$() to position
the pointer on the name
408F76: FLdRfVar local_00DC
408F79: CStrVarTmp
408F7A: FStStr local_008C
408F7D: FFreeVar
408F84: ILdRf local_008C
408F87: ImpAdCallI2 rtcAnsiValueBstr yep, call ASC() to get the
ASCII value of the name_char
408F8C: FStI2 local_0088 ; "push" it here (?)
408F8F: FLdI2 local_0088 ; "pop" it here (?)
408F92: LitI2_Byte: 0x2 2 (.) ; save a 2 for...
408F94: MulI2 ; multiplication
408F95: LitI2_Byte: 0x68 104 (h) ; save a 0x68 for..
408F97: AddI2 ; addition
408F98: FStI2 local_0088
408F9B: FLdI2 local_008E
408F9E: FLdI2 local_0088
408FA1: AddI2 ; note this! This acts as the "accumulator"
for the above
408FA2: FStI2 local_008E
408FA5: FLdRfVar local_0086
408FA8: NextI2: (continue) 408F5D ; yeah, get the next since we've
not yet reached the final_value yet
Ahhh, BIG code snippet isn't it? But we're NOT over yet! Oh no! The
most important parts are yet to come. But to
sum up the above, here it
is: (again, in Pascal code coz this is one of my faves, beside ASM :)
for Count := 1 to Length(Name) do
begin
x := ord(Name[Count]);
x := x * 2;
x := x + $68;
y := y + x;
end;
Anyway, these routine resulted for my nick 1892 (already in decimal). Then
continuing to examine the dasm, I was
kinda sure that the next (not shown)
just converts the serial to a fully qualified integer (ie. the entered 1234
would REALLY be 1234). Anyway, we'll skip these and goto the second part
of the calculation, where I relied on my intuition to the fullest :) Note:
I'll be calling usercode as our input and realcode as, well...
the REAL code! But NOT YET the final realcode, but that 1892
above which resulted from the initial for-loop. Oh yeah, the usercode is the
fully qualified integer, btw.
4090AD: FStR4 local_0128 ; "push" usercode
4090B0: ILdRf local_0128 ; "pop" usercode
4090B3: LitI4: 0x4d2 1234 (....) ; save a 0x4D2 then...
4090B8: Lead0/11 XorI2 ; xor usercode with it!
4090BA: FStR4 local_0128 ; "push" usercode here
4090BD: FLdI2 local_008E ; "pop" realcode here
4090C0: LitI2: 0x8b9 2233 (..) ; save a 0x8B9 then...
4090C3: Lead0/11 XorI2 ; xor realcode with it!
4090C5: FStI2 local_008E ; "push" realcode here
4090C8: FLdI2 local_008E ; "pop" realcode here
4090CB: CI4UI1 ; dunno :)
4090CC: ILdRf local_0128 ; "pop" usercode here
4090CF: EqI4 ; compare them here
4090D0: BranchF: 409135 ; yep, jump to :409135 if <>, else...
4090D3: LitI4: 0xd 13 (....)
4090D8: FLdRfVar local_00BC
4090DB: ImpAdCallFPR4:
4090E0: LitVar_Missing
4090E3: LitVar_Missing
4090E6: LitVarStr: ( local_00EC ) Congratulation
4090EB: FStVarCopyObj local_011C
4090EE: FLdRfVar local_011C
4090F1: LitI4 0x40 64 (...@)
4090F6: LitVarStr: ( local_00AC ) Great, Good work.Now, you can become a HAH member
4090FB: FLdRfVar local_00BC
4090FE: Lead0/94 AddVar local_00DC
409102: LitVarStr: ( local_00CC ) I you want to join us, please send to me: serial+name+tutorial or a keygen
409107: Lead0/94 AddVar local_00FC
Ahhh, our target message, which is my "goal", btw :)
Ok. This is my explanation of the algo: (numbers with the "0x"
prefixes are hex (as in C standard), the rest are in decimal)
- 1234 (usercode) xor 0x4D2 = 0
- 1892 (initial) xor 0x8B9 = 4061 (final realcode)
But since 0 is not equal with 4061, we're the bad_boys! So how are we going
to reversed this algo? Simple. It's just a
simple algebra. Ok. We know
that 4061 is our (well, my) final realcode noh? So what we do is this:
- 4061 (final) xor 0x4D2 = 2831 (usercode)
Let's check:
- 2831 (usercode) xor 0x4D2 = 4061
- 1892 (initial) xor 0x8B9 = 4061 (final realcode)
So that's it! The serial is sniffed (heh!). So if I entered 2831
by moving the topmost bar to 2, the 2nd to 8, the 3rd to 3
and the 4th
to 1. Then hit "Check", it'll register! But we don't
just want a serial right? Anyway, here's my keygen in JavaScript. Note:
The could be some problems though, just imagine. We could only enter 4
numbers, but what if
the result was >= 4 numbers. I never encountered
this myself though, but what if? Oh yeah, if the output for a name
resulted to only 3 numbers, you could bet that the 1st bar should be 0, then
just continue on with the rest.
The Keygen