CROHACK PROUDLY PRESENTS
EMBIRD TUTORIAL
BY
NORTON_LEN

Cracking Embird 7.11 Evaluation

Tools used - SoftIce, W32DASM, IDA, PE Explorer, any hex editor, Win32 API Reference manual

A very interesting program to crack, as it contains so many examples of protection -
1. Debugger detect.
2. Program and file CRC checks.
3. Encrypted strings.
4. No obvious registration ability.
5. Use of program interrupts to pass control around the program.
6. Time and Use limited trial.
 

1. Debugger detect.
In my case the first thing that happened when I started the program was that it detected I had SoftIce installed on my machine. It issued a message "This program is not designed to run with a debugger" and closed down.
I'd recently read a crack tutorial about SoftIce detection, so I started checking for each one in turn.
In this case the program checked to see if a file with the name "\\.\SICE" was open in the system.
Apparently this indicates that the SoftIce Virtual Device Driver has been loaded.
Here is the code used (from my annotated IDA listing) -

0049619C detect_softice:      ; CODE XREF: debug_detect+CD_j
0049619C    lea    eax, [ebp+var_10]
0049619F    mov    edx, offset aL3kilR7mjfxg ; This is encrypted "\\.\SICE"
004961A4    call    sub_403DC0
004961A9    lea    eax, [ebp+var_10]
004961AC    call    sub_462544    ; decrypt to "\\.\SICE"
004961B1    push    0     ; setup parms
004961B3    push    80h     ;  for CreateFileA
004961B8    push    3
004961BA    push    0
004961BC    push    1
004961BE    push    80000000h
004961C3    mov    eax, [ebp+var_10]
004961C6    call    check_EAX_not_0
004961CB    push    eax     ; EAX -> "\\.\SICE"
004961CC    call    j_CreateFileA_0 ; Open the file for input
004961D1    cmp    eax, 0FFFFFFFFh ; invalid file handle returned?
004961D4    jz    short detect_TRW ; Yes - SoftIce not active- check for TRW debugger
004961D6    push    eax
004961D7    call    j_CloseHandle_0
004961DC    mov    [ebp+var_6], 1  ; set "SoftIce active" flag
004961E0    jmp    short loc_49624F
004961E2
004961E2 detect_TRW:       ; CODE XREF: debug_detect+154_j
004961E2    lea    eax, [ebp+var_10]
 

The string "\\.\SICE" is first referenced at 49619C in encrypted form - so you won't find it if you search the Embird exec for "\\.\SICE".
After being decrypted, it is passed as a filename to a CreateFileA at 4961CC. The CreateFileA is issued with the create option OPEN_EXISTING - if the file exists the function will return a valid file handle.
The obvious crack is to alter the string "L3kiL>R7MJFXG<\xFF\xFF\xFF\xFF\f" on disk so that it does not decrypt to "\\.\SICE" - which I did, and which lead me on to Step 2 - Program and file CRC checks.
Before leaving this section I should mention that the program does similar checks at this point for NTICE, and the TRW debugger and then follows with a generalised check for ANY debugger, which will be covered in Step 5 - Use of program Interrupts.
It is also worth mentioning that all this Debugger Detect stuff is repeated at the END of program initialisation, using different encrypted strings and the obsolete _LCREAT file call (just to make things more difficult, I guess).
 

2. Program and file CRC checks.
After patching the encrypted string on disk, I started the program again.
This time I got a "File is probably damaged" message, because I had patched it on disk, and the program closed.
I put a SoftIce breakpoint on the Message Box routine - BPX MessageBoxA, and when it triggered, worked my way back up the call stack using the F12 key until I found some interesting-looking code -

004960A0     mov    byte ptr [ebp-5], 0
004960A4     mov    eax, [ebp-4]
004960A7     cmp    byte ptr [eax+8D4h], 0  ; has embird.exe been modified?
                                                   ;    detected by CRC check at 494490
004960AE     jnz    short detect_SoftIce    ; No - go on to SoftIce detection
004960B0     push    1                       ; Yes - do error code
004960B2     lea    edx, [ebp-14h]
004960B5     mov    eax, 2
004960BA     call    sub_408E64
004960BF     mov    eax, [ebp-14h]
004960C2     mov    cx, ds:word_4962F4
004960C9     mov    dl, 1
004960CB     call    do_msg_beep_box         ; issue "File is probably damaged"
004960D0     mov    byte ptr [ebp-5], 1     ; set "CRC Fail" flag
004960D4     jmp    short loc_496142
004960D6 detect_SoftIce:      ; CODE XREF: debug_detect+2E_j

The decision whether to issue the message is taken at 4960A7, so I noted the address of this byte, reloaded the program into SoftIce and put a read/write memory breakpoint on it - BPM xxxxxx RW.
I wanted to find out exactly where this flag was set as a result of the CRC check failure.

00494490 CRC_check:       ; DATA XREF: CODE:00494473_o
00494490    mov    bx, 0Ah
00494494    lea    eax, [ebp-0Fh]
00494497    lea    edx, [ebp-19h]
0049449A
0049449A CRC_compare_loop:      ; CODE XREF: CODE:004944A9_j
0049449A    mov    cl, [eax]
0049449C    cmp    cl, [edx]               ; check CRC values
0049449E    jz    short CRC_do_next_byte  ; CRACK - change this JZ to a JMP
004944A0    mov    byte ptr [ebp-5], 0     ; set "CRC fail" flag
004944A4
004944A4 CRC_do_next_byte:      ; CODE XREF: CODE:0049449E_j
004944A4    inc    edx
004944A5    inc    eax
004944A6    dec    bx
004944A9    jnz    short CRC_compare_loop
004944AB
004944AB CRC_done:       ; CODE XREF: CODE:00494354_j
004944AB               ; CODE:00494414_j
004944AB    xor    eax, eax
004944AD    pop    edx

Well, it was set at 4944A0. I wanted to bypass setting that flag byte, so I just altered the JZ at 49449E to a JMP.
At this point we are free to actually start debugging and patching the program as much as we like without being detected.
 

3. Encrypted strings.
I have already mentioned these back in Step 1.
However, it is worth mentioning that W32DASM provides an excellent string Xref, and this can be a very valuable asset.

* Possible Reference to String Resource ID=00086: "Unregistered"
                                  |
:00495EC9 B856000000              mov eax, 00000049
:00495ECE E8912FF7FF              call 00408E64

Note that these are "possible" string references - if the string is resource number 49, for example,
then any time the number 49 is used it is a POSSIBLE use of that resource - you just have to develop a "feel" for this, and set LOTS of breakpoints :)
 

4. No obvious registration ability.
This was very strange - none of the menus contained an option that allowed you to register the program. Even when the trial expired there was no option to register. I'm not sure whether this is a deliberate "feature", or a bug. (I discovered later that it was a deliberate trick - the menu item is marked as "Visible=False" in the Resource Table).
You could do this other ways, but I used a recently acquired tool "PE Explorer" (Trial version at www.heaventools.com) to find all the resources in the program.

I could see from the Resource List that it should appear as an item in the Help menu, but it didn't <shrug>. So, I did an IDA label search for the name "RegistrationMenu" and, unexpectedly, found this -

004935E6                 dd offset sub_496068
004935EA aRegistrationmenu db 15h,'RegistrationMenuClick',14h,0
00493602                 dd offset sub_49B7B0
00493606 aCopymenuclick  db 0Dh,'CopyMenuClick',18h,0
00493616                 dd offset sub_49B800
0049361A                 dd 6E6F4311h, 746E6574h, 6E654D73h, 696C4375h, 116B63h
0049362E                 dd offset sub_49B844

(Now, I don't want to turn this into an IDA tutorial, but let me just say that those strings were not produced by IDA, but by me, manually redefining them.
They originally looked like the data at 0049361A.
IDA was not able to determine that this was a string - I just happened to be browsing the listing a few days earlier and saw what looked like some ASCII in hex format, so I asked IDA to try turning them into ASCII.)

At this point, I took a guess (don't we always) that the subroutine address held at 004935E6 would display the registration menu.

I can't show all the code here, but the routine at 496068 did display the registration dialog, read the serial number, and validated it.

Another routine starting at 495F40 checked a flag, and decided whether to show "Unregistered" or "Registered To -" in the main window title.
So, in memory, at 495F40 I patched a JMP 496068 (this routine above).
I wasn't concerned about returning to the correct place in the program - I just wanted to see the Registration dialog, and set a SoftIce BPM on the serial number.
So I just entered any number as a serial number, and let the routine (sub_495D9C) do all its validation (which, of course, failed). But I didn't care, I was just going to alter a JZ instruction to a JMP after the flag test in 496068.
OK, so now we're at 495F40.
This still contains the JMP 496068 that I put there earlier (and we have a recusive loop), so I alter that back to its original instruction, and step down the code until the registration flag byte is checked - which I alter to say OK. Then I just let the code run.
To my surprise, the program started, AND in the title bar was "Registered to - xxxxxxx", where xxxxxxx was the fake serial number I had entered!
(The registration data is held in some encrypted file - I don't care which one - it's not important to know. I found later, that it's held in clear text in embird.ini). Now I patch the program on disk with some JMPs to force our incorrect serial number (our name, in fact) to be OK and we have a nice working version.
 

5. Use of program interrupts to pass control around the program.
This is not easy for me to explain - mainly because I don't fully understand it myself.
The program makes a lot of use of "RaiseException" and "UnhandledExceptionFilter" calls to pass control  around the program in a very confusing way.
He issues RaiseException with his own exception codes which causes execution to pass into the Windows Kernel routines, THEN onto the debugger, before getting control back in his UnhandledExceptionFilter.
At this point the Windows Kernel tells him if he is running under a debugger (ANY debugger) and he just issues ExitProcess if that is the case.
If he is NOT running under a debugger he inspects the exception code to see it was one that he issued, and passes control to subroutines to do normal functions.
There is an INT 3 instruction at 496236 which I think is an important part of this.
In case you don't know, an INT 3 is how a debugger sets breakpoints in your code. Normally, an INT 3 would cause your program to abort, but the debugger sets himself up to handle it. If it is one that he has set, then that's fine; otherwise he just lets it through for normal processing - which is normally an abort. However, the application program can ALSO request that he is allowed to handle an INT 3, which I think is how he can detect that a debugger has been allowed to look at it first.
I admit to being very unclear about all this, and I need to do some more research on it.

NOTE: See Microsoft Win32 Programmer's Reference for more information - the most complete version I have found is included in the B5STD.ZIP download at -
http://www.borland.com/techpubs/bcppbuilder/v5/updates/std.html
You need to read it together with a WINDOWS.INC file if you want to understand all the flag settings for API calls.
 

6. Time and Use limited trial.
These routines are never executed now, because we have forced the program to think that it is a registered version.
In fact, earlier in my debugging I had found these routines by using W32DASM string xref and bypassed them fairly easily.
 

Well, I know that wasn't easy to understand - there are places where I can't fully describe what I did or why I did it.
I went down many "dead ends", and I also had quite a lot of lucky guesses.
But, for me, that's part of the cracking process.
I learnt a LOT cracking this program - even though I nearly gave up many times.

       NORTON_LEN
-=CROHACK=-

nd 58CA