【破文标题】某英语复读软件MFC简单算法
【破文作者】KiLlL
【破解时间】2006-01-21 23:25
【破解声明】仅为技术交流之用!
【破解过程】

很好的复读软件,这里仅做算法分析。名字省去了。

MFC,没有壳,很方便。机器码的生成用到了dll,那个dll是aspack压缩的。

根据错误提示的对话框很容易定位到下面:


0041A88F    .  E8 BC7AFFFF      call 00412350  //关键call
0041A894    .  84C0             test al,al
0041A896    .  53               push ebx
0041A897    .  68 58A84200      push 0042A858
0041A89C    .  75 2D            jnz short 0041A8CB //注册成功

开始直接爆破00412350,让al返回值为1,结果发现有暗桩,某些功能在使用时还是有提示,索性跟进去看看:

00412350       51               push ecx
00412351       53               push ebx
00412352       55               push ebp
00412353   |.  56               push esi
00412354   |.  57               push edi
00412355   |.  8BE9             mov ebp,ecx
00412357   |.  E8 74110000      call 004134D0
0041235C   |.  8BCD             mov ecx,ebp
0041235E   |.  E8 5D110000      call 004134C0
00412363   |.  8BCD             mov ecx,ebp
00412365   |.  E8 F60A0000      call 00412E60
0041236A   |.  8B45 14          mov eax,[arg.4]
0041236D   |.  8D7D 14          lea edi,[arg.4]
00412370   |.  8378 F8 08       cmp dword ptr ds:[eax-8],8                   ;  注册码 8位
00412374       74 08            je short 0041237E
00412376       5F               pop edi
00412377       5E               pop esi
00412378       5D               pop ebp
00412379   |.  32C0             xor al,al
0041237B   |.  5B               pop ebx
0041237C   |.  59               pop ecx
0041237D   |.  C3               retn
0041237E   |>  8BCF             mov ecx,edi
00412380   |.  E8 8DCD0000      call <jmp.&MFC42.#4202_CString::MakeLower>
00412385   |.  8B75 18          mov esi,[arg.5]                              ;  我的机器码 "46674926D"
00412388   |.  8B3F             mov edi,dword ptr ds:[edi]                   ;  假码 12345678
0041238A   |.  0FBE46 05        movsx eax,byte ptr ds:[esi+5]                ;  机器码第六位 9
0041238E   |.  0FBE16           movsx edx,byte ptr ds:[esi]                  ;  机器码第一位 4
00412391   |.  8D0C40           lea ecx,dword ptr ds:[eax+eax*2]             ;  39*3=AB
00412394   |.  8D0488           lea eax,dword ptr ds:[eax+ecx*4]             ;  eax= eax+AB*4
00412397   |.  8BCA             mov ecx,edx                                  ;  34
00412399   |.  C1E1 05          shl ecx,5                                    ;  ecx=ecx*2^5
0041239C   |.  03CA             add ecx,edx                                  ;  ecx=680 +34
0041239E   |.  8D0C49           lea ecx,dword ptr ds:[ecx+ecx*2]             ;  ecx=ecx*3 6b4*3=141c
004123A1   |.  8D144A           lea edx,dword ptr ds:[edx+ecx*2]             ;  edx+=ecx*2 286c
004123A4   |.  B9 24000000      mov ecx,24
004123A9   |.  03C2             add eax,edx                                  ;  eax+=edx 2e5+286c
004123AB   |.  33D2             xor edx,edx
004123AD   |.  F7F1             div ecx                                      ;  2b51/24
004123AF   |.  0FBE0F           movsx ecx,byte ptr ds:[edi]                  ;  注册码第一位
004123B2   |.  8D41 D0          lea eax,dword ptr ds:[ecx-30]                ;  Switch (cases 30..7A)
004123B5   |.  83F8 4A          cmp eax,4A                                   ;  ascii-30
004123B8   |.  0F87 34010000    ja 004124F2
004123BE   |.  33DB             xor ebx,ebx
004123C0   |.  8A98 302A4100    mov bl,byte ptr ds:[eax+412A30]              ;  查表
004123C6   |.  FF249D 9C294100  jmp dword ptr ds:[ebx*4+41299C]
004123CD   |>  B8 13000000      mov eax,13                                   ;  Case 31 ('1') of switch 004123B2
004123D2   |.  E9 20010000      jmp 004124F7
004123D7   |>  B8 02000000      mov eax,2                                    ;  Case 32 ('2') of switch 004123B2
004123DC   |.  E9 16010000      jmp 004124F7
004123E1   |>  B8 01000000      mov eax,1                                    ;  Case 33 ('3') of switch 004123B2
004123E6   |.  E9 0C010000      jmp 004124F7
004123EB   |>  B8 07000000      mov eax,7                                    ;  Case 34 ('4') of switch 004123B2
004123F0   |.  E9 02010000      jmp 004124F7
004123F5   |>  B8 22000000      mov eax,22                                   ;  Case 35 ('5') of switch 004123B2
004123FA   |.  E9 F8000000      jmp 004124F7
004123FF   |>  B8 05000000      mov eax,5                                    ;  Case 36 ('6') of switch 004123B2
00412404   |.  E9 EE000000      jmp 004124F7
00412409   |>  B8 04000000      mov eax,4                                    ;  Case 37 ('7') of switch 004123B2
0041240E   |.  E9 E4000000      jmp 004124F7
00412413   |>  B8 10000000      mov eax,10                                   ;  Case 38 ('8') of switch 004123B2
00412418   |.  E9 DA000000      jmp 004124F7
0041241D   |>  33C0             xor eax,eax                                  ;  Case 39 ('9') of switch 004123B2
0041241F   |.  E9 D3000000      jmp 004124F7
00412424   |>  B8 11000000      mov eax,11                                   ;  Case 30 ('0') of switch 004123B2
00412429   |.  E9 C9000000      jmp 004124F7
0041242E   |>  B8 1C000000      mov eax,1C                                   ;  Case 61 ('a') of switch 004123B2
00412433   |.  E9 BF000000      jmp 004124F7
00412438   |>  B8 0C000000      mov eax,0C                                   ;  Case 62 ('b') of switch 004123B2
0041243D   |.  E9 B5000000      jmp 004124F7
00412442   |>  B8 14000000      mov eax,14                                   ;  Case 63 ('c') of switch 004123B2
00412447   |.  E9 AB000000      jmp 004124F7
0041244C   |>  B8 0E000000      mov eax,0E                                   ;  Case 64 ('d') of switch 004123B2
00412451   |.  E9 A1000000      jmp 004124F7
00412456   |>  B8 0D000000      mov eax,0D                                   ;  Case 65 ('e') of switch 004123B2
0041245B   |.  E9 97000000      jmp 004124F7
00412460   |>  B8 08000000      mov eax,8                                    ;  Case 66 ('f') of switch 004123B2
00412465   |.  E9 8D000000      jmp 004124F7
0041246A   |>  B8 09000000      mov eax,9                                    ;  Case 67 ('g') of switch 004123B2
0041246F   |.  E9 83000000      jmp 004124F7
00412474   |>  B8 12000000      mov eax,12                                   ;  Case 68 ('h') of switch 004123B2
00412479   |.  EB 7C            jmp short 004124F7
0041247B   |>  B8 03000000      mov eax,3                                    ;  Case 69 ('i') of switch 004123B2
00412480   |.  EB 75            jmp short 004124F7
00412482   |>  B8 0F000000      mov eax,0F                                   ;  Case 6A ('j') of switch 004123B2
00412487   |.  EB 6E            jmp short 004124F7
00412489   |>  B8 15000000      mov eax,15                                   ;  Case 6B ('k') of switch 004123B2
0041248E   |.  EB 67            jmp short 004124F7
00412490   |>  B8 1B000000      mov eax,1B                                   ;  Case 6C ('l') of switch 004123B2
00412495   |.  EB 60            jmp short 004124F7
00412497   |>  B8 18000000      mov eax,18                                   ;  Case 6D ('m') of switch 004123B2
0041249C   |.  EB 59            jmp short 004124F7
0041249E   |>  B8 17000000      mov eax,17                                   ;  Case 6E ('n') of switch 004123B2
004124A3   |.  EB 52            jmp short 004124F7
004124A5   |>  B8 21000000      mov eax,21                                   ;  Case 6F ('o') of switch 004123B2
004124AA   |.  EB 4B            jmp short 004124F7
004124AC   |>  B8 1A000000      mov eax,1A                                   ;  Case 70 ('p') of switch 004123B2
004124B1   |.  EB 44            jmp short 004124F7
004124B3   |>  B8 16000000      mov eax,16                                   ;  Case 72 ('r') of switch 004123B2
004124B8   |.  EB 3D            jmp short 004124F7
004124BA   |>  B8 1D000000      mov eax,1D                                   ;  Case 73 ('s') of switch 004123B2
004124BF   |.  EB 36            jmp short 004124F7
004124C1   |>  B8 1E000000      mov eax,1E                                   ;  Case 74 ('t') of switch 004123B2
004124C6   |.  EB 2F            jmp short 004124F7
004124C8   |>  B8 23000000      mov eax,23                                   ;  Case 75 ('u') of switch 004123B2
004124CD   |.  EB 28            jmp short 004124F7
004124CF   |>  B8 20000000      mov eax,20                                   ;  Case 76 ('v') of switch 004123B2
004124D4   |.  EB 21            jmp short 004124F7
004124D6   |>  B8 19000000      mov eax,19                                   ;  Case 77 ('w') of switch 004123B2
004124DB   |.  EB 1A            jmp short 004124F7
004124DD   |>  B8 06000000      mov eax,6                                    ;  Case 78 ('x') of switch 004123B2
004124E2   |.  EB 13            jmp short 004124F7
004124E4   |>  B8 1F000000      mov eax,1F                                   ;  Case 79 ('y') of switch 004123B2
004124E9   |.  EB 0C            jmp short 004124F7
004124EB   |>  B8 0A000000      mov eax,0A                                   ;  Case 7A ('z') of switch 004123B2
004124F0   |.  EB 05            jmp short 004124F7
004124F2   |>  B8 0B000000      mov eax,0B                                   ;  Default case of switch 004123B2
004124F7   |>  3BD0             cmp edx,eax
004124F9   |.  74 0C            je short 00412507
004124FB   |.  5F               pop edi
004124FC   |.  C645 0F 10       mov byte ptr ss:[ebp+F],10
00412500   |.  5E               pop esi
00412501   |.  5D               pop ebp
00412502   |.  32C0             xor al,al
00412504   |.  5B               pop ebx
00412505   |.  59               pop ecx
00412506   |.  C3               retn


这里首先验证注册码位数,然后逐位验证。验证时没有出现真正的注册码,而是通过假码第一位跟第六位运行后得到一个数字,再利用假码第一位查表得到另外一个数字,比较这两个数字,相等则继续,否则注册失败。

注意 mov byte ptr ss:[ebp+F],10这句,成功了是 mov byte ptr ss:[ebp+F],13,这里估计是个暗桩。有兴趣下个读断点试试。

给出vb的注册机源码,对比程序代码很容易看:

    str = "1234567890abcdefghijklmnoprstuvwxyz{"
    str1 = "130201072205041000111c0c140e0d080912030f151b1817211a161d1e232019061f0a0b"

    eax = Asc(Mid$(mc, 6, 1))
    edx = Asc(Mid$(mc, 1, 1))
    ecx = eax * 3
    eax = eax + ecx * 4
    ecx = edx
    ecx = ecx * 2 ^ 5
    ecx = ecx + edx
    ecx = ecx * 3
    edx = edx + ecx * 2
    ecx = &H24
    eax = eax + edx
    edx = eax Mod ecx


    For i = 1 To Len(str1) - 1 Step 2
        If Right$("00" & Hex$(edx), 2) = UCase$(Mid$(str1, i, 2)) Then
            Tmp = Mid$(str, i \ 2 + 1, 1)
            Exit For
        End If
    Next

    If Tmp = "" Then Tmp = "{"

后面的7位计算方法与之类似。有几个地方要注意:

004128E8   |.  C645 0C 01       mov byte ptr ss:[ebp+C],1                    ;  1

00412941   |.  C645 0D 01       mov byte ptr ss:[ebp+D],1                    ;  2

0041298E   |.  C645 0F 13       mov byte ptr ss:[ebp+F],13                   ;  3


【破解心得】
有了mfc的Lib文件,mfc的函数一目了然,所以很容易看清注册流程。该软件的思路不错,在关键call里面设置了其他返回数据,因此不能采取在函数开始直接返回al值的方法来爆破,但是还是很容易找到关键点。注册成功后结果保存在注册表内。

关于利用dll取得机器码的方法不是很可靠,简单编写一个dll就可以一码多用了。