S.l.e!ep.¢%

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

OllyDBG 之旅 (八)

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

假设输入的用户名和序列号为:
11111
22222

004010D6  |.  B9 10000000   mov     ecx, 10
004010DB  |.  2BC8          sub     ecx, eax
004010DD  |.  BE 60214000   mov     esi, 00402160                            ;  ASCII "11111"
004010E2  |.  8BFE          mov     edi, esi
004010E4  |.  03F8          add     edi, eax
004010E6  |.  FC            cld
004010E7  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]
004010E9  |.  33C9          xor     ecx, ecx
004010EB  |.  BE 71214000   mov     esi, 00402171                            ;  ASCII "22222"

ecx = 0x10
ecx = ecx - eax = 0x10 - 0x5 = 0x0b
esi =  00402160 
edi = 00402160 
edi= edi+0x5 = 00402165
使标志位 D 为0

接下来是这一个语句:  004010E7  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]

此时 edi 指向 用户名后面的数据空间
edi = 0x00402165
00402155  40 79 61 68 6F 6F 2E 63 6F 6D 00 31 31 31 31 31  @yahoo.com.11111
00402165  00 00 00 00 00 00 00 00 00 00 00 00 32 32 32 32  ............2222
00402175  32 00 00 00 00 00 00 00 00 00 00 00 00 98 BA DC  2............樅

esi = 0x00402160
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 这个长度,那么就不做任何操作了

执行完之后的结果
00402155  40 79 61 68 6F 6F 2E 63 6F 6D 00 31 31 31 31 31  @yahoo.com.11111
00402165  31 31 31 31 31 31 31 31 31 31 31 00 32 32 32 32  11111111111.2222
00402175  32 00 00 00 00 00 00 00 00 00 00 00 00 98 BA DC  2............樅

接下来的代码:

004010E9  |.  33C9          xor     ecx, ecx
004010EB  |.  BE 71214000   mov     esi, 00402171                            ;  ASCII "22222"
004010F0  |>  41            /inc     ecx
004010F1  |.  AC            |lods    byte ptr [esi]
004010F2  |.  0AC0          |or      al, al
004010F4  |.  74 0A         |je      short 00401100
004010F6  |.  3C 7E         |cmp     al, 7E
004010F8  |.  7F 06         |jg      short 00401100
004010FA  |.  3C 30         |cmp     al, 30
004010FC  |.  72 02         |jb      short 00401100
004010FE  |.^ EB F0         \jmp     short 004010F0
00401100  |>  83F9 11       cmp     ecx, 11
00401103  |.  75 1A         jnz     short 0040111F
00401105  |.  E8 E7000000   call    004011F1

INC OPR //Byte/Word
执行操作: OPR=OPR+1
1.OPR可以是寄存器和存储器操作数, 但不能是立即数和段寄存器
2.影响标志位OF,SF,ZF,PF 和AF,不影响CF

lods
字符串操作中,从串取指令,从DS:SI所指向的空间中取出一个字节/字/双字放入寄存器中AL/AX/EAX,同时把SI+(-)1/2/4.(LODS相当于MOV AL,[SI]   INC SI.)
从串取指令就是从DS:SI所指向字符串中取出一个字符.

ecx = 0
esi = 00402171  (esi 指向输入的序列号)
ecx += 1
eax=0x32       esi+=1   == 0x00402171 + 1 = 0x00402172 (取出序列号的一个字母,并把 esi 指向下一个字母)
or      al, al   (判断上一步取出来的字符是否为 0,   因为 lods 指令用了 byte ptr, 所以这里只需要比较 al 就可以了)
|je      short 00401100    (如果al,即取出来的字符等于0,就是跳转到00401100   ,字符取出来有可能是0????  这里的 0 是结束字符 )
cmp     al, 7E    (将 al 跟 0x7e 进行比较, 7e 的十进制是 126,  7E 对应的字符是 '~')
jg      short 00401100   ( j 表示 jump,  g 表示 greater , 也就是说,取出来的字符如果大于 '~' 这个字符,就是跳转到 00401100 )
cmp     al, 30     (将 al跟 0x30 进行比较,30的十进制是 48, 0x30 对应的字符是 '-')
jb      short 00401100  ( j 表示 jump, b 表示 below, jb 判断 cf 标志位,低于时跳转, jl 用于带符号的运算,jb用于 无符号的运算)

看回 ascii 表示,可见字符是从 0x30 - 0x7E,  上面这几句很明显,是在判断输入序列号的字符是否合法
同时 ecx 存放着序列号的长度

0401100  |>  83F9 11       cmp     ecx, 11       ;  ecx 跟 11 比较
00401103  |.  75 1A         jnz     short 0040111F

cmp 算术减法运算结果为零,就把ZF(零标志)置1.    jnz 判断当 ZF(零标志位)为 0 时就跳转
所以这两个语句就是,当 ecx 不等于 0x11, 就 跳转到 0040111F

0040111F  |> \C3            retn

0040111F  是一个 retn ,,,,,,

按 F9 让它过去,然后把序列号改为  2222222222222222      (16个2)

当 ecx == 11 时,会继续往下走, call 004011F1

00401100  |> \83F9 11       cmp     ecx, 11
00401103  |.  75 1A         jnz     short 0040111F
00401105  |.  E8 E7000000   call    004011F1
0040110A  |.  B9 01FF0000   mov     ecx, 0FF01
0040110F  |.  51            push    ecx
00401110  |.  E8 7B000000   call    00401190

F7 跟进子调用 004011F1

代码如下:
004011F1  /$  A1 60214000   mov     eax, dword ptr [402160]
004011F6  |.  8B1D 64214000 mov     ebx, dword ptr [402164]
004011FC  |.  3305 71214000 xor     eax, dword ptr [402171]
00401202  |.  331D 75214000 xor     ebx, dword ptr [402175]
00401208  |.  25 0F1F3F7F   and     eax, 7F3F1F0F
0040120D  |.  81E3 00010307 and     ebx, 7030100
00401213  |.  33C9          xor     ecx, ecx

地址 402160 指向的是输入的用户名开头
地址 402164 指向的是输入的用户名第五个字节
地址 402171 指向的是输入的序列号开头
地址 402175 指向的是输入的序列号第五个字节

那么语句的意思大概是
1. 用户名的前1-4个字节放到  eax
2. 用户名的前5-8个字节放到 ebx
3. 用户名与序列号的前四个字节异或放到 eax
4. 用户名与序列号的前5-8字节异或放到 ebx
5. eax 位与 0x7F3F1F0F  放到 eax
6. ebx 位与 0x7030100    放到 ebx
7. ecx 清 0

接着往下看

00401213  |.  33C9          xor     ecx, ecx
00401215  |>  8BF0          /mov     esi, eax
00401217  |.  8BFB          |mov     edi, ebx
00401219  |.  D3E6          |shl     esi, cl
0040121B  |.  D3E7          |shl     edi, cl
0040121D  |.  81E6 80808080 |and     esi, 80808080
00401223  |.  81E7 80808080 |and     edi, 80808080
00401229  |.  8BD6          |mov     edx, esi

1. 把 eax 放到 esi
2. 把 ebx 放到 edi

把 eax 和 ebx 分别放到 esi, edi 干嘛?

shl 指令是逻辑左移,右面补零。
shl  x, y      y为移动的位数

00401219  |.  D3E6          |shl     esi, cl
0040121B  |.  D3E7          |shl     edi, cl

此时, cl 为0, 所以这两句暂时没用

0040121D  |.  81E6 80808080 |and     esi, 80808080
00401223  |.  81E7 80808080 |and     edi, 80808080

接着把 esi 跟 edi 分别跟 0x80808080 与

00401229  |.  8BD6          |mov     edx, esi    ;   把 esi 放到 edx

0040122B  |.  C0EE 07       |shr     dh, 7      对dh右移7位
0040122E  |.  66:C1E2 07    |shl     dx, 7     对dx左移7位

把 dx 的后半截清0, 不过此时dx为0, 所以这两句暂时不起

00401232  |.  C1EA 08       |shr     edx, 8
00401235  |.  C0EE 07       |shr     dh, 7
00401238  |.  66:C1E2 07    |shl     dx, 7
0040123C  |.  C1EA 08       |shr     edx, 8
0040123F  |.  C0EE 07       |shr     dh, 7
00401242  |.  66:D1EA       |shr     dx, 1

上面的一堆指令都是对 edx 进行无聊的移位

00401245  |.  8BF2          |mov     esi, edx
00401247  |.  8BD7          |mov     edx, edi

将 edx 放到 esi
将 edi 放到 edx 

接着往下看

00401270  |.  51            |push    ecx                                  将 ecx 跟 edx 都放到堆栈, 此时 ecx 跟 edx 都为 0, 没意义
00401271  |.  52            |push    edx
00401272  |.  BA 08000000   |mov     edx, 8                     edx = 8
00401277  |.  91            |xchg    eax, ecx                            交换指令XCHG(exchange),    ecx 跟 eax 交换,  eax 在上边是取用户名前四位进行一些位操作的结果
00401278  |.  83F8 03       |cmp     eax, 3                           比较 eax 跟 3
0040127B  |.  7F 0F         |jg      short 0040128C                如果 eax 大于 3 则跳转
0040127D  |.  F6E2          |mul     dl                                     此时 dl 为0
0040127F  |.  5A            |pop     edx                                    恢复 edx
00401280  |.  83C0 08       |add     eax, 8                             eax + 8
00401283  |.  91            |xchg    eax, ecx                               eax 跟 ecx 交换
00401284  |.  D3C0          |rol     eax, cl                                ROL 循环左移指令 , 左移,移出位填充到右边最高位
00401286  |.  33C2          |xor     eax, edx                            此时,edx 为 0, 所以 eax 的值还是不变
00401288  |.  D3C8          |ror     eax, cl                               ROR 循环右移指令,  右移,移出位填充到左边最高位
0040128A  |.  EB 0D         |jmp     short 00401299
0040128C  |>  83E8 03       |sub     eax, 3
0040128F  |.  F6E2          |mul     dl
00401291  |.  5A            |pop     edx


循环移位指令

格式: ROL OPRD1,COUNT ;不含进位标志位CF在循环中的左循环移位指令.

      ROR OPRD1,COUNT ;不含进位示志位CF在循环中的右循环移位指令.

      RCL OPRD1,COUNT ;带进位的左循环移位指令.

     RCR OPRD1,COUNT ;带进位的右循环移位指令.

说明:

1. 本指令组只影响标志CF、OF.OF由移入CF的内容决定,OF取决于移位一次后符号位是否改变,如改变,则OF=1.

2. 由于是循环移位,所以对字节移位8次; 对字移位16次,就可恢复为原操作数.由于带CF的循环移位,可以将CF的内容移入,
   所以可以利用它实现多字节的循环.


 


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