查看: 11416|回复: 7

一个简单的CrackMe分析

[复制链接]
  • TA的每日心情
    奋斗
    2017-1-16 20:03
  • 签到天数: 116 天

    [LV.6]常住居民II

    发表于 2013-10-22 22:51:03 | 显示全部楼层 |阅读模式
        这是一个简单的CrackMe分析,大牛勿笑,欢迎指教。
        这个CrackMe没有关键字符串提醒,没有敏感函数的调用,常规的查找字符串和对敏感函数下断点都行不通,只能另想办法。用IDA打开软件,在函数列表中看到一个函数UpDateData,于是眼前一亮。因为在MFC中,这个函数是用来更新控件数据的,所以就猜想这个CrackMe是通过这个函数来获取用户名和序列号,找到这个函数的调用位置,然后用OD加载CrackMe,找到UpDateData函数的调用位置,并下断点。按下F9运行,输入用户名和序列号,点击“确定”后,程序停在下面这个位置:
    [AppleScript] 纯文本查看 复制代码
    00401A09   .  E8 1E070000   call    <jmp.&MFC71.#6236_CWnd::UpdateData>
    00401A0E   .  68 A8394000   push    004039A8                               ; /FileName = "Reg.dll"
    00401A13   .  FF15 34304000 call    dword ptr [<&KERNEL32.LoadLibraryA>]   ; \LoadLibraryA
    

          这是通过UpDateData获取用户名和序列号,然后调用LoadLibraryA函数加载Reg.dll,然后取出用户名,代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;获取用户名和序列号
    00401A09   .  E8 1E070000   call    <jmp.&MFC71.#6236_CWnd::UpdateData>
    ;调用LoadLibraryA来加载Reg.dll
    00401A0E   .  68 A8394000   push  004039A8  ; /FileName = "Reg.dll"
    00401A13   .  FF15 34304000 call    dword ptr [<&KERNEL32.LoadLibraryA>]               
    ; \LoadLibraryA
    00401A19   .  68 70394000   push    00403970
    00401A1E   .  8D4C24 18     lea     ecx, dword ptr [esp+18]
    ;保存Reg.dll的句柄
    00401A22   .  894424 24     mov     dword ptr [esp+24], eax
    ;取出用户名
    00401A6A   .  FF15 9C314000 call    dword ptr [<&MFC71.#876_ATL::CSimpleStringT<char,1>;  MFC71.7C158BCD
    

         到这里,eax中已经存放了用户输入的用户名的首地址,接下来先将用户名存入前面定义的数组中,代码如下:
    [AppleScript] 纯文本查看 复制代码
    00401A70   .  8D6C24 24     lea     ebp, dword ptr [esp+24]
    00401A74   >  8A08          mov     cl, byte ptr [eax]
    00401A76   .  40            inc     eax
    00401A77   .  884D 00       mov     byte ptr [ebp], cl
    00401A7A   .  45            inc     ebp
    00401A7B   .  84C9          test    cl, cl
    00401A7D   .^ 75 F5         jnz     short 00401A74
    

         然后取出用户名的前三个字节,通过一些算法来对其进行计算,代码如下:
    [AppleScript] 纯文本查看 复制代码
    00401A7F   .  33ED          xor     ebp, ebp
    ;取出用户名的一个字节
    00401A81   >  8A442C 24     mov     al, byte ptr [esp+ebp+24]
    ;判断其是否为字符0,如果是则结束注册
    00401A85   .  3C 30         cmp     al, 30
    00401A87   .  0F84 D1000000 je      00401B5E
    ;将al扩充为eax
    00401A8D   .  0FBEC0        movsx   eax, al
    00401A90   .  57            push    edi
    ;将eax的最高位扩充到edx
    00401A91   .  99            cdq
    00401A92   .  56            push    esi
    00401A93   .  52            push    edx
    00401A94   .  50            push    eax
    ;这个函数对输入的参数进行计算
    00401A95   .  E8 96070000   call    00402230
    00401A9A   .  45            inc     ebp
    ;通过ebp来限制获取用户名的字节数
    00401A9B   .  83FD 03       cmp     ebp, 3
    ;将用户名计算结果的低32位存入esi,高32位存入edi
    00401A9E   .  8BF0          mov     esi, eax
    00401AA0   .  8BFA          mov     edi, edx
    00401AA2   .^ 7C DD         jl      short 00401A81
    

        现在来看看00401A95   .  E8 96070000   call    00402230这个函数里都做了些什么,代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;获取第二个参数
    00402230  /$  8B4424 08     mov     eax, dword ptr [esp+8]
    ;获取第四个参数
    00402234  |.  8B4C24 10     mov     ecx, dword ptr [esp+10]
    ;用第二个参数和第四个参数进行或运算
    00402238  |.  0BC8          or      ecx, eax
    ;获取第三个参数
    0040223A  |.  8B4C24 0C     mov     ecx, dword ptr [esp+C]
    ;如果或的结果部位0则跳转
    0040223E  |.  75 09         jnz     short 00402249
    ;获取第一个参数
    00402240  |.  8B4424 04     mov     eax, dword ptr [esp+4]
    ;第一个参数与第三个参数相乘,结果低32位存eax,高32位存edx
    00402244  |.  F7E1          mul     ecx
    00402246  |.  C2 1000       retn    10
    ;前面相或后结果不为0的计算
    00402249  |>  53            push    ebx
    ;用相或后的结果乘以第二个参数
    0040224A  |.  F7E1          mul     ecx
    0040224C  |.  8BD8          mov     ebx, eax
    ;由于前面有个push ebx,所以这里esp+8是取出第一个参数
    0040224E  |.  8B4424 08     mov     eax, dword ptr [esp+8]
    ;第一个参数乘以第四个参数,结果存与eax
    00402252  |.  F76424 14     mul     dword ptr [esp+14]
    ;将所得的积与前面所得的积相加
    00402256  |.  03D8          add     ebx, eax
    ;取出第一个参数
    00402258  |.  8B4424 08     mov     eax, dword ptr [esp+8]
    ;ecx存放的是第三个参数,这里将第一个参数与第三个参数相乘
    0040225C  |.  F7E1          mul     ecx
    ;将所得结果与前面的和相加
    0040225E  |.  03D3          add     edx, ebx
    00402260  |.  5B            pop     ebx
    00402261  \.  C2 1000       retn    10
    

        到这里,用户名前三个字节的计算已经结束,接下来是用户名长度的判断,代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;取出用户名数组的第七个元素
    00401AA4   .  8A4424 2A     mov     al, byte ptr [esp+2A]
    ;判断其是否为0,如果不为0则结束注册
    00401AA8   .  84C0          test    al, al
    00401AAA   .  0F85 AE000000 jnz     00401B5E
    ;取出用户名数组的第6个原素,如果为0则结束注册
    00401AB0   .  8A4424 29     mov     al, byte ptr [esp+29]
    00401AB4   .  84C0          test    al, al
    00401AB6   .  0F84 A2000000 je      00401B5E
    

        通过上面的两个判断可知,用户名的长度只能为6个字节。接下来是通过00401AC1   .  E8 BA010000   call    00401C80这个函数来获取CPU信息的函数,这个函数代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;实例化4个CString对象
    00401CE1  |.  FF15 A8314000 call    dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>;  MFC71.7C173199
    00401CE7  |.  8D4C24 0C     lea     ecx, dword ptr [esp+C]
    00401CEB  |.  FF15 A8314000 call    dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>;  MFC71.7C173199
    00401CF1  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
    00401CF5  |.  FF15 A8314000 call    dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>;  MFC71.7C173199
    00401CFB  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
    00401CFF  |.  FF15 A8314000 call    dword ptr [<&MFC71.#310_ATL::CStringT<char,StrTraitMFC>;  MFC71.7C173199
    00401D05  |.  C64424 40 04  mov     byte ptr [esp+40], 4
    ;获取CPU制造商信息信息
    00401D0A  |.  33C0          xor     eax, eax
    00401D0C  |.  0FA2          cpuid
    00401D0E  |.  895C24 24     mov     dword ptr [esp+24], ebx
    00401D12  |.  895424 28     mov     dword ptr [esp+28], edx
    00401D16  |.  894C24 2C     mov     dword ptr [esp+2C], ecx
    00401D1A  |.  8D4C24 24     lea     ecx, dword ptr [esp+24]
    00401D1E  |.  51            push    ecx
    00401D1F  |.  8D5424 1C     lea     edx, dword ptr [esp+1C]
    ;将CPU制造商信息以字符串的形式存储与一个CString对象中
    00401D23  |.  68 BC394000   push    004039BC                                               ;  ASCII "%s-"
    00401D28  |.  52            push    edx
    00401D29  |.  FF15 DC314000 call    dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>;  MFC71.7C146A9D
    00401D2F  |.  83C4 0C       add     esp, 0C
    ;获取CPU序列号的高两个WORD
    00401D32  |.  B8 01000000   mov     eax, 1
    00401D37  |.  33D2          xor     edx, edx
    00401D39  |.  0FA2          cpuid
    00401D3B  |.  895424 1C     mov     dword ptr [esp+1C], edx
    00401D3F  |.  894424 20     mov     dword ptr [esp+20], eax
    00401D43  |.  8B4424 20     mov     eax, dword ptr [esp+20]
    00401D47  |.  8B4C24 1C     mov     ecx, dword ptr [esp+1C]
    00401D4B  |.  50            push    eax
    00401D4C  |.  51            push    ecx
    00401D4D  |.  8D5424 18     lea     edx, dword ptr [esp+18]
    ;将CPU序列号转为十六进制,再将其格式化为字符串存入一个CString中
    00401D51  |.  68 B0394000   push    004039B0                                               ;  ASCII "%08X%08X"
    00401D56  |.  52            push    edx
    00401D57  |.  FF15 DC314000 call    dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>;  MFC71.7C146A9D
    00401D5D  |.  83C4 10       add     esp, 10
    ;获取CPU序列号的4个WORD
    00401D60  |.  B8 03000000   mov     eax, 3
    00401D65  |.  33C9          xor     ecx, ecx
    00401D67  |.  33D2          xor     edx, edx
    00401D69  |.  0FA2          cpuid
    00401D6B  |.  895424 1C     mov     dword ptr [esp+1C], edx
    00401D6F  |.  894C24 20     mov     dword ptr [esp+20], ecx
    00401D73  |.  8B4424 20     mov     eax, dword ptr [esp+20]
    00401D77  |.  8B4C24 1C     mov     ecx, dword ptr [esp+1C]
    00401D7B  |.  50            push    eax
    00401D7C  |.  51            push    ecx
    00401D7D  |.  8D5424 1C     lea     edx, dword ptr [esp+1C]
    ;将这4个WORD转为16进制,并格式化为字符串存入一个CString中
    00401D81  |.  68 B0394000   push    004039B0                                               ;  ASCII "%08X%08X"
    00401D86  |.  52            push    edx
    00401D87  |.  FF15 DC314000 call    dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMF>;  MFC71.7C146A9D
    00401D8D  |.  8D4424 24     lea     eax, dword ptr [esp+24]
    00401D91  |.  50            push    eax
    00401D92  |.  8D4C24 24     lea     ecx, dword ptr [esp+24]
    00401D96  |.  51            push    ecx
    00401D97  |.  8D5424 34     lea     edx, dword ptr [esp+34]
    00401D9B  |.  52            push    edx
    ;这里将CPU序列号的两个字符串连成一个字符串
    00401D9C  |.  E8 3FFEFFFF   call    00401BE0
    

        接下来通过00401ADC   .  E8 CFFDFFFF   call    004018B0来对获取的CPU序列号进行计算,这个函数的实现过程如下:
    [AppleScript] 纯文本查看 复制代码
    00401903  |> /33F6          /xor     esi, esi
    ;要获取的元素下标
    00401905  |> |8D0437        |/lea     eax, dword ptr [edi+esi]
    00401908  |. |50            ||push    eax
    ;源字符串的存放位置
    00401909  |. |8D4C24 58     ||lea     ecx, dword ptr [esp+58]
    ;这里调用的是GetAt函数,来获取相应位置的字符
    0040190D  |. |FF15 D4314000 ||call    dword ptr [<&MFC71.#2451_ATL::CSimpleStringT<char,1>>;  MFC71.7C1894E7
    00401913  |. |8D4C24 0C     ||lea     ecx, dword ptr [esp+C]
    00401917  |. |50            ||push    eax
    00401918  |. |FF15 D0314000 ||call    dword ptr [<&MFC71.#782_ATL::CStringT<char,StrTraitM>;  MFC71.7C18B1DF
    0040191E  |. |8D4C24 0C     ||lea     ecx, dword ptr [esp+C]
    00401922  |. |51            ||push    ecx
    00401923  |. |8BCD          ||mov     ecx, ebp
    ;将字符存入CString对象中
    00401925  |. |FF15 CC314000 ||call    dword ptr [<&MFC71.#907_ATL::CStringT<char,StrTraitM>;  MFC71.7C14E599
    0040192B  |. |46            ||inc     esi
    ;每个CString对象存放8个字符
    0040192C  |. |83FE 08       ||cmp     esi, 8
    0040192F  |.^|7C D4         |\jl      short 00401905
    00401931  |. |83C7 08       |add     edi, 8
    00401934  |. |83C5 04       |add     ebp, 4
    00401937  |. |83FF 20       |cmp     edi, 20
    0040193A  |.^\7C C7         \jl      short 00401903
    	接下来把CString中的字符串转为数字,代码如下:
    00401942  |> /6A 10         /push    10
    00401944  |. |51            |push    ecx
    00401945  |. |8BCC          |mov     ecx, esp
    00401947  |. |896424 18     |mov     dword ptr [esp+18], esp
    0040194B  |. |57            |push    edi
    0040194C  |. |FF15 C8314000 |call    dword ptr [<&MFC71.#297_ATL::CStringT<char,StrTraitMFC_D>;  MFC71.7C14E575
    ;字符串转换成数字函数
    00401952  |. |E8 79FDFFFF   |call    004016D0
    00401957  |. |83C4 08       |add     esp, 8
    ;保存转换结果
    0040195A  |. |8944F4 24     |mov     dword ptr [esp+esi*8+24], eax
    0040195E  |. |8954F4 28     |mov     dword ptr [esp+esi*8+28], edx
    00401962  |. |46            |inc     esi
    00401963  |. |83C7 04       |add     edi, 4
    00401966  |. |83FE 04       |cmp     esi, 4
    00401969  |.^\7C D7         \jl      short 00401942
    

        字符串转换为数字的函数代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;获取要转换的字符串首
    004016EE  |.  8D4C24 3C     lea     ecx, dword ptr [esp+3C]
    004016F2  |.  896C24 34     mov     dword ptr [esp+34], ebp
    ;获取要转换的字符串长度
    004016F6  |.  FF15 C4314000 call    dword ptr [<&MFC71.#2902_ATL::CSimpleStringT<char,1>::GetLength>]   ;  MFC71.7C146AB0
    ;如果字符串长度小于等于0,则结束转换
    004016FC  |.  3BC5          cmp     eax, ebp
    ;保存要转换的次数
    004016FE  |.  894424 18     mov     dword ptr [esp+18], eax
    00401702  |.  896C24 1C     mov     dword ptr [esp+1C], ebp
    00401706  |.  896C24 20     mov     dword ptr [esp+20], ebp
    0040170A  |.  896C24 10     mov     dword ptr [esp+10], ebp
    0040170E  |.  0F8E 0E010000 jle     00401822
    00401714  |.  8B7C24 18     mov     edi, dword ptr [esp+18]
    00401718  |.  8D58 FF       lea     ebx, dword ptr [eax-1]
    0040171B  |.  895C24 14     mov     dword ptr [esp+14], ebx
    0040171F  |.  90            nop
    00401720  |> /8B4424 40     /mov     eax, dword ptr [esp+40]
    00401724  |. |50            |push    eax
    00401725  |. |55            |push    ebp
    ;获取要转换的字符串地址
    00401726  |. |8D4C24 44     |lea     ecx, dword ptr [esp+44]
    ;获取要转换的字符
    0040172A  |. |FF15 C0314000 |call    dword ptr [<&MFC71.#865_ATL::CSimpleStr>;  MFC71.7C1894E7
    00401730  |. |50            |push    eax
    ;判断该字符是否为0~f之一,如果是则返回1,否则返回0
    00401731  |. |E8 1AFFFFFF   |call    00401650
    00401736  |. |83C4 08       |add     esp, 8
    ;如果返回0则说明该字符并非0~f之一,则直接结束
    00401739  |. |85C0          |test    eax, eax
    0040173B  |. |8D4C24 3C     |lea     ecx, dword ptr [esp+3C]
    0040173F  |. |0F84 02010000 |je      00401847
    00401745  |. |55            |push    ebp
    ;获取要检测的字符
    00401746  |. |FF15 C0314000 |call    dword ptr [<&MFC71.#865_ATL::CSimpleStr>;  MFC71.7C1894E7
    0040174C  |. |0FBEC8        |movsx   ecx, al
    0040174F  |. |51            |push    ecx                                     ; /c
    ;用isdugit函数来检测该字符是否为数字, 如果为数字则返回1,否则返回0
    00401750  |. |FF15 F4324000 |call    dword ptr [<&MSVCR71.isdigit>]          ; \isdigit
    00401756  |. |83C4 04       |add     esp, 4
    ;如果是字符,则进入字符处理
    00401759  |. |85C0          |test    eax, eax
    0040175B  |. |8D4C24 3C     |lea     ecx, dword ptr [esp+3C]
    0040175F  |. |55            |push    ebp
    00401760  |. |74 0E         |je      short 00401770
    ;获取字符
    00401762  |. |FF15 C0314000 |call    dword ptr [<&MFC71.#865_ATL::CSimpleStr>;  MFC71.7C1894E7
    00401768  |. |0FBEF8        |movsx   edi, al
    ;如果是数字,则直接用它的ascii码减去字符0的ascii码,然后跳到下面的处理部分
    0040176B  |. |83EF 30       |sub     edi, 30
    0040176E  |. |EB 47         |jmp     short 004017B7
    ;获取字符
    00401770  |> |FF15 C0314000 |call    dword ptr [<&MFC71.#865_ATL::CSimpleStr>;  MFC71.7C1894E7
    00401776  |. |0FBEC0        |movsx   eax, al
    ;用该字符啊ascii码减去大写字母A的ascii码
    00401779  |. |83C0 BF       |add     eax, -41                                ;  Switch (cases 41..66)
    ;大于f则不进行字符转数字的处理
    0040177C  |. |83F8 25       |cmp     eax, 25
    0040177F  |. |77 36         |ja      short 004017B7
    00401781  |. |0FB690 841840>|movzx   edx, byte ptr [eax+401884]
    ;这里用个switch语句来将字母转为相应的数字
    00401788  |. |FF2495 681840>|jmp     dword ptr [edx*4+401868]
    ;字母A或a则转为0x0A
    0040178F  |> |BF 0A000000   |mov     edi, 0A                                 ;  Cases 41 ('A'),61 ('a') of switch 00401779
    00401794  |. |EB 21         |jmp     short 004017B7
    ;字母B或b则转为0x0B
    00401796  |> |BF 0B000000   |mov     edi, 0B                                 ;  Cases 42 ('B'),62 ('b') of switch 00401779
    0040179B  |. |EB 1A         |jmp     short 004017B7
    ;字母C或c则转为0x0C
    0040179D  |> |BF 0C000000   |mov     edi, 0C                                 ;  Cases 43 ('C'),63 ('c') of switch 00401779
    004017A2  |. |EB 13         |jmp     short 004017B7
    ;字母D或d则转为0x0D
    004017A4  |> |BF 0D000000   |mov     edi, 0D                                 ;  Cases 44 ('D'),64 ('d') of switch 00401779
    004017A9  |. |EB 0C         |jmp     short 004017B7
    ;字母E或e则转为0x0E
    004017AB  |> |BF 0E000000   |mov     edi, 0E                                 ;  Cases 45 ('E'),65 ('e') of switch 00401779
    004017B0  |. |EB 05         |jmp     short 004017B7
    ;字母F或f则转为0x0F
    004017B2  |> |BF 0F000000   |mov     edi, 0F                                 ;  Cases 46 ('F'),66 ('f') of switch 00401779
    004017B7  |> |33F6          |xor     esi, esi                                ;  Default case of switch 00401779
    ;ebx保存的是剩余为转换的字符个数,如果小于等于0,则说明字符已转换完毕
    004017B9  |. |85DB          |test    ebx, ebx
    004017BB  |. |B9 01000000   |mov     ecx, 1
    004017C0  |. |7E 2A         |jle     short 004017EC
    ;eax存放的值为0x10
    004017C2  |. |8B4424 40     |mov     eax, dword ptr [esp+40]
    004017C6  |. |99            |cdq
    004017C7  |. |8BE8          |mov     ebp, eax
    004017C9  |. |895424 28     |mov     dword ptr [esp+28], edx
    004017CD  |. |8D49 00       |lea     ecx, dword ptr [ecx]
    ;下面这个循环用来确定字符在转换化后数字所处的位置
    004017D0  |> |8B4424 28     |/mov     eax, dword ptr [esp+28]
    004017D4  |. |56            ||push    esi
    004017D5  |. |51            ||push    ecx
    004017D6  |. |50            ||push    eax
    004017D7  |. |55            ||push    ebp
    004017D8  |. |E8 530A0000   ||call    00402230
    004017DD  |. |4B            ||dec     ebx
    004017DE  |. |8BC8          ||mov     ecx, eax
    004017E0  |. |8BF2          ||mov     esi, edx
    004017E2  |.^|75 EC         |\jnz     short 004017D0
    004017E4  |. |8B6C24 10     |mov     ebp, dword ptr [esp+10]
    004017E8  |. |8B5C24 14     |mov     ebx, dword ptr [esp+14]
    004017EC  |> |56            |push    esi
    004017ED  |. |8BC7          |mov     eax, edi
    004017EF  |. |99            |cdq
    004017F0  |. |51            |push    ecx
    004017F1  |. |52            |push    edx
    004017F2  |. |50            |push    eax
    ;这里实现的是用字符串转化后的数字乘以它所处的位置,从而得到一个整数的某一位
    004017F3  |. |E8 380A0000   |call    00402230
    004017F8  |. |8B4C24 1C     |mov     ecx, dword ptr [esp+1C]
    004017FC  |. |8B7424 20     |mov     esi, dword ptr [esp+20]
    00401800  |. |03C8          |add     ecx, eax
    00401802  |. |8B4424 18     |mov     eax, dword ptr [esp+18]
    00401806  |. |13F2          |adc     esi, edx
    00401808  |. |45            |inc     ebp
    00401809  |. |4B            |dec     ebx
    ;判断转换是否结束
    0040180A  |. |3BE8          |cmp     ebp, eax
    ;保存转换结果
    0040180C  |. |894C24 1C     |mov     dword ptr [esp+1C], ecx
    00401810  |. |897424 20     |mov     dword ptr [esp+20], esi
    00401814  |. |896C24 10     |mov     dword ptr [esp+10], ebp
    00401818  |. |895C24 14     |mov     dword ptr [esp+14], ebx
    0040181C  |.^\0F8C FEFEFFFF \jl      00401720
    

        所有的字符串都转为数字之后,接下来就对它进行计算。转换的结果保存在一个长度为8的int型数组中,下面是计算部分的代码:
    [AppleScript] 纯文本查看 复制代码
    0040196B  |.  8B4C24 40     mov     ecx, dword ptr [esp+40]
    0040196F  |.  8B7C24 28     mov     edi, dword ptr [esp+28]
    00401973  |.  8B5424 3C     mov     edx, dword ptr [esp+3C]
    00401977  |.  8B7424 24     mov     esi, dword ptr [esp+24]
    0040197B  |.  8B6C24 38     mov     ebp, dword ptr [esp+38]
    0040197F  |.  8B4424 34     mov     eax, dword ptr [esp+34]
    00401983  |.  33F9          xor     edi, ecx
    00401985  |.  8B4C24 30     mov     ecx, dword ptr [esp+30]
    00401989  |.  33F2          xor     esi, edx
    0040198B  |.  8B5424 2C     mov     edx, dword ptr [esp+2C]
    0040198F  |.  33FD          xor     edi, ebp
    00401991  |.  33F0          xor     esi, eax
    00401993  |.  33F9          xor     edi, ecx
    00401995  |.  8D4C24 0C     lea     ecx, dword ptr [esp+C]
    00401999  |.  33F2          xor     esi, edx
    

        计算出结果后,将所得结果与用户名前三字节的计算结果相或,代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;edx保存的是所得结果的高32位,eax保存的是所得结果的低32位,edi保存的是用户名前三字节结算结果的高32位,esi保存的是计算所得结果的低32位
    00401AE1   .  0BFA          or      edi, edx
    00401AE3   .  0BF0          or      esi, eax
    

        接下来将所得结果转化为字符串,代码如下:
    [AppleScript] 纯文本查看 复制代码
    00401AE5   .  57            push    edi
    00401AE6   .  56            push    esi
    00401AE7   .  8D4424 1C     lea     eax, dword ptr [esp+1C]
    00401AEB   .  68 A4394000   push    004039A4                                                       ;  ASCII "%x"
    00401AF0   .  50            push    eax
    00401AF1   .  FF15 DC314000 call    dword ptr [<&MFC71.#2322_ATL::CStringT<char,StrTraitMFC_DLL<ch>;  MFC71.7C146A9D
    00401AF7   .  8B4C24 34     mov     ecx, dword ptr [esp+34]
    00401AFB   .  83C4 14       add     esp, 14
    

        然后调用reg.dll中的加密函数,代码如下:
    [AppleScript] 纯文本查看 复制代码
    00401AFE   .  68 98394000   push    00403998                                                       ; /ProcNameOrOrdinal = "GetMD5Str"
    00401B03   .  51            push    ecx                                                            ; |hModule
    00401B04   .  FF15 38304000 call    dword ptr [<&KERNEL32.GetProcAddress>]                         ; \GetProcAddress
    00401B0A   .  8D4C24 10     lea     ecx, dword ptr [esp+10]
    00401B0E   .  8BF0          mov     esi, eax
    00401B10   .  FF15 9C314000 call    dword ptr [<&MFC71.#876_ATL::CSimpleStringT<char,1>::operator >;  MFC71.7C158BCD
    00401B16   .  50            push    eax
    ;调用reg.dll中的GetMD5Str函数
    00401B17   .  FFD6          call    esi
    

        然后将所得结果存入一个CString对象中,并对这个字符串进行计算,计算方式与对CPU序列号的计算一样,代码如下:
    [AppleScript] 纯文本查看 复制代码
    00401B19   .  50            push    eax
    00401B1A   .  8D4C24 18     lea     ecx, dword ptr [esp+18]
    00401B1E   .  FF15 D8314000 call    dword ptr [<&MFC71.#784_ATL::CStringT<char,StrTraitM>;  MFC71.7C14FF74
    00401B24   .  51            push    ecx
    00401B25   .  8D5424 18     lea     edx, dword ptr [esp+18]
    00401B29   .  8BCC          mov     ecx, esp
    00401B2B   .  896424 20     mov     dword ptr [esp+20], esp
    00401B2F   .  52            push    edx
    00401B30   .  FF15 C8314000 call    dword ptr [<&MFC71.#297_ATL::CStringT<char,StrTraitM>;  MFC71.7C14E575
    ;对所生成的MD5字符串进行计算
    00401B36   .  E8 75FDFFFF   call    004018B0
    

        通过这次计算后,得到的结果就是这个CM所需要的序列号了,接下来就是序列号的比较,代码如下:
    [AppleScript] 纯文本查看 复制代码
    ;这里获取用户输入的序列号
    00401B3B   .  8B4B 78       mov     ecx, dword ptr [ebx+78]
    00401B3E   .  83C4 04       add     esp, 4
    ;eax中保存的是通过计算后所得的结果,如果用户输入的序列号与所得结果相等,则说明序列号是正确的,否则不正确
    00401B41   .  3BC1          cmp     eax, ecx
    00401B43   .  75 0F         jnz     short 00401B54
    00401B45   .  3B53 7C       cmp     edx, dword ptr [ebx+7C]
    00401B48   .  75 0A         jnz     short 00401B54
    

        分析终于完成了,长呼一口气,接下来就是注册机的代码了
    [AppleScript] 纯文本查看 复制代码
    /**
     * @brief 序列号生成函数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述			版本号
     * -------	  ------------	  --------------	 ----------
     * IceAmber	   2013-04-14		计算序列号		v1.0
     * @endcode
     */
    void CCRACKME4KeygenDlg::OnBnClickedGenerate()
    {
    	// TODO: 在此添加控件通知处理程序代码
    	int iNameCaculate = 0;
    	int iCpuCaculate = 0;
    	int iResult = 0;
    	EightInt iSerial = {0};
    	HMODULE lHandle = 0;
    	CString strDigest;
    	typedef char* (__stdcall *LPFNGETMD5)(CString);
    	LPFNGETMD5 lpfnRegister = NULL;
    	char *cDigestAddr;
    
    	//加载DLL
    	lHandle = LoadLibrary("Reg.dll");
    	if(NULL != lHandle)
    	{
    		iNameCaculate = DealName();
    		//获取CPUID
    		iCpuCaculate = GetCPUIDFunction();
    
    		iResult = iNameCaculate | iCpuCaculate;
    		strDigest.Format("%x",iResult);
    		lpfnRegister = (LPFNGETMD5)GetProcAddress(lHandle, "GetMD5Str");
    
    		if(NULL != lpfnRegister)
    		{
    			cDigestAddr = (*lpfnRegister)(strDigest);
    			strDigest.Format("%s",cDigestAddr);
    			iSerial = DealString(strDigest);
    			strDigest.Format("%d", iSerial.lEax);
    		}
    	}
    	SetDlgItemText(IDC_SERIAL, strDigest);
    	FreeLibrary(lHandle);
    }
    
    /**
     * @brief 用户名计算函数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述			版本号
     * -------	  ------------	  --------------	 ----------
     * IceAmber	   2013-04-14     用户名计算函数		v1.0
     * @endcode
     */
    EightInt CCRACKME4KeygenDlg::NameCaculete(int iParam1, int iParam2, int iParam3, int iParam4)
    {
    	EightInt lResult = {0};
    	int iEaxReg, iEcxReg;
    	iEaxReg = iParam2;
    	iEcxReg = iParam4;
    	if(0 == (iEaxReg | iEcxReg))
    	{
    		iEcxReg = iParam3;
    		iEaxReg = iParam1;
    		__asm
    		{
    			mov		eax, iEaxReg
    			mov		ecx, iEcxReg
    			mul		ecx
    			mov		lResult.lEax, eax
    			mov		lResult.lEdx, edx
    		}
    	}
    	
    	return lResult;
    }
    
    /**
     * @brief 用户名处理函数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述				版本号
     * -------	  ------------	  -------------------	  ----------
     * IceAmber	   2013-04-14    计算用户名前三个字母	    v1.0
     * @endcode
     */
    int CCRACKME4KeygenDlg::DealName(void)
    {
    	int i = 0;
    	EightInt lRet = {0};
    	int iEdi = 0;
    	int iEsi = 2;	//用来处理用户名前三个字母的密钥
    	int iEdx = 0;
    	int iEax = 0;
    	int iLenth = 0;	
    	CString strName; //用户名
    	int iResult = 0;	//用户名计算结果
    
    	//获取用户名
    	GetDlgItemText(IDC_NAME, strName);
    	
    	iLenth = strName.GetLength(); //获取用户名长度
    	
    	for(i = 0; i < iLenth / 2; i ++)
    	{
    		if('0' == strName[i])	//用户名不能有字符'0'
    		{
    			return 0;
    		}
    		iEax = (int)strName[i];
    		//获取前三个字母的计算结果
    		lRet = NameCaculete(iEax, iEdx, iEsi, iEdi);
    		iEax = (int)lRet.lEax;
    		iEdx = (int)lRet.lEdx;
    		
    		iEsi = iEax;
    		iEdi = iEdx;
    	}
    
    	if(6 != iLenth)			//用户名长度不为6则退出
    	{
    		return 0;
    	}
    	//因为edx的值为0
    	iResult = iEax;
    
    	return iResult;
    }
    
    /**
     * @brief 获取CPUID函数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述		版本号
     * -------	  ------------	  -------------	  ----------
     * IceAmber	   2013-04-14       获取CPUID	    v1.0
     * @endcode
     */
    int CCRACKME4KeygenDlg::GetCPUIDFunction(void)
    {
    	char cCpuID[16];
    	int iRecieve1, iRecieve2;
    	EightInt ret = {0};
    	int iResult = 0;
    	CString strCpuInfo1, strCpuInfo2, strCpuInfo3;
    
    	__asm
    	{
    		mov		eax, 0
    		cpuid
    		mov		dword ptr cCpuID, ebx
    		mov		dword ptr cCpuID[4], edx
    		mov		dword ptr cCpuID[8], ecx
    		mov		dword ptr cCpuID[12], 0
    	}
    
    	__asm
    	{	
    		mov		eax, 1
    		xor		edx, edx
    		cpuid
    		mov		dword ptr iRecieve1, edx
    		mov		dword ptr iRecieve2, eax
    	}
    
    	strCpuInfo2.Format("%08X%08X", iRecieve1, iRecieve2);
    
    	__asm
    	{
    		mov		eax, 3
    		xor		ecx, ecx
    		xor		edx, edx
    		cpuid
    		mov		dword ptr iRecieve1, edx
    		mov		dword ptr iRecieve2, ecx
    	}
    
    	strCpuInfo3.Format("%08X%08X", iRecieve1, iRecieve2);
    
    	strCpuInfo = strCpuInfo2 + strCpuInfo3;
    
    	ret = DealString(strCpuInfo);
    
    	iResult = ret.lEax;
    
    	return iResult;
    }
    
    /**
     * @brief 字符串处理函数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述		版本号
     * -------	  ------------	  -------------	  ----------
     * IceAmber	   2013-04-14       处理字符串	    v1.0
     * @endcode
     */
    EightInt CCRACKME4KeygenDlg::DealString(CString strParam)
    {
    	int i = 0;
    	int j = 0;
    	EightInt iRecieve[4] = {0};
    	EightInt iResult = {0};
    	char cNumber;
    	char cStr[9];
    	CString str[4];
    
    	//进行处理的字符串长度为32个字符
    	for (i = 0; i < 4; i ++)
    	{
    		for (j = 0; j < 8 ; j++)
    		{
    			cStr[j] = strParam[i*8+j];
    		}
    		cStr[j] = '\0';
    		str[i].Format("%8s", cStr);
    	}
    
    	for(i = 0; i < 4; i ++)
    	{
    		iRecieve[i] = CharChangeToNumber(str[i], 8, 16);
    	}
    	iRecieve[0].lEdx ^= iRecieve[3].lEdx;
    	iRecieve[0].lEax ^= iRecieve[3].lEax;
    	iRecieve[0].lEdx ^= iRecieve[2].lEdx;
    	iRecieve[0].lEax ^= iRecieve[2].lEax;
    	iRecieve[0].lEdx ^= iRecieve[1].lEdx;
    	iRecieve[0].lEax ^= iRecieve[1].lEax;
    
    	iResult = iRecieve[0];
    
    	return iResult;
    }
    
    /**
     * @brief 将字符转成数字
     * @param [in] str 要判断的字符串
     * @param [in] iStrLen 字符串的长度
     * @param [in] iJudgeTimes 字符的判断次数
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述		版本号
     * -------	  ------------	  -------------	  ----------
     * IceAmber	   2013-04-21       处理字符串	    v1.0
     * @endcode
     */
    EightInt CCRACKME4KeygenDlg::CharChangeToNumber(CString str, int iStrLen, int iJudgeTimes)
    {
    	int i = 0;
    	int j = 0;
    	int iCounter = 0;
    	int iTimes = 0;
    	int iChange = 0;
    	int iRegister = 0;
    	int iEcx = 0;
    	int iEsi = 0;	//用来处理用户名前三个字母的密钥
    	int iEdx = 0;
    	int iEax = 0;
    	int iRet = 0;
    	EightInt iResult = {0};
    	EightInt eightint = {0};
    
    	iCounter = iStrLen;
    	if(iStrLen <= 0)
    	{
    		return iResult;
    	}
    
    	for(i = 0; i < iStrLen; i ++)
    	{
    
    		iRet = CharJudge(iJudgeTimes, str[i]);
    		if(0 == iRet)
    		{
    			iResult.lEax = 0;
    			iResult.lEdx = 0;
    			break;
    		}
    		else
    		{
    			iChange = (int)str[i];
    			iRet = isdigit((int)str[i]);
    			if(0 == iRet)
    			{
    				//传入的是字母
    				iChange -= 65;
    				if(iChange <= 37)
    				{
    					if(iChange >= 32)
    					{
    						//小写字母
    						iChange -= 32;
    					}
    					switch (iChange)
    					{
    					case 0:
    						iRegister = 0x0a;
    						break;
    					case 1:
    						iRegister = 0x0b;
    						break;
    					case 2:
    						iRegister = 0x0c;
    						break;
    					case 3:
    						iRegister = 0x0d;
    						break;
    					case 4:
    						iRegister = 0x0e;
    						break;
    					case 5:
    						iRegister = 0x0f;
    						break;
    					default:
    						break;
    					}
    				}
    			}
    			else
    			{
    				iRegister = iChange - 0x30;
    			}
    			iEcx = 1;
    			if(iCounter > 0)
    			{
    				for(j = 0; j < iCounter - 1; j ++)
    				{
    					//获取前三个字母的计算结果
    					eightint = NameCaculete(iJudgeTimes, 0, iEcx, iEsi);
    					
    					iEcx = (int)eightint.lEax;
    					iEsi = (int)eightint.lEdx;
    				}
    			}
    
    			eightint = NameCaculete(iRegister, 0, iEcx, iEsi);
    			iResult.lEax += eightint.lEax;
    			iResult.lEdx += eightint.lEdx;
    			iCounter --;
    		}
    	}
    
    	return iResult;
    }
    
    /**
     * @brief 判断该字符是否为0~f
     * @param [in] iJudgeNum 要判断的次数
     * @param [in] cJudgeChar 要判断的字符
     * @per 修改历史
     * @code
     *	作者		修改时间		函数描述		版本号
     * -------	  ------------	  -------------	  ----------
     * IceAmber	   2013-04-21       处理字符串	    v1.0
     * @endcode
     */
    int CCRACKME4KeygenDlg::CharJudge(int iJudgeNum, char cJudgeChar)
    {
    	int i = 0;
    	int iResult = 0;
    	char sJudgeStr[] = "00112233445566778899aAbBcCdDeEfF";
    
    	//如果计算的次数小于2或大于16,则返回0
    	if(iJudgeNum < 2 || iJudgeNum > 16)
    	{
    		return 0;
    	}
    
    	for(i = 0; i < iJudgeNum; i ++)
    	{
    		if((cJudgeChar == sJudgeStr[i * 2]) || (cJudgeChar == sJudgeStr[i * 2 + 1]))
    		{
    			//如果输入的字符为0~f之间则返回1
    			iResult = 1;
    			break;
    		}
    	}
    
    	return iResult;
    }
    

    这个CrackMe+注册机的分析就到此结束了,欢迎指教,让大家共同进步。

    评分

    参与人数 4i币 +40 收起 理由
    KingSKY + 10 支持原创
    ilx + 10 支持原创
    土豆 + 10 支持个。
    Free_小东 + 10 顶一个

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-4-29 10:22
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2013-10-22 23:19:02 | 显示全部楼层
    小白菜看不懂。。。

    点评

    入群要发帖,我等不会入侵的,只能发这些了  详情 回复 发表于 2013-10-22 23:25
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-16 20:03
  • 签到天数: 116 天

    [LV.6]常住居民II

     楼主| 发表于 2013-10-22 23:25:34 | 显示全部楼层
    mojitingliu 发表于 2013-10-22 23:19
    小白菜看不懂。。。

    入群要发帖,我等不会入侵的,只能发这些了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2020-12-4 20:42
  • 签到天数: 23 天

    [LV.4]偶尔看看III

    发表于 2013-10-22 23:57:16 | 显示全部楼层
    PL。支持一个。   学习了。

    点评

    只会逆向,其他的还需大家指点  详情 回复 发表于 2013-10-23 00:05
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-16 20:03
  • 签到天数: 116 天

    [LV.6]常住居民II

     楼主| 发表于 2013-10-23 00:05:49 | 显示全部楼层
    土豆 发表于 2013-10-22 23:57
    PL。支持一个。   学习了。

    只会逆向,其他的还需大家指点
    回复 支持 反对

    使用道具 举报

    头像被屏蔽

    该用户从未签到

    发表于 2013-10-23 00:54:54 | 显示全部楼层
    提示: 作者被禁止或删除 内容自动屏蔽
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2017-8-10 19:40
  • 签到天数: 33 天

    [LV.5]常住居民I

    发表于 2013-10-23 10:12:49 | 显示全部楼层
    虽然我完全看不懂。。。。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-10-23 21:22:29 | 显示全部楼层
    顶,虽然看不懂,楼主发这么多也不容易啊
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    指导单位

    江苏省公安厅

    江苏省通信管理局

    浙江省台州刑侦支队

    DEFCON GROUP 86025

    旗下站点

    邮箱系统

    应急响应中心

    红盟安全

    联系我们

    官方QQ群:112851260

    官方邮箱:security#ihonker.org(#改成@)

    官方核心成员

    Archiver|手机版|小黑屋| ( 苏ICP备2021031567号 )

    GMT+8, 2024-5-16 01:32 , Processed in 0.034834 second(s), 19 queries , Gzip On, MemCache On.

    Powered by ihonker.com

    Copyright © 2015-现在.

  • 返回顶部