Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Tuesday, March 31 2020 @ 05:31 PM CEST

Disassembly of Detten's 'Small Linux Starter Crackme'

   

TutorialsLevel : beginner

Using gdb to retrieve a deadlisting of a linux binary, comment the algoritm, and writing a keygen in C++



First I fired up gdb on the program, set the disassembly type to intel instead of the default att and turned on asm-demangle. I then set a breakpoint on main and disassembled the program and got the following output.

PS - I did not do any stepping through of the code through gdb's debugger, I only used it to disassemble the code and then manually analyzed it.



linux2[1]% gdb small
GNU gdb Red Hat Linux (6.1post-1.20040607.52rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb) set disassembly-flavor intel
(gdb) set print asm-demangle on
(gdb) break *main
Breakpoint 1 at 0x80487bc
(gdb) run
Starting program: /afs/bla/bla/home/small

Breakpoint 1, 0x080487bc in main ()
(gdb) disassemble
Dump of assembler code for function main:
0x080487bc :    push   ebp
0x080487bd :    mov    ebp,esp
0x080487bf :    sub    esp,0xe8
0x080487c5 :    and    esp,0xfffffff0
0x080487c8 :   mov    eax,0x0
0x080487cd :   sub    esp,eax
0x080487cf :   sub    esp,0x8
0x080487d2 :   push   0x80486d8
0x080487d7 :   sub    esp,0xc
0x080487da :   push   0x8048ae0
0x080487df :   push   0x8049db8
0x080487e4 :   call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x080487e9 :   add    esp,0x14
0x080487ec :   push   eax
0x080487ed :   call   0x8048658 
0x080487f2 :   add    esp,0x10
0x080487f5 :   sub    esp,0x8
0x080487f8 :   push   0x8048b20
0x080487fd :   push   0x8049db8
0x08048802 :   call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x08048807 :   add    esp,0x10
0x0804880a :   sub    esp,0x8
0x0804880d :   lea    eax,[ebp-72]
0x08048810 :   push   eax
0x08048811 :   push   0x8049e48
0x08048816 :   call   0x80486c8  >& std::operator>> >(std::basic_istream >&, char*)>
0x0804881b :   add    esp,0x10
0x0804881e :   sub    esp,0x8
0x08048821 :  push   0x8048b60
0x08048826 :  push   0x8049db8
0x0804882b :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x08048830 :  add    esp,0x10
0x08048833 :  sub    esp,0x8
0x08048836 :  lea    eax,[ebp-136]
0x0804883c :  push   eax
0x0804883d :  push   0x8049e48
0x08048842 :  call   0x80486c8  >& std::operator>> >(std::basic_istream >&, char*)>
0x08048847 :  add    esp,0x10
0x0804884a :  mov    DWORD PTR [ebp-204],0x0
0x08048854 :  lea    eax,[ebp-72]
0x08048857 :  add    eax,DWORD PTR [ebp-204]
0x0804885d :  cmp    BYTE PTR [eax],0x0
0x08048860 :  jne    0x8048864 
0x08048862 :  jmp    0x80488a6 
0x08048864 :  lea    eax,[ebp-200]
0x0804886a :  mov    ecx,eax
0x0804886c :  add    ecx,DWORD PTR [ebp-204]
0x08048872 :  lea    eax,[ebp-72]
0x08048875 :  add    eax,DWORD PTR [ebp-204]
0x0804887b :  mov    al,BYTE PTR [eax]
0x0804887d :  movsx  dx,al
0x08048881 :  mov    DWORD PTR [ebp-218],0xa
0x0804888a :  mov    eax,edx
0x0804888c :  cwd
0x0804888e :  data16
---Type  to continue, or q  to quit---
0x0804888f :  idiv   DWORD PTR [ebp-218]
0x08048895 :  mov    al,dl
0x08048897 :  add    eax,0x30
0x0804889a :  mov    BYTE PTR [ecx],al
0x0804889c :  lea    eax,[ebp-204]
0x080488a2 :  inc    DWORD PTR [eax]
0x080488a4 :  jmp    0x8048854 
0x080488a6 :  lea    eax,[ebp-200]
0x080488ac :  add    eax,DWORD PTR [ebp-204]
0x080488b2 :  mov    BYTE PTR [eax],0x0
0x080488b5 :  lea    eax,[ebp-136]
0x080488bb :  lea    edx,[ebp-200]
0x080488c1 :  sub    esp,0x8

0x080488c4 :  push   eax
0x080488c5 :  push   edx
0x080488c6 :  call   0x8048668 
0x080488cb :  add    esp,0x10
0x080488ce :  test   eax,eax
0x080488d0 :  jne    0x80488fa 
0x080488d2 :  sub    esp,0x8
0x080488d5 :  push   0x80486d8
0x080488da :  sub    esp,0xc
0x080488dd :  push   0x8048b84
0x080488e2 :  push   0x8049db8
0x080488e7 :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x080488ec :  add    esp,0x14
0x080488ef :  push   eax
0x080488f0 :  call   0x8048658 
0x080488f5 :  add    esp,0x10
0x080488f8 :  jmp    0x8048920 
0x080488fa :  sub    esp,0x8
0x080488fd :  push   0x80486d8
0x08048902 :  sub    esp,0xc
0x08048905 :  push   0x8048b90
0x0804890a :  push   0x8049db8
0x0804890f :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x08048914 :  add    esp,0x14
0x08048917 :  push   eax
0x08048918 :  call   0x8048658 
0x0804891d :  add    esp,0x10
0x08048920 :  mov    eax,0x0
0x08048925 :  leave
0x08048926 :  ret
0x08048927 :  nop
End of assembler dump.
(gdb) quit
The program is running.  Exit anyway? (y or n) y
linux2[2]%
After this I began going through the code manually and adding my own C Style comments as seen below.

Dump of assembler code for function main:
// function prolog
0x080487bc :    push   ebp
0x080487bd :    mov    ebp,esp
// allocate some memory on the stack (232 bits or 29 bytes)
0x080487bf :    sub    esp,0xe8

// rounds the last digit in esp to 0..... purpose being?
0x080487c5 :    and    esp,0xfffffff0

// set eax to 0
0x080487c8 :   mov    eax,0x0

// esp -= eax (huh, we just set eax to 0)
0x080487cd :   sub    esp,eax

// esp -= 8 //allocate another byte)
0x080487cf :   sub    esp,0x8


0x080487d2 :   push   0x80486d8
0x080487d7 :   sub    esp,0xc

// print out..... "-> Small crackme for Stingduk :   push   0x8048ae0
0x080487df :   push   0x8049db8
0x080487e4 :   call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>

// adjust stack pointer from making the c call....
0x080487e9 :   add    esp,0x14

// print out..... "Give me your name (max 50 chars):"
0x080487ec :   push   eax
0x080487ed :   call   0x8048658 
0x080487f2 :   add    esp,0x10
0x080487f5 :   sub    esp,0x8
0x080487f8 :   push   0x8048b20
0x080487fd :   push   0x8049db8
0x08048802 :   call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>

// adjust stackframe
0x08048807 :   add    esp,0x10
0x0804880a :   sub    esp,0x8


// accepts the name from cin ebp-72 (72 to 22)
// load the address of the local mem storage we created
0x0804880d :   lea    eax,[ebp-72]
0x08048810 :   push   eax
0x08048811 :   push   0x8049e48
0x08048816 :   call   0x80486c8  >& std::operator>> >(std::basic_istream >&, char*)>
0x0804881b :   add    esp,0x10
0x0804881e :   sub    esp,0x8

// print out.......... Pass me the serial (max 50 chars):
0x08048821 :  push   0x8048b60
0x08048826 :  push   0x8049db8
0x0804882b :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x08048830 :  add    esp,0x10
0x08048833 :  sub    esp,0x8

// accepts the userSerial from cin ebp-136 (136 to 86)
// load the address of the local mem storage we created
0x08048836 :  lea    eax,[ebp-136]
// push the local address on stack
0x0804883c :  push   eax
0x0804883d :  push   0x8049e48
0x08048842 :  call   0x80486c8  >& std::operator>> >(std::basic_istream >&, char*)>
// adjust stackframe
0x08048847 :  add    esp,0x10


// fill a dword (4 bytes) 204 to 200
// counter = 0;
0x0804884a :  mov    DWORD PTR [ebp-204],0x0


ebp-72 to -22 holds Name
ebp-136 to -86 holds userSerial

//------Begin Loop--------/

// load the address of Name from local memory
0x08048854 :  lea    eax,[ebp-72]

// add whats in ebp-204 to eax... initially 0, incremented at the end of each loop.
0x08048857 :  add    eax,DWORD PTR [ebp-204]


// compare 1 byte at a time, contents of eax and 0
// check for null char termination
0x0804885d :  cmp    BYTE PTR [eax],0x0

// if (!null char)
//   continue;
// else 
//   break;
0x08048860 :  jne    0x8048864 
0x08048862 :  jmp    0x80488a6 

// load address of ebp-200 to eax (calculatedSerial)
0x08048864 :  lea    eax,[ebp-200]


// using ecx as a temp var/reg
// ecx = eax
// ecx = calculatedSerial;
0x0804886a :  mov    ecx,eax

// ecx += contents of ebp-204 (counter/offset variable)
// ecx = &calculatedSerial[counter];
0x0804886c :  add    ecx,DWORD PTR [ebp-204]

// get first char of name
// eax = address of [ebp-72]
// eax = name;
0x08048872 :  lea    eax,[ebp-72]

// 204 to 200
// eax += contents of 4 bytes from ebp-204 (counter/offset variable)
// eax = &name[counter];
0x08048875 :  add    eax,DWORD PTR [ebp-204]

// al = name[counter];
// al = contents of eax
0x0804887b :  mov    al,BYTE PTR [eax]

// dx = al, converting a single byte al to double byte dx
0x0804887d :  movsx  dx,al

// move 0xa or 10 into contents of ebp-218 TO -214
// divideBy = 10;
0x08048881 :  mov    DWORD PTR [ebp-218],0xa

// move edx into eax..... what about high bits of edx?
0x0804888a :  mov    eax,edx


// sign extend ax to dx:ax
// word to dword, bit 15 of ax will be copied into all of dx (all 1's or 0's)
0x0804888c :  cwd
0x0804888e :  data16 // this ensures its a 16 bit operation even tho dword i think..

// DX = just the sign, AX = *name[counter];


// divide DX:AX by 10 and store result in AX and remainder in DX
0x0804888f :  idiv   DWORD PTR [ebp-218]  // signed dividing by 10

// DX = ASCII value of currChar % 10
// AX = ASCII value of currChar / 10


// take low byte from remainder and store in al.... previously division
// al = dl
0x08048895 :  mov    al,dl


// add 30h to eax... makes sense 48 is 0 in ascii., mod 10 system will return us in 0 to 9
// range of possible ints for eax is 48 to 57, they will all be ASCII 0's to 1's
0x08048897 :  add    eax,0x30

// *calculatedSerial[counter] = al;
// *ecx = al (low byte is going into mem contents of ecx, remainder of previous division % 10...)
0x0804889a :  mov    BYTE PTR [ecx],al


// eax = address of ebp-204 or counter
0x0804889c :  lea    eax,[ebp-204]

// (*eax)++ or counter++ contained at ebp-204 to 200
0x080488a2 :  inc    DWORD PTR [eax]


0x080488a4 :  jmp    0x8048854 
//-------END LOOP------/

// eax = address of ebp-200 (calculatedSerial)
0x080488a6 :  lea    eax,[ebp-200]


// (add the counter to calculatedSerial store in eax)
// eax += contents of 4 bytes of ebp-204 to 200
0x080488ac :  add    eax,DWORD PTR [ebp-204]

// null delimit the calculatedSerial
// contents of eax = 0
0x080488b2 :  mov    BYTE PTR [eax],0x0

// load address of ebp-136 (User supplied serial) into eax
0x080488b5 :  lea    eax,[ebp-136]

// load address of ebp-200 (calculatedSerial)
0x080488bb :  lea    edx,[ebp-200]

// adjust stack pointer
0x080488c1 :  sub    esp,0x8

// push &userSerial and &calculatedSerial onto stack and compare the two with strcmp
0x080488c4 :  push   eax
0x080488c5 :  push   edx
0x080488c6 :  call   0x8048668 

// adjust stack frame
0x080488cb :  add    esp,0x10

// test to see what strcmp returns
0x080488ce :  test   eax,eax
// jump to main+318 if not equal (failed check)
0x080488d0 :  jne    0x80488fa 

// adjust stack frame
0x080488d2 :  sub    esp,0x8


// print out cracked message.... "Great work!"
0x080488d5 :  push   0x80486d8
0x080488da :  sub    esp,0xc
0x080488dd :  push   0x8048b84
0x080488e2 :  push   0x8049db8
0x080488e7 :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x080488ec :  add    esp,0x14
0x080488ef :  push   eax
0x080488f0 :  call   0x8048658 
0x080488f5 :  add    esp,0x10

// must jump to very end of program regardless to end the program.
0x080488f8 :  jmp    0x8048920 


// adjust stack frame
0x080488fa :  sub    esp,0x8

// print out error message..... "No luck here mate :("
0x080488fd :  push   0x80486d8
0x08048902 :  sub    esp,0xc
0x08048905 :  push   0x8048b90
0x0804890a :  push   0x8049db8
0x0804890f :  call   0x8048698  >& std::operator >(std::basic_ostream >&, char const*)>
0x08048914 :  add    esp,0x14
0x08048917 :  push   eax
0x08048918 :  call   0x8048658 
0x0804891d :  add    esp,0x10

// put 0 in eax to exit the program
0x08048920 :  mov    eax,0x0

// destroy stack frame and buhbye
0x08048925 :  leave
0x08048926 :  ret
0x08048927 :  nop
End of assembler dump.

So basically the program loops through each char of the name, mods the ASCII's decimal value by 10 and then adds 48 to that remainder.
A mod system of 10 will always bring you back to the numbers 0 to 9 and then adding 48 will always bring you to the ASCII values 0 to 9.

My first test was to check my handle to see if I could get 'aa' to work.

a = 97 in ASCII decimal 97 % 10 = 7 7 + 48 = 55 55 in ASCII decimal = 7 so the key should be 77

linux2[28]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): aa
Pass me the serial (max 50 chars): 77
Great work!

And as we can see it works.

Now to write a Keygen.....

//------------------------
// keygen.cpp
// tested with g++ 3.2.3
//------------------------
#include <iostream>
#include <string>

using namespace std;

int main()
{
  string name;
  cout << "Please enter a name: ";
  cin >> name;
  cout << "Your key is: ";

  for (int i = 0; i < name.size(); i++)
     cout << (int) name[i] % 10;

  cout << endl;
  return 0;
}



linux2[32]% g++ keygen.cpp -o keygen
linux2[33]% ./keygen
Please enter a name: Koffee
Your key is: 512211
linux2[34]% ./keygen
Please enter a name: BiWReversing
Your key is: 657218145503
linux2[35]% ./keygen
Please enter a name: somenamehere
Your key is: 519107914141
linux2[36]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): Koffee
Pass me the serial (max 50 chars): 512211
Great work!
linux2[37]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): BiWReversing
Pass me the serial (max 50 chars): 657218145503
Great work!
linux2[38]% ./small
-> Small crackme for Stingduk <-
Give me your name (max 50 chars): intentionalFail
Pass me the serial (max 50 chars): 1421532523532
No luck here mate :(
linux2[39]%




What's Related

Story Options

Disassembly of Detten's 'Small Linux Starter Crackme' | 3 comments | Create New Account
The following comments are owned by whomever posted them. This site is not responsible for what they say.
Disassembly of Detten's 'Small Linux Starter Crackme'
Authored by: stingduk on Sunday, September 11 2005 @ 04:57 PM CEST
oh my lazy ass :) i was planning to do this but it never happened :) and you beat me to it :)
nice work there
well a complimentary tut just using objdump is availbale here for any one interested to do it the
deadlisting way :)
[url]http://www.reversing.be/article.php?story=2005030218170966[/url]
Disassembly of Detten's 'Small Linux Starter Crackme'
Authored by: thorpe on Monday, September 12 2005 @ 10:58 AM CEST
gdb... brings me horrible memories of debugging my stupid binary tree made in C. *shivers*
 Copyright © 2020 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.80 seconds