吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5553|回复: 18
收起左侧

[CTF] 学破解第103天,《攻防世界reverse练习区Windows_Reverse1》分析

  [复制链接]
小菜鸟一枚 发表于 2020-5-17 14:51

学破解第103天,《攻防世界reverse练习区Windows_Reverse1》分析

前言:
  一直对黑客充满了好奇,觉得黑客神秘,强大,无所不能,来论坛两年多了,天天看各位大佬发帖,自己只能做一个伸手党。也看了官方的入门视频教程,奈何自己基础太差,看不懂。自我反思之下,决定从今天(2019年6月17日)开始定下心来,从简单的基础教程开始学习,希望能从照抄照搬,到能独立分析,能独立破解。
不知不觉学习了好几个月,发现自己离了教程什么都不会,不懂算法,不懂编程。随着破解学习的深入,楼主这个半吊子迷失了自我,日渐沉迷水贴装X,不能自拔。
==========申明:从第71天楼主开始水贴装X,帖子不再具有连续性,仅供参考,后续帖子为楼主YY专用贴!!!==========

立帖为证!--------记录学习的点点滴滴

0x1查壳

  1.程序下载后,查壳UPX 0.89 - 3.xx,ESP定律脱壳。
  2.运行程序,提示:please input code:要我们输入正确的字符串。

0x2动态调试分析(OD)

  1.搜索字符串,定位到关键跳。

004010FB   /75 27           jnz short dumped_.00401124
004010FD   |8D4C24 04       lea ecx,dword ptr ss:[esp+0x4]
00401101   |51              push ecx
00401102   |68 20214000     push dumped_.00402120                    ; You've got it!!%s\n
00401107   |FFD6            call esi
00401109   |83C4 08         add esp,0x8
0040110C   |33C0            xor eax,eax
0040110E   |5E              pop esi                                  ; kernel32.7C817077
0040110F   |8B8C24 00080000 mov ecx,dword ptr ss:[esp+0x800]
00401116   |33CC            xor ecx,esp
00401118   |E8 29000000     call dumped_.00401146
0040111D   |81C4 04080000   add esp,0x804
00401123   |C3              retn
00401124   \68 34214000     push dumped_.00402134                    ; Try again later.\n

  2.当然了,咋们的目的是追码,爆破这里毫无意义。关键跳上面必有关键call,找到它:

0040109D    68 08214000     push dumped_.00402108                    ; please input code:
004010A2    FFD6            call esi
004010A4    8D9424 20040000 lea edx,dword ptr ss:[esp+0x420]
004010AB    52              push edx                                 ; ntdll.KiFastSystemCallRet
004010AC    68 1C214000     push dumped_.0040211C                    ; %s
004010B1    FF15 A4204000   call dword ptr ds:[<&msvcr90.#1343>]     ; msvcr90.scanf
004010B7    8D8424 28040000 lea eax,dword ptr ss:[esp+0x428]
004010BE    50              push eax
004010BF    8D4C24 2C       lea ecx,dword ptr ss:[esp+0x2C]
004010C3    E8 38FFFFFF     call dumped_.00401000

  3.我F4到004010C3这里,程序运行起来,随便输入一个字符串123456,可以清晰的看到,此时eax就是我输入的123456,作为参数传递给call dumped_.00401000。
1.png

  4.接下来就F7进去,开始F8单步向下走,给它都分析出来

00401000    51              push ecx
00401001    55              push ebp
00401002    8B6C24 0C       mov ebp,dword ptr ss:[esp+0xC]           ; 123456赋值给ebp
00401006    56              push esi                                 ; msvcr90.printf
00401007    8BC5            mov eax,ebp                              ; ebp(123456)赋值给eax
00401009    57              push edi                                 ; dumped_.004033D4
0040100A    33FF            xor edi,edi                              ; dumped_.004033D4
0040100C    8D70 01         lea esi,dword ptr ds:[eax+0x1]           ; 将eax+1后指向的地址给esi
0040100F    90              nop
00401010    8A10            mov dl,byte ptr ds:[eax]                 ; 从eax中低位取一个字节,也就是1
00401012    40              inc eax                                  ; eax+1,指针右移一位
00401013    84D2            test dl,dl                               ; 判断dl是否为NULL
00401015  ^ 75 F9           jnz short dumped_.00401010               ; 循环判断
00401017    2BC6            sub eax,esi                              ; eax-esi,计算123456的长度,保存在eax中
00401019    74 26           je short dumped_.00401041                ; 相等就跳,也就是字符串长度为0
0040101B    53              push ebx
0040101C    8BDD            mov ebx,ebp                              ; ebp(123456)赋值给ebx
0040101E    2BD9            sub ebx,ecx                              ; ECX的值哪来的?相减后ebx为400
00401020    0FBE040B        movsx eax,byte ptr ds:[ebx+ecx]          ; ebx+ecx那不就是还原ebp(123456),从中取一个字节(1)给eax
00401024    8A90 F82F4000   mov dl,byte ptr ds:[eax+0x402FF8]        ; 从常量值中取出m赋值为edx的低八位给dl
0040102A    8BC5            mov eax,ebp                              ; ebp(123456)赋值给eax
0040102C    8811            mov byte ptr ds:[ecx],dl                 ; 将dl(m)存入ecx指向的内存中
0040102E    47              inc edi                                  ; edi+1=1
0040102F    41              inc ecx                                  ; ecx内存地址+1
00401030    8D70 01         lea esi,dword ptr ds:[eax+0x1]           ; 将eax+1后指向的地址给esi
00401033    8A10            mov dl,byte ptr ds:[eax]                 ; 从eax中低位取一个字节,也就是1
00401035    40              inc eax                                  ; eax+1,指针右移一位
00401036    84D2            test dl,dl                               ; 判断dl是否为NULL
00401038  ^ 75 F9           jnz short dumped_.00401033               ; 循环判断
0040103A    2BC6            sub eax,esi                              ; eax-esi,计算123456的长度,保存在eax中
0040103C    3BF8            cmp edi,eax                              ; edi=1,eax=6
0040103E  ^ 72 E0           jb short dumped_.00401020                ; edi < eax则跳转
00401040    5B              pop ebx                                  ; dumped_.004010C8
00401041    5F              pop edi                                  ; dumped_.004010C8
00401042    5E              pop esi                                  ; dumped_.004010C8
00401043    5D              pop ebp                                  ; dumped_.004010C8
00401044    59              pop ecx                                  ; 此时ecx值为mlkjih,0040102C 这一行循环写入
00401045    C3              retn

  5.从这个call出来后,继续往下跟,详细分析如下:

004010C3    E8 38FFFFFF     call dumped_.00401000
004010C8    83C4 28         add esp,0x28
004010CB    B9 F4204000     mov ecx,dumped_.004020F4                 ; DDCTF{reverseME}字符串赋值给eax
004010D0    8D4424 04       lea eax,dword ptr ss:[esp+0x4]           ; esp+4就是ecx(mlkjih)
004010D4    8A10            mov dl,byte ptr ds:[eax]                 ; 从eax中取出第一个字节m存放在dl
004010D6    3A11            cmp dl,byte ptr ds:[ecx]                 ; 判断m == D
004010D8    75 1A           jnz short dumped_.004010F4
004010DA    84D2            test dl,dl
004010DC    74 12           je short dumped_.004010F0
004010DE    8A50 01         mov dl,byte ptr ds:[eax+0x1]
004010E1    3A51 01         cmp dl,byte ptr ds:[ecx+0x1]             ; 比较第二个字符
004010E4    75 0E           jnz short dumped_.004010F4
004010E6    83C0 02         add eax,0x2
004010E9    83C1 02         add ecx,0x2
004010EC    84D2            test dl,dl
004010EE  ^ 75 E4           jnz short dumped_.004010D4
004010F0    33C0            xor eax,eax                              ; 清空eax
004010F2    EB 05           jmp short dumped_.004010F9
004010F4    1BC0            sbb eax,eax
004010F6    83D8 FF         sbb eax,-0x1
004010F9    85C0            test eax,eax                             ; 判断eax是否为NULL
004010FB    75 27           jnz short dumped_.00401124
004010FD    8D4C24 04       lea ecx,dword ptr ss:[esp+0x4]
00401101    51              push ecx                                 ; msvcr90.7855215C
00401102    68 20214000     push dumped_.00402120                    ; You've got it!!%s\n
00401107    FFD6            call esi                                 ; msvcr90.printf

显然必须要让ecx等于DDCTF{reverseME}它,才能成功,所以要从关键call中ecx的赋值寻找突破口。

  6.然而我没学过汇编,依靠百度而来的意思,并不能让我知道ecx的每一次取值之间的关系,那么就运用数学知识,多测试几组数据,观察变量之间的关系。
输入:123456
输出:mlkjih

输入:654321
输出:hijklm

输入:abcdef
输出:=<;:98

输入:fedbca
输出:89:;<=

观察上面,我可以猜测字符串输入的顺序与输出的字符串没有关系,每一个输入的字符有唯一对应的输出。

  7.接下来显然就是要找到密码表和key,找出对应关系,重新跑一边程序,梳理前面的整理出来的注释,发现决定ecx值的为这一行:00401024    8A90 F82F4000   mov dl,byte ptr ds:[eax+0x402FF8]
密码表显然就是0x402FF8处的字符串了。
输入:123456
循环取每一个字符
  第一次取1的的ASCII 0x31 + 0x402FF8处字符就是m,如图所示!
2.png

  8.现在知道key了,将“DDCTF{reverseME}”字符串一个个还原也能得出密码了吧!
D = 0x403052, C = 0x403053, T = 0x403042, F = 0x403050
{ = 0x40301B, r = 0x403024, e = 0x403031, v = 0x403020
s = 0x403023, M = 0x403049, E = 0x403051, } = 0x403019
然后将每一个地址与0x402FF8相减即可得到对应的ASCII:ZZ[JX#,9(9,+9QY!,成功得到flag。

0x3静态调试分析(IDA)

  1.尝试完累死人的OD追码,现在试试IDA放松一下吧。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@2
  char v4; // [sp+4h] [bp-804h]@1
  char v5; // [sp+5h] [bp-803h]@1
  char v6; // [sp+404h] [bp-404h]@1
  char Dst; // [sp+405h] [bp-403h]@1

  v6 = 0;
  memset(&Dst, 0, 0x3FFu);
  v4 = 0;
  memset(&v5, 0, 0x3FFu);
  printf("please input code:");
  scanf("%s", &v6);
  sub_401000(&v6);
  if ( !strcmp(&v4, "DDCTF{reverseME}") )
  {
    printf("You've got it!!%s\n", &v4);
    result = 0;
  }
  else
  {
    printf("Try again later.\n");
    result = 0;
  }
  return result;
}

很清晰的看到,v6是我们输入的值,调用00401000函数,接着比较v4和DDCTF{reverseME}是否相等。

  2.那么我就进去看一下00401000函数内部啥样子。

unsigned int __cdecl sub_401000(const char *a1)//
{
  _BYTE *v1; // ecx@0
  unsigned int v2; // edi@1
  unsigned int result; // eax@1
  int v4; // ebx@2

  v2 = 0;
  result = strlen(a1);//计算输入字符串的长度
  if ( result )
  {
    v4 = a1 - v1;
    do
    {
      *v1 = byte_402FF8[v1[v4]];
      ++v2;
      ++v1;
      result = strlen(a1);
    }
    while ( v2 < result );
  }
  return result;//返回字符串长度
}

然后有点懵,外面v4没有传进来,里面怎么改变它的值???

  3.不过我可是已经OD把它掀了个底朝天,重点看循环部分。

    do
    {
      *v1 = byte_402FF8[v1[v4]];这个v1其实就是V4了,看注释是ecx,OD调试时我就知道了ecx保存计算后的字符串
      ++v2;//+1控制循环
      ++v1;//+1赋值
      result = strlen(a1);//a1也就是输入字符串的长度
    }
    while ( v2 < result );//循环控制条件

byte402FF8是个常量字符串:前面部分不知道是啥,从00403018开始为:
~}|{zyxwvutsrqponmlkjihgfedcba`
^][ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!
然后出去这里面的v1(外面的&v4)与DDCTF{reverseME}比较就完事了。

0x3逆算法

  1.因为字符数组有部分显示不过来,我就不用上面那个字符串了,直接二进制复制。
00 00 00 00 00 00 00 00 64 CC 3D CC 9B 33 C2 33 FF FF FF FF FF FF FF FF FE FF FF FF 01 00 00 00
7E 7D 7C 7B 7A 79 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 68 67 66 65 64 63 62 61 60 5F
5E 5D 5C 5B 5A 59 58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 48 47 46 45 44 43 42 41 40 3F
3E 3D 3C 3B 3A 39 38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 28 27 26 25 24 23 22 21

  2.整理一下,逆算法如下:

int main()
{
    //密码表
    int arr[126] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xCC, 0x3D, 0xCC, 0x9B, 0x33,
        0xC2, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
        0x00, 0x00, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71,
        0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61,
        0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51,
        0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
        0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
        0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21 };

    char ch[20] = "DDCTF{reverseME}";//密码

    for (int i = 0; ch[i] != 0;i++)//DDCTF{reverseME},逐个比较
    {
        for (int j = 0; j < 126; j++)//查找下标
        {
            if (arr[j] == ch[i])//找到下标,替换成ASCII字符
            {
                ch[i] = j;
                break;//开始下一次循环
            }
        }
    }

    printf("%s",ch);//输出解密后的字符串

    system("pause");
    return 0;
}

成功解密字符串:ZZ[JX#,9(9,+9QY!

0x4总结

  1.我个人不太会用IDA,因为一开始我是从论坛零基础学脱壳教程入门,所以习惯先OD。
  2.因为看不懂汇编,很多时候只能靠百度,解密的时候习惯通过输入和输出寻找变量之间的关系,建立数学模型,也就是靠猜了。
  3.建议坛友们也可以练练手,这个程序就一个函数,OD反汇编出来也就那么几行代码,一句一句的对照百度解释的指令含义,既能学习汇编知识,又能锻炼调试能力。
  4.虽然花了大半天很累,但是很值得,最终提交的flag:flag{ZZ[JX#,9(9,+9QY!}



总结:楼主是个小菜鸟,离了教程啥都不会!

免费评分

参与人数 15威望 +1 吾爱币 +34 热心值 +14 收起 理由
bullshit + 1 + 1 用心讨论,共获提升!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
相妨 + 1 + 1 我很赞同!
zy401541 + 1 + 1 用心讨论,共获提升!
jnez112358 + 1 + 1 谢谢@Thanks!
Ctrl十C + 1 我很赞同!
sunnylds7 + 1 + 1 热心回复!
万里绿枫叶 + 1 + 1 学无止境
dns2018 + 1 谢谢@Thanks!
daymissed + 1 + 1 我也是菜鸟,学习。
wmslecz + 1 + 1 谢谢@Thanks!
zz08808 + 1 + 1 热心回复!
pwp + 3 + 1 大佬的这种教程适合我这种菜鸟看,给个能给的最高分
玖公子 + 1 + 1 我很赞同!
深爱我的女孩 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
魅惑灬 发表于 2020-5-17 14:52
提示: 作者被禁止或删除 内容自动屏蔽
深爱我的女孩 发表于 2020-5-17 14:58
hmily65 发表于 2020-5-17 15:26
白长青丶 发表于 2020-5-17 15:54
学习了 楼主加油!
头像被屏蔽
Ryan袁奥 发表于 2020-5-17 16:34
提示: 作者被禁止或删除 内容自动屏蔽
wangzhiguo9807 发表于 2020-5-17 17:35
真羡慕你有这个毅力学习,我都是断断续续的。求帮助,
堕落怪物 发表于 2020-5-17 17:39
很棒的文章,仔细读了
zjf123456 发表于 2020-5-17 21:52
感谢分享!
努力的小七 发表于 2020-5-17 22:00
技术贴,可以慢慢学习了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-27 17:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表