Easy CrackMe
发布日期:2019年02月03日 类别:reversing 题目来源:reversing.kr 题目链接:http://reversing.kr/challenge.php双击点开 Easy CrackMe.exe,将弹出一个对话框,要求输入密码。点击按钮后将对密码进行验证。

首先用 Cutter 打开 Easy CrackMe.exe,看看 Strings 里面有没有什么特别的:

AGR3versing 似乎有点奇怪。输进去看看,不对。除此之外,就是 Wrong Password 和 Congratulations 最吸引我们了。看一下 Congratulations 的交叉引用,跳到了:
|      ||   0x00401114      push 0x40 ; '@' ; 64
|      ||   0x00401116      push str.EasyCrackMe ; 0x406058 ; "EasyCrackMe"
|      ||   0x0040111b      push str.Congratulation ; 0x406044 ; "Congratulation !!"
|      ||   0x00401120      push edi
|      ||   0x00401121      call dword [sym.imp.USER32.dll_MessageBoxA] ; 0x4050a0 ; "NU"
|      ||   0x00401127      push 0
|      ||   0x00401129      push edi
|      ||   0x0040112a      call dword [sym.imp.USER32.dll_EndDialog] ; 0x4050a4 ; "BU"
|      ||   0x00401130      pop  edi
|      ||   0x00401131      add  esp, 0x64 ; 'd'
|      ||   0x00401134      ret
|      ``-> 0x00401135      push 0x10 ; 16
|           0x00401137      push str.EasyCrackMe ; 0x406058 ; "EasyCrackMe"
|           0x0040113c      push str.Incorrect_Password ; 0x406030 ; "Incorrect Password"
|           0x00401141      push edi
|           0x00401142      call dword [sym.imp.USER32.dll_MessageBoxA] ; 0x4050a0 ; "NU"
|           0x00401148      pop  edi
|           0x00401149      add  esp, 0x64 ; 'd'
\           0x0040114c      ret看起来这就是最终弹出检查结果的地方了。往上翻一下,在同一个函数里面,就是检查的逻辑:
/ (fcn) sub.USER32.dll_GetDlgItemTextA_401080 205
|   long sub.USER32.dll_GetDlgItemTextA_401080 (HWND hDlg, int nIDDlgItem, LPSTR lpString, int nMaxCount);
|           ; var unsigned int local_4h @ esp+0x4
|           ; var unsigned int local_5h @ esp+0x5
|           ; var int local_8h @ esp+0x8
|           ; var int local_ah @ esp+0xa
|           ; var int local_10h @ esp+0x10
|           ; arg int arg_70h @ esp+0x70
|           0x00401080      sub  esp, 0x64 ; 'd'
|           0x00401083      push edi
|           0x00401084      mov  ecx, 0x18 ; 24
|           0x00401089      xor  eax, eax
|           0x0040108b      lea  edi, [local_5h] ; 5
|           0x0040108f      mov  byte [local_4h], 0
|           0x00401094      push 0x64 ; 'd' ; 100
|           0x00401096      rep  stosd dword es:[edi], eax
|           0x00401098      stosw word es:[edi], ax
|           0x0040109a      stosb byte es:[edi], al
|           0x0040109b      mov  edi, dword [arg_70h] ; [0x70:4]=-1 ; 'p' ; 112
|           0x0040109f      lea  eax, [local_8h] ; 8 ;; !local_4h
|           0x004010a3      push eax
|           0x004010a4      push 0x3e8 ; 1000
|           0x004010a9      push edi
|           0x004010aa      call dword [sym.imp.USER32.dll_GetDlgItemTextA] ; 0x40509c ; "\U"
|           0x004010b0      cmp  byte [local_5h], 0x61 ; 'a' ; [0x5:1]=255 ; 97
|       ,=< 0x004010b5      jne  0x401135
|       |   0x004010b7      push 2 ; 2
|       |   0x004010b9      lea  ecx, 
|           0x004010b9      lea  ecx, [local_ah] ; 0xa ; 10 ;; local_6h
|           0x004010bd      push 0x406078 ; 'x`@' ; "5y"
|           0x004010c2      push ecx
|           0x004010c3      call fcn.00401150
|           0x004010c8      add  esp, 0xc
|           0x004010cb      test eax, eax
|       ,=< 0x004010cd      jne  0x401135
|       |   0x004010cf      push ebx
|       |   0x004010d0      push esi
|       |   0x004010d1      mov  esi, 0x40606c ; 'l`@' ; "R3versing"
|       |   0x004010d6      lea  eax, [local_10h] ; 0x10 ; 16 ;; local_8h
|      .--> 0x004010da      mov  dl, byte [eax]
|      :|   0x004010dc      mov  bl, byte [esi]
|      :|   0x004010de      mov  cl, dl
|      :|   0x004010e0      cmp  dl, bl
|     ,===< 0x004010e2      jne  0x401102
|     |:|   0x004010e4      test cl, cl
|    ,====< 0x004010e6      je   0x4010fe
|    ||:|   0x004010e8      mov  dl, byte [eax + 1] ; [0x1:1]=255 ; 1
|    ||:|   0x004010eb      mov  bl, byte [esi + 1] ; [0x1:1]=255 ; 1
|    ||:|   0x004010ee      mov  cl, dl
|    ||:|   0x004010f0      cmp  dl, bl
|   ,=====< 0x004010f2      jne  0x401102
|   |||:|   0x004010f4      add  eax, 2
|   |||:|   0x004010f7      add  esi, 2
|   |||:|   0x004010fa      test cl, cl
|   |||`==< 0x004010fc      jne  0x4010da
|   |`----> 0x004010fe      xor  eax, eax
|   | |,==< 0x00401100      jmp  0x401107
|   `-`---> 0x00401102      sbb  eax, eax
|      ||   0x00401104      sbb  eax, 0xffffffffffffffff
|      `--> 0x00401107      pop  esi
|       |   0x00401108      pop  ebx
|       |   0x00401109      test eax, eax
|      ,==< 0x0040110b      jne  0x401135
|      ||   0x0040110d      cmp  byte [local_4h], 0x45 ; 'E' ; [0x4:1]=255 ; 69
|     ,===< 0x00401112      jne  0x401135
|     |||   0x00401114      push 0x40 ; '@' ; 64
|     |||   0x00401116      push str.EasyCrackMe ; 0x406058 ; "EasyCrackMe"
|     |||   0x0040111b      push str.Congratulation ; 0x406044 ; "Congratulation !!"由于这个函数的局部变量由 esp 索引,而 R2 没有捕捉到 esp 的变化,导致函数中的变量名的使用会有些误导,在分析时需要注意。举例来说,上面的代码片段 14 行有一处 push,导致第 20 行的 local_8h(esp+8)实际应为 local_4h。我在有问题的语句后做了注释。
首先来看第 24 行,GetDlgItemText 是一个 Win32 API,其中第三个参数是字符串的地址。第 21 行压入的 eax 即为第三个参数,它指向的是 local_4h,因此 local_4h 就是字符串的第零个字符的地址。
随后,第 25 行判断了一下第一个字符的内容是否为 a;第 32 行将 5y 和第三个字符地址的地址传入了 fcn.00401150。去看一下这个函数:
/ (fcn) fcn.00401150 56
|   fcn.00401150 (int arg_8h, unsigned int arg_ch, int arg_10h);
|           ; arg int arg_8h @ ebp+0x8
|           ; arg unsigned int arg_ch @ ebp+0xc
|           ; arg int arg_10h @ ebp+0x10
|           0x00401150      push ebp
|           0x00401151      mov  ebp, esp
|           0x00401153      push edi
|           0x00401154      push esi
|           0x00401155      push ebx
|           0x00401156      mov  ecx, dword [arg_10h] ; [0x10:4]=-1 ; 16
|       ,=< 0x00401159      jecxz 0x401181
|       |   0x0040115b      mov  ebx, ecx
|       |   0x0040115d      mov  edi, dword [arg_8h] ; [0x8:4]=-1 ; 8
|       |   0x00401160      mov  esi, edi
|       |   0x00401162      xor  eax, eax
|       |   0x00401164      repne scasb al, byte es:[edi]
|       |   0x00401166      neg  ecx
|       |   0x00401168      add  ecx, ebx
|       |   0x0040116a      mov  edi, esi
|       |   0x0040116c      mov  esi, dword [arg_ch] ; [0xc:4]=-1 ; 12
|       |   0x0040116f      repe cmpsb byte [esi], byte ptr es:[edi]
|       |   0x00401171      mov  al, byte [esi - 1]
|       |   0x00401174      xor  ecx, ecx
|       |   0x00401176      cmp  al, byte [edi - 1]
|      ,==< 0x00401179      ja   0x40117f
|     ,===< 0x0040117b      je   0x401181
|     |||   0x0040117d      dec  ecx
|     |||   0x0040117e      dec  ecx
|     |`--> 0x0040117f      not  ecx
|     `-`-> 0x00401181      mov  eax, ecx
|           0x00401183      pop  ebx
|           0x00401184      pop  esi
|           0x00401185      pop  edi
|           0x00401186      leave
\           0x00401187      ret看起来只是在做字符串比较,所以第三四个字符应该是 5y 。再继续看,从第38行开始,字符串 R3versing 出现了,下面的代码又是在不断地比较每一个字符是否与 R3versing 相同。最后 64 行比较了第一个字符是否为 E,至此密码已经找到了:
