L                ZZZZZZ         RRRRR           SSSSS
                     L                    Z          R    R         S
                     L          aaa      Z      aaa  R    R  u   u  S
                     L            a     Z         a  RRRRR   u   u  SSSSS
               XX    L         aaaa    Z       aaaa  R    R  u   u       S
              XXXX   L        a   a   Z       a   a  R    R  u   u       S
             XXXXXX  LLLLLLL  aaaaa  ZZZZZZZ  aaaaa  R    R  uuuuu  SSSSSS
             XXXXXX       
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
             XXXXXX
             XXXXXX
              XXXX        proudly presents his 23.Cracking Tutorial (06.07.1999)
               XX                    Cracking VB5 progs with W32Dasm

I.    Introduction
II.   The essay
III.  BTW
IV.   All Tutorials by LaZaRuS

I.   Welcome to my 23st cracking tutorial.
     Yep, I know: There's a handy little tool call Smartcheck. I tried to download it once, but
     I got a corrupted RAR file. D/l it again? Nah, not with my "turtle"-connection. I already
     have a disassembler and a debugger: W32Dasm and SICE. Actually there are some guys that
     say the only thing you get for VB progs in W32Dasm is garbage. *Completely* wrong. It's
     just a matter of interpretation. A VB5 prog in W32Dasm does (generally) look like a W32Asm 
     prog without string references. The main difference is that VB progs are *easier* to crack.
     It seems obvious that VB coders use the predefined functions for the comparison of the
     good/bad serial. (and btw: razzia didn't have Smartcheck for his famous VB essay, too :P)
     As examples I take two CrackMe's of BuLLeT (1.75 and 2.75).

I.1  W32Dasm 8.9
     BuLLeT's CrackMe 1.75
     BuLLeT's CrackMe 2.75
     Audio List Maker 1.52.1016
 
II.  The essay
     Let's start with the first CrackMe. When you disassemble it you will nothing but the 
     functions that are called MSVBVM50.DLL.

     Import Module 001: MSVBVM50.DLL
     Addr:0F0399BC hint(0000) Name: _CIcos
     Addr:0F0E7F94 hint(0000) Name: _adj_fptan
     Addr:0F0E7855 hint(0000) Name: _adj_fdiv_m64
     Addr:0F0E7EDC hint(0000) Name: _adj_fprem1
     Addr:0F02B4EB hint(0000) Name: __vbaHresultCheckObj
     Addr:0F0E7809 hint(0000) Name: _adj_fdiv_m32
     Addr:0F01E2F2 hint(0000) Name: __vbaObjSet
     Addr:0F0E78A1 hint(0000) Name: _adj_fdiv_m16i
     Addr:0F0E79A1 hint(0000) Name: _adj_fdivr_m16i
     Addr:0F0399B2 hint(0000) Name: _CIsin
     Addr:0F01F90B hint(0000) Name: __vbaChkstk
     Addr:0F02299D hint(0000) Name: EVENT_SINK_AddRef
     Addr:0F01F8F6 hint(0000) Name: __vbaStrCmp
     Addr:0F0E7F91 hint(0000) Name: _adj_fpatan
     Addr:0F037FD1 hint(0000) Name: EVENT_SINK_Release
     Addr:0F0342BF hint(0000) Name: _CIsqrt
     Addr:0F03634A hint(0000) Name: EVENT_SINK_QueryInterface
     Addr:0F022B59 hint(0000) Name: __vbaExceptHandler
     Addr:0F0E7C24 hint(0000) Name: _adj_fprem
     Addr:0F0E7955 hint(0000) Name: _adj_fdivr_m64
     Addr:0F10A1A4 hint(0000) Name: __vbaFPException
     Addr:0F0342B5 hint(0000) Name: _CIlog
     Addr:0F0E78D5 hint(0000) Name: _adj_fdiv_m32i
     Addr:0F0E79D5 hint(0000) Name: _adj_fdivr_m32i
     Addr:0F0E7909 hint(0000) Name: _adj_fdivr_m32
     Addr:0F0E7344 hint(0000) Name: _adj_fdiv_r
     Addr:0F00A1BF hint(0064) Name: ThunRTMain
     Addr:0F0342AB hint(0000) Name: _CIatan
     Addr:0F0EA765 hint(0000) Name: _allmul
     Addr:0F0EA75B hint(0000) Name: _CItan
     Addr:0F01F2DD hint(0000) Name: _CIexp
     Addr:0F01F878 hint(0000) Name: __vbaFreeStr
     Addr:0F01DC7F hint(0000) Name: __vbaFreeObj

     Some of the names are selfexplaining, some of them are cryptic, but some of them have an
     interesting name: At least __vbaStrCmp - Doesn't it sound like StringCompare?
     Let's search for appearances in the deadlisting. The first one is obviously not the one
     that compares the good serial with the one you entered (Look at it and you'll see). The
     second (and last) one looks more interesting.

     * Referenced by a (U)nconditional or (C)onditional Jump at Address:
     |:004106D3(C)
     |
     :004106E6 FF75E8                  push [ebp-18]
     :004106E9 6850014100              push 00410150

     * Reference To: MSVBVM50.__vbaStrCmp, Ord:0000h
                                       |
     :004106EE E8C509FFFF              Call 004010B8
     :004106F3 8BD8                    mov ebx, eax
     :004106F5 8D4DE8                  lea ecx, dword ptr [ebp-18]
     :004106F8 F7DB                    neg ebx
     :004106FA 1BDB                    sbb ebx, ebx
     :004106FC 43                      inc ebx
     :004106FD F7DB                    neg ebx

     Enter the debug mode of W32Dasm and set a breakpoint on :004106E9. Then trace into the
     next call. Tracing little further, you'll come to this:

     __vbaStrCmp()
        :0F01F8F6 push [esp+08]
        :0F01F8FA push [esp+08]
        :0F01F8FE push 00000000
        :0F01F900 call MSVBVM50.__vbaStrComp
        :0F01F905 movsx eax, ax
        :0F01F908 ret 0008

     MSVBVM50.__vbaStrComp? It's getting interesting, isn't it? Trace into this one, too.

     __vbaStrComp()
        :0F003563 push ebp
        :0F003564 mov ebp, esp
        :0F003566 push ebx
        :0F003567 push esi
        :0F003568 push edi
        :0F003569 cmp dword ptr [ebp+10], 00000000 // [ebp+10] points to the first string
        :0F00356D mov esi, 00000000
        :0F003572 je 0F00357A // if first string = "", then jump
        :0F003574 mov eax, dword ptr [ebp+10]  //Here is the first string that is compared
        :0F003577 mov esi, dword ptr [eax-04]  //ESI = Length(first string)*2
        :0F00357A cmp dword ptr [ebp+0C], 00000000 //[ebp+0C] points to the second string
        :0F00357E mov edi, 00000000
        :0F003583 je 0F00358B
        :0F003585 mov ecx, dword ptr [ebp+0C] // ECX = second string that is compared
        :0F003588 mov edi, dword ptr [ecx-04] // EDI = Length(second string)*2
        :0F00358B cmp edi, esi // compare stringlength of both strings
        :0F00358D mov ebx, edi // save lenght of second string in EBX
        :0F00358F jnb 0F0035B6 // if string two has less chars, then string one, then jump
        :0F003591 cmp dword ptr [ebp+08], 00000000
        :0F003595 jne 0F0035CD
        :0F003597 test ebx, ebx
        :0F003599 je 0F0035C3
        :0F00359B mov eax, ebx
        :0F00359D shr eax, 1
        :0F00359F push eax
        :0F0035A0 push [ebp+0C] // points to second string
        :0F0035A3 push [ebp+10] // points to first string
        :0F0035A6 call MSVBVM50.0F00D9EA // this one compares them "really" and sets flag
        :0F0035AB test eax, eax // if they are the same
        :0F0035AD je 0F0035BA // then jump
        :0F0035AF pop edi // else return from call with "Not same" flag
        :0F0035B0 pop esi
        :0F0035B1 pop ebx
        :0F0035B2 pop ebp
        :0F0035B3 ret 000C
        :0F0035B6 mov ebx, esi
        :0F0035B8 jmp MSVBVM50.0F003591

     Here is the call at :F0035A6 that compares the two strings really.

        :0F00D9EA push esi // save esi
        :0F00D9EB push edi // save edi
        :0F00D9EC mov edi, dword ptr [esp+10] // edi = first string
        :0F00D9F0 mov esi, dword ptr [esp+0C] // esi = second string
        :0F00D9F4 mov ecx, dword ptr [esp+14] // ecx = length of both strings
        :0F00D9F8 xor eax, eax // erase eax
        :0F00D9FA repz // this one
        :0F00D9FB cmpsw // compares them
        :0F00D9FD je 0F00DA04 // if they are equal, then jump
        :0F00D9FF sbb eax, eax // else
        :0F00DA01 sbb eax, FFFFFFFF // set "not equal" flag
        :0F00DA04 pop edi // restore edi
        :0F00DA05 pop esi // restore esi
        :0F00DA06 ret 000C // return from call

     What do I want to show you? Just that every standard comparison of two strings must pass
     this lines of code. So breakpointing with SICE at :0F00D9F4 would easily reveal which 
     strings are compared.

     Another example: BuLLeT's CrackMe 2.75:
     In this CrackMe we have no __vbaStrCmp :( - The important call is __vbaVarTstEq. The second
     appearance is the correct here, too. After some tracing (enter every callyou come - Yeah 
     guess where you come. You will come to __vbaStrComp() again and then to the passage 
     described above where the two strings are compared. 

     :0F00D9EC mov edi, dword ptr [esp+10] // edi = real serial
     :0F00D9F0 mov esi, dword ptr [esp+0C] // esi = serial, you entered

     Just as I said: No matter which method of comparison is used by the programmer, this part
     of code will always be executed. One string will always be in esi, the other one will always
     be in edi.

     btw: I nearly forgot
     The serial for the first CrackMe is 2hard4u2crackm8
     The serial for the second CrackMe is 2rK4HJ4-7n8RgT09IW6a7kSlg33

     Attention: Remember that strings in VB are stored in "Wide char" format like this:

     [edi+00000000] - 00720032  2.r.
     [edi+00000004] - 0034004b  K.4.
     [edi+00000008] - 004a0048  H.J.
     [edi+0000000C] - 002d0034  4.-.
     [edi+00000010] - 006e0037  7.n.
     [edi+00000014] - 00520038  8.R.
     [edi+00000018] - 00540067  g.T.
     [edi+0000001C] - 00390030  0.9.
     [edi+00000020] - 00570049  I.W.
     [edi+00000024] - 00610036  6.a.
     [edi+00000028] - 006b0037  7.k.
     [edi+0000002C] - 006c0053  S.l.
     [edi+00000030] - 00330067  g.3.
     [edi+00000034] - 00000033  3...

     Just get rid of every 00h and you will get the serial.
     Farthermore the wide char format is the reason, that not the "real" length of the strings 
     is compared, but length*2.


     Eh, do I still hear doubts in your voice? Just CrackMes? Small deadlisting? I had luck?
     May a crack for a "real" program convince you? OK, here it comes. The target is Audio 
     List Maker 1.52.1016. The EXE file is 355 KB big, the deadlisting is 6445KB. I hope that 
     satisfies you. There are quite many __vbaStrCmp in the listing, but that shouldn't frighten
     us. With some *zen* we can easily eliminate most. When you enter a wrong serial, a 
     messagebox appears. I believe that there's a messagebox when you enter a correct serial,
     too. Now it's only speculation, but we will later see, that it is indeed so. So look at
     the __vbaStrCmp calls and you will soon find this one:

     :0044877B 8B55E4                  mov edx, dword ptr [ebp-1C] ;; point to real serial
     :0044877E 8B45D8                  mov eax, dword ptr [ebp-28] ;; point to entered serial
     :00448781 52                      push edx ;; save real serial to stack
     :00448782 50                      push eax ;; save entered serial to stack

     * Reference To: MSVBVM50.__vbaStrCmp, Ord:0000h
                                       |
     :00448783 FF1540824500            Call dword ptr [00458240] ;; compare them and set flag
     :00448789 85C0                    test eax, eax ;; test flag
     :0044878B 0F85B6050000            jne 00448D47 ;; if not set, then jump to "beggar off"

     I strongly believed that this one is "our" __vbaStrCmp, as there is a conditioned jump right
     after the call that jumps to a MessageBox (MSVBVM50.rtcMsgBox). If the jump is not taken,
     a messagebox will appear, too. Read the real serial out at :0044877B. For LaZaRuS it is
     ALM4-3111-7951-9X2K where the "-" mustn't be entered in the program as there are only 16
     chars allowed.

     Alright, I know what you are saying. When the serials are pushed in front of the __vbaStrCmp
     why did we trace into the call in the two CrackMes??? Imagine that there are some ways
     to hide the __vbaStrCmp in the deadlisting (for example: call edi - the indirect call 
     through a register). In a deadlisting there won't be much chances to find that, but if you
     put a breakpoint on the correct place inside the __vbaStrComp() function you can easily find
     the addresses that call the __vbaStrCmp with the help of SICE.


III. BTW
     
     Greets to: tKC, Ed!son, Moral Insanity, +Sandman, Fravia+ and everyone at #cracking4newbies,
     +Sandman's forum and Fravia+'s forum.

IV.  All tutorials by LaZaRuS