EasyRE WriteUp

题源:XCTF-Reverse进阶-004

0x0 新知识

XOR 常用于置0
XOR 运算可逆

0x1 运行

在这里插入图片描述
运行提示输入,回车后即退出

0x2 查壳

在这里插入图片描述

0x3 载入IDA 32bit

在这里插入图片描述
在这里插入图片描述
可以知道 sub_401020这个call是printf()
在这里插入图片描述
因为我还是个小白,并不能像大神们一样看静态汇编代码就完全理解程序逻辑,所以我使用IDA 与 OD动静结合的方式来进行分析。

0x4 关闭ASLR,地址对齐

我是在WIN7下进行测试,所以可以手动关闭ASLR使得程序运行不进行随机加载。
在这里插入图片描述
使用VIEW辅助查看文件偏移,使用WinHex修改数据。在Win下数据为小端序存储,所以在十六进制文件中将看到 40 81
在这里插入图片描述
关闭ASLR的目的在于将OD中的地址与IDA中的地址进行对齐方便查看,如果不会修改ASLR还可以通过下API断点进行定位。
在这里插入图片描述
在IAT中可以看到导入的所有API,我发现了这两个在IDA中出现过的函数,我们要定位程序开始运行的代码段,只要在 scanf 的函数头下断点并通过堆栈回到上一层即可。
在这里插入图片描述
在这里插入图片描述

0x5 分析

在这里插入图片描述
在这里插入图片描述
ecx被赋值为数组的首地址(char *)
在这里插入图片描述
经典的字符串数组遍历(说是经典,其实我是调试后才能知道这是取字符串长度,嘿嘿嘿),再来看看IDA中的Graph。
在这里插入图片描述

edx = ecx + 0x1 
do{
	al = ecx
	ecx++
}while( al&al != 0)
sub ecx,edx
cmp ecx,0x10

最终字符串长度存放在ecx中,长度必须为0x18位

在这里插入图片描述
这里看到push esipop esi 临时保存esi的状态,可以知道esi是一个临时变量 。xor edx,edx自身与自身进行异或得到结果0x0,mov esi , ebp + ecx - 0x25 可知esi存放了数组的最后一个字符的地址。通过以下计算得到:
arr[0] = ebp - 0x24
arr[0x18-1] = ebp - 0x24 + ecx - 0x1

在这里插入图片描述
通过这个循环可以看出esi递减,edx递增,将字符串进行逆序操作。

在这里插入图片描述
紧跟着的循环再次将 edx 寄存器置0,用于循环计次
将每一个元素自增1后与0x6做异或运算后存回
在这里插入图片描述
比较两个字符串
在这里插入图片描述

0x6 总结

  1. 输入
  2. 长度限制为0x18 即24个字符
  3. 逆序数组
  4. 每个元素进行 +1 ^ 6 操作
  5. 对比字符串是否相等

0x7 脚本编写

在这里插入图片描述
异或运算是可逆的,下面是争对1bit的运算结果
明文 ^ 密文,相当于就是

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
/*
.rdata:00402124	00000012	C	xIrCj~<r|2tWsv3PtI
.rdata:00402137	00000006	C	zndka
*/
int main(){
    string str = "xIrCj~<r|2tWsv3PtIzndka";
    cout << str.length()<<endl;
    string flag = str;
    for(int i = 0; i < str.length() ;i++){
        flag[i] = (str[i] ^ 0x6) - 1;
    }
    reverse(flag.begin(),flag.end());
    cout << flag;
}

在这里插入图片描述

0x8 尝试IDA一键反编译

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // kr00_4
  signed int v4; // edx
  char *v5; // esi
  char v6; // al
  unsigned int v7; // edx
  int v8; // eax
  __int128 v10; // [esp+2h] [ebp-24h]
  __int64 v11; // [esp+12h] [ebp-14h]
  int v12; // [esp+1Ah] [ebp-Ch]
  __int16 v13; // [esp+1Eh] [ebp-8h]

  sub_401020(&unk_402150, v10);
  v12 = 0;
  v13 = 0;
  v10 = 0i64;
  v11 = 0i64;
  sub_401050((const char *)&unk_402158, (unsigned int)&v10);
  v3 = strlen((const char *)&v10);
  if ( v3 >= 0x10 && v3 == 24 )
  {
    v4 = 0;
    v5 = (char *)&v11 + 7;
    do
    {
      v6 = *v5--;
      byte_40336C[v4++] = v6;
    }
    while ( v4 < 24 );
    v7 = 0;
    do
    {
      byte_40336C[v7] = (byte_40336C[v7] + 1) ^ 6;
      ++v7;
    }
    while ( v7 < 0x18 );
    v8 = strcmp(byte_40336C, (const char *)&unk_402124);
    if ( v8 )
      v8 = -(v8 < 0) | 1;
    if ( !v8 )
    {
      sub_401020("right\n", v10);
      system("pause");
    }
  }
  return 0;
}

可以发现,获取长度、逆序等,如果一开始直接看IDA的反编译结果效率会更高,虽然代码看着有点奇怪…慢慢适应吧!我也是今天刚刚安装好IDA!!!继续冲压。

原创文章 38 获赞 35 访问量 1万+

猜你喜欢

转载自blog.csdn.net/shipsail/article/details/106158602
今日推荐