S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

OllyDBG 之旅 (十一)国庆复习

Posted on 2009-10-04 06:43 S.l.e!ep.¢% 阅读(406) 评论(0)  编辑 收藏 引用 所属分类: Crack

http://www.cppblog.com/Files/sleepwom/cycle.zip

Name: ffff
Serial:  11223344556677889

在所有 GetDlgItemTextA API设置断点

004010A6  |.  6A 11         push    11                                          ; /Count = 11 (17.)
004010A8  |.  68 71214000   push    00402171                                    ; |Buffer = cycle.00402171
; 右击 -> 数据窗口中跟随 -> 立即数

004010AD  |.  68 E9030000   push    3E9                                         ; |ControlID = 3E9 (1001.)
004010B2  |.  FF75 08       push    dword ptr [ebp+8]                           ; |hWnd
004010B5  |.  E8 0F020000   call    <jmp.&USER32.GetDlgItemTextA>               ; \GetDlgItemTextA
; 00402171  31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38  1122334455667788
; 00402181  00 98 BA DC FE 43 79 63 6C 65 43 72 61 63 6B 6D  .樅荥CycleCrackm

004010BA  |.  0BC0          or      eax, eax                                       ; 判断 eax 是否为 0, 如果是 jump 0040111F
004010BC  |.  74 61         je      short 0040111F

004010BE  |.  6A 11         push    11                                          ; /Count = 11 (17.)
004010C0  |.  68 60214000   push    00402160                                    ; |Buffer = cycle.00402160
; 右击 -> 数据窗口中跟随 -> 立即数

004010C5  |.  68 E8030000   push    3E8                                         ; |ControlID = 3E8 (1000.)
004010CA  |.  FF75 08       push    dword ptr [ebp+8]                           ; |hWnd
004010CD  |.  E8 F7010000   call    <jmp.&USER32.GetDlgItemTextA>               ; \GetDlgItemTextA
; 00402160  66 66 66 66 00 00 00 00 00 00 00 00 00 00 00 00  ffff............
; 00402170  00 31 31 32 32 33 33 34 34 35 35 36 36 37 37 38  .112233445566778

004010D2  |.  0BC0          or      eax, eax                                      ; 判断 eax 是否为 0, 如果是 jump 0040111F
004010D4  |.  74 49         je      short 0040111F

004010D6  |.  B9 10000000   mov     ecx, 10                               ; ecx = 0x10
004010DB  |.  2BC8          sub     ecx, eax                                   ;  ecx = ecx - eax (eax 此时存放用户名的长度)
004010DD  |.  BE 60214000   mov     esi, 00402160                   ; esi 指向用户名
004010E2  |.  8BFE          mov     edi, esi                                     ;  edi 指向用户名
004010E4  |.  03F8          add     edi, eax                                     ;  edi 指向用户名后面的位置
004010E6  |.  FC            cld
; 清除方向标志,在字符串的比较,赋值,读取等一系列和rep连用的操作中,
; di或si是可以自动增减的而不需要人来加减它的值,
; cld即告诉程序si,di向前移动,std指令为设置方向,告诉程序si,di向后移动
004010E7  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]
; rep 指令
;格式:REP MOVS(或REP STOS,或REP LODS);
;执行的操作:使REP后面的串操作指令重复执行,执行的次数预先存放在CX寄存器中,每执行一次串操作指令,
;CX寄存器的内容自动减1,一直重复执行到CX=0,指令才结束。具体的操作步骤是:
;第1步 如果CX=0,则退出REP,否则执行REP后面的串操作指令;
;第2步 CX ← CX-1; 
;第3步 执行串操作指令
;第4步 重复第1步~第3步。
;rep     movs byte ptr es:[edi], byte ptr [esi]
;的意思是,重复执行  movs byte ptr es:[edi], byte ptr [esi] 这个语句,次数是 ecx 寄存器中的次数
;1. esi 指向输入的用户名
;2. edi 指向输入用户名后面的内存
;3. ecx 是通过 0x10- 输入用户名的长度得来的
;也就是说,如果输入的用户名,不足 0x10 这个长度, 就是用‘输入的用户名’重复去填充,直至 0x10 这个长度
;如果输入的用户名已经是 0x10 这个长度,那么就不做任何操作了

004010E9  |.  33C9          xor     ecx, ecx                                                ; ecx 清 0
004010EB  |.  BE 71214000   mov     esi, 00402171                               ;  ASCII "11223344556677889"  ; esi 指向输入的序列号, 为 lods 指令作准备
004010F0  |>  41            /inc     ecx                                                         ; ecx 自增 1
004010F1  |.  AC            |lods    byte ptr [esi]
; 字符串操作中,从串取指令,
;从DS:SI所指向的空间中取出一个字节/字/双字放入寄存器中AL/AX/EAX,
;同时把SI+(-)1/2/4.(LODS相当于MOV AL,[SI]   INC SI.)
;从串取指令就是从DS:SI所指向字符串中取出一个字符.
004010F2  |.  0AC0          |or      al, al                            ; 判断字符是否为 0?  字符串结束标志
004010F4  |.  74 0A         |je      short 00401100            ;如果al,即取出来的字符等于0,就是跳转到00401100  这里的 0 是结束字符
004010F6  |.  3C 7E         |cmp     al, 7E                        ; 将 al 跟 0x7e 进行比较, 7e 的十进制是 126,  7E 对应的字符是 '~'
004010F8  |.  7F 06         |jg      short 00401100           ;  j 表示 jump,  g 表示 greater , 也就是说,取出来的字符如果大于 '~' 这个字符,就是跳转到 00401100
004010FA  |.  3C 30         |cmp     al, 30                        ; 将 al跟 0x30 进行比较,30的十进制是 48, 0x30 对应的字符是 '-'
004010FC  |.  72 02         |jb      short 00401100           ; j 表示 jump, b 表示 below, jb 判断 cf 标志位,低于时跳转, jl 用于带符号的运算,jb用于 无符号的运算
004010FE  |.^ EB F0         \jmp     short 004010F0       ; 循环,直至字符串结束

00401100  |>  83F9 11       cmp     ecx, 11                   ; 判断字符串长度是否为  0x11
00401103  |.  75 1A         jnz     short 0040111F           ; cmp 算术减法运算结果为零,就把ZF(零标志)置1.    jnz 判断当 ZF(零标志位)为 0 时就跳转


00401105  |.  E8 E7000000   call    004011F1
0040110A  |.  B9 01FF0000   mov     ecx, 0FF01
0040110F  |.  51            push    ecx
00401110  |.  E8 7B000000   call    00401190
00401115  |.  83F9 01       cmp     ecx, 1
00401118  |.  74 06         je      short 00401120                                <------------- 破解关键点 1,   使 ZF 标志位 ==1
0040111A  |>  E8 47000000   call    00401166
0040111F  |>  C3            retn
00401120  |>  A1 68214000   mov     eax, dword ptr [402168]
00401125  |.  8B1D 6C214000 mov     ebx, dword ptr [40216C]
0040112B  |.  33C3          xor     eax, ebx
0040112D  |.  3305 82214000 xor     eax, dword ptr [402182]
00401133  |.  0D 40404040   or      eax, 40404040
00401138  |.  25 77777777   and     eax, 77777777
0040113D  |.  3305 79214000 xor     eax, dword ptr [402179]
00401143  |.  3305 7D214000 xor     eax, dword ptr [40217D]
00401149  |.^ 75 CF         jnz     short 0040111A                              <-------------  破解关键点 2, 使 ZF 标志位 ==1
0040114B  |.  E8 2B000000   call    0040117B                                  ; 指向成功显示"Congratulations!"
00401150  \.  C3            retn

不难得出,破解有两个关键点

00401105  |.  E8 E7000000   call    004011F1                                 <------------- 作用未知
0040110A  |.  B9 01FF0000   mov     ecx, 0FF01                            <------------- ecx = 0X0FF01
0040110F  |.  51            push    ecx                                                  <-------------- ecx 进栈
00401110  |.  E8 7B000000   call    00401190                                 <-------------- ***** 在此设置断点进去分析 *****
00401115  |.  83F9 01       cmp     ecx, 1                                          <------------- 只要使 ecx == 1
00401118  |.  74 06         je      short 00401120                                <------------- 破解关键点 1,   使 ZF 标志位 ==1


===============================================================================================
call    00401190 断点处
00401190  /$  5F            pop     edi                                         ;  cycle.00401115
; Call 会先将返回地址入栈,再进行跳转,这里跳转后的第一条指令就是POP
; 明显就是 先取出返回地址,
; 这里这么做,是为了取 ecx 的值,因为在调用call之前, 会先把 ecx 入栈
00401191  |.  59            pop     ecx 
00401192  |.  57            push    edi
00401193  |.  81F9 80000000 cmp     ecx, 80       ; 这里比较ecx 是否小于或等于 0x80, 如果小于或等于 0x80 ,就直接 return
00401199  |.  7E 55         jle     short 004011F0                       
; JLE∶ 指令助记符——(有符号数比较)小于或等于转移(等价于JNG)。当SF和OF异号或ZF=1时转移(段内直接短转移)。

0040119B  |.  51            push    ecx
0040119C  |.  8BF1          mov     esi, ecx
0040119E  |.  81E1 FF000000 and     ecx, 0FF
004011A4  |.  8BF8          mov     edi, eax
004011A6  |.  83F9 08       cmp     ecx, 8
004011A9  |.  7E 05         jle     short 004011B0
004011AB  |.  8BFB          mov     edi, ebx
004011AD  |.  C1E9 04       shr     ecx, 4                  ;
; SHR 指令助记符——无符号数的逻辑右移。经常用来除以2。 当移位次数大于 1时,则移位次数应预先置于CL寄存器中,写成“SHR …,CL”。

004011B0  |>  C1C7 08       /rol     edi, 8
; ROL∶ 指令助记符——循环左移。
; 格式为:ROL 目的操作数,1
;    或ROL 目的操作数,CL  (其中CL中存放的是移动次数)

004011B3  |.  D1E9          |shr     ecx, 1
004011B5  |.^ 75 F9         \jnz     short 004011B0

004011B7  |.  C1EE 08       shr     esi, 8
004011BA  |.  23FE          and     edi, esi
004011BC  |.  81E7 FF000000 and     edi, 0FF
004011C2  |.  59            pop     ecx
004011C3  |>  BE 80000000   mov     esi, 80
004011C8  |>  85FE          /test    esi, edi
;test属于逻辑运算指令 功能: 执行BIT与BIT之间的逻辑运算
; 两操作数作与运算,仅修改标志位,不回送结果.

004011CA  |.  74 20         |je      short 004011EC
004011CC  |.  33FE          |xor     edi, esi
004011CE  |.  57            |push    edi
004011CF  |.  81E1 00FF0000 |and     ecx, 0FF00
004011D5  |.  87CE          |xchg    esi, ecx
004011D7  |.  32E9          |xor     ch, cl
004011D9  |.  33F1          |xor     esi, ecx
004011DB  |.  87F1          |xchg    ecx, esi
004011DD  |.  51            |push    ecx
004011DE  |.  FF05 82214000 |inc     dword ptr [402182]
004011E4  |.  E8 A7FFFFFF   |call    00401190                      ;递归调用
004011E9  |.  5F            |pop     edi
004011EA  |.^ EB D7         |jmp     short 004011C3
004011EC  |>  D1EE          |shr     esi, 1
004011EE  |.^ 75 D8         \jnz     short 004011C8
004011F0  \>  C3            retn

将上面的汇编转换成C,大概是...

#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;

// 模拟ASM的 PUSH, POP 操作
template<class T>
class Stack
{
public:
 void push(T data)
 {
  vstack.push_back(data);
 }

 void pop(T& data)
 {
  if (vstack.empty())
  {
   data = 0;
  }
  else
  {
   data = vstack.back();
   vstack.pop_back();
  }
 }

private:
 vector<T> vstack;
};

typedef unsigned long DWORD;

Stack<DWORD> thisStack;

DWORD n402182 = 0xFEDCBA98;

std::vector<DWORD> g_stack;

void XChange(DWORD& a, DWORD& b)
{
 DWORD c = 0;
 c = a;
 a = b;
 b = c;
}

int SHR(DWORD& a)
{
 int nBit = a & 0x01;
 a >>= 0x01;
 return nBit;
}

void XOR_HIGH_LOW(DWORD& a)
{
 char value[2] = {0};
 memcpy(value, &a, sizeof(short));
 value[1] |= value[0];
 memcpy(&a, value, sizeof(short));
 
}

DWORD fun(DWORD nECX)
{
    DWORD nRtn = nECX;

    if( nECX <= 0x80 )       // cmp ecx, 80
        return nRtn;         // jle short 004011F0

    thisStack.push(nECX);    //  push ecx
    DWORD nESI  = nECX;      //  mov esi, ecx
    nECX &= 0xFF;            //  and ecx, 0FF
    DWORD nEDI = 0x549417E7; // nEAX 值   mov edi, eax  //////////////////////  EAX 值
   
    if( nECX <= 0x08 )            // cmp ecx, 8
  goto LABEL_004011B0;      // jle short 004011B0

    nEDI = 0x02F23D32;         // nEBX 值  mov edi, ebx /////////////////////   EBX 值
    nECX >>= 0x04;             // shr ecx, 4
 
LABEL_004011B0:
 _asm rol nEDI, 8           // rol edi, 8
    int nBit = SHR(nECX);      // SHR ecx, 1    
    if( !nBit )
  goto LABEL_004011B0;   // jnz short 004011B0
   
    nESI >>= 0x08; 
    nEDI &= nESI;
    nEDI &= 0xFF;
    thisStack.pop(nECX);

LABEL_004011C3:
    nESI = 0x80;    // mov esi, 80

LABEL_004011C8:
    int nResult = (nESI & nEDI);
    if( nResult == 0x00 )           // test esi, edi
        goto LABEL_004011EC;     // je short 004011EC

    nEDI ^= nESI;
    thisStack.push(nEDI);        // push edi

    nECX &= 0xFF00;              // and ecx, 0FF00

    XChange(nESI, nECX);         // xchg esi, ecx
 XOR_HIGH_LOW(nECX);          // xor ch, cl
 nESI ^= nECX;                // xor esi, ecx
 XChange(nECX, nESI);         // xchg ecx, esi
 
    n402182++;   // push ecx; inc dword ptr [402182]         // n402182 地址
    nECX = fun(nECX);   // call 00401190

    thisStack.pop(nEDI); // pop edi
    goto LABEL_004011C3;

LABEL_004011EC:
 
    if( SHR(nESI) != 1)
        goto LABEL_004011C8;

 return nECX;
}

void main()
{
 printf("0x%x\n", fun(0x0FF01));
}


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理