LYQingYe 发表于 2015-8-30 22:21

送给那些不会分析算法朋友的一篇图文教程-exescope

本帖最后由 LYQingYe 于 2015-9-4 13:48 编辑

{:5_118:}放荡了三天,我又回来了,{:5_121:}介于前面的那两节算法课,我看到了不少的意见和建议,为此我只想说,感谢大家宝贵的建议,{:5_116:}介于很多朋友说 “看不懂” , 我提以下小小的建议。
         ① 要懂得MOV SUB ADD DIV MUL INC DEC 几个对数据操作的简单指令 以及他们的扩展形式指令,MOV EAX,BYTE PTR
在这条指令中 的作用是 取出 ECX指向的内存单元的值,因为是32位的指令,最多能取出四个字节的内容,然而 BYTE PTR 控制了获取的字节数, BYTE等于一个字节,所以 这条指令的作用就是把,ECX指向内存单元的第一个字节内容给EAX ,当然 还有很多扩展的,例如 像 MOV EAX ,DS: 之类的我就不一一详解了。
          ② 懂得数据操作指令还不够,例如还要懂得CMP TEST JNZ JZ JB 之类的逻辑流程控制指令,什么时候跳,什么时候不跳,这是必须要懂的,指令不一定要你背下来,看多了用多了就记住了。
          ③ 提升自己的逻辑连贯能力,就比如 某个算法 用到了机器码 或者 USENAME 做运算的时候 ,就要留心 用到机器码 或者 USENAME的CALL ,用记事本 记下每一次的运行结果,通过观察计算获得注册码,高级的就需要学会逆向算法。


          今天,我打算给那些不会分析算法的人做一篇简单而又不简单的图文教程。为什么是简单 ? 因为他的流程很简单,之所以又不简单,是因为在某些小流程里不简单。那我们就愉快的开始吧!
          软件名称:eXeScope
            eXeScope是款功能强大的exe程序修改器,能修改exe程序中的字体、菜单位置、对话框排序、字符串、图片资源等。
            保护状态:无壳,貌似 VC编译,这并不重要。哈
         


            先说简单一下关键CALL的找法,当输入错误的时候会弹出一个错误 对话框, IVALID ID OR NAME   我采用的方法是,暂停->看堆栈窗口,查找我们输入的 NAME 和 ID 然后 找到相应的返回 CALL 某些CALL可能是 消息循环。 可以看下图 。
      
   关键CALL地址004C2A44 ,本次调试用的 USERNAME 为 WWW.XUEPOJIE.COM   ID 为 8888888888
   
      Frsit那简单而又熟悉的开始   
004C2A44    55            push ebp
004C2A45    8bec            mov ebp, esp
004C2A47    33c9            xor ecx, ecx
004C2A49    51            push ecx
004C2A4A    51            push ecx
004C2A4B    51            push ecx
004C2A4C    51            push ecx
004C2A4D    51            push ecx
004C2A4E    53            push ebx
004C2A4F    56            push esi
004C2A50    57            push edi
004C2A51    8bd8            mov ebx, eax
004C2A53    33c0            xor eax, eax
004C2A55    55            push ebp
004C2A56    68a12b4c00      push 0x4c2ba1
004C2A5B    64ff30          push dword ptr fs:
004C2A5E    648920          mov dword ptr fs:, esp
004C2A61    a15cfc4c00      mov eax, dword ptr
004C2A66    803800          cmp byte ptr , 0
004C2A69    740f            je 0x4c2a7a
004C2A6B    c7834c020000020>mov dword ptr , 2
004C2A75    e9ff000000      jmp 0x4c2b79
004C2A7A    8d55fc          lea edx, dword ptr
004C2A7D    8b83f8020000    mov eax, dword ptr
004C2A83    e8f4f8faff      call 0x47237c                                    ; GetText(Void)GetUserName
004C2A88    8b55fc          mov edx, dword ptr                      ; EDX - >UserName    WWW.XUEPOJIE.COM
004C2A8B    a1e8fe4c00      mov eax, dword ptr
004C2A90    e84f1ff4ff      call 0x4049e4
004C2A95    8d55f8          lea edx, dword ptr
004C2A98    8b83fc020000    mov eax, dword ptr
004C2A9E    e8d9f8faff      call 0x47237c                                    ; GetTexy(Void)GetID
004C2AA3    8b55f8          mov edx, dword ptr                      ; EDX-> ID'8888888888'
004C2AA6    a14cfe4c00      mov eax, dword ptr
004C2AAB    e8341ff4ff      call 0x4049e4
004C2AB0    8b154cfe4c00    mov edx, dword ptr                       ; EDX-> P -> '8888888888' 二级指针 指向 ID
004C2AB6    8b12            mov edx, dword ptr                            ; 转化为一级指针 -> ID '8888888888'
004C2AB8    a154fc4c00      mov eax, dword ptr
004C2ABD    8b00            mov eax, dword ptr
004C2ABF    e8b8940000      call 0x4cbf7c                                    ; 意味着这是一个关键CALL
004C2AC4    84c0            test al, al                                        ; 判断 AL是否等于 0
004C2AC6    0f848d000000    je 0x4c2b5a                                        ; 如果AL = 0走向死亡 。
既然是关键CALL 我们就进去看下 。004CBF7C    55            push ebp
004CBF7D    8bec            mov ebp, esp
004CBF7F    51            push ecx
004CBF80    53            push ebx
004CBF81    8955fc          mov dword ptr , edx                     ; 将ID '8888888888' 放入 局部变量
004CBF84    8b45fc          mov eax, dword ptr                      ; 再把 ID 给EAX
004CBF87    e8b48ef3ff      call 0x404e40                                    ; 判断ID 所在内存地址 是否合法
004CBF8C    33c0            xor eax, eax                                       ; EAX 清零
004CBF8E    55            push ebp
004CBF8F    681bc04c00      push 0x4cc01b
004CBF94    64ff30          push dword ptr fs:
004CBF97    648920          mov dword ptr fs:, esp                        ; 用到 FS寄存器 就没什么好看的了,VC机制操作
004CBF9A    33db            xor ebx, ebx
004CBF9C    8b45fc          mov eax, dword ptr                      ; EAX ->ID '8888888888'
004CBF9F    e8ac8cf3ff      call 0x404c50                                    ; 判断ID所在内存地址是否合法顺便取出他的长度VC程序会放在字符串地址前4个字节
004CBFA4    83f80a          cmp eax, 0xa                                       ; 长度要 = 100XA否则直接返回 0 走向失败
004CBFA7    755c            jne 0x4cc005
004CBFA9    8b55fc          mov edx, dword ptr                      ; EDX ->ID '8888888888' 下面好有个怪怪的字符串,跟进去 看看
004CBFAC    b830c04c00      mov eax, 0x4cc030                                  ; ASCII "A1910"
004CBFB1    e8de8ff3ff      call 0x404f94跟进去看看
004CBFB6    48            dec eax
004CBFB7    7410            je 0x4cbfc9
   Second那引人的困境
00404F94    85c0            test eax, eax                                    ; 判断字符串是否合法 'A1910'
00404F96    7440            je 0x404fd8
00404F98    85d2            test edx, edx                                    ; 判断 ID '8888888888' 是否合法
00404F9A    7431            je 0x404fcd
00404F9C    53            push ebx
00404F9D    56            push esi
00404F9E    57            push edi
00404F9F    89c6            mov esi, eax                                       ; ESI -> 字符串 'A1910'
00404FA1    89d7            mov edi, edx                                       ; EDI -> ID '8888888888'
00404FA3    8b4ffc          mov ecx, dword ptr                      ; ECX = ID的长度 0XA
00404FA6    57            push edi                                           ; ID 入栈保存起来
00404FA7    8b56fc          mov edx, dword ptr                      ; EDX = 字符串 'A1910'的长度
00404FAA    4a            dec edx                                          ; EDX = EDX - 1
00404FAB    781b            js 0x404fc8
00404FAD    8a06            mov al, byte ptr                            ; 字符串第一个字节 'A'的ASICC 值给 AL 指向一个新的固定字符串 ‘1423’
00404FAF    46            inc esi                                          ; ESI= ESI + 1 指针往后一位 挪动一位
00404FB0    29d1            sub ecx, edx
00404FB2    7e14            jle 0x404fc8
00404FB4    f2ae            repne scasb al, byte ptr es:
00404FB6    7510            jne 0x404fc8                                       ; 找不到则跳,走向死亡
详解那令人困惑的汇编指令 repne scasb al, byte ptr es:    在字符串查找指定的字节数据 如果找不到 则 ZF = 0或者 ECX = 0
repne scasb al, byte ptr es:   在 EDI 指向的字符串中 匹配 和 AL 一样的字符串 如果匹配到 则 ECX - 1   匹配不到 则 ZF = 0或者 ECX = 0,并且重复判断 直到 匹配完 EDI指向的字符串。
此时 AL = '41'- 'A'    EDI 是ID '8888888888'所以说 ID 第一位 要 是 字母A否则则走向死亡


这次 我们换个 ID 'A88888888' 继续往下

00404FB8    89cb            mov ebx, ecx                                        ; EBX = 字符串长度
00404FBA    56            push esi
00404FBB    57            push edi
00404FBC    89d1            mov ecx, edx
00404FBE    f3a6            repe cmpsb byte ptr , byte ptr es:该指令下面详解
00404FC0    5f            pop edi
00404FC1    5e            pop esi
00404FC2    740c            je 0x404fd0                                       ; 相等则跳 走向胜利
00404FC4    89d9            mov ecx, ebx
00404FC6^ ebec            jmp 0x404fb4
00404FC8    5a            pop edx
00404FC9    31c0            xor eax, eax
00404FCB    eb08            jmp 0x404fd5
00404FCD    31c0            xor eax, eax
00404FCF    c3            ret
repe cmpsb byte ptr , byte ptr es: 这指令和上面的 差不多 ,此时 ESI -> '1910'这个字符串EDI ->'888888888'我们的ID 是 A8888888888    ,从 字面上来看 repe 是重复操作 指令, cmp 是比较 指令 s b 是 stringbyte的缩写 ,故 指令作用为 ,重复操作,分别 比较 ESI -> 指向的字符串 EDI -> 指向的字符串一定要相等,否则下面就会走向死亡所以说 ID里面 要有 '1910' 这个字符串
结合上面,我们可以得出 前5个固定的字符 'A1910'
这次我们换个 ID A191088888好了,我们继续 。
004CBFB7   /7410            je 0x4cbfc9
004CBFB9   |8b55fc          mov edx, dword ptr
004CBFBC   |b840c04c00      mov eax, 0x4cc040                                 ; ASCII "A1423"
004CBFC1   |e8ce8ff3ff      call 0x404f94这个CALL和上面那个是一样的。
004CBFC6   |48            dec eax
004CBFC7   |753c            jne 0x4cc005
可以得出,正确的ID 前五个字符 必须要是 A1423 或者 是 A1910继续 往下
004CBFC9    b802000000      mov eax, 2                                          ; EAX 初始化 为 2
004CBFCE    8b55fc          mov edx, dword ptr                         ; EDX ->ID 'A191088888'
004CBFD1    8a5402ff      mov dl, byte ptr
004CBFD5    80fa30          cmp dl, 0x30
004CBFD8    722b            jb 0x4cc005                                       ; ASCII 小于 0X30 则走向失败
004CBFDA    80fa39          cmp dl, 0x39
004CBFDD    7726            ja 0x4cc005                                       ; ASCII 大于 0x 39则走向失败了
004CBFDF    40            inc eax                                             ; 字符串指针往后移动 一个字节
004CBFE0    83f80b          cmp eax, 0xb                                        ; 判断是否 遍历到 字符串 后面了
004CBFE3^ 75e9            jne 0x4cbfce
004CBFE5    8b45fc          mov eax, dword ptr                         ; EAX -> ID
004CBFE8    0fb64008      movzx eax, byte ptr                      ; 取倒数第二个字节 内容给EAX
004CBFEC    8b55fc          mov edx, dword ptr                         ; EAX -> ID
004CBFEF    0fb65209      movzx edx, byte ptr                      ; 取ID 最后一位值给EDX
004CBFF3    03c2            add eax, edx                                        ; EAX + EDX
004CBFF5    b90a000000      mov ecx, 0xa                                        ; ECX 初始化 为 0XA
004CBFFA    33d2            xor edx, edx                                        ; EDX 清零
004CBFFC    f7f1            div ecx                                             ; EAX / ECX 商在 EAX 余数在 EDX
004CBFFE    83fa04          cmp edx, 4                                          ; 不相等 就跳
004CC001    7502            jne 0x4cc005                                        ; 跳过去就死了
004CC003    b301            mov bl, 1
004CC005    33c0            xor eax, eax
004CC007    5a            pop edx
004CC008    59            pop ecx
004CC009    59            pop ecx
004CC00A    648910          mov dword ptr fs:, edx
004CC00D    6822c04c00      push 0x4cc022
004CC012    8d45fc          lea eax, dword ptr
004CC015    e87689f3ff      call 0x404990
004CC01A    c3            ret
通过上面的算法我们 可以知道 正确的 ID要满足 一下 条件 : 前五个字符 必须要是 A1423 或者 是 A1910   长度必须为 0XA = 10
全部字符的 ASCII值 必须大于等于 0x30小于等于 0x39 所以满足规则只有 一下字符 0,1,2,3,4,5,6,7,8,9   还有 最后 两位字符的ASCII值的和,在这里 我设为 STR   要满足以下条件STR / 0XA   商 不能等于 0余数 要等于B


知道需要满足的规则 我们来 推导 后 两位的 逆运算 。
现在设 后两位字符的 ASCII 为   M,N   且 M , N满足大于等于 0X30小于等于 0X39   ,另外设一个 未知数Z 为正整数
则应该有M + N =Z X A + B   因为本人 不会C++ {:5_191:}所以无法写出注册机。在这就偷懒一下 。本次教程就到此结束,我是LYQingYe 我爱雪坡姐。 看完了的 别忘记评分哦。{:5_193:}


   
   



      

灰色 发表于 2015-8-30 22:28

此贴必火,支持

逍遥枷锁 发表于 2015-8-30 22:32

好吧,算法是很强悍,来观望学习下,谢谢。

Gustab.m 发表于 2015-8-30 22:39

{:5_116:}虽然没看明白 但是还是支持一下

Shark恒 发表于 2015-8-30 22:43

我相信对汇编略懂的人,看完这个教程,应该就没啥问题了,应该都可以简单的分析算法了。

白白_小荷 发表于 2015-8-30 22:45

学习一下哦

Flowerinjury 发表于 2015-8-30 22:51

楼主好样的!

太阳花 发表于 2015-8-30 22:58

感谢发布算法教程,学习了!!

Mycool 发表于 2015-8-30 23:21

不错。感谢楼主无私分享了。支持

追梦 发表于 2015-8-31 05:11

膜拜算法大牛,真厉害
页: [1] 2 3 4 5
查看完整版本: 送给那些不会分析算法朋友的一篇图文教程-exescope