Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Friday, June 23 2017 @ 01:59 AM CEST
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Detten's Crackme 13

 
Post new topic   Reply to topic    www.reversing.be Forum Index -> Code Reversing
View previous topic :: View next topic  
Author Message
highenergy
Occasional Poster
Occasional Poster


Joined: 08 Mar 2005
Posts: 32

PostPosted: Tue Jul 03, 2012 10:05 am    Post subject: Detten's Crackme 13 Reply with quote

Hi there,

I am trying to solve the serial generator algorithm but I bumped a dead end. Below is the dump of algo but in order to get a working serial function/subroutine should return DEADBABE in eax. If you examine the code below you never reach

Code:

mov eax, DEADBABE


instruction. And you never get a working serial. So my question is, is the algo possibly wrong? Or am I doing something wrong?

Subroutine:
Code:

02201D0    90              NOP
002201D1    90              NOP
002201D2    90              NOP
002201D3    33C0            XOR EAX,EAX
002201D5    33C9            XOR ECX,ECX
002201D7    33DB            XOR EBX,EBX
002201D9    8A99 48304000   MOV BL,BYTE PTR DS:[ECX+403048] ; 403048 points to name (character array)
002201DF    03C3            ADD EAX,EBX
002201E1    D3C0            ROL EAX,CL
002201E3    3305 5E304000   XOR EAX,DWORD PTR DS:[40305E]   ; 40305E points to serial (integer)
002201E9    D3C8            ROR EAX,CL
002201EB    41              INC ECX
002201EC    80B9 48304000 0>CMP BYTE PTR DS:[ECX+403048],0
002201F3  ^ 75 E4           JNZ SHORT 002201D9
002201F5    66:B9 0200      MOV CX,2                 
002201F9    99              CDQ
002201FA    50              PUSH EAX
002201FB    F7F9            IDIV ECX                 ; divide edx:eax with ecx. Start ecx with 2.   
002201FD    58              POP EAX
002201FE    83FA 00         CMP EDX,0                ; remainder of divition could be zero or not
00220201    74 10           JE SHORT 00220213        ; if it's zero return (bad boy)
00220203    66:41           INC CX                   ; else increase ecx and divide again.
00220205  ^ 75 F2           JNZ SHORT 002201F9       ; this is looks like conditional jump but actually zero flag is set at 002201FE. So it behaves like unconditional jmp.
00220207    3D FFFFFFBF     CMP EAX,BFFFFFFF         ;---> Below three block never executes
0022020C    76 05           JBE SHORT 00220213       ;--->
0022020E    B8 BEBAADDE     MOV EAX,DEADBABE         ;---> So never return good boy
00220213    C3              RETN

regards
Back to top
View user's profile Send private message
detten
Site Admin


Joined: 05 Feb 2005
Posts: 317

PostPosted: Wed Jul 18, 2012 12:52 pm    Post subject: Reply with quote

Almost everything you deducted so far is correct, but there is no error in the algorithm afaik.
Quote:
00220205 ^ 75 F2 JNZ SHORT 002201F9 ; this is looks like conditional jump but actually zero flag is set at 002201FE. So it behaves like unconditional jmp.

There is another way to quit this loop, it is not that obvious to spot. I requires a little mathematical thinking Wink

So far you deducted it cannot be dividable by any integer or it triggers the badboy return.
Which implies you need a prime number, and 'some' relation to CX...

_________________
Ignorance is bliss, knowledge is power
Back to top
View user's profile Send private message Visit poster's website
highenergy
Occasional Poster
Occasional Poster


Joined: 08 Mar 2005
Posts: 32

PostPosted: Fri Feb 22, 2013 10:49 pm    Post subject: Reply with quote

Analysis:
Code:

002201D0    90              NOP
002201D1    90              NOP
002201D2    90              NOP

// Initialisation
002201D3    33C0            XOR EAX,EAX                     ; eax = 0
002201D5    33C9            XOR ECX,ECX                     ; ecx = 0
002201D7    33DB            XOR EBX,EBX                     ; abx = 0

// Read every character of name then add them together
002201D9    8A99 48304000   MOV BL,BYTE PTR DS:[ECX+403048] ; 403048 points to name (character array)
                                             ; reads one byte at a time.   
002201DF    03C3            ADD EAX,EBX                     ; eax += name[ecx]
002201E1    D3C0            ROL EAX,CL                      ; rol(eax, ecx)
002201E3    3305 5E304000   XOR EAX,DWORD PTR DS:[40305E]   ; 40305E points to serial (integer)
002201E9    D3C8            ROR EAX,CL                      ; ror(eax, ecx)
002201EB    41              INC ECX                         ; ecx++
002201EC    80B9 48304000 0>CMP BYTE PTR DS:[ECX+403048],0  ; while name[ecx]!='\0'
002201F3  ^ 75 E4           JNZ SHORT 002201D9

// Test eax for being a prime number or not
// This sectiom of code checks whether or not eax is prime. Normally a prime number checking routine should
// check all numbers between 2 <= cx <= eax-1.
// Because a prime number is a number which can only has dividents 1 and itself.
002201F5    66:B9 0200      MOV CX,2                        ; ecx = 2
002201F9    99              CDQ                             ; sign extend eax into edx:eax
002201FA    50              PUSH EAX                        ; save eax
002201FB    F7F9            IDIV ECX                        ; signed division of edx:eax with ecx.     
002201FD    58              POP EAX                         ; put back into eax
002201FE    83FA 00         CMP EDX,0                       ; check remainder. If remainder is zero then eax is not a prime,
                                             ; increase ecx until overflow word boundry 0xFFFF.
00220201    74 10           JE SHORT 00220213               ; bad boy jump
00220203    66:41           INC CX                          ; else increase ecx and divide again.

// Following opcode tests if cx overflows. All cx values will be tested againist being divisor of eax.
// If all cx values are tested and there is no overflow then it means there is a divisor.
// So eax should not be between 2 <= eax <= cx, but should be bigger than 0xFFFF.
// Otherwise cx would divide eax.
// Hmm, the cx has only gets 2 <= cx <= 0xFFFF values. That means this routine is not an complete prime number tester.
// I would expect cx get values between 1 < ecx <eax.
// This routine only test that eax has no diviser below and including 0xFFFF.
00220205  ^ 75 F2           JNZ SHORT 002201F9              ;

// Below line states that eax should be above 0xBFFFFFFF.
// So we are looking for a prime number which has no divisor below 0xFFFF and bigger than 0xBFFFFFFF.
// Following opcode treats comparison as unsigned numbers.
// signed 0xBFFFFFFF equals -1073741825 in decimal.
00220207    3D FFFFFFBF     CMP EAX,BFFFFFFF


0022020C    76 05           JBE SHORT 00220213              ;---> Bad boy jump
0022020E    B8 BEBAADDE     MOV EAX,DEADBABE                ;---> Good boy return value
00220213    C3              RETN

RESULT

eax is a signed number, a prime number (has no divisor below 0xFFFF)
and bigger than BFFFFFFF. Since division is carried out in a signed sense prime numbers
we are looking for are negative numbers. Prime numbers should be between 0xFFFFFFFF (-1)
and BFFFFFFF (-1073741825).

Because eax is a prime number, and has no divisor, cx register overflows after 0xFFFF value.
That causes zero flag gets set and conditional jump at 00220205 is not taken.


KEYGEN

I am not sure finding a serial without brute force. Because serial gets mixed in every iteration.
In each iteration serial and characters of name gets mixed with xor, rol and ror insructions.
The only way I see to find a serial is using brute force the algorithm.
Here is my brute force way of getting a working serial.

Code:

#include <iostream>
#include <stdlib.h>
using namespace std;

bool isPrime(int input);
bool findSerial(char name[], unsigned int& output);
unsigned int rol(unsigned int input, int times);
unsigned int ror(unsigned int input, int times);

int main()
{
   // initialization
   char name[35];
   unsigned int serial = 0;
   
   for (int i = 0; i < sizeof(name); i++ ) {
      name[i] = '\0';
   }
   
   cout << "Your Name: " << endl;
   cin >> name;
   cout << "Please wait while searching for a serial..." << endl;
   
   if (findSerial(name, serial)){
      cout << "Serial: " << serial;
   } else {
      cout << "Couldn't find a serial, sorry" << endl;
   }
   
   cout << endl;
   system("pause");
   return 0;
}


bool isPrime(int input) {
   // Tests input, whether it is a prime or not
   // Actually the comparison condition (j < 0xFFFF) would be j < i
   // But since crackme doesn't cares values after 0xFFFF
   // we are also letting for loop ends early
   if (input > 0xBFFFFFFF && input <=0xFFFFFFFF) {
      for (int divisor = 2; divisor <= 0xFFFF; ++divisor) {      
         if (!(input%divisor)) {
            return false;
         }
      }
      return true;     
   } else {
      return false;
   }
}

bool findSerial(char name[], unsigned int& output) {
   
   for (unsigned int serial = 0; serial < 0xFFFFFFFF; serial++) {
      int i = 0;
      unsigned int sum = 0;
      
      do {
         sum += name[i];
         sum = rol(sum, i);
         sum = sum ^ serial;
         sum = ror(sum, i);
         i++;   
      } while (name[i] != '\0');
      
      if (isPrime(sum)) {
         output = serial;
         return true;
      }
   }
   return false;
}

unsigned int rol(unsigned int input, int times) {
    return (input << times) | ((input & 0xFFFFFFFF) >> (32-times));
}

unsigned int ror(unsigned int input, int times) {
   return (input >> times) | ((input & 0xFFFFFFFF) << (32-times));
}


Above code works well. Here is the proof.

username = highenergy
Password = 19

username = detten
password = 135
Back to top
View user's profile Send private message
detten
Site Admin


Joined: 05 Feb 2005
Posts: 317

PostPosted: Fri Mar 08, 2013 10:16 am    Post subject: Reply with quote

Great work highenergy,
I hope you had some fun with this crackme Smile

I will see if I can dig up the original tutorial (maybe the source code) and submit it on the site. I already promised bor0 I would do that, but so far I had no luck finding it in my 'well-organized' archives Wink

_________________
Ignorance is bliss, knowledge is power
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    www.reversing.be Forum Index -> Code Reversing All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group
 Copyright © 2017 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.06 seconds