re学习笔记(22)爱春秋CTF答题夺旗赛(第四季)-re-basebasebase

在这里插入图片描述
题目下载:
链接:https://pan.baidu.com/s/1ArbrvREhcbzVPFsHGoo2yA
提取码:3khv

IDA载入,寻找main函数
在这里插入图片描述
sub_401000()函数内部是一个反调试
在这里插入图片描述
而nullsub_1无法打开
在这里插入图片描述
查看main函数的汇编代码,发现有未定义的函数
在这里插入图片描述
继续下滑发现有关键代码
在这里插入图片描述
在函数头摁下快捷键P,将其定义为一个函数,摁下F5键发现还是无法F5
在这里插入图片描述
找到IDA设置,打开stack pointer
在这里插入图片描述
在这里插入图片描述
发现函数的最后,retn的栈小于0了,导致不能F5
在这里插入图片描述
先在pop 或者call那里,将栈指针调整(快捷键Alt+k),使得retn的栈指针大于等于0
如果出现下图情况(一会出现一会不出现,,玄学问题)

  1. 点进这个地址,让IDA自动分析一下,退出来就能F5
  2. 这道题,此call刚开始未定义,然后输出“Successful”的代码在此call的上面,可以判断此call并不是关键代码,因此将其取消定义(右键→undefine)
    在这里插入图片描述
void __usercall hanshu1(int a1@<ebp>)
{
  int v1; // ecx

  *(a1 - 132) = 0;
  *(a1 - 40) = 89;
  *(a1 - 39) = 110;
  *(a1 - 38) = 123;
  *(a1 - 37) = 107;
  *(a1 - 36) = 89;
  *(a1 - 35) = 32;
  *(a1 - 34) = 119;
  *(a1 - 33) = 106;
  *(a1 - 32) = 90;
  *(a1 - 31) = 91;
  *(a1 - 30) = 77;
  *(a1 - 29) = 111;
  *(a1 - 28) = 91;
  *(a1 - 27) = 67;
  *(a1 - 26) = 90;
  *(a1 - 25) = 42;
  *(a1 - 24) = 90;
  *(a1 - 23) = 67;
  *(a1 - 22) = 119;
  *(a1 - 21) = 101;
  *(a1 - 20) = 86;
  *(a1 - 19) = 110;
  *(a1 - 18) = 85;
  *(a1 - 17) = 67;
  *(a1 - 16) = 89;
  *(a1 - 15) = 91;
  *(a1 - 14) = 73;
  *(a1 - 13) = 121;
  *(a1 - 12) = 89;
  *(a1 - 11) = 91;
  *(a1 - 10) = 42;
  *(a1 - 9) = 41;
  *(a1 - 8) = 3;
  printf(Format);
  *(a1 - 76) = 0;
  *(a1 - 75) = 0;
  *(a1 - 71) = 0;
  *(a1 - 67) = 0;
  *(a1 - 63) = 0;
  *(a1 - 59) = 0;
  *(a1 - 55) = 0;
  *(a1 - 51) = 0;
  *(a1 - 47) = 0;
  scanf(aS, a1 - 76);                           // a1-76  为用户的输入
  *(a1 - 128) = a1 - 76;                        // a1-128  是一个指针,指向用户输入
  *(a1 - 144) = *(a1 - 128) + 1;                // a1-144存储用户输入第二个字符
  do
    *(a1 - 113) = *(*(a1 - 128))++;
  while ( *(a1 - 113) );
  *(a1 - 140) = *(a1 - 128) - *(a1 - 144);
  *(a1 - 148) = hanshu2((a1 - 76), *(a1 - 140), (a1 - 136));// a1-140  为编码之前的长度
                                                // a1-136  为base64编码后的长度
  for ( *(a1 - 124) = 0; *(a1 - 124) < 33; ++*(a1 - 124) )// a1-124 为计数器   <33   33位
    *(a1 + *(a1 - 124) - 112) = *(*(a1 - 124) + *(a1 - 148)) ^ 3;// base64编码后与3异或
                                                // 赋给a1-112
  for ( *(a1 - 120) = 0; *(a1 - 120) < *(a1 - 136); ++*(a1 - 120) )// a1-120为计数器,循环次数为base64编码后的长度
  {
    if ( *(a1 + *(a1 - 120) - 112) != *(a1 + *(a1 - 120) - 40) )// base64编码后,再与3异或,然后与a1-40比较
    {
      printf(asc_40302C);
      exit(0);
    }
    if ( *(a1 + *(a1 - 120) - 112) == *(a1 + *(a1 - 120) - 40) )
      ++*(a1 - 132);                            // 如果不相等,a1-132就不加,不加的话,下面判断就会失败
  }
  if ( *(a1 - 132) == *(a1 - 136) )
    printf(aSuccessful);
  v1 = a1 ^ *(a1 - 4);
  JUMPOUT(loc_40121B);
}

在这里插入图片描述
可以发现他把所有的变量都用指针来表示了,,,
定义了一个字符串,(从a1-40到a1-8)
这是最后与变换后的flag比较的字符串
hanshu2()是一个base64加密
可以参考Base16,Base32,Base64编码详细学习
查看其字符表,发现是一个自定义字符表的base64加密
在这里插入图片描述
其中&amp;=&是一个转义字符串

转义字符串(Escape String),即字符实体(Character Entity)分成三部分:第一部分是一个&符号,英文叫ampersand;第二部分是实体(Entity)名字或者是#加上实体(Entity)编号;第三部分是一个分号。
在这里插入图片描述

总体流程为,程序将用户的输入进行base64加密,然后与3异或,最后与存储在栈上的字符串进行比对

写脚本
在这里插入图片描述
因为text长度为33,而base64将原字符串长度变为4/3,所以密文长度要能被4整除
所以密文的长度应该为36,需要加上三个"="

import base64
text = [89,110,123,107,89,32,119,106,90,91,77,111,91,67,90,42,90,67,119,101,86,110,85,67,89,91,73,121,89,91,42,41,3]
for i in range(len(text)):
    text[i] ^= 3
    text[i] = chr(text[i])
text = ''.join(text)
text += "==="
print(base64.b64decode(text.translate(str.maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz)!@#$%^&*(+/","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")).encode('utf-8')))

最后得出flag为flag{base_f4ck_Reverse}

发布了50 篇原创文章 · 获赞 7 · 访问量 3586

猜你喜欢

转载自blog.csdn.net/Palmer9/article/details/103704377