downloadbrowseksydfius's Reverse My Algo

Download ksydfius7.zip, 1 kb (password: crackmes.de)
Browse contents of ksydfius7.zip

ASM crackme.

Reverse the algo and find the pass :)

Enjoy!

-ksydfius

Difficulty: 1 - Very easy, for newbies
Platform: Windows
Language: Assembler

Published: 21. Nov, 2012
Downloads: 850

Rating

Waiting for at least 3 votes
(we have only 2).

Rate this crackme:

Send a message to ksydfius »

View profile of ksydfius »

Solutions

There are no solutions to this crackme yet.

The submission of solutions is closed.

Discussion and comments

mausy131
22. Nov 2012
Nice one. Working on it :)
terraNova
23. Nov 2012
easy as told, but nice work!
lheer
26. Nov 2012
Good job
That is correct!
audit
27. Nov 2012
That is correct!
Borgiman
28. Nov 2012
I hope someone is writing a tut, i'm too dumb to solve this myself :P
Kempniu
14. Dec 2012
Newbie here. Trying to solve this one, wrote a solver which generated a key that passes 3 of 4 checks and my last value only differs from the valid one by 1 bit (I get 5A74AC33 instead of 5A742C33). My suspicion is that I cannot simply reverse the RORs and XORs as the values in memory after the region checked by the crackme depend on the key provided, so I don't know what the memory contents for reversing are without the proper key. Any hints?
lemc
14. Dec 2012
I have solved this one by trial and error but by reversing the algo at: 00401028 and entering random data each time I noticed certain letters always wound up in the same spot after decryption. I tried multiple phrases and finally got the solution. I want to make my first ever tutorial for the community but dont know the sure shot method of getting the answer without trial and error. Hopefully ksydfius or anyone else can help me a little since i did infact get the solution. Thank you for the fun excersise ksydfius!
terraNova
15. Dec 2012
Wrote a solution and submitted it (23. Nov), but it's still not checked by a moderator.
Fresco
16. Dec 2012
i made the equivalent to c++;

#include<iostream>
#include<stdlib.h>
#include<fstream>

typedef unsigned char byte;
using namespace std;

unsigned char rotateright( unsigned char v, unsigned char x );
unsigned int int_rotateright( unsigned int v, unsigned char x );
void function_one( );
void function_two( int esi );
void hex_dump( );
void data_dump( );

char start_arry[]={
0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74,
0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x54, 0x68, 0x61, 0x74, 0x20, 0x69,
0x73, 0x20, 0x63, 0x6F, 0x72, 0x72, 0x65, 0x63,
0x74, 0x21, 0x00, 0x57, 0x68, 0x61, 0x74, 0x41,
0x72, 0x65, 0x59, 0x6F, 0x75, 0x44, 0x6F, 0x69,
0x6E, 0x67, 0x3F, 0x00, 0x54, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00,
};
char *filename=start_arry, *wayd=start_arry+0x23, *data=start_arry+0x38;

int main (){
ifstream data_txt( filename );
if( data_txt.good()==false ){
cout << "File does not exist!";
system("pause");
return 0;
}
data_txt.seekg(0, ios::beg);
data_txt.read(data, 0x10);
data_txt.close();
function_one();
function_two( 0x12 );
function_two( 0x23 );
function_two( 0x38 );
function_two( 0x23 );
function_two( 0x12 );
int *data_comparson = reinterpret_cast <int*>( start_arry+0x38 );
if( data_comparson[0]!=0xCD4558AD ){
cout << "Wrong code!";
system("pause");
return 0;
}
if( data_comparson[1]!=0xF7D5C9DB ){
cout << "Wrong code!";
system("pause");
return 0;
}
if( data_comparson[2]!=0x33C57B08 ){
cout << "Wrong code!";
system("pause");
return 0;
}
if( data_comparson[3]!=0x5A742C33 ){
cout << "Wrong code!";
system("pause");
return 0;
}
data_comparson = reinterpret_cast <int*>( start_arry+0x12 );
data_comparson[0]-=0x42ED41AE;
data_comparson[1]-=0xB6DFFEA1;
data_comparson[2]-=0xFA050ABE;
data_comparson[3]-=0x6B43746C;
cout << "Title = " << start_arry+0x9;
cout << "Body = " << start_arry+0x12;
system("pause");
return 0;
}

void function_one( ){
int esi=0x23,
edi=0x38;
unsigned char al=1;
while( 1 ){
al=start_arry[esi];
if( al==0 ){
break;
}
al = rotateright( al,3 );
start_arry[edi]=start_arry[edi] ^ al;
esi++;
edi++;
}
return;
}

void function_two( int esi ){
int eax=0,
ecx=0,
i=0;
int *int_arry = reinterpret_cast <int*>( start_arry+esi );
while( 1 ){
eax=int_arry[i];
if( eax==0 ){
break;
}
eax=eax^0x7671295A;
ecx=eax;
ecx= int_rotateright( ecx,5 );
ecx=ecx+0xBADC0DED;
ecx= int_rotateright( ecx,5 );
int_arry[i]=ecx;
i++;
}
return;
}

unsigned char rotateright( unsigned char v, unsigned char x ){
int i=0;
loop:
if( i==x )
return v;
i++;
unsigned char temp = v & 1; // extract the low bit
v >>= 1; // shift right
v |= ( temp<<7 ); // put the previous low bit in the high bit
goto loop;
}

unsigned int int_rotateright( unsigned int v, unsigned char x ){
int i=0;
loop:
if( i==x )
return v;
i++;
unsigned int temp = v & 1; // extract the low bit
v >>= 1; // shift right
v |= ( temp<<31 ); // put the previous low bit in the high bit
goto loop;
}
terraNova
17. Dec 2012
http://pastebin.com/RiW5xbqk - Here is my solution if you guys are interested (Code to obtain the key and a quick description how i got there).
nekrobunny
17. Dec 2012
many keys that pass the check:

20 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
24 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
25 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
26 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
27 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
41 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
42 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
43 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
4c 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
58 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
59 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
5a 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
5b 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
5d 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
5e 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
5f 7d 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
91 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
92 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
93 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
9c 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
a8 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
a9 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
aa 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
ab 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
ad 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
ae 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
af 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
b0 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
b4 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
b5 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
b6 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d
b7 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 6
b7 7e 66 61 6c dc 79 73 69 6b 25 ba 68 69 83 0d

and many more...
lemc
20. Dec 2012
Nice work on the solutions! When I solved it myself it was "ureallylikethis" (without quotes) in the data.txt file.
Fresco
20. Dec 2012
yeah! it's really strange because my solution is: Seal\ysik%chis. and it works!

#lemc How did you figure out "ureallylikethis" solution?
here's how i did mine:
1) place a breakpoint before the checks.
2) replace the generated bad code with the correct code (form the checks)
3) the result should be something like the byte memory array in the decryption algo below;

here's the c++ decryption algo:

#include <iostream>
#include <stdlib.h>
#include <fstream>

typedef unsigned char byte;
using namespace std;

byte memory[]={
0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74,
0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67,
0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7,
0xB7, 0x8C, 0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E,
0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C,
0x57, 0xA2, 0xFF, 0x7A, 0x36, 0xC9, 0x96, 0x9E,
0xAD, 0x58, 0x45, 0xCD, 0xDB, 0xC9, 0xD5, 0xF7,
0x08, 0x7B, 0xC5, 0x33, 0x33, 0x2C, 0x74, 0x5A,
0x0B, 0x22, 0xD3, 0x63, 0xB7, 0x87, 0xB9, 0x7C,
0xF4, 0xCA, 0x00, 0x00, 0x00, 0x00
};

char* filename_char = reinterpret_cast <char*> ( memory+0x00 ),
* title_char = reinterpret_cast <char*> ( memory+0x09 ),
* text_char = reinterpret_cast <char*>( memory+0x12 ),
* data_char = reinterpret_cast <char*> ( memory+0x38 );
byte* key_byte = reinterpret_cast <byte*> ( memory+0x23 ),
* data_byte = reinterpret_cast <byte*> ( memory+0x38 );
int* text_int = reinterpret_cast <int*>( memory+0x12 ),
* data_int = reinterpret_cast <int*> ( memory+0x38 );

byte ror8 ( byte x, byte times );
byte rol8 ( byte x, byte times );
unsigned int ror32 ( unsigned int x, byte times );
unsigned int rol32 ( unsigned int x, byte times );

void encryptstring();
void data_calculation ( byte offset );
void debug();

int main (){
text_int[0]+=0x42ED41AE;
text_int[1]+=0xB6DFFEA1;
text_int[2]+=0xFA050ABE;
text_int[3]+=0x6B43746C;

data_calculation( 0x12 );
data_calculation( 0x23 );
data_calculation( 0x38 );
data_calculation( 0x23 );
data_calculation( 0x12 );
encryptstring();

ofstream data_txt( filename_char );
if( data_txt.good()==false ){
cout << "File: " << (char)0x22 << filename_char << (char)0x22 << " is used by another application" << endl;
system( "pause" );
return 0;
}
data_txt.seekp( 0, ios::beg );
data_txt.write( data_char, 0x10 );
data_txt.close();
cout << "Data was successfully written to: " << (char)0x22 << filename_char << (char)0x22 << "!" << endl;
cout << "In order to make algo work you have to copy the generated file: " << (char)0x22 << filename_char << (char)0x22 << " alongwith the executable itself." << endl;
system( "pause" );
return 1;
}

void encryptstring(){
byte al=key_byte[0];
for( int i=0; al!=0; i++ ){
al = key_byte[i];
al = ror8( al,3 );
data_byte[i] ^= al;
}
return;
}

void data_calculation ( byte offset ){
int* raw_data = reinterpret_cast <int*> ( memory+offset );
for( int i=0; raw_data[i]!=0; i++ ){
raw_data[i] = rol32( raw_data[i],5 );
raw_data[i]-=0xBADC0DED;
raw_data[i] = rol32( raw_data[i],5 );
raw_data[i]^=0x7671295A;
}
return;
}

void debug(){
for( int i=0; i<82; i++ ){
cout.width( 2 );
cout.fill( '0' );
if ( i%8==0 )
cout << endl;
cout << hex << (int)memory[i] << " ";
}
cout << endl << endl;
return;
}

byte ror8 ( byte x, byte times ){
byte temp=0;
for( byte i=0; i<times; i++ ){
temp = x&0x01;
x >>= 1;
x |= ( temp<<7 );
}
return x;
}

byte rol8 ( byte x, byte times ){
byte temp=0;
for( byte i=0; i<times; i++ ){
temp = x&0x80;
x <<= 1;
x |= ( temp>>7 );
}
return x;
}

unsigned int ror32 ( unsigned int x, byte times ){
unsigned int temp=0;
for( byte i=0; i<times; i++ ){
temp = x&0x00000001;
x >>= 1;
x |= ( temp<<31 );
}
return x;
}

unsigned int rol32 ( unsigned int x, byte times ){
unsigned int temp=0;
for( byte i=0; i<times; i++ ){
temp = x&0x80000000;
x <<= 1;
x |= ( temp>>31 );
}
return x;
}
lemc
24. Dec 2012
#Fresco: Nice work on a c++ decrypter! What I did to get my "ureallylikethis"solution was to first inline the reverse of the algo under the main code. Then I tried 16 char long phrases such as the ones used in this program. I tried the following (from what I can remember cause there were other phrases): "is this correct?", "imdoingasolution" and "thatsthesolution". When the process finished the 16 chars of data that was left didn't work. Now even though the return values didn't work they all had a similar pattern of recurring chars in sequence. Such as "ally", "ike" and "his". After trying a few words together I got "ureallylikethis" but realized it was only 15 chars long. This is where luck comes in cause I wasn't going to try it but decided to for kicks and voila! It worked! Hope this helped you understand how I got my solution. If you really want I can remake my reverse algo solution in delphi + asm. Thanks again to everyone who helped me understand this program more with your solutions! And if you celebrate them, "Happy Holidays"!
[Wizzer]
24. Dec 2012
Got stuck a bit, almost same issue as Kempniu, but 2 bytes difference. I made a reverse algo, so when I put the whole data array from Olly (for some known input) it goes right to left and decrypts correctly. Problem is that when I take that data array, replace "key parts" with correct values from comparison, I can't get a valid key.
As example, data.txt file has text HelloPeople12345

Before first comparison I see this result in Olly:

0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74, 0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67, 0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7,
0xB7, 0x8C, 0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E, 0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C,
0x57, 0xA2, 0xFF, 0x41, 0x33, 0xC9, 0x0C, 0x6A, 0xCB, 0x98, 0x62, 0x84, 0x18, 0x8A, 0x96, 0x66,
0x0E, 0x75, 0xF4, 0x73, 0x65, 0x4E, 0x74, 0x5A, 0xFF, 0x0E, 0xD3, 0x63, 0x97, 0x81, 0xB9, 0x7C,
0x74, 0xD4, 0x00, 0x00, 0x00, 0x00

(I added 0x myself and last 4 0x00)

I decided to use Fresco's decrypter for testing, after running this I got file containing HelloPeople12345, so it is ok, now I will replace "key" location bytes with known values (from comparisons):

0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74,
0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67,
0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7,
0xB7, 0x8C, 0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E,
0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C,
0x57, 0xA2, 0xFF, 0x41, 0x33, 0xC9, 0x0C, 0x6A,
0xAD, 0x58, 0x45, 0xCD, 0xDB, 0xC9, 0xD5, 0xF7,
0x08, 0x7B, 0xC5, 0x33, 0x33, 0x2C, 0x74, 0x5A,
0xFF, 0x0E, 0xD3, 0x63, 0x97, 0x81, 0xB9, 0x7C,
0x74, 0xD4, 0x00, 0x00, 0x00, 0x00

and now run the application again, it generates file, copy file, rerun app in Olly, breakpoint at first comparison, data is:

64 61 74 61 2E 74 78 74 00 47 6F 6F 64 20 6A 6F
62 00 02 AA 4E B7 C1 67 53 D7 21 7A 77 6C D1 D7
B7 8C 40 5E DA 4A A9 5E 1E 7A 5B 5A 47 0E 0D 7C
57 A2 FF 41 33 C9 0C 6A AD 58 45 CD DB CA D5 F7
08 7B C5 33 33 2C 74 5A FF 0E D3 63 97 81 B9 7C
74 D4

and that key fails...

What am I doing wrong? Could it be a byte at 0x34 affecting, the one that is hresult of CreateFileA (40107B)?

(when I tried to decrypt data array that was in Fresco's sources - it worked, but can't get it working with my data)
lemc
25. Dec 2012
#Wizzer: That was my issue when I tried my own random data in the decryption routine I inlined. It wouldn't work with the decrypted data I got. I guess we just need to wait for ksydfius to post a working submitted solution or if not then hopefully a solution of his own so we can all understand the true decryption algo. Either way I had fun with it and hope to see a 100% solution!
[Wizzer]
25. Dec 2012
#lemc: Indeed, I've used a lot of efforts and no success, when I almost gave up and came here to see the solution, I was surprised that it was so "simple", I felt like I missed some crucial part and everything went upside down, but when I tried to test use decryptor provided here I realized that it doesn't work either. Main difference are the bytes just before the key and right after, some do repeat, but around 8-10 of those are different (have to open logs to see for sure). Those effect decryption algo and when I "inject" values from comparison into data set generated from, for ex. HelloPeople12345, it comes to 1-2 (sometimes 3-4) bytes difference after decryption anyway.

So I made a bruteforcer for my decrypting algo, I was substituting only bytes that differ depending on data.txt content - 6 of those in the tail (I didn't touch leading bytes, some differ there too), I was comparing 10 bytes after key location to be zeros after 5 passes of decryption, if all are - high chance that I got correct values, I tried it in a small range (in the tail, last 4 changing (not just last 4 bytes)) bytes for test) for a valid data set (the data set that was generated from data.txt, but key locations are not substituted). As soon as I tried the small range - brute found correct 4 last changing bytes.

Bruteforcing to all changing bytes would take a long time... my assumption was author's original idea wasn't bruteforcing, cause of the range to brute, so I left that idea aside for now.

P.S.: it is funny, but when I read your solution "ureallylikethis", I could see letters that are part of it, so my own decrypting algo was trying to get exactly this key, when data.txt has default text, so input key was "Greetings crackm", I took that data set, inject key parts from comparison, I ended up having:

WreallysikeІhism
0x57 0x72 0x65 0x61 0x6c 0x6c 0x79 0x73 0x69 0x6b 0x65 0xb2 0x68 0x69 0x73 0x6d 0x02 (!!!)

as you can see, it looks very familiar, but doesn't work as input key (and actually it is 17 bytes long, trailing 0x02, remember that what I said that all bytes after keylocation+16 must be zeros? So this one is obviously a wrong key. It passes 3 of 4 checks and fails on last one:
5A73AC33 compared to 5A742C33 - 2 bytes difference.

Not let's take a look at a data set for that key:

02 AA 4E B7 C1 67 53 D7 21 7A 77 6C D1 D7 B7 8C 40 5E DA 4A A9 5E 1E 7A 5B 5A 47 0E 0D 7C 57 A2 FF 42 33 C9 4F 66 AD 58 45 CD DB C9 D5 7 08 7B C5 33 33 AC 73 5A FB ED D3 63 77 6C B9 7C 34 D5

And this is a data set for "ureallylikethis":

02 AA 4E B7 C1 67 53 D7 21 7A 77 6C D1 D7 B7 8C 40 5E DA 4A A9 5E 1E 7A 5B 5A 47 0E 0D 7C 57 A2 FF 40 33 C9 57 66 AD 58 45 CD DB C9 D5 F7 08 7B C5 33 33 2C 74 5A BB 23 D3 63 F7 73 B9 7C 74 D4

10 bytes difference, including 2 bytes in key itself, now let me test my algo by feeding it latter dataset if I can get "ureallylikethis"... and I do get that 15 bytes length key, so algo does decrypt correctly:

Thatiscorrect!WhatAreYouDoing?\ureallylikethis <-- 0x00 were removed, but here is a decrypted dataset that provides accurate view:

0x54 0x68 0x61 0x74 0x20 0x69 0x73 0x20 0x63 0x6f 0x72 0x72 0x65 0x63 0x74 0x21 0x00 0x57 0x68 0x61 0x74 0x41 0x72 0x65 0x59 0x6f 0x75 0x44 0x6f 0x69 0x6e 0x67 0x3f 0x00 0x5c 0x00 0x00 0x00 0x75 0x72 0x65 0x61 0x6c 0x6c 0x79 0x6c 0x69 0x6b 0x65 0x74 0x68 0x69 0x73 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

As I said 10 last bytes are zeros (11 here because key is 15 bytes)

But I'm really looking forward a correct solution too :) According to IMHO (my lvl 1) point of view bruteforcing is required to get correct the key, that will make sure that last 10 bytes are zeros, 3 bytes before the key location are zeros and original texts (starting 403012) match, hresult byte 403034 can be ignored.

That's all for now :)

Thank you very much and happy holidays!
ksydfius
Author
30. Dec 2012
ok, here is my solution:

unsigned long func1 (unsigned long l){
return rol(rol(l, 5) - 0xBADC0DED, 5) ^ 0x7671295A;
}

void func2 (unsigned char data[], char string1[], int len, int len_string1){
for (int n = 0; n < len; n++){
unsigned char a = string1[n%len_string1];
a = ((a << 5) | (a >> 3)) & 0xFF;
data[n] ^= a;
}
}

void Decrypt (unsigned char data[], int len, int offset){
unsigned long dword;
for (int n = offset; n < len; n+=4){
dword = (data[n+3] << 24) | (data[n+2] << 16) | (data[n+1] << 8) | data[n];
dword = func1(dword);
data[n] = dword & 0xFF; data[n+1] = (dword & 0xFF00) >> 8;
data[n+2] = (dword & 0xFF0000) >> 16; data[n+3] = (dword & 0xFF000000) >> 24;
}
}

int main(){
unsigned char data[] = {0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67, 0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7, 0xB7, 0x8C,
0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E, 0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C, 0x57, 0xA2,
0xFF, 0xA4, 0x34, 0xC9, 0x54, 0x66, 0xAD, 0x58, 0x45, 0xCD, 0xDB, 0xC9, 0xD5, 0xF7, 0x08, 0x7B,
0xC5, 0x33, 0x33, 0x2C, 0x74, 0x5A, 0xBB, 0x23, 0xD3, 0x63, 0xF7, 0x73, 0xB9, 0x7C, 0x74, 0xD4};
int len = 64;

char* string1 = "WhatAreYouDoing?";

Decrypt(data, len, 0);
Decrypt(data, len, 0x11);
Decrypt(data, len, 0x26);
Decrypt(data, len, 0x11);
Decrypt(data, len, 0);

unsigned char enc[16];
for (int n = 0x26; n < 0x26+16; n++) enc[n-0x26] = data[n];

func2(enc, string1, 16, 16);
printf("%s\n", enc);

getch();
}
ksydfius
Author
30. Dec 2012
answer: ireallylikethis
[Wizzer]
02. Jan 2013
#ksydfius, thank you for your reply and Happy New Year :)

I tried your source code with Fresco's rol32 function implementation, I can see "ireallylikethis" text output. My question is how did you get data[] byte content?

What I did now:
1)copy-pasted ReadMe.txt as data.txt file, edited, now file has "Greetings crackm" text inside, no quotes and yeah, editing wasn't necessary, so I see that file is 16 bytes now
2)I run crackme in Olly, set breakpoint at first comparison at 4010F3 and binary copied 64 bytes starting at 403012 in memory dump
3)I added 0x and commas in front of each
4)pasted that data into your solution
5)replaced 16 bytes in that data starting at 0x26 (key location) with bytes that are used in comparison: 0xAD, 0x58 ,0x45, 0xCD, 0xDB, 0xC9, 0xD5, 0xF7, 0x08, 0x7B, 0xC5, 0x33, 0x33, 0x2C, 0x74, 0x5A
6)ran the application, btw I added to the end:
FILE* f = fopen("data.txt", "wb");
fputs((char*)enc, f);
fclose(f);
7)copy resulting data.txt to crackme's folder, run it in Olly with breakpoints set on first comparison
8)3 of 4 checks pass, one fails with 2 bytes difference

That is what I wrote about in my previous post, that my reverse algo gives some near solution answer too, but not the solution. I have a feeling that not every input can be reversed to a correct key or I'm still missing something :)

Could you please comment on this? Thank you!
ksydfius
Author
02. Jan 2013
Wizzer,

I think most of the bytes are constant, except for 2 or 3 that change depending on the input, so you will have to BF the bytes that change, then for each possibility decrypt the bytes
The problem is the check routine is a bit loose, but you can narrow down the possibilities to find the correct one
[Wizzer]
02. Jan 2013
#ksydfius, I feel like there are more bytes needed to be brute forced, in one of my posts I already wrote that I made a small bruteforcer, but saw that range to brute was big and gave up that idea, but seems I was correct, that bruteforcing might be required. Another way to brute could be to randomize input key and see if decryption succeeds, but that brings us to a condition that one needs to be lucky to get the correct input in the first place :)

To summarize, I think:
1)one has to be lucky with random input that would be correctly decrypted (byte difference will not affect key location)

2)bruteforce bytes that are different to meet decryption requirements

So, imho, second option is the correct solution to that crackme, though range (imho again) might be large (and probably also depends on initial input). If there was a constraint that key must be only a-zA-Z then bruteforcing seems to be even more of a correct (and the only?) solution :)

But anyway, thank you for the challenge :)
lemc
05. Jan 2013
#ksydfius: Wow, I was co close with my solution lol. Mine was "ureallylikethis" and your was "ireallylikethis". Thank you for posting your solution!
Fresco
07. Jan 2013
for me, the solution can be everything that passes the check, it's just a guesswork :D but fun after all :D
as for Wizzer ... here's how i got the arry:
place some random string in the data.txt file and the place a breakpoint before the checks, ... just copy / pase the hex vals, use my algo, and it'll return a valid key ... obviously i couldn't know what the creator of the algo had in mind and i labeled vals with eax ebx etc and it's kinda confusing, but if you analyse it i's the same thing, the second one is better than the first one :D
Fresco
08. Jan 2013
https://docs.google.com/folder/d/0B6cGfCmkO563S1NsTlVySUZVWlk/edit
[Wizzer]
12. Jan 2013
#Fresco, still no luck for me :)

0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74,
0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67,
0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7,
0xB7, 0x8C, 0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E,
0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C,
0x57, 0xA2, 0xFF, 0x55, 0x33, 0xC9, 0x0C, 0x6A,
0xCB, 0x98, 0x62, 0x84, 0x18, 0x8A, 0x96, 0x66,
0x0E, 0x75, 0xF4, 0x73, 0x65, 0x4E, 0x74, 0x5A,
0xFF, 0x0E, 0xD3, 0x63, 0x97, 0x81, 0xB9, 0x7C,
0x74, 0xD4, 0x00, 0x00, 0x00, 0x00

put that into your algo, you will get HelloPeople12345, what is correct, now let's replace in that array "key" location bytes with bytes from 4 cmps:

0x64, 0x61, 0x74, 0x61, 0x2E, 0x74, 0x78, 0x74,
0x00, 0x47, 0x6F, 0x6F, 0x64, 0x20, 0x6A, 0x6F,
0x62, 0x00, 0x02, 0xAA, 0x4E, 0xB7, 0xC1, 0x67,
0x53, 0xD7, 0x21, 0x7A, 0x77, 0x6C, 0xD1, 0xD7,
0xB7, 0x8C, 0x40, 0x5E, 0xDA, 0x4A, 0xA9, 0x5E,
0x1E, 0x7A, 0x5B, 0x5A, 0x47, 0x0E, 0x0D, 0x7C,
0x57, 0xA2, 0xFF, 0x55, 0x33, 0xC9, 0x0C, 0x6A,

/*0xCB, 0x98, 0x62, 0x84, 0x18, 0x8A, 0x96, 0x66,
0x0E, 0x75, 0xF4, 0x73, 0x65, 0x4E, 0x74, 0x5A, */

0xAD, 0x58, 0x45, 0xCD, 0xDB, 0xC9, 0xD5, 0xF7,
0x08, 0x7B, 0xC5, 0x33, 0x33, 0x2C, 0x74, 0x5A,

0xFF, 0x0E, 0xD3, 0x63, 0x97, 0x81, 0xB9, 0x7C,
0x74, 0xD4, 0x00, 0x00, 0x00, 0x00

run, copy generated file, run crackme in olly, you will see that 3 of 4 checks pass, 1 fails with 1 byte difference (second check):
F7D5C9DB compared to array's F7D5CADB
Fresco
31. Jan 2013
yes, bruteforce may be necessary ;)
loizos
03. Mar 2013
Hey guys :P i got a question >.> How you reverse a program in C ??? I am actually using 'ollydbg' to reverse my staff.So please any1 help?
loizos
31. Mar 2013
Hello i learned how to reverse program am now can crack programs with difficulty level 3.This one was very easy.I 90 the jmp and past the serial key so easy :)
[Wizzer]
08. Apr 2013
@loizos you missed the whole point here :) read the author's intro text again
Articstorm
02. Jun 2013
is it normal that i cant open the *.exe file? it just terminates! :(
Shivajitheboss
14. Oct 2015
I was able to patch it and get "That is correct !" message. But the problem I faced was the exe just wont start. Still working on it ;) Nice work bro.

You may leave your comment, thoughts and discuss this crackme with other reversers here.
Acting childish will not be tolerated.
HTML and such will be left as-is, so don't try.