• 抹除花指令


    系统 : Windows xp

    程序 : 2015_nctf_re

    程序下载地址 :http://pan.baidu.com/s/1hryN1Wg

    要求 : 拆解Nag窗口 & 找出密钥

    使用工具 :OD & IDA & PEID & Hex Workshop & CodeBlocks

    可在看雪论坛中找到关于此程序的讨论:http://bbs.pediy.com/showthread.php?t=199609&highlight=%E8%8A%B1%E6%8C%87+%E6%8C%87%E4%BB%A4+%E4%BB%A4

    花指令是一些专门用来迷惑反汇编软件的代码数据,而对于cpu来说,依旧还是会执行正确的代码。通过插入无效数据,干扰反汇编软件对PE文件的分析,导致其显示出很多无用的信息。

    今天,我们逆向一个小程序,来加深对花指令的了解。

    打开PEID拖入该程序,发现无壳。

    双击运行2015_nctf_re,将会显示一个窗口:

    单击关闭,发现又弹出一个相同的对话框,关闭N次无效后,只好打开任务管理器结束该进程。

    OD载入该程序,对MessageBoxA下断,F9运行后中断,接着回到程序领空:

    00405B59  |.  FF75 14       push    dword ptr [ebp+14]               ; /Style
    00405B5C  |.  FF75 10       push    dword ptr [ebp+10]               ; |Title
    00405B5F  |.  FF75 0C       push    dword ptr [ebp+C]                ; |Text
    00405B62  |.  FF75 08       push    dword ptr [ebp+8]                ; |hOwner
    00405B65  |.  FF15 34344300 call    dword ptr [<&USER32.MessageBoxA>>; MessageBoxA
    00405B6B  |.  8945 E4       mov     dword ptr [ebp-1C], eax
    00405B6E  |.  C745 FC FEFFF>mov     dword ptr [ebp-4], -2
    00405B75  |.  E8 0B000000   call    00405B85
    00405B7A  |.  8B45 E4       mov     eax, dword ptr [ebp-1C]
    00405B7D  |>  E8 5FB40100   call    00420FE1
    00405B82  .  C3            retn

    一直跟踪下去,会发现代码又回到了405B59,据此分析,有一个循环在不停地显示该窗口:

    004012FB   > BE 00010000   mov     esi, 100
    00401300   >  6A 00         push    0
    00401302   .  6A 00         push    0
    00401304   .  68 70894300   push    00438970
    00401309   .  E8 F84A0000   call    00405E06
    0040130E   .  83EE 01       sub     esi, 1
    00401311   .^ 75 ED         jnz     short 00401300                   ;  判断语句
    00401313   .  5F            pop     edi
    00401314   .  8D46 01       lea     eax, dword ptr [esi+1]
    00401317   .  5E            pop     esi
    00401318   .  C3            retn

    将401311处的跳转指令改为jz并保存。

    打开Hex Workshop载入保存之后的程序,搜索ansi string“小兄弟,搞基吗?”,将其替换为“小兄弟,我是傻哔”。

    重新打开效果如下:

    ========================小剧场模式启动=======================》

    “喂,110吗?”

    “是的,你有什么事?”

    “我要举报!有一个傻[哔]出现在我附近!”

    “嗯?可傻[哔]不触犯法律啊。”

    “对了,你是怎么知道他是傻[哔]的?”

    “嗨,也没什么,就是破解人家软件的时候发现的。”

    。。。。。。。

    “小朋友,下午来局子里喝杯茶吧~”

    ========================小剧场模式关闭=======================》

    用OD载入修改过的程序,对GetDlgItemTextA下断,运行后中断,接着返回程序领空:

    0040B45F  |.  FF75 10       push    dword ptr [ebp+10]               ; /Count
    0040B462  |.  FF75 0C       push    dword ptr [ebp+C]                ; |Buffer
    0040B465  |.  FF75 08       push    dword ptr [ebp+8]                ; |ControlID
    0040B468  |.  FF71 20       push    dword ptr [ecx+20]               ; |hWnd
    0040B46B  |.  FF15 68334300 call    dword ptr [<&USER32.GetDlgItemTe>; GetDlgItemTextA
    0040B471  |.  5D            pop     ebp                              ;  0012F82C
    0040B472  |.  C2 0C00       retn    0C

    继续跟踪:

    0040141F   .  A1 3C524400   mov     eax, dword ptr [44523C]          ;  取出输入字串
    00401424   .  51            push    ecx                              ;  USER32.77D321CC
    00401425   .  52            push    edx
    00401426   .  53            push    ebx
    00401427   .  E8 00000000   call    0040142C
    0040142C  /$  5A            pop     edx
    0040142D  |.  83C2 07       add     edx, 7
    00401430  |.  52            push    edx                              ;  等价于 jmp edx
    00401431  .  C3            retn                                     ;  跳入1433,则1432没有被执行
    00401432      C4            db      C4
    00401433      5B            db      5B                               ;  CHAR '['
    00401434      5A            db      5A                               ;  CHAR 'Z'
    00401435      59            db      59                               ;  CHAR 'Y'
    00401436      51            db      51                               ;  CHAR 'Q'
    00401437      52            db      52                               ;  CHAR 'R'
    00401438      53            db      53                               ;  CHAR 'S'
    00401439      33            db      33                               ;
    0040143A      DB            db      DB
    0040143B      74            db      74                               ;
    0040143C      01            db      01
    0040143D      E8            db      E8
    0040143E      5B            db      5B                               ;  CHAR '['
    0040143F      5A            db      5A                               ;  CHAR 'Z'
    00401440      59            db      59                               ;  CHAR 'Y'
    00401441      80            db      80                               ;
    00401442      30            db      30                               ;  CHAR '0'

    发现程序后面出现了一大段无用数据,继续运行,发现程序跟入了无用数据中,但寄存器的值却在不停的变换,说明该处指令被混淆过。选择40141F-401431处指令,右键->去除花指令->Obsidium即可去除花指令:

    0040141F      A1 3C524400   mov     eax, dword ptr [44523C]          ;  取出输入字串
    00401424      51            push    ecx                              ;  USER32.77D321CC
    00401425      52            push    edx
    00401426      53            push    ebx
    00401427      E8 00000000   call    0040142C
    0040142C      5A            pop     edx
    0040142D      83C2 07       add     edx, 7
    00401430      52            push    edx                              ;  等价于 jmp edx
    00401431      C3            retn                                     ;  跳入1433,则1432没有被执行
    00401432      C45B 5A       les     ebx, fword ptr [ebx+5A]
    00401435      59            pop     ecx
    00401436      51            push    ecx
    00401437      52            push    edx
    00401438      53            push    ebx
    00401439      33DB          xor     ebx, ebx                         ;  清空ebx
    0040143B      74 01         je      short 0040143E                   ;  跳入143E,143D没有被执行
    0040143D      E8 5B5A5980   call    80996E9D
    00401442      306E 51       xor     byte ptr [esi+51], ch
    00401445      52            push    edx
    00401446      53            push    ebx
    00401447      33DB          xor     ebx, ebx                         ;  清空ebx
    00401449      74 01         je      short 0040144C                   ;  跳入144C,144B没有被执行

    可以看到接下来的指令依旧有些奇怪,地址143B跳入143E,而该条指令的地址却是143D,有一个字节没有被执行。确定其是垃圾数据,用nop填充之(“剩余的用nop填充”不要打钩):

    0040143B     /74 01         je      short 0040143E                   ;  跳入143E,143D没有被执行
    0040143D     |90            nop
    0040143E     5B            pop     ebx
    0040143F      5A            pop     edx
    00401440      59            pop     ecx
    00401441      8030 6E       xor     byte ptr [eax], 6E               ;  第一个字符与6E异或
    00401444      51            push    ecx
    00401445      52            push    edx
    00401446      53            push    ebx

    之后的花指令都用此法抹除:

    0040141F      A1 3C524400   mov     eax, dword ptr [44523C]          ;  取出输入字串
    00401424      51            push    ecx
    00401425      52            push    edx
    00401426      53            push    ebx
    00401427      E8 00000000   call    0040142C
    0040142C      5A            pop     edx
    0040142D      83C2 07       add     edx, 7
    00401430      52            push    edx                              ;  等价于 jmp edx
    00401431      C3            retn                                     ;  跳入1433,则1432没有被执行
    00401432      90            nop
    00401433      5B            pop     ebx
    00401434      5A            pop     edx
    00401435      59            pop     ecx
    00401436      51            push    ecx
    00401437      52            push    edx
    00401438      53            push    ebx
    00401439      33DB          xor     ebx, ebx                         ;  清空ebx
    0040143B      74 01         je      short 0040143E                   ;  跳入143E,143D没有被执行
    0040143D      90            nop
    0040143E      5B            pop     ebx
    0040143F      5A            pop     edx
    00401440      59            pop     ecx
    00401441      8030 6E       xor     byte ptr [eax], 6E               ;  第一个字符与6E异或
    00401444      51            push    ecx
    00401445      52            push    edx
    00401446      53            push    ebx
    00401447      33DB          xor     ebx, ebx                         ;  清空ebx
    00401449      74 01         je      short 0040144C                   ;  跳入144C,144B没有被执行
    0040144B      90            nop
    0040144C      5B            pop     ebx
    0040144D      5A            pop     edx
    0040144E      59            pop     ecx
    0040144F      8070 01 62    xor     byte ptr [eax+1], 62             ;  第二个字符与62异或
    00401453      51            push    ecx
    00401454      52            push    edx
    00401455      53            push    ebx
    00401456      33DB          xor     ebx, ebx                         ;  清空ebx
    00401458      74 01         je      short 0040145B                   ;  跳入145B,145A没有被执行
    0040145A      90            nop
    0040145B      5B            pop     ebx
    0040145C      5A            pop     edx
    0040145D      59            pop     ecx
    0040145E      8070 02 76    xor     byte ptr [eax+2], 76             ;  第三个字符与76异或
    00401462      51            push    ecx
    00401463      52            push    edx
    00401464      53            push    ebx
    00401465      33DB          xor     ebx, ebx                         ;  清空ebx
    00401467      74 01         je      short 0040146A                   ;  跳入146A,1469没有被执行
    00401469      90            nop
    0040146A      5B            pop     ebx
    0040146B      5A            pop     edx
    0040146C      59            pop     ecx
    0040146D      8070 03 65    xor     byte ptr [eax+3], 65             ;  第四个字符与65异或
    00401471      51            push    ecx
    00401472      52            push    edx
    00401473      53            push    ebx
    00401474      33DB          xor     ebx, ebx                         ;  清空ebx
    00401476      74 01         je      short 00401479                   ;  跳入1479,1478没有被执行
    00401478      90            nop
    00401479      5B            pop     ebx
    0040147A      5A            pop     edx
    0040147B      59            pop     ecx
    0040147C      8070 04 7F    xor     byte ptr [eax+4], 7F             ;  第五个字符与7F异或
    00401480      51            push    ecx
    00401481      52            push    edx
    00401482      53            push    ebx
    00401483      33DB          xor     ebx, ebx                         ;  清空ebx
    00401485      74 01         je      short 00401488                   ;  跳入1488,1487没有被执行
    00401487      90            nop
    00401488      5B            pop     ebx
    00401489      5A            pop     edx
    0040148A      59            pop     ecx
    0040148B      8070 05 49    xor     byte ptr [eax+5], 49             ;  第六个字符与49异或
        ;省略一部分指令

    异或操作都完成后,来到判断算法:

    0040156C      8B0D 3C524400 mov     ecx, dword ptr [44523C]          ;  取出异或后的输入字串
    00401572      0FB611        movzx   edx, byte ptr [ecx]              ;  判断首字符
    00401575      85D2          test    edx, edx                         ;  非0则跳转出错
    00401577      75 4A         jnz     short 004015C3                   ;  则退出
    00401579      C645 FF 00    mov     byte ptr [ebp-1], 0              ;  一开始计数器置零
    0040157D      EB 08         jmp     short 00401587
    0040157F      8A45 FF       mov     al, byte ptr [ebp-1]
    00401582      04 01         add     al, 1
    00401584      8845 FF       mov     byte ptr [ebp-1], al
    00401587      0FB64D FF     movzx   ecx, byte ptr [ebp-1]
    0040158B      83F9 14       cmp     ecx, 14                          ;  计数器为0x14?
    0040158E      7D 33         jge     short 004015C3                   ;  是则直接结束
    00401590      0FB655 FF     movzx   edx, byte ptr [ebp-1]
    00401594      0FB645 FF     movzx   eax, byte ptr [ebp-1]
    00401598      8B0D 3C524400 mov     ecx, dword ptr [44523C]          ;  异或后字符地址存入ecx
    0040159E      0FB60401      movzx   eax, byte ptr [ecx+eax]
    004015A2      3BD0          cmp     edx, eax                         ;  迭代字串的第n个字符是否等于n?
    004015A4      75 19         jnz     short 004015BF                   ;  否则直接结束比较
    004015A6      0FB64D FF     movzx   ecx, byte ptr [ebp-1]
    004015AA      83F9 13       cmp     ecx, 13                          ;  计数器为0x13?
    004015AD      75 0E         jnz     short 004015BD                   ;  否则跳转 继续循环
    004015AF      6A 00         push    0
    004015B1      6A 00         push    0
    004015B3      68 84894300   push    00438984
    004015B8      E8 49480000   call    00405E06
    004015BD      90            nop
    004015BE      90            nop
    004015BF      90            nop
    004015C0      90            nop
    004015C1    ^ EB BC         jmp     short 0040157F
    004015C3      5B            pop     ebx
    004015C4      8BE5          mov     esp, ebp
    004015C6      5D            pop     ebp
    004015C7      C3            retn

    该处将我们输入的字串和一串固定的密钥进行异或,结果字串值应为0,1,2,3,4。。。。

    写一段C代码实现逆算法:

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char ch = 0x7F;
        string str = "nbve";
    
        str += ch;
        str +="I6KWyoex>QDy #n";                        //粘合用来异或的字串
    
        string::iterator iter = str.begin();
        for ( int i = 0 ; iter != str.end() ; iter++,i++ ){
            *iter ^= i;
        }
    
        cout << str << endl;
    
        return 0;
    }

    结果为:

    复制黏贴至程序:

    我们一路奋战,不是为了改变世界,而是不让世界改变我们 ——《熔炉》
  • 相关阅读:
    CSS布局--坑(2)
    CSS布局--坑(1)
    微信小程序wx:for 循环中item的keng
    初体验小程序Vue交互
    vue中数组变动更新检测
    【vue】v-if和v-show的区别
    babel把ES6转化为ES5的时候报错
    Vue.js大总结
    性能测试完整流程(二)
    性能测试完整流程(一)
  • 原文地址:https://www.cnblogs.com/ZRBYYXDM/p/5192953.html
Copyright © 2020-2023  润新知