Black Shadow

Target "RE-venge" by Crudd on Windows 2000

Tools
IDA
SoftIce
HexWorkshop


Ok , let's  examine this interesting crackme:


From here we start analysing:

_text:00401146                 push    0
_text:00401148                 push    172h
_text:0040114D                 push    hWnd
_text:00401153                 call    SendMessageA
_text:00401158                 call    sub_0_40123C     <-we land here
_text:0040115D                 cmp     byte_0_403008, 1 <-if everything is ok...
_text:00401164                 jz      short loc_0_40116B
_text:00401166                 call    sub_0_401183 <-continue to the next step



_text:0040123C                 push    offset hKey    <- receives the handle of the opened key
_text:00401241                 push    2001Fh         <- option to access the key
_text:00401246                 push    0              <- option "Reserved"
_text:00401248                 push    offset aSoftwareRetReVenge <- the location of subkey to open is "Software\RET\Re-Venge"
_text:0040124D                 push    80000001h       <- the handle of key is "HKEY_CURRENT_USER"
_text:00401252                 call    RegOpenKeyExA
_text:00401257                 cmp     eax, 0          <- compare the returned value to 0
_text:0040125A                 jnz     short loc_0_401294 <-if it's not found jmp to bad message!
_text:0040125C                 mov     dword_0_4030DA, 30h
_text:00401266                 push    offset dword_0_4030DA <- reads 30h bytes from the key
_text:0040126B                 push    offset aWsastartup <- store that at this address
_text:00401270                 push    offset aReg_binary <- REG_BINARY type of the key
_text:00401275                 push    0               <- option "reserved"
_text:00401277                 push    offset aRet     <- the address of the name of the key
_text:0040127C                 push    hKey            <- the handle of key to query
_text:00401282                 call    RegQueryValueExA
_text:00401287                 push    eax             <- the handle of key to query
_text:00401288                 call    RegCloseKey
_text:0040128D                 call    sub_0_401033    <- next step
_text:00401292                 jmp     short locret_0_401299


Firstly,the crackme opens from the registry the key: "[HKEY_CURRENT_USER\Software\RET\Re-Venge]"
where the binary key "[RET]" is stored.Then,it reads 30h characters.If everything was done correctly it proceeds to the next step.



_text:00401033                 pusha                   <- saves all the registers
_text:00401034                 lea     eax, ds:40304Ch <- the address which stored what it read
_text:0040103A                 xor     ecx, ecx        <- null ecx

_text:0040103C loc_0_40103C:
_text:0040103C                 cmp     ecx, 30h  <- counter
_text:0040103F                 jz      short loc_0_40104C <- is this the end?if no,continue
_text:00401041                 mov     bl, [eax] <- takes one by one all characters
_text:00401043                 sub     bl, 20h   <- substract 20h
_text:00401046                 mov     [eax], bl <- stores it back again
_text:00401048                 inc     eax       <- next character
_text:00401049                 inc     ecx       <- increase counter
_text:0040104A                 jmp     short loc_0_40103C <- repeat it

_text:0040104C loc_0_40104C:
_text:0040104C                 mov     eax, hModule
_text:00401051
_text:00401051 loc_0_401051:
_text:00401051                 dec     eax
_text:00401052                 cmp     dword ptr [eax], 905A4Dh  <- ZM
_text:00401058                 jnz     short loc_0_401051
_text:0040105A                 mov     hModule, eax <- find the module to use it for GetProcAddress
_text:0040105F                 xor     ebx, ebx
_text:00401061                 lea     edi, ds:40304Ch <- the names of functions
_text:00401067                 lea     esi, ds:4030E6h <- the address that stores the returned value of GetProcAddress
_text:0040106D
_text:0040106D loc_0_40106D:
_text:0040106D                 push    edi             <- parameter
_text:0040106E                 push    hModule         <- parameter
_text:00401074                 call    GetProcAddress  <- retrieve addresses of exported functions
_text:00401079                 cmp     eax, 0          <- is everything ok?(not zero)
_text:0040107C                 jz      short loc_0_40108E <- yes,continue - no, not registered
_text:0040107E                 mov     [esi], eax   <- store the address at the location of esi
_text:00401080                 add     edi, 16      <- next names function
_text:00401083                 add     esi, 4       <- increase esi to store the next address
_text:00401086                 inc     ebx          <- increase ebx (counter)
_text:00401087                 cmp     ebx, 3       <- 3 functions
_text:0040108A                 jnz     short loc_0_40106D <- till the end
_text:0040108A

_text:0040108C loc_0_40108C:
_text:0040108C                 popa <- restores all registers
_text:0040108D                 retn <- return

Now after it reads from the registry key, it substracts 20h from our value.Then it takes the result
as the names of the three functions and with the help of GetProcAddress it retrieves the addresses
which we will use for the next step to call them.The 'difficulty' was to find the names of the functions.

_text:00401183                 pusha
_text:00401184                 mov     eax, dword_0_4030E6  <-the first returned address of GetProcAddress
_text:00401189                 push    0
_text:0040118B                 push    offset aRet_key      <- "RET.Key" inversed name of the key??
_text:00401190                 call    eax                 <- call function ( maybe it's _lopen ??)
_text:00401192                 mov     dword_0_4030CA, eax  <- store the file handle
_text:00401197                 cmp     eax, 0FFFFFFFFh      <- it's not found!
_text:0040119A                 jz      short loc_0_401211   <- I'm sorry...
_text:0040119C                 mov     eax, dword_0_4030EA  <- the second returned address of GetProcAddress
_text:004011A1                 push    0   <- not overlapped
_text:004011A3                 push    offset dword_0_403085 <-address of number of bytes it read
_text:004011A8                 push    20h  <- 20h bytes to read
_text:004011AA                 push    offset unk_0_4030AC <-stores what it reads
_text:004011AF                 push    dword_0_4030CA      <- file handle
_text:004011B5                 call    eax  <- call ReadFile ?
_text:004011B7                 cmp     eax, 0  <-zero? something goes wrong
_text:004011BA                 jz      short loc_0_401211 <- bad message
_text:004011BC                 cmp     dword_0_403085, 0  <- zero bytes read?
_text:004011C3                 jz      short loc_0_401211 <- bye bye
_text:004011C5                 lea     ecx, ds:4030ACh <-the address of what it reads from the file
_text:004011CB                 mov     ebx, [ecx]
_text:004011CD                 cmp     ebx, 54455200h     <-it starts with " RET"
_text:004011D3                 jnz     short loc_0_401211 <-no? you are not with us!
_text:004011D5                 add     ecx, 4 <-next characters
_text:004011D8                 movzx   ebx, byte ptr [ecx] <-fourth byte
_text:004011DB                 movzx   eax, byte ptr [ecx+1] <-fifth byte
_text:004011DF                 mul     ebx      <- eax=eax*ebx
_text:004011E1                 movzx   ebx, byte ptr [ecx+2] <-sixth byte
_text:004011E5                 sub     eax, ebx <-eax=eax-ebx
_text:004011E7                 movzx   ebx, byte ptr [ecx+3] <-seventh byte
_text:004011EB                 mul     ebx      <-eax=ebx*eax
_text:004011ED                 add     ecx, 4   <-next 4 bytes

_text:004011F0 loc_0_4011F0:
_text:004011F0                 cmp     byte ptr [ecx], 0  <-we found zero?
_text:004011F3                 jz      short loc_0_4011FF <-yes, check if this is the end

_text:004011F5 loc_0_4011F5:
_text:004011F5                 add     al, [ecx]   <- the eighth byte
_text:004011F7                 sub     al, [ecx+1] <- al=al-nineth byte
_text:004011FA                 add     ecx, 2      <-add 2 to ecx (takes next two bytes)
_text:004011FD                 jmp     short loc_0_4011F0 <- jmp to find zero (end)


_text:004011FF                 cmp     byte ptr [ecx+1], 0 <-is this the end?
_text:00401203                 jz      short loc_0_401207  <-continue to "jmp eax
_text:00401205                 jmp     short loc_0_4011F5  <- repeat to find one

_text:00401207 loc_0_401207:
_text:00401207                 jmp     eax <-the magic address i think it must jmp below



_text:00401218                 lea     eax, ds:4030ACh
_text:0040121E                 add     eax, 8
_text:00401221                 push    eax
_text:00401222                 push    offset aRegisteredTo ; "Registered to: "
_text:00401227                 call    lstrcatA
_text:0040122C                 push    eax
_text:0040122D                 push    14h
_text:0040122F                 push    hDlg
_text:00401235                 call    SetDlgItemTextA
_text:0040123A                 jmp     short loc_0_40120F
_text:0040123C

So Crudd opens the file "key.RET" and reads it.If it starts with " RET" the program continues to read.After some calculations,it jumps to the registered message.To find which bytes will jump to the "registered" address we have to calulate this first (a*b-c)*d==00401218h.When we find
the 4 values it's over.But if you want to add your name ,you have to solve the next
calculation : i=lenght of your name ,name[i]-name[i+1]==0 or you can combine it with
the previous calculation so the "jmp eax" ,jumps to the address : 00401218.

Kind Regards

 Black Shadow













