Log in

View Full Version : Crack me help


TB10
December 22nd, 2013, 11:17
Hello,

Can someone help me with this crackme, a password protected Setup, written in Delphi, PEid shows me that its not packed with protector.
But it seems to me that it is a selfmodifying exe., i´ve tried to remove the password dialog window in olly, but it looks like there is only one window for all messages, just the text changes(search for text etc. dont help), you can set a breakpoint at "GetKeyState" API, and olly breaks while input Passwort in the Box.
The "Next" Button is grayed out as long you dont insert the right password.
As an Beginner this is not the usual stuff like search for text strings or nag screens, very hard !
So i need help from some good reverser, thank you !
Andy.

CrackZ
December 22nd, 2013, 16:03
Looks pretty easy to me. Study sub_417524 in IDA.

Regards,

CrackZ.

TB10
December 23rd, 2013, 05:25
Ok, sounds interesting, olly and IDA breaks at 417524, but how could be a code solution looks like, nop, jmp or other ?2869

Kayaker
December 23rd, 2013, 21:48
In this case you can do a 1 byte patch, but I don't think that's the point of the crackme. You should be able to easily see your password compared in the registers (and determine the length it's looking for), and you can change the zero flag on jz/jnz calls to continue in the right direction with a mock password. Then see if you can find the 1 byte patch solution which will EnableWindow() to proceed with the installation even without a password.
Once you do that though you'll want to go back and work on the real algorithm.

blabberer
December 24th, 2013, 03:57
keygen for the crackmes first letter and proof of validity crack me first to crack the rest
Code:

:\>windbg -c "bp KERNEL32!VirtualAlloc;g;gu;bc *;r $t1= @eax+26a0;ba w1 @$t1;g;
db @eax;bc *;ba r1 @$t1-8;g;g;bd *;db esi;? ('V'*'V'+1)%'Z'+30;g" Setup.exe

TB10
December 24th, 2013, 07:41
First, thank you all !
Hm, i try to understand, at 00417588 CMP EBX,30 Olly breaks when you try to insert first key letter, but where can i find the needed length of password ?
Until now i have no luck changing the zero flags at the jumps, i got only error messages, but there must be a jump to the install window(after the password dialog) right ?

How can i use your Keygen Code !?, sorry i´m just beginning in reverse

2870

reverser
December 24th, 2013, 21:09
People who post screenshots in jpg need to be quartered and shot.
2872

Aimless
December 25th, 2013, 02:14
Come on, PNG lost the battle long ago...

JPG for life!!!!

Have Phun

TB10
December 25th, 2013, 04:52
Indeed, PNG ist better for screenshots, smaller file size, so next time PNG , no problem(before i get quartered here...)

blabberer
December 25th, 2013, 06:51
How can i use your Keygen Code !?, sorry i´m just beginning in reverse

yep that question is indeed beginning in reverse how about moving forward and making some efforts to tow from the front ?
did you find out what windbg is ?
what bp is in that context ?
where bp is set in the command and why ?
what does g do in windbg ?
what does gu do in windbg ?
what would eax hold when returning from a function universally ?
what is an access breakpoint ?
how does an access breakpoint work ?
does it work for both read access and write acesss ?
what other accesses can access breakpoint work for ?
what sizes does it take ?
how many access breakpoints are available ?
what does bd do ?
is there an expression evaluator in the cryptic command ?
if yes what does it evaluate ?
what is the relation if any with the first letter as posted?
do you see a display of it ?
what is displayed on the screen when you simply follow
can you emulate the same scenerio in ollydbg / gdb / ida / hopper / <your own whatever >
if yes what did you understand ?
finally what is the moral of the story ?
now when you reach here you would be able to use the keygen code without asking anyone

niaren
December 25th, 2013, 17:56
Quote:
[Originally Posted by blabberer;95891]
Code:

:\>windbg -c "bp KERNEL32!VirtualAlloc;g;gu;bc *;r $t1= @eax+26a0;ba w1 @$t1;g;
db @eax;bc *;ba r1 @$t1-8;g;g;bd *;db esi;? ('V'*'V'+1)%'Z'+30;g" Setup.exe


OMG what kind of encryption is that!
How did you find out that the hashed input is save at offset 26a0 so quickly. Clearly (after setting bp on getwindowtext and stepping out a couple of times) the hash it stored at address 26a0 (start address looks to be offset 269c) but how did you determine that this is the offset into some chunk of memory allocated previously in the first call to VirtualAlloc? (Sorry for the noob question)

blabberer
December 26th, 2013, 02:08
@niaren the address does not hold hashed output take a look again and for start of the hash you are off by another 4 bytes
look at crackZ hint a very superb hint there ( i just latched into it that is all)
i didnt do anything except finding out who calls the function and then latch into kayakers second hint of one byte patch

must have taken about two minutes to bypass the check without password

once you know you can bypass it without password you are then sure that one of the parameter earlier must be the key
search for the address and you find it is allocated memory
so whooooddddonit?
what is result of the act?
is the offset you saw earlier constant?
how to verify ?
once you verified what else it is looking for ? what could be the algorithm what is the length etc etc

these question should automatically pop up

TB10
December 26th, 2013, 07:55
@blabberer, if i can answer all the List, there ist really no need for any further questions !, well i know, for an expert it´s boring to answer all the stupid beginners questions over and over again, but, without questions - no learning ok, windbg is an debugger, the name says it.
This debugger code stuff is very,very hard to understand for me, just for this small crackme you get tons of code, something of abstract, and which of them is usefull or not ?, try to learning step by step(very small steps) and i read lots of tutorials but until now i found no answer for this special crackme with this intresting keystroke trapping, thats why im asking here, right now an "easy solution" bypassing the password window would be enough for me, i am not in the position to understand detailed whats going on in every line of code, sorry.
2 minutes to bypassing password check ?, oh no !!! woooow , is it really so easy ?, i´m a looser

blabberer
December 26th, 2013, 14:09
well you seem to miss the point of posting

i do not want you to answer all those question
neither do i want you to be an expert answering all those question or even pretend to undertand those question
nor i am bore to answer noobish questions

i just want you to try to understand some of those questions
i just want you to put some efforts into the TRYING part

and i am sure if you try you will find the path

yes it is sbsolutely under 2 minutes to patch a sete opcode somewhere to make this crackme work without password

Kayaker
December 26th, 2013, 20:37
Don't worry TB10, no one is mocking you or anything here. Believe me, we've all been exactly where you are at one time. Part of the learning process is to work through things on your own until the "lightbulb" goes on, one small step at a time. You learn a lot more that way, having to do little researches to understand what people or the code is saying.

One thing that will help you at this point is to learn what each of the opcode instructions DO, before trying to understand what the code DOES. i.e., learn what the words mean before trying to read the language.

For example, I mentioned specifically about changing the zero flag on JZ/JNZ calls to force the code to go in a direction you want so you can continue tracing. Then you seemed to focus on JBE/JAE jumps and complained about not being able to modify them. You need to understand what those jumps actually mean in the context of the previous comparison instructions and how register flags other than the Zero Flag (ZF) are affected, if you want to control them (not that you want to in this particular case anyway).

Similarly, blabberer gave a clue about a SETE opcode which might be important - what exactly is that and what does it do? That's something you need to know more about.


I've attached 2 files, one is the standard opcode mnemonic help file from the Masm32 install. The other, perhaps lesser known, is a small opcode instruction table program that made the rounds on the masm/win32asm forums many years ago. If you can get comfortable with what they are telling you it should help your progress. And if you want to continue to learn assembly language you should at some point devour Iczelion's tutorials, inlcuding the PE tutorials.

http://win32assembly.programminghorizon.com/tutorials.html

Good luck


btw, excellent resolution on the PNG file blabberer. Reverser was bang on! We need to enforce that somehow

TB10
December 27th, 2013, 07:39
Thanks to blabberer and kayaker !, thats my intention, to learn by trying, the hard thing is to find the right point in the tons oft code, so the hints for "look at xxxxxx" and the thing with the SETE is helpfull, thats excatly what im lookin for !, changing a register flag on some position, but the lot of jumps and rtn. confusing me.(like a ping pong game)
Hm, there a some SETE opcodes...hm, i suspect someone of this enables the grayed out "next" Button.
I will check this.

thank you for opcode map !, also find a good web page with detailed opcode descripton.

Aimless
December 27th, 2013, 08:02
Quote:
[Originally Posted by Kayaker;95924]

btw, excellent resolution on the PNG file blabberer. Reverser was bang on! We need to enforce that somehow



Nooooo.....!!!! Et Tu, Brutus????

What thus happens to my jpgs? My preciousssss.s.s......

Have Phun

niaren
December 27th, 2013, 18:03
Quote:
[Originally Posted by blabberer;95912]@niaren the address does not hold hashed output take a look again and for start of the hash you are off by another 4 bytes
look at crackZ hint a very superb hint there ( i just latched into it that is all)
i didnt do anything except finding out who calls the function and then latch into kayakers second hint of one byte patch


Hi blabberer
What I meant was that in general if you take any address you see in the debugger and its in the heap somewhere then I'm unsure if it is straight forward to decompose it into base + offset like you did in the windbg command...the reason I'm asking is that there could be a vast amount of memory allocations and deallocations in a program.

For the setup.exe there is an alternative (and also easy) way to get to the interesting code as shown by crackz. IDA shows two references to GetWindowTextA. The one at 00408851 is most interesting. Setting a BP there (windbg will break immediately), stepping out one time (gu) and we land here

2885

Unfortunately, I have spent a couple of hours trying to work out the keygen both in assembly and in octave. Unless I have made some bugs (which is most likely ) it seems that no input string can map to the expected hash string

niaren
December 28th, 2013, 15:49
This script generates 3000+ valid keys

Code:

%00992698 17 00 00 00 50 58 31 51 47 ....PX1QG
%009926a1 54 54 45 55 3c 53 37 3f 3c TTEU<S7?<
%009926aa 39 54 34 33 33 38 37 4d 33 9T43387M3

hash = {'50', '58' '31' '51' '47' '54' '54' '45' '55' '3c',...
'53' '37' '3f' '3c' '39' '54' '34' '33' '33' '38' '37' '4d' '33'};
hash2 = hex2dec(hash);

Nkeys = 0;
L = 23;
minkey = 48;
maxkey = 90;
key = minkey*ones(1,L);
accs = zeros(1,L);
i = 1;
M = 2^32;
while(i>0 & i<=L)
Li = L-i;
acc = accs(i);
c = key(i);
t = rem(acc*Li,M);
acc = rem(acc + t,M) + c;
y = rem(acc*c,M) + i;
y = rem(y,90);
if(y<48)
y = y+48;
end
while(y<48 | y>90)
y = rem(y,90);
if(y<48)
y = y+48;
end
end

if(y == hash2(i))
if(i==23)
Nkeys = Nkeys +1;
char(key)
key(i) = c + 1;
if(key(i) > maxkey)
key(i) = minkey;
i = i - 1;
if(i>0)
key(i) = key(i) + 1;
end
end
else
i = i +1;
accs(i) = acc;
end
else
key(i) = c + 1;
if(key(i) > maxkey)
key(i) = minkey;
i = i - 1;
if(i>0)
key(i) = key(i) + 1;
end
end
end
end
Nkeys


The first key generated is:=4PC1HSMJ28A@L86M7JF:K0
The last key generated is: OX4SGJIKLX<1=:0RU?1<H?K

Many more keys can be generated if the range of input chars is expanded.

niaren
December 28th, 2013, 15:59
Hi blabberer,

Code:
:\>windbg -c "bp KERNEL32!VirtualAlloc;g;gu;bc *;r $t1= @eax+26a0;ba w1 @$t1;g;
db @eax;bc *;ba r1 @$t1-8;g;g;bd *;db esi;? ('V'*'V'+1)%'Z'+30;g" Setup.exe



Code:
bp KERNEL32!VirtualAlloc;g;


Set BP on that function and let the debugger run. Somehow you found out that the first call to this function allocates the memory (for program instance or some other large object) that contains the target hash string. We need to save the address returned here in order to set BP on the VA of some byte in the target hash string.

Code:
gu;


Let VirtualAlloc return, eax holds the base address of the allocated memory.

Code:
bc *;


Clear all BPs, we need no further breaks on VirtualAlloc.

Code:
r $t1= @eax+26a0;


Store the VA of some byte into the target hash string into the pseudo register $t1. We need to store this address because this address is used to set a BP.

Code:
ba w1 @$t1;g;


Set a BP which will stop the debugger when the byte at the address in register $t1 is written to. I don't know why but it seems that windbg also accepts this command "ba w1 $t1" without the @ in front of $t1. Also windbg will break at exactly the same place if the BP is written "ba w4 @$t1;" with dword access. Then make the debugger run. The debugger will break at address 403cc8 inside some LStrSetLength function. Eax holds the start address of the target hash string which is offset 269c. offset 26a0 is thus the 4th byte of the string.

Code:
db @eax


dump the memory (byte-wise) starting at offset 269c. It will show the first 3 characters of the target hash string.

Code:
bc *;


Clear all BPs again.

Code:
ba r1 @$t1-8;g;g;


Set a BP which will stop the debugger when the byte at offset 2698h is read. The length of the target hash string is stored in this dword. I guess the idea of setting a read BP here is that when the program is going to compare the target hash string to the input hash string this BP is hit. Then make the debugger run. First time the debugger stops it is at address 403928 inside some LStrCat function. Second time the debugger stops it is at address 403cc4 inside the LStrSetLength function.

Code:
bd *;


disable all BPs

Code:
db esi


esi does not contain a valid address at this moment so this command will show a bunch of question marks. Pressing g one or two additional times esi contains a valid address near the target hash string and a part of the target hash string is shown in the memory dump.

Code:
? ('V'*'V'+1)%'Z'+30


Clearly you know how the program computes the hash from the input The command ? means that windbg is running the command in 'calculator mode' instead of in 'command mode'. If the first char in the input is 'V' this expression gives the first char in the hash string. However, 'V' is not an acceptable first char in the input in my setup. Could it be that the crackme expects different keys when run on different machines?

TB10
December 28th, 2013, 16:24
Quote:
Could it be that the crackme expects different keys when run on different machines?

Definitely not, the password ist always the same, no matter on what computer system the crackme runs, thats one of the few things i now about, and it is build with "smart install maker" i found out.

CrackZ
December 28th, 2013, 16:25
I concur entirely with niaren. An interesting exercise might be to narrow the range of valid input chars to just the alphanumeric set; a look through the valid results might uncover the authors actual password as opposed to those that work ;-).

Kayaker
December 29th, 2013, 03:53
Keygenning in Matlab niaren? That's different

niaren
December 29th, 2013, 05:47
Quote:
[Originally Posted by TB10;95940]Definitely not, the password ist always the same, no matter on what computer system the crackme runs, thats one of the few things i now about, and it is build with "smart install maker" i found out.


It seems that the password is the same in that it reads the target hash from the file at offset 0x1E4DF. Maybe you can check if you read the same string at that address in your setup.exe

2886

By the way, is it possible that you can reveal where you got the crackme from?

niaren
December 29th, 2013, 05:55
Quote:
[Originally Posted by Kayaker;95943]Keygenning in Matlab niaren? That's different


Hi Kayaker, I almost fell of my chair laughing when I saw your comment I'm a little embarrased about the Matlab thing but I hoped that nobody would recognize Matlab to a hammer everything looks like......
From blabberers post I learned about the ? command. That is very interesting. Because I also saw that it supports loops. Then maybe it is possible to keygen in windbg

niaren
December 29th, 2013, 06:18
Quote:
[Originally Posted by CrackZ;95941]I concur entirely with niaren. An interesting exercise might be to narrow the range of valid input chars to just the alphanumeric set; a look through the valid results might uncover the authors actual password as opposed to those that work ;-).


Hi CrackZ, I did try that but have not found anything obvious. Constraining the valid input chars to the alphanumeric set including lower and uppper letters ([0-9A-Za-z]) the keygen generates more than 7.000.000 possible keygens.
Considering only lower letters ([a-z])the keygen produces 6 possible keys
whdklposvbnaazjdqscrzua
whdklposvbnaazjdqscrzui
whdklposvbnaazjdqscrzup
whdklposvbnaaztrwwttzua
whdklposvbnaaztrwwttzui
whdklposvbnaaztrwwttzup
Considering only Upper letters or Upper letters in combination with digits the keygen is not able to generate any valid keys. Dunno what else to try..

TB10
December 29th, 2013, 16:19
Quote:
It seems that the password is the same in that it reads the target hash from the file at offset 0x1E4DF

Bingo !, thats the ENCRYPTED password !, sorry, unfortunately i do not remember exactly the adress where i got this crackme, buuuut i simply try the tool with which it was created !, the "smart install maker", nice programm to create installers, so i build one exe. with my own password to look on the same position in hex editor, and find that it shows really the encrypted password just tried to change the LENGTH of it to compare)so, next step i simply copy the password of my own exe. to the crackme(and replace original), the length MUST be equal ! in hex editor, an tried my luck, and it works fine !
Ok, thats indeed not a really smart reverser solution, but easy for an newbie, and a good learning step.But it intrests me how the encryption works and is there a way to decrypt that thing in ollydbg(or other) it seems that the encryption algorythm is not randomize, that means, for example 123 results always in same encrypted letters, but it depends on the whole combination of the Password, not on single letters.
The keygen stuff sounds interesting, but how how can that work on custom (not generated) passwords ?

i´ve created the screenshot as PNG but upload Manager changed it to (bad) JPEG, only external filehoster for PNG ?

blabberer
December 29th, 2013, 17:10
@niaren
nice to see you crack the windbg encryption
you use @ in windbg when playing with registers or pseudo registers to eliminate symbol resolving time
windbg interprets @Ecx as pointing to register ECX not to some symbol named ecx many a times you can get away with $t1 but once in a while it will bite you and start loading infinite no of symbols and downlaod infinite number of pdbs and then will print out error symbol ecx not resolved
iirc this behaviour is documented i think but i made it a habit to do poi(@ecx) poi(@esp+4) instead of poi(eax)

yes you can keygen in windbg

as to resolving to base+offset yes it should hold true if you break and trap the return

just let loose L= 23 in your script

for starters this password
Code:
CX2g!F%q9&gf6R1D11ssdr4442222222226
should get you the first 8 of the hash constantly


EAX 009B40F4 ASCII "PX1QGTTEO>:0ERPZHY7C36UVI<3L3R;>YN="
ECX 00000000
EDX 009926A8 ASCII "PX1QGTTEU<S7?<9T43387M3"

Kayaker
December 29th, 2013, 18:00
Quote:
[Originally Posted by TB10;95947]i´ve created the screenshot as PNG but upload Manager changed it to (bad) JPEG, only external filehoster for PNG ?


That's fine, vBulletin automatically converts PNG to JPG if it's over a certain size (currently set at 1024x768).

Preciousssss is safe from the sneaky little hobbitses...

blabberer
December 29th, 2013, 18:14
@niaren there is a typo address should be 26b0 and not 26A0

when you run the command windbg should print the first 8 letters of the hardcoded hash and continue till you input a letter in the edit box
when you enter a letter it should dump the result as well as the answer for the expression
'V' is just a letter if you input C in edit box windbg should show you the dump and answer like below corresponding to the first letter


Code:

Processing initial command 'bp KERNEL32!VirtualAlloc;g;gu;bc *;r $t1= @eax+26b0;ba w1 @$t1;g;db @eax;bc *;ba r1 @$t1-8;g;g;bd *;db esi;? ('C'*'C'+1)%'Z'+30;g'0:000> bp KERNEL32!VirtualAlloc;g;gu;bc *;r $t1= @eax+26b0;ba w1 @$t1;g;db @eax;bc *;ba r1 @$t1-8;g;g;bd *;db esi;? ('C'*'C'+1)%'Z'+30;g
Breakpoint 0 hit < valloc break
Breakpoint 0 hit < ba w1 break
009926a8 50 58 31 51 47 54 54 00-00 00 00 00 00 00 00 00 PX1QGTT.........
009926b8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009926c8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009926d8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009926e8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009926f8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00992708 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
00992718 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
Breakpoint 0 hit <------ ba r1 break and continue with g to start running the crackme;
Breakpoint 0 hit <------ ba r1 second break when you input a charecter in edit box

009b40c4 50 00 00 00 f8 b5 41 00-f8 b5 41 00 34 3f 00 00 P.....A...A.4?..
009b40d4 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009b40e4 00 00 00 00 00 00 00 00-00 00 00 00 20 9e 40 00 ............ .@.
009b40f4 00 00 00 00 00 00 00 00-00 00 00 00 00 80 01 00 ................
009b4104 00 01 00 00 00 00 00 00-00 00 ff ff ff ff 00 00 ................
009b4114 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
009b4124 00 00 00 00 00 00 00 00-00 00 00 00 f8 b5 41 00 ..............A.
009b4134 f8 b5 41 00 cc 3e 00 00-30 00 00 00 01 00 01 00 ..A..>..0.......
Evaluate expression: 128 = 00000080



if you want to test the generation and try your hand at bruteforcing till you can keygen

put this in a txt file and run windbg like this
Code:

windbg -c "$$>a< setuppw.txt" Setup.exe


here are the commands

Code:

bp /1 KERNEL32!VirtualAlloc;
g;
gu;
r $t1= @eax+26b0;
ba w1 /1 @$t1;
g;
r $t2 = @eax;
db @$t2;
ba r1 @$t1-8;
g;
g;
bs 0 "db /c 20 @esi L20;db /c 20 @$t2 L20;.echo ================;gc";
g;

niaren
December 30th, 2013, 16:47
Quote:
[Originally Posted by blabberer;95950]
if you want to test the generation and try your hand at bruteforcing till you can keygen

put this in a txt file and run windbg like this
Code:

windbg -c "$$>a< setuppw.txt" Setup.exe


here are the commands

Code:

bp /1 KERNEL32!VirtualAlloc;
g;
gu;
r $t1= @eax+26b0;
ba w1 /1 @$t1;
g;
r $t2 = @eax;
db @$t2;
ba r1 @$t1-8;
g;
g;
bs 0 "db /c 20 @esi L20;db /c 20 @$t2 L20;.echo ================;gc";
g;


Hi blabberer, if I run windbg with the setuppw.txt script file in the command line windbg does not break when I enter anything into the password edit box. After pressing next and entering something into the edit box windbg does not break. I think the problem is that BP ba r1 @$t1-8; does not get hit (I tried to follow the procedure manually). It is strange that after entering a string of length 23 and with the first 10 chars valid it does still not break

2894

niaren
December 30th, 2013, 16:58
Quote:
[Originally Posted by TB10;95947]
But it intrests me how the encryption works and is there a way to decrypt that thing in ollydbg(or other) it seems that the encryption algorythm is not randomize, that means, for example 123 results always in same encrypted letters, but it depends on the whole combination of the Password, not on single letters.

Hi TB10, technically it may not be regarded as encryption in that the keygen process is irreversible, information is lost, you can't come up with a decryption algo that restores the original password (unless for specific cases). Try to understand what is going on in that function crackz pointed out and I'm sure you will understand much better. The function is not very long or hard to understand/reverse. You also have some hints in this thread about what is going on in that function if need input

Kayaker
December 30th, 2013, 18:30
Pardon me if you already did, but did you modify the script to use the offset that *you* are getting (269C)?

The offset will change a bit depending, as I found out, on the length of the full pathname of the exe. For example, if I run setup.exe from the folders
C:\, C:\a or C:\ab - the password key is copied to offset 2678
the slightly longer pathname C:\abc - offset is shifted to 267C
an even longer pathname - offset 2680

Apparently something related to the pathname is stored in the virtual memory block before the password string and that shifts everything depending on the length.

blabberer
December 31st, 2013, 02:36
yes it doesnt look like any encryption but some pseudo random generator based on some original password i guessed so when i first saw the second and third charecters are replaced on addition of every charecter to the password because it is generated based on the lenght of the pw
(generated from backwards) so obviously every thing would depend on the lenght of the pw

yes as kayaker pointed out the offsets do change based on various factors like path name , password lenght etc the algo keeps on copy pasting data to different places in the allocated 0x28000 block.

in your screen shot i see the 2 bps hit so you may need to view memory a bit up and down and see where the generated hash is stored
my script wont let windbg break it will simply print the output and keep on continuing and you can watch the passowrd generated as you enter charecters in the edit box (if you loose focus of edit box it will be quiet some time to see them again till WM_PAINT WM_MOUXEXXXX msgs are processed by the windowing system ) keep windbg in background and crackme in top of Z order and enter password to view output in windbg below

i trivially bruteforced it in ollydbg with the ripped algo from sub crackZ hinted but there are further checks and from a fleet glance at comparison algo next to the sub i think you need a password that is of certain length and 23 is not the right size either add eax,eax or cmp ch.bh should set the zer0 flag ) so that dl is set in sete dl
here is a full password for your test

Code:

CX2g!F%q2FP]$f,B+7,&@G.000000000000
Press any key to continue . . .



here is the shabby shitty bruteforcer for the above password
Code:

// setuppw.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define HARDCODED_HASH_LENGHT 0x17
#define CRYPTED_HASH_LENGTH HARDCODED_HASH_LENGHT + 0xc

BYTE HARDCODED_HASH[HARDCODED_HASH_LENGHT] = //009926A8 PX1QGTTEU<S7?<9T43387M3
{
0x50, 0x58, 0x31, 0x51, 0x47, 0x54, 0x54, 0x45,
0x55, 0x3C, 0x53, 0x37, 0x3F, 0x3C, 0x39, 0x54,
0x34, 0x33, 0x33, 0x38, 0x37, 0x4D, 0x33
};

BYTE CRYPTED_HASH[CRYPTED_HASH_LENGTH] = {0};
BYTE PASSWORD_HASH[CRYPTED_HASH_LENGTH] = {0};
DWORD count = 0;

int _tmain(int argc, _TCHAR* argv[])
{
// i started with '!' filled buffer to brute force but i saw it generating non printable bytes
// so ripped correct printable bytes from ollydbg to the array which made the generation of all printable
// charecters possible the array below generates a correct HARDCODED_HASH but few more checks need to be
// passed in the comaprison algo (add eax,eax or cmp ch.bh one of this should set the zero flag)
// have fun finding how to do it

memset(&CRYPTED_HASH,0x21,sizeof(CRYPTED_HASH));

CRYPTED_HASH[0] = 'C';
CRYPTED_HASH[1] = 'X';
CRYPTED_HASH[2] = '2';
CRYPTED_HASH[3] = 'g';
CRYPTED_HASH[4] = '!';
CRYPTED_HASH[5] = 'F';
CRYPTED_HASH[6] = '%';
CRYPTED_HASH[7] = 'q';
CRYPTED_HASH[8] = '2';
CRYPTED_HASH[9] = 'F';
CRYPTED_HASH[10] = 'P';
CRYPTED_HASH[11] = ']';
CRYPTED_HASH[12] = '$';
CRYPTED_HASH[13] = 'f';
CRYPTED_HASH[14] = ',';
CRYPTED_HASH[15] = 'B';
CRYPTED_HASH[16] = '+';
CRYPTED_HASH[17] = '7';
CRYPTED_HASH[18] = ',';
CRYPTED_HASH[19] = '&';
CRYPTED_HASH[20] = '@';
CRYPTED_HASH[21] = 'G';
CRYPTED_HASH[22] = '.';


__asm
{
pushad
redo:
xor edi,edi
mov ebp,CRYPTED_HASH_LENGTH
mov esi,1
looper:
mov eax, offset CRYPTED_HASH[0]
movzx eax,byte ptr [eax+esi-1]
mov edx,eax
mov ecx,CRYPTED_HASH_LENGTH
sub ecx,esi
imul ecx,edi
add edx,ecx
add edi,edx
mov ebx,eax
imul ebx,edi
add ebx,esi
BACK:
mov eax,ebx
mov ecx,5ah
xor edx,edx
div ecx
imul eax,eax,5ah
sub ebx,eax
cmp ebx,30h
jnb FORWARD
add ebx,30h
FORWARD:
cmp ebx,2fh
jbe BACK
cmp ebx,5bh
jnb BACK
mov eax,offset PASSWORD_HASH[0]
mov byte ptr [eax+esi-1],bl
inc esi
dec ebp
jnz looper
push ebx
mov ebx,offset HARDCODED_HASH[0]
add ebx,count
movzx ebx,byte ptr [ebx]
push eax
add eax,count
cmp byte ptr [eax] , bl
pop eax
pop ebx
je ARGH
push ebx
mov ebx,offset CRYPTED_HASH[0]
add ebx,count
inc Byte ptr [ebx]
pop ebx
jmp redo
ARGH:
cmp count,0x16
je finished
inc count
jmp redo
finished:
popad
}
printf("%s\n",&CRYPTED_HASH);
return 0;
}



the windbg output from script take a look at last output it shows full comaprison


Code:

ModLoad: 77b40000 77b62000 C:\WINDOWS\system32\apphelp.dll
ModLoad: 755c0000 755ee000 C:\WINDOWS\system32\msctfime.ime
Breakpoint 0 hit
Breakpoint 0 hit
ModLoad: 4b400000 4b486000 C:\WINDOWS\system32\msftedit.dll
Breakpoint 0 hit
009b40c4 50 00 00 00 f8 b5 41 00-f8 b5 41 00 34 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 P.....A...A.4?..................
009926a8 50 58 31 51 47 54 54 45-55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 00 12 00 00 00 01 00 00 00 PX1QGTTEU<S7?<9T43387M3.........
009b40c4 50 34 00 00 f8 b5 41 00-f8 b5 41 00 34 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 P4....A...A.4?..................
009926a8 50 58 31 51 47 54 54 45-55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 00 12 00 00 00 01 00 00 00 PX1QGTTEU<S7?<9T43387M3.........
================
009b40c4 50 38 42 00 f8 b5 41 00-f8 b5 41 00 34 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 P8B...A...A.4?..................
009926a8 50 58 31 51 47 54 54 45-55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 00 12 00 00 00 01 00 00 00 PX1QGTTEU<S7?<9T43387M3.........
================
================
009b40f4 50 58 31 51 47 54 54 45-55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 50 3b 4a 3f 46 4f 36 37 50 PX1QGTTEU<S7?<9T43387M3P;J?FO67P
009926a8 50 58 31 51 47 54 54 45-55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 00 12 00 00 00 01 00 00 00 PX1QGTTEU<S7?<9T43387M3.........
================



since this post developed a bit more than the usual google and poster disappearing after that without making effort or if he made effort without sharing the results
i took a loook again to complete the brute forcing again in ollydbg with the code above with only one modification that of making both hash length equal viz 0x17
because add eax eax can set the zero flag only if eax is 0 and eax can be zero only when both lengths are equal

this password solves the mystery
Code:

wbd584e'!P"/AX6$s/!L>1+


anyone want to post a neat and clean keygen for this ??

the concept should be the buffer must be filled with say 0x20 (first printable charecter <space> for 0x17 characters
increased one at a time upto 0x7f (last printable charecter viz ~ tilde) till the first character of the hardcoded hash is found viz 'P'.

then second X (if no valid second increase first by one and reset count back to zero so the next valid charecter for P is found

in my case above 'C' produced 'P' with certain sequnce of charecters in first brute session

in the second brute session 'w' produces 'P' with another sequence

and remember to reset the rest of characters back to what it was viz 0x20 before relooping to find the next character

it is fs$%%% easy to brute in this manner in ollydbg manually with the ripped algo no need to even pause the app can be done with just binary edit in dump window
while the exe is running need just one breakpoint at inc count line

i modified the code above a little bit to check for minimum acceptable charecter as PASSWORD for runnning brute session in ollydbg

Code:

// setuppw.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define HARDCODED_HASH_LENGHT 0x17
#define CRYPTED_HASH_LENGTH HARDCODED_HASH_LENGHT

BYTE HARDCODED_HASH[HARDCODED_HASH_LENGHT] = //009926A8 PX1QGTTEU<S7?<9T43387M3
{
0x50, 0x58, 0x31, 0x51, 0x47, 0x54, 0x54, 0x45,
0x55, 0x3C, 0x53, 0x37, 0x3F, 0x3C, 0x39, 0x54,
0x34, 0x33, 0x33, 0x38, 0x37, 0x4D, 0x33
};

BYTE CRYPTED_HASH[CRYPTED_HASH_LENGTH] = {0};
BYTE PASSWORD_HASH[CRYPTED_HASH_LENGTH] = {0};
DWORD count = 0;

int _tmain(int argc, _TCHAR* argv[])
{
// i started with '!' filled buffer to brute force but i saw it generating non printable bytes
// so ripped correct printable bytes from ollydbg to the array which made the generation of all printable
// charecters possible the array below generates a correct HARDCODED_HASH but few more checks need to be
// passed in the comaprison algo (add eax,eax or cmp ch.bh one of this should set the zero flag)
// have fun finding how to do it

memset(&CRYPTED_HASH,0x20,sizeof(CRYPTED_HASH));

//CRYPTED_HASH[0] = 'C';
//CRYPTED_HASH[1] = 'X';
//CRYPTED_HASH[2] = '2';
//CRYPTED_HASH[3] = 'I';
//CRYPTED_HASH[4] = 't';
//CRYPTED_HASH[5] = '\\';
//CRYPTED_HASH[6] = '-';
//CRYPTED_HASH[7] = 'i';
//CRYPTED_HASH[8] = '5';
//CRYPTED_HASH[9] = 'X';
//CRYPTED_HASH[10] = 'h';
//CRYPTED_HASH[11] = '9';
//CRYPTED_HASH[12] = '\\';
//CRYPTED_HASH[13] = '@';
//CRYPTED_HASH[14] = '6';
//CRYPTED_HASH[15] = 'z';
//CRYPTED_HASH[16] = '5';
//CRYPTED_HASH[17] = 'A';
//CRYPTED_HASH[18] = '7';
//CRYPTED_HASH[19] = '^';
//CRYPTED_HASH[20] = '>';
//CRYPTED_HASH[21] = '-';
//CRYPTED_HASH[22] = ':';

// wbd584e'!P"/AX6$s/!L>1+


__asm
{
pushad
redo:
xor edi,edi
mov ebp,CRYPTED_HASH_LENGTH
mov esi,1
looper:
mov eax, offset CRYPTED_HASH[0]
movzx eax,byte ptr [eax+esi-1]
mov edx,eax
mov ecx,CRYPTED_HASH_LENGTH
sub ecx,esi
imul ecx,edi
add edx,ecx
add edi,edx
mov ebx,eax
imul ebx,edi
add ebx,esi
BACK:
mov eax,ebx
mov ecx,5ah
xor edx,edx
div ecx
imul eax,eax,5ah
sub ebx,eax
cmp ebx,30h
jnb FORWARD
add ebx,30h
FORWARD:
cmp ebx,2fh
jbe BACK
cmp ebx,5bh
jnb BACK
mov eax,offset PASSWORD_HASH[0]
mov byte ptr [eax+esi-1],bl
inc esi
dec ebp
jnz looper
push ebx
mov ebx,offset HARDCODED_HASH[0]
add ebx,count
movzx ebx,byte ptr [ebx]
push eax
add eax,count
cmp byte ptr [eax] , bl
pop eax
pop ebx
je ARGH
adder:
push ebx
mov ebx,offset CRYPTED_HASH[0]
add ebx,count
inc Byte ptr [ebx]
pop ebx
jmp redo
ARGH:
push ebx
mov ebx,offset CRYPTED_HASH[0]
add ebx,count
movzx ebx,byte ptr [ebx]
cmp bl, 0x21
pop ebx
jl adder
cmp count,0x16
je finished
inc count
jmp redo
finished:
popad
}
printf("%s\n",&CRYPTED_HASH);
return 0;
}


niaren
January 1st, 2014, 18:10
Hi blabberer, I'm impressed how quickly you dig up this info and to be honest the amount of info is a bit overwhelming

Quote:

yes as kayaker pointed out the offsets do change based on various factors like path name , password lenght etc the algo keeps on copy pasting data to different places in the allocated 0x28000 block.

Thanks to both of you for pointing that out. I was not aware of this. I admit I was also a bit confused about exactly what byte the ba BP should be targeting. My string is indeed stored at offset 0x269c, therefore I was slightly confused that the target byte seems to be offset 0x269c-8. That seems be some kind of ID field...

Code:
struct DelphiString
{
int ID;
int Length;
char array[Length];
};


And this ID field is obviously being read every time a char is appended. After fixing the offset windbg now spits out a bunch of lines like this

Code:
================
00992090 a4 4c 40 00 00 00 00 00-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ac 20 99 00 b8 74 40 00 .L@...................... ...t@.
00992694 01 00 00 00 17 00 00 00-50 58 31 51 47 54 54 45 55 3c 53 37 3f 3c 39 54 34 33 33 38 37 4d 33 00 ........PX1QGTTEU<S7?<9T43387M3.
================




Quote:

in your screen shot i see the 2 bps hit so you may need to view memory a bit up and down and see where the generated hash is stored
my script wont let windbg break it will simply print the output and keep on continuing and you can watch the passowrd generated as you enter charecters in the edit box (if you loose focus of edit box it will be quiet some time to see them again till WM_PAINT WM_MOUXEXXXX msgs are processed by the windowing system ) keep windbg in background and crackme in top of Z order and enter password to view output in windbg below

Isn't it correctly understood that the windbg script is only supposed to break during build up of the target hash? I get the impression that windbg also should dump info (that the ba BP triggers) when entering chars into the edit box. That is not happening

I will have to wait until tomorrow to look into those additional checks you mention and also your very neat keygen

niaren
January 2nd, 2014, 15:33
Quote:
[Originally Posted by blabberer;95954]
i trivially bruteforced it in ollydbg with the ripped algo from sub crackZ hinted but there are further checks and from a fleet glance at comparison algo next to the sub i think you need a password that is of certain length and 23 is not the right size either add eax,eax or cmp ch.bh should set the zer0 flag ) so that dl is set in sete dl
here is a full password for your test

Code:

CX2g!F%q2FP]$f,B+7,&@G.000000000000
Press any key to continue . . .




That password looks like one of your 'encrypted' windbg commands
You may be right, there could be further checks in that there are many xrefs to the function at 0040C5A8 that updates the enable state of a window (including the next button).
I have now taken a quite detailed look at the comparison algo and I'm pretty sure that the password/key must be of length 23. If this is not the case the comparison does not set the zero flag.
The comparison algo computes the minimum string length between the two strings. Eax contains the difference in lengths between the two strings. Therefore in the end "add eax,eax" will clear the zero flag if the lengths are not equal.
If I paste CX2g!F%q2FP]$f,B+7,&@G.000000000000 into the password field the next button is not enabled but I'm sure if you mean that this should be the case..

Edit. Sorry I can see further down in your post that you already found out about the add eax,eax. So if I understand your keygen algo correct (I have to compile it later, need to install visual studio) then you start with an initial guess and then you process one char at a time until you find the 'closest' valid password/key. One thing that could be interesting to know is if the creator of the crackme used a password that had some meaning like 'ShaniaTwainsSecondLover' or something but that seems very difficult considering the vast number of valid passwords that can be generated.

niaren
January 2nd, 2014, 16:50
Hi blabberer,

I found this link for demystifying the $$>a< part of the windbg command line.
http://msdn.microsoft.com/en-us/library/windows/hardware/ff566261%28v=vs.85%29.aspx

But I'm still not done with the line
bs 0 "db /c 20 @esi L20;db /c 20 @$t2 L20;.echo ================;gc";

I understand that the line executes the commands when the 0th BP is reached instead of breaking. But I'm unsure about the gc part. It seems to turn the BP into a conditional BP but what is the condition?

If I put the following lines into setuppw.txt

Code:

bp 416c4e;
g;
bs 0 "db /c 20 @eax L20;db /c 20 @edx L20;.echo ================;gc";
g;


I get sort of what I think you also intended, namely that the target hash and the input hash is shown right above each other. However, it is annoying that the BP is hit so many times.

blabberer
January 3rd, 2014, 00:03
bs does not execute any commands
it updates the existing breakpoint

in this context ba r1 breakpoint is hit two times and run two times to avoid spurious breaks
on the second break the break point is updated to print esi and @$t2 and continue without breaking
gc is continue from conditional breakpoint command it is equivalent to pressing g in windbg command window but
satisfies certain internal varibales set in windbg while it broke on a condition g alone instead of gc should work without problems
but gc is recommended to be used in conditional breaks instead of g


omg you still havent found why it breaks so many time step away and start from start

hint indirectly uses a driver in ring 0 go search


well to compile the algo you dont need vs even old 9 mb bcc if you substitute unsigned long to DWORD byte gcc should be able to compile that
strip the stdafx crap
#include stdio , windows .hhh
compiler foo.cpp


yes it is manual brute forcing and can be done quiet fast (15 20 minutes max )inspite of 17 character and full printable set of possibilities.

niaren
January 3rd, 2014, 02:35
Quote:
[Originally Posted by blabberer;95964]
omg you still havent found why it breaks so many time step away and start from start

hehe, I do know its a timer callback and placing a BP in it explains why the there is so many breaks!


Quote:
yes it is manual brute forcing and can be done quiet fast (15 20 minutes max )inspite of 17 character and full printable set of possibilities.

Then I definitely have to try it because Matlab seemed to be faster! (and that cannot be true of course).

Thanks for all your patience on the windbg explanations its been quite fun to play with it

blabberer
January 3rd, 2014, 17:47
yes it is a TimerCallback so once the clock ticked it is bound to break

btw when i wrote 15 20 minutes i was not sure of exact time just to be sure i ran it again this time in windbg from start and all it takes is 7 iterations in windbg to retrieve a password the breaks are manual breaks with ctrl+break due to infinte looping caused by invalid charecter

Code:

=4PC1HSM&2t/=J2Ruo..&s)


src code converted to masm below also attached is an assembled binary

Code:

.386
.model flat, stdcall
option casemap:none
include f:\masm32\include\windows.inc
include f:\masm32\include\KERNEL32.inc
include f:\masm32\include\masm32.inc
includelib f:\masm32\lib\KERNEL32.lib
includelib f:\masm32\lib\masm32.lib

.data
HARDCODED_HASH db 50h,58h,31h,51h,47h,54h,54h,45h,55h,3Ch,53h,37h,3Fh,3Ch,39h,54h,34h,33h,33h,38h,37h,4Dh,33h,00h
CRYPTED_HASH db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
PASSWORD_HASH db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
count dd 0;
FormatStr db "%s\n",0

.data?
buffer db 512 dup(?)

.code
start:
pushad
redo:
xor edi,edi
mov ebp,17h
mov esi,1
looper:
mov eax, offset CRYPTED_HASH[0]
movzx eax,byte ptr [eax+esi-1]
mov edx,eax
mov ecx,17h
sub ecx,esi
imul ecx,edi
add edx,ecx
add edi,edx
mov ebx,eax
imul ebx,edi
add ebx,esi
BACK:
mov eax,ebx
mov ecx,5ah
xor edx,edx
div ecx
imul eax,eax,5ah
sub ebx,eax
cmp ebx,30h
jnb FORWARD
add ebx,30h
FORWARD:
cmp ebx,2fh
jbe BACK
cmp ebx,5bh
jnb BACK
mov eax,offset PASSWORD_HASH[0]
mov byte ptr [eax+esi-1],bl
inc esi
dec ebp
jnz looper
push ebx
mov ebx,offset HARDCODED_HASH[0]
add ebx,count
movzx ebx,byte ptr [ebx]
push eax
add eax,count
cmp byte ptr [eax] , bl
pop eax
pop ebx
je ARGH
adder:
push ebx
mov ebx,offset CRYPTED_HASH[0]
add ebx,count
inc Byte ptr [ebx]
pop ebx
jmp redo
ARGH:
push ebx
mov ebx,offset CRYPTED_HASH[0]
add ebx,count
movzx ebx,byte ptr [ebx]
cmp bl, 021h
pop ebx
jl adder
cmp count,016h
je finished
inc count
jmp redo
finished:
popad
mov eax, offset CRYPTED_HASH[0]
invoke StdOut , eax
retn
end start



run in windbg
set this break
fill the buffer and run the exe
reset buffer and count few times until you get a password like below

Code:

0:000> bp 4010a2 "db /c 18 403018 l18;gc"
0:000> eb 403018 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 2e 26 20 20 20 20 20-20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 =.& .
(f1c.19c): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 28 20 20 20 20 20-20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 =4( .
(f1c.ac4): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 29 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 44 20 20 20 20 20-20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 =4D .
(f1c.e70): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 45 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 4c 20 20 20 20 20-20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 00 =4L .
(f1c.b68): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 4d 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 50 25 22 48 53 35-26 3c 28 20 20 20 20 20 20 20 20 20 20 20 20 00 =4P%"HS5&<( .
(f1c.e78): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 4d 26 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 50 2b 24 4e 31 29-32 28 3e 27 4c 20 20 20 20 20 20 20 20 20 20 00 =4P+$N1)2(>'L .
(f1c.ac0): Break instruction exception - code 80000003 (first chance)
0:001> eb 403018 3d 2f 4d 2c 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;ed 403048 0;g

00403018 3d 34 50 43 31 48 53 4d-26 32 74 2f 3d 4a 32 52 75 6f 2e 2e 26 73 29 00 =4PC1HSM&2t/=J2Ruo..&s).