吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4904|回复: 25
上一主题 下一主题
收起左侧

[CTF] 学破解第141天,《攻防世界reverse练习区IgniteMe》学习

  [复制链接]
跳转到指定楼层
楼主
小菜鸟一枚 发表于 2021-8-31 22:10 回帖奖励

学破解第141天,《攻防世界reverse练习区IgniteMe》学习

前言:
  从小学到大专(计算机网络技术专业),玩过去的,所以学习成绩惨不忍睹,什么证书也没考,直到找不到工作才后悔,不知道怎么办才好。

  2017年12月16日,通过19元注册码注册论坛账号,开始做伸手党,潜水一年多,上来就是找软件。(拿论坛高大上的软件出去装X)

  2018年8月10日,报名了华中科技大学网络教育本科(计算机科学与技术专业)2018级秋季。(开始提升学历)

  2019年6月17日,不愿再做小菜鸟一枚,开始零基础学习破解。(感谢小糊涂虫大哥在我刚开始学习脱壳时,录制视频解答我的问题)

  2020年7月7日,感谢H大对我的鼓励,拥有了第一篇获得优秀的文章。(接下来希望学习逆向,逆天改命)

  2021年8月11日,华科学位英语2次不过,仅取得了毕业证书,学业提升失败,开始琢磨考注册类和职称类证书,谋求涨薪

  坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1278021-1-1.html
立帖为证!--------记录学习的点点滴滴

0x1 下载文件

  1.下载CM,是一个exe文件。

  2.exeInfo工具查壳:
https://z3.ax1x.com/2021/08/31/hdVKWd.png

  3.使用studyPE查看程序信息:
https://z3.ax1x.com/2021/08/31/hdVUYQ.png

  4.可能有的坛友不知道为什么我都要重复这个步骤,这里说明下:
第一步看文件类型,exe是win平台,elf是Linux平台,能在win平台跑我就可以动态调试了。
第二步看目标程序是否有壳,以决定是脱壳还是带壳打补丁。
第三步主要是看程序基址是否固定以便固定基址方便调试和打补丁,另自带有密码学探测工具,这里暂时用不到。

  5.通过上述信息,我知道了这个程序大概率是vc++6.0编写的32位程序,无壳,固定基址,未使用标准加密算法。

0x2 OD调试分析

  1.既然是exe文件还是先爆破,将程序载入OD,搜索字符串,进度条拉到最上方:
https://z3.ax1x.com/2021/08/31/hdZ5CQ.png

  2.回车,在几处错误提示的字符串处F2下断点:

00401069  |.  83F8 04       cmp eax,0x4
0040106C  |.  77 25         ja short fac4d129.00401093
0040106E  |>  68 70364000   push fac4d129.00403670
00401073  |.  68 60B14300   push fac4d129.0043B160                   ;  Sorry, keep trying!
004010F5  |.  3BD1          |cmp edx,ecx
004010F7  |.  74 25         |je short fac4d129.0040111E
004010F9  |.  68 70364000   |push fac4d129.00403670
004010FE  |.  68 40B14300   |push fac4d129.0043B140                  ;  Sorry, keep trying!
004010F5  |.  3BD1          |cmp edx,ecx
004010F7  |.  74 25         |je short fac4d129.0040111E
004010F9  |.  68 70364000   |push fac4d129.00403670
004010FE  |.  68 40B14300   |push fac4d129.0043B140                  ;  Sorry, keep trying!
00401124  |.  83FA 7D       cmp edx,0x7D
00401127  |.  74 22         je short fac4d129.0040114B
00401129  |.  68 70364000   push fac4d129.00403670
0040112E  |.  68 40B14300   push fac4d129.0043B140                   ;  Sorry, keep trying!
0040115C  |.  85C0          test eax,eax                             ;  kernel32.BaseThreadInitThunk
0040115E  |.  75 22         jnz short fac4d129.00401182
00401160  |.  68 70364000   push fac4d129.00403670
00401165  |.  68 40B14300   push fac4d129.0043B140                   ;  Sorry, keep trying!

  3.将程序跑起来,输入123456,断在0040106C 这里,单步往下走看看:
00401069  |.  83F8 04       cmp eax,0x4
这里必须跳过去,否则失败,eax的值6,可以推测就是我输入的123456的长度

004010F5  |.  3BD1          |cmp edx,ecx
edx是0x31,可以猜到是输入的第一个字符1对应的ASCII值,ecx是0x45 E,判断两个值是否相等,不相等就失败,这里我们在寄存器窗口点Z,改变标志,让它跳过这个失败,开始下一次循环。
https://imgtu.com/i/hdmqtU

第一轮循环
ECX 00000045  E
EDX 00000031  1

第二轮循环
ECX 00000049  I
EDX 00000032  2

第三轮循环
ECX 00000053  S
EDX 00000033  3

第四轮循环
ECX 0000007B  {
EDX 00000034  4

00401124  |.  83FA 7D       cmp edx,0x7D
这里目前还没看出来什么意思,改跳转继续往正确的流程走

0040114F  |.  E8 6C000000   call fac4d129.004011C0
00401154  |.  83C4 04       add esp,0x4
00401157  |.  25 FF000000   and eax,0xFF
0040115C  |.  85C0          test eax,eax
0040115E  |.  75 22         jnz short fac4d129.00401182

再往下只有Sorry, keep trying! 和Congratulations! 两条路。

  4.显然0040114F这里调用的call就是关键函数了,在回到第一个断点往上翻:

00401058  |.  83F8 1E       cmp eax,0x1E
0040105B  |.  73 11         jnb short fac4d129.0040106E
0040105D  |.  8D55 80       lea edx,[local.32]
00401060  |.  52            push edx
00401061  |.  E8 6AE20100   call fac4d129.0041F2D0
00401066  |.  83C4 04       add esp,0x4
00401069  |.  83F8 04       cmp eax,0x4
0040106C  |.  77 25         ja short fac4d129.00401093
0040106E  |>  68 70364000   push fac4d129.00403670
00401073  |.  68 60B14300   push fac4d129.0043B160                   ;  Sorry, keep trying!

这里判断了0x1E和0x4,jnb不小于则跳转,ja大于则跳转,根据前面推测,eax是我输入字符串的长度,所以我输入的字符串长度应该是4-30位,而开头的4位必须是“EIS{”

  5.到这里把0040115E这个jnz让它跳过就成功爆破了。
https://z3.ax1x.com/2021/08/31/hd8y0H.png

  6.当然了,爆破对CTF题来说意义不大,接下来还是分析一下算法吧。

0x3 IDA代码分析

  1.将程序用32位IDA打开,找到main函数,F5反编译一下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  size_t i; // [esp+4Ch] [ebp-8Ch]
  char v5[8]; // [esp+50h] [ebp-88h] BYREF
  char Str[128]; // [esp+58h] [ebp-80h] BYREF

  sub_402B30(&unk_446360, "Give me your flag:");
  sub_4013F0(sub_403670);
  sub_401440(Str, 127);
  if ( strlen(Str) < 0x1E && strlen(Str) > 4 )
  {
    strcpy(v5, "EIS{");
    for ( i = 0; i < strlen(v5); ++i )
    {
      if ( Str[i] != v5[i] )
        goto LABEL_7;
    }
    if ( Str[28] != 125 )
    {
LABEL_7:
      sub_402B30(&unk_446360, "Sorry, keep trying! ");
      sub_4013F0(sub_403670);
      return 0;
    }
    if ( (unsigned __int8)sub_4011C0(Str) )
      sub_402B30(&unk_446360, "Congratulations! ");
    else
      sub_402B30(&unk_446360, "Sorry, keep trying! ");
    sub_4013F0(sub_403670);
    result = 0;
  }
  else
  {
    sub_402B30(&unk_446360, "Sorry, keep trying!");
    sub_4013F0(sub_403670);
    result = 0;
  }
  return result;
}

  2.前面和我在OD中分析的一样,先判断我输入的字符串长度是否满足要求,再看是否为EIS{开头,再调用sub_4011C0函数验证

    if ( (unsigned __int8)sub_4011C0(Str) )
      sub_402B30(&unk_446360, "Congratulations! ");

通过OD查找调用过程,发现从004019C3这个地址调用的004017F0函数,向上翻找到段首00401890。

  3.看一看sub_4011C0函数反编译后的代码:

bool __cdecl sub_4011C0(char *Str)
{
  size_t v2; // eax
  int v3; // [esp+50h] [ebp-B0h]
  char Str2[32]; // [esp+54h] [ebp-ACh] BYREF
  int v5; // [esp+74h] [ebp-8Ch]
  int v6; // [esp+78h] [ebp-88h]
  size_t i; // [esp+7Ch] [ebp-84h]
  char v8[128]; // [esp+80h] [ebp-80h] BYREF

  if ( strlen(Str) <= 4 )
    return 0;
  i = 4;
  v6 = 0;
  while ( i < strlen(Str) - 1 )
    v8[v6++] = Str[i++];
  v8[v6] = 0;
  v5 = 0;
  v3 = 0;
  memset(Str2, 0, sizeof(Str2));
  for ( i = 0; ; ++i )
  {
    v2 = strlen(v8);
    if ( i >= v2 )
      break;
    if ( v8[i] >= 97 && v8[i] <= 122 )
    {
      v8[i] -= 32;
      v3 = 1;
    }
    if ( !v3 && v8[i] >= 65 && v8[i] <= 90 )
      v8[i] += 32;
    Str2[i] = byte_4420B0[i] ^ sub_4013C0(v8[i]);
    v3 = 0;
  }
  return strcmp("GONDPHyGjPEKruv{{pj]X@rF", Str2) == 0;
}

while ( i < strlen(Str) - 1 )
v8[v6++] = Str[i++];
v8[v6] = 0;
将str字符串给到char数组v8,末尾补0;

memset(Str2, 0, sizeof(Str2));
初始化str2字符串

接下来就是一段关键的字符串处理了,最后比较str2和GONDPHyGjPEKruv{{pj]X@rF是否相等,这段for循环可以像前面一样不用理解它做了什么,直接等式变换,大于变小于等于,加变减,异或不用变,直接用它的算法些脚本得到flag,这里我们学习一下阅读代码,如果能读懂一会写脚本就不会知其然不知其所以然。

  4.继续看看for循环这段代码:
v2 = strlen(v8);
if ( i >= v2 )
break;
这里就是判断是否超过我输入的字符串长度了,超过了直接跳出循环,失败

if ( v8[i] >= 97 && v8[i] <= 122 )
{
v8[i] -= 32;
v3 = 1;
}
这里急判断如果我输入的是小写字母就变成大写字母,这里v3的作用目前还看不出来。

if ( !v3 && v8[i] >= 65 && v8[i] <= 90 )
v8[i] += 32;
如果是大写字母就变成小写字母,使用完后v3又重置为0,v3是大小写判断,例如前面判断小写了,则这里不再判断是否为大写。

Str2[i] = byte_4420B0[i] ^ sub_4013C0(v8[i]);
这段代码就这句有用,这里又调用了一个函数
int __cdecl sub_4013C0(int a1)
{
return (a1 ^ 0x55) + 72;
}

所以str2[i] = byte_4420B0[i]^((v8[i] ^ 0x55) + 72),循环执行。
byte_4420B0[i]是一个char数组,存储的内容为:
https://z3.ax1x.com/2021/08/31/hdU3X6.png
为了便于一会容易理解,将str2[i] = byte_4420B0[i]^((v8[i] ^ 0x55) + 72)拆分:
v8[i] = v8[i] ^ 0x55
v8[i] = v8[i] + 72
str2[i] = v8[i] ^ byte_4420B0[i]
倒过来就是:
v8[i] = str2[i] ^ byte_4420B0[i]
v8[i] = v8[i] -72
v8[i] = v8[i] ^ 0x55

  5.整理后的代码:

package ctf0;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        char temp[] = { 0x0D, 0x13, 0x17, 0x11, 0x2, 0x1, 0x20, 0x1D, 0x0C, 0x2, 0x19, 0x2F, 0x17, 0x2B, 0x24, 0x1F,
                0x1E, 0x16, 0x9, 0xF, 0x15, 0x27, 0x13, 0x26, 0x0A, 0x2F, 0x1E, 0x1A, 0x2D, 0x0C, 0x22, 0x4 };

        StringBuffer str = new StringBuffer("GONDPHyGjPEKruv{{pj]X@rF");
        StringBuffer flag = new StringBuffer("GONDPHyGjPEKruv{{pj]X@rF");

        boolean on = true;//大写

        for (int i = 0; i < str.length(); i++) {
            flag.setCharAt(i, (char) (str.charAt(i)^temp[i])); 
            flag.setCharAt(i, (char) (flag.charAt(i)-72)); 
            flag.setCharAt(i, (char) (flag.charAt(i)^0x55)); 
            if(flag.charAt(i)>=97&&flag.charAt(i)<=122)
            {
                on = false;//小写
                flag.setCharAt(i,(char) (flag.charAt(i)-32));
            }
            if(on==true&&flag.charAt(i)>=65&&flag.charAt(i)<=90)
            {
                flag.setCharAt(i,(char) (flag.charAt(i)+32));
            }
            on = true;
        }
        System.out.println(flag);
    }

}

运行后:wadx_tdgk_aihc_ihkn_pjlm

  6.提交flag,发现一直不对???什么情况!!!一脸懵X,回去复盘一下代码,看看忽略了什么,还记得前面OD分析的时候,必须EIS{开头吗?再去看看:
if ( strlen(Str) < 0x1E && strlen(Str) > 4 )
这是长度要求
strcpy(v5, "EIS{");
for ( i = 0; i < strlen(v5); ++i )
{
if ( Str[i] != v5[i] )
goto LABEL_7;
}
这是判断flag开头前四位是否是EIS{
if ( Str[28] != 125 )
这是判断flag第29位是}
i = 4;
v6 = 0;
while ( i < strlen(Str) - 1 )
v8[v6++] = Str[i++];
再看,i是从4开始的,赋值时去掉了前四位,strlen(Str) - 1,赋值时去掉了最后一位。

所以flag应该是EIS{wadx_tdgk_aihc_ihkn_pjlm}

  7.再次提交flag,验证通过:
https://z3.ax1x.com/2021/08/31/hdDl1H.png

0x4总结

  1.分析的时候应该逐步推进,不能只盯着关键函数,注意循环时变量的起始位置,字符串拷贝不一定全部复制过去了。
  2.flag不对时小菜鸟差点哭了,明明分析的没问题,为什么会这样,最后冷静下来,耐心复盘就找到了原因。
  3.编写脚本时用了不熟悉的java,查找函数耗费了一些时间(不能总是只会一门c语言吧,适当了解别的语言)
  4.这是道1分题,主要是还是大意了,将脚本跑起来以为就成功了,却忘了前面为什么判断EIS{了。
  5.尝试读懂代码,更有利于编写脚本。

0x5参考资料

  1.Java™ Platform, Standard Edition 8API Specification

  PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!

免费评分

参与人数 13威望 +1 吾爱币 +31 热心值 +13 收起 理由
QRQ + 1 + 1 我很赞同!
liuye + 3 + 1 加油&amp;amp;#128170;
user002 + 1 + 1 我很赞同!
娃娃菜啊 + 1 + 1 从你开始十几天的时候加的关注,没想打我已经放弃这么久了,加油兄弟
nnicetry + 1 + 1 热心回复!
zx618 + 1 + 1 用心讨论,共获提升!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Ouyang520 + 1 热心回复!
OYyunshen + 1 + 1 我很赞同!
mantuner + 1 + 1 热心回复!
艺举成名 + 1 + 1 谢谢@Thanks!
sdaza + 1 我很赞同!
lingyun011 + 1 热心回复!

查看全部评分

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

推荐
ychiou 发表于 2021-9-2 10:03
楼主我觉得你不如多放点精力琢磨考注册类和职称类证书,破解这类东西作为兴趣玩玩可以
沙发
6302638 发表于 2021-8-31 22:19
感谢楼主分享,我也刚入坑,不知道怎么学习哇,现在有前辈的经验,我们后辈会少走很多弯路啊
3#
空白白 发表于 2021-8-31 22:57
4#
转身鬼魅 发表于 2021-8-31 23:10
点赞加油
5#
carryff 发表于 2021-8-31 23:47
正想学软件和破解,挺有用的
6#
傲天正 发表于 2021-9-1 08:14
祝楼主涨薪100美元
7#
anychen 发表于 2021-9-1 08:26
破解APP不,去一下广告
8#
GuiXiaoQi 发表于 2021-9-1 08:34
向楼主学习
9#
216288461 发表于 2021-9-1 08:36
码住,试一下
10#
蒹葭苍苍白露霜 发表于 2021-9-1 08:45
加油 加油 一起学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-25 23:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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