• 抬起头,继续前进吧,去把这个不完美的故事,变成你成所期望的样子
  • 登山路上我们会放弃很多东西,但这些被我们丢掉在我们登上山顶之际,都会一一回来
  • 不论开发还是逆向,数学水平的高低直接决定了”你的饭碗里有没有肉”
  • 万丈高楼平地起,勿在浮沙筑高台

OllyDbg学习-记一次简单的算法逆向分析

OllyDbg 菜鸟 6个月前 (12-21) 1294次浏览 未收录 0个评论
[隐藏]

简单记录一次算法分析步骤(图片看不清可点击图片查看大图)

一、环境

TraceMe.exe:《加密与解密》第二章,Unicode 版
界面如下:
OllyDbg 学习-记一次简单的算法逆向分析
OllyDbg: 1.10

二、获取信息

使用 OllyDbg 加载,执行指令下断点

bp GetDlgItemTextW

输入测试内容
        用户名:helloworlduser
        序列号:helloworldpasswd
运行,中断到第一次调用 GetDlgItemTextW 这里,以下是分析:
第一个 GetDlgItemTextW 获取的是用户名,第一个 GetDlgItemTextW 获取的是序列号

0040116F      8D4C24 4C     lea     ecx, dword ptr [esp+4C]          ;  ; szUserName
00401173   .  6A 51         push    51                               ; /Count = 51 (81.)
00401175   .  51            push    ecx                              ; |Buffer
00401176   .  6A 6E         push    6E                               ; |ControlID = 6E (110.)
00401178   .  56            push    esi                              ; |hWnd
00401179   .  FFD7          call    edi                              ; \GetDlgItemTextW
0040117B   .  8D9424 EC0000>lea     edx, dword ptr [esp+EC]          ;  ; szPasswd
00401182   .  6A 65         push    65                               ; /Count = 65 (101.)
00401184   .  52            push    edx                              ; |Buffer
00401185   .  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
0040118A   .  56            push    esi                              ; |hWnd
0040118B   .  8BD8          mov     ebx, eax                         ; |; 保存用户名长度
0040118D   .  FFD7          call    edi                              ; \GetDlgItemTextW
0040118F   .  66:837C24 4C >cmp     word ptr [esp+4C], 0             ;  ; if ("\0" != szUserName) {
00401195   .  74 76         je      short 0040120D
00401197   .  83FB 05       cmp     ebx, 5                           ;  ; 检测用户名长度
0040119A   .  7C 71         jl      short 0040120D                   ;  ; if (uiUserLen >= 5) {
0040119C > .  8D4424 4C     lea     eax, dword ptr [esp+4C]
004011A0   .  53            push    ebx                              ;  ; 传入用户名长度
004011A1   .  8D8C24 F00000>lea     ecx, dword ptr [esp+F0]          ;  ; 因为 push 了一次,所以密码从 esp+EC 变为 esp+F0
004011A8   .  50            push    eax                              ;  ; 传入用户名地址
004011A9   .  51            push    ecx                              ;  ; 传入密码地址
004011AA   .  E8 71010000   call    00401320                         ;  ; 校验算法
004011AF   .  8B3D BC404000 mov     edi, dword ptr [<&USER32.GetDlgI>;  USER32.GetDlgItem
004011B5   .  83C4 0C       add     esp, 0C
004011B8   .  85C0          test    eax, eax
004011BA   .  74 37         je      short 004011F3                   ;  ; if (校验成功) {
004011BC   .  8D5424 0C     lea     edx, dword ptr [esp+C]
004011C0   .  52            push    edx                              ; /String2
004011C1   .  68 E4544000   push    004054E4                         ; |String1 = TraceMe.004054E4
004011C6   .  FF15 60404000 call    dword ptr [<&KERNEL32.lstrcpyW>] ; \lstrcpyW
004011CC   .  6A 00         push    0                                ; /Enable = FALSE
004011CE   .  6A 6E         push    6E                               ; |/ControlID = 6E (110.)
004011D0   .  56            push    esi                              ; ||hWnd
004011D1   .  FFD7          call    edi                              ; |\GetDlgItem
004011D3   .  8B1D A4404000 mov     ebx, dword ptr [<&USER32.EnableW>; |USER32.EnableWindow
004011D9   .  50            push    eax                              ; |hWnd
004011DA   .  FFD3          call    ebx                              ; \EnableWindow
004011DC   .  6A 00         push    0                                ; /Enable = FALSE
004011DE   .  68 E8030000   push    3E8                              ; |/ControlID = 3E8 (1000.)
004011E3   .  56            push    esi                              ; ||hWnd
004011E4   .  FFD7          call    edi                              ; |\GetDlgItem
004011E6   .  50            push    eax                              ; |hWnd
004011E7   .  FFD3          call    ebx                              ; \EnableWindow
004011E9   .  68 E8030000   push    3E8                              ; /ControlID = 3E8 (1000.)
004011EE   .  56            push    esi                              ; |hWnd
004011EF   .  FFD7          call    edi                              ; \GetDlgItem
004011F1   .  EB 33         jmp     short 00401226                   ;  ; }}}

目前信息总结如下:
        用户名限制:
                1、不能为空
                2、长度必须大于等于 5
        序列号校验算法:
                地址:0x00401320
                参数:序列号的地址, 用户名的地址, 用户名的长度

三、算法还原

反汇编分析(栈平衡就不再标注):

00401320  /$  8B5424 0C     mov     edx, dword ptr [esp+C]           ;  ; 保存用户名长度
00401324  |.  55            push    ebp
00401325  |.  8B6C24 0C     mov     ebp, dword ptr [esp+C]           ;  ; 保存 wszUserName 地址到 ebp
00401329  |.  56            push    esi
0040132A  |.  33F6          xor     esi, esi                         ;  ; long lCheckSum = 0;
0040132C  |.  33C0          xor     eax, eax                         ;  ; int cntI = 0;
0040132E  |.  83FA 03       cmp     edx, 3
00401331  |.  7E 29         jle     short 0040135C                   ;  ; if (uiUserNameLen) > 3 {
00401333 >|.  53            push    ebx
00401334  |.  57            push    edi
00401335  |.  8D4D 06       lea     ecx, dword ptr [ebp+6]           ;  ; 用户名第 4 个字符开始的地址
00401338  |.  8D7A FD       lea     edi, dword ptr [edx-3]           ;  ; uiUserNameLen - 3
0040133B  |>  83F8 07       /cmp     eax, 7                          ;  ; while (uiUserNameLen != 0) {
0040133E  |.  7E 02         |jle     short 00401342                  ;  ; if (cntI > 7) {
00401340  |.  33C0          |xor     eax, eax                        ;  ;    cntI = 0; }
00401342  |>  33D2          |xor     edx, edx                        ;  ; char cOne = '\0';
00401344  |.  33DB          |xor     ebx, ebx                        ;  ; char cTwo = '\0';
00401346  |.  8A90 30504000 |mov     dl, byte ptr [eax+405030]       ;  ; cOne =  *(char *)(0x00405030 + cntI);
0040134C  |.  8A19          |mov     bl, byte ptr [ecx]              ;  ; cTwo = *(char *)wszUserName;
0040134E  |.  0FAFD3        |imul    edx, ebx                        ;  ; cOne *= cTwo;
00401351  |.  03F2          |add     esi, edx                        ;  ; lCheckSum += cOne;
00401353  |.  83C1 02       |add     ecx, 2                          ;  ; wszUserName += 1;
00401356  |.  40            |inc     eax                             ;  ; cntI++;
00401357  |.  4F            |dec     edi                             ;  ; uiUserNameLen--;
00401358  |.^ 75 E1         \jnz     short 0040133B                  ;  ; } //! while END
0040135A  |.  5F            pop     edi
0040135B  |.  5B            pop     ebx                              ;  ; wsprintfW(wszUserName, _T(%ld), lCheckSum);
0040135C  |>  56            push    esi                              ; /<%ld>
0040135D  |.  68 78504000   push    00405078                         ; |Format = "%ld"
00401362  |.  55            push    ebp                              ; |s
00401363  |.  FF15 9C404000 call    dword ptr [<&USER32.wsprintfW>]  ; \wsprintfW
00401369  |.  8B4424 18     mov     eax, dword ptr [esp+18]
0040136D  |.  83C4 0C       add     esp, 0C                          ;  ; 下面的就是与密码比对了
00401370  |.  55            push    ebp                              ; /String2
00401371  |.  50            push    eax                              ; |String1
00401372  |.  FF15 04404000 call    dword ptr [<&KERNEL32.lstrcmpW>] ; \lstrcmpW
00401378  |.  F7D8          neg     eax                              ;  ; ~(eax) + 1
0040137A  |.  1BC0          sbb     eax, eax                         ;  ; eax - eax - CF
0040137C  |.  5E            pop     esi                              ;  ; (流水线优化)
0040137D  |.  40            inc     eax                              ;  ; eax + 1
0040137E  |.  5D            pop     ebp
0040137F  \.  C3            retn
0x00405030 就是用来计算序列号的 Key 的保存位置

四、序列号计算

简单写了个 Python 脚本

#-- coding:utf-8 --
import os

def main():
    key = [0x0C, 0x0A, 0x13, 0X09, 0x0C, 0x0B, 0x0A, 0x08]

    user_name = raw_input("Input user name: ")
    if len(user_name) > 3:
        user_name = user_name[3:]

    user_name_len = len(user_name);

    passwd = ""
    index = 0
    check_sum = 0

    while user_name_len > 0:
        if index > 7:
            index = 0

        check_sum += key[index] * ord(user_name[0])
        print(check_sum)
        user_name = user_name[1:]
        user_name_len -= 1
        index += 1

    passwd = str(check_sum)
    print("Password: %s" % passwd)

    os.system("pause")

if __name__ == '__main__':
    main()

测试:
OllyDbg 学习-记一次简单的算法逆向分析


学习心得 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明OllyDbg 学习-记一次简单的算法逆向分析
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址