简单逆向31(OD调试,亦或)

35 篇文章 5 订阅

使用IDA打开,通过搜索字符串找到主函数:

int __thiscall sub_AC2810(void *this)
{
  int v1; // eax
  int v2; // ecx
  int v3; // eax
  char *v4; // esi
  signed int v5; // edi
  unsigned int v6; // kr00_4
  char *v7; // ecx
  char **v8; // ecx
  char *v9; // ecx
  char *v10; // edx
  unsigned int v11; // edi
  int v12; // eax
  int v13; // eax
  bool v14; // cf
  unsigned __int8 v15; // al
  unsigned __int8 v16; // al
  unsigned __int8 v17; // al
  const char *v18; // edx
  int v19; // eax
  char *v20; // eax
  int v22; // [esp-14h] [ebp-D8h]
  int v23; // [esp-10h] [ebp-D4h]
  char *v24; // [esp+24h] [ebp-A0h]
  int len; // [esp+34h] [ebp-90h]
  unsigned int v26; // [esp+38h] [ebp-8Ch]
  __int128 v27; // [esp+3Ch] [ebp-88h]
  __int128 v28; // [esp+4Ch] [ebp-78h]
  int v29; // [esp+5Ch] [ebp-68h]
  __int128 key; // [esp+60h] [ebp-64h]
  __int128 v31; // [esp+70h] [ebp-54h]
  int v32; // [esp+80h] [ebp-44h]
  __int64 v33; // [esp+84h] [ebp-40h]
  int v34; // [esp+8Ch] [ebp-38h]
  int v35; // [esp+94h] [ebp-30h]
  int v36; // [esp+98h] [ebp-2Ch]
  int v37; // [esp+9Ch] [ebp-28h]
  int v38; // [esp+A0h] [ebp-24h]
  int v39; // [esp+A4h] [ebp-20h]
  int v40; // [esp+A8h] [ebp-1Ch]
  int v41; // [esp+ACh] [ebp-18h]
  int v42; // [esp+B0h] [ebp-14h]
  int v43; // [esp+C0h] [ebp-4h]

  len = 0;
  v26 = 15;
  LOBYTE(v24) = 0;
  v43 = 0;
  LOBYTE(v43) = 1;
  v1 = printf(this, "Please input your flag: ");
  sub_AC3050(v1);
  scanf(&dword_AF0068, &v24);
  strcpy((char *)&v34, "9_CTF");
  v33 = *(_QWORD *)aSwpu2019Ctf;                // SWPU_2019_CTF
  if ( len == 32 )
  {
    v39 = -1173078761;
    v40 = 494076752;
    v41 = -1811652486;
    v42 = 688582768;
    v5 = 0;
    key = 0i64;
    v32 = 0;
    v31 = 0i64;
    v6 = strlen((const char *)&v33);
    do                                          // 1:亦或
    {
      v7 = (char *)&v24;
      if ( v26 >= 16 )
        v7 = v24;
      v7[v5] ^= *((_BYTE *)&v33 + v5 % v6);
      ++v5;
    }
    while ( v5 < 32 );
    v8 = &v24;
    v4 = v24;
    if ( v26 >= 16 )
      v8 = (char **)v24;
    v29 = 0;
    v27 = 0i64;
    v28 = 0i64;
    *(_QWORD *)&key = *(_QWORD *)v8;
    *((_QWORD *)&key + 1) = *((_QWORD *)v8 + 1);
    *(_QWORD *)&v31 = *((_QWORD *)v8 + 2);
    *((_QWORD *)&v31 + 1) = *((_QWORD *)v8 + 3);
    sub_AC25C0(v22, v23, 256, (unsigned int)&key, (unsigned int)&v27);// 一种加密
    v35 = 0xF80F37B3;
    v36 = 0x5DAEBCBC;
    v9 = (char *)&v35;
    v37 = 0x864D5ABA;
    v10 = (char *)&v27;
    v38 = 0xD3629744;
    v11 = 28;
    v39 = 0x1624BA4F;
    v40 = 0x1A729F0B;
    v41 = 0x266D6865;
    v42 = 0x67C86BBA;
    while ( 1 )
    {
      v12 = *(_DWORD *)v9;
      if ( *(_DWORD *)v9 != *(_DWORD *)v10 )
        break;
      v9 += 4;
      v10 += 4;
      v14 = v11 < 4;
      v11 -= 4;
      if ( v14 )
      {
        v13 = 0;
        goto LABEL_19;
      }
    }
    v14 = (unsigned __int8)v12 < (unsigned __int8)*v10;
    if ( (_BYTE)v12 != *v10
      || (v15 = v9[1], v14 = v15 < (unsigned __int8)v10[1], v15 != v10[1])
      || (v16 = v9[2], v14 = v16 < (unsigned __int8)v10[2], v16 != v10[2])
      || (v17 = v9[3], v14 = v17 < (unsigned __int8)v10[3], v17 != v10[3]) )
    {
      v13 = -v14 | 1;
    }
    else
    {
      v13 = 0;
    }
LABEL_19:
    if ( v13 )
      v18 = "Try again!\r\n";
    else
      v18 = "Congratulations! I always knew you could do it.";
    v19 = printf(v9, v18);
    sub_AC3050(v19);
    sub_ACADBE("pause");
  }
  else
  {
    v3 = printf(v2, "Try again!\r\n");
    sub_AC3050(v3);
    sub_ACADBE("pause");
    v4 = v24;
  }
  if ( v26 >= 0x10 )
  {
    v20 = v4;
    if ( v26 + 1 >= 0x1000 )
    {
      v4 = (char *)*((_DWORD *)v4 - 1);
      if ( (unsigned int)(v20 - v4 - 4) > 0x1F )
        sub_ACAFF7(v26 + 36);
    }
    sub_AC64DE(v4);
  }
  return 0;
}

先静心浏览代码,先与一个值亦或,再把亦或后的数据放到了一个函数进行加密,然后比较;

这里注意几点:
1.后面比较字符串因为是整数类型,要注意大小端(后面OD动态调试在寄存器里找亦或的数据也要注意大小端)。

2.前面虽然只传入了四次数据,但是一次是QWORD,也就是4 * 8 = 32。

当然流程不知道是什么,可以先动态调试,一般是同时进行的。

因为看了加密函数里面很多常量的混淆,下面使用动态调试:

OD打开(IDA报错):
在IDA中可以看到函数地址是,AC2810
在这里插入图片描述
找到地址(注意基地址可能不一样,后面相同就行),下个断点

在这里插入图片描述
F9运行,F8跟踪
printf
在这里插入图片描述
scanf
在这里插入图片描述
随便输入数据,32位
在这里插入图片描述
check长度是否位0x20(32),不是输出错误
在这里插入图片描述
这里应该是第一个亦或(xor),知道亦或的数据,就不用记录了:
在这里插入图片描述

看到这里有一片移动数据:
在这里插入图片描述

[ecx]地址的值移动到[EBP-64]
ecx的值是前面亦或后的数据,就相当于把数据移动到了新的地址,ds是数据段寄存器,ss是栈段寄存器在这里插入图片描述然后是加密函数:在这里插入图片描述
EBP-64的数据就是上面转移的新地址,这个数据需要在栈中查看。也可以在数据窗口中跟随。
栈段:
在这里插入图片描述
数据窗口跟随方法:
先跟踪到要跟随的数据操作地址,比如这里是ss:[EBP-64]
在这里插入图片描述

下面有个提示堆栈,右键选择跟随;
在这里插入图片描述
32字节刚好两排,数据应该和上面段中的地址一样,这里不一样是因为我这次输入的数据不一样,这个功能相当于段内存映射
在这里插入图片描述

然后因为这个加密函数我跟进去看了一下,发现思路不明确,然后可以使用一个内存断点的功能;
如下
在这里插入图片描述

只要有指令改变这个地方的数据OD就会给我们短下来,F9运行

断到了一个亦或

EAX-4是刚刚那个数据
在这里插入图片描述
我们搜寻每次亦或ECX的数据:
CA3E0C86
19AED798
A66B77E2
B077A16A
05379169
307BF97A
104B5A43
28D47D86

这里有个重点,前面说了。
因为xor每次亦或,后面使用的dword(2字节),产生大小端的问题,所以要就行处理,可以将ECX数据重新排列,也可以将另外一个字符串重新排列;

继续,后面还有一个比较:
在这里插入图片描述
数据在上面:
在这里插入图片描述

脚本:

#输入的永远是一个字节一个字节的输入,所以没有大小端。但是比较的时候会大小端,所以要将比较的数据还原就行了
data = [0xB3, 0x37, 0x0F, 0xF8, 0xBC, 0xBC, 0xAE, 0x5D, 0xBA, 0x5A, 0x4D, 0x86, 0x44, 0x97, 0x62, 0xD3, 0x4F, 0xBA, 0x24, 0x16, 0x0B ,0x9F, 0x72, 0x1A, 0x65, 0x68, 0x6D, 0x26, 0xBA, 0x6B, 0xC8, 0x67] 

flag = ""

#字符形式不考虑大小端
check1 = "SWPU_2019_CTF"

#本来是4个字节4个字节的亦或,也可以转换为一个字节一个字节的亦或
#比较是dwrod类型,所以每四个字节需要使用大小端转换

check2 = [0X86,0X0C,0X3E,0XCA,0X98,0XD7,0XAE,0X19,0XE2,0X77,0X6B,0XA6,0X6A,0XA1,0X77,0XB0,0X69,0X91,0X37,0X05,0X7A,0XF9,0X7B,0X30,0X43,0X5A,0X4B,0X10,0X86,0X7D,0XD4,0X28]

for i in range(len(data)):
    #每个数据只亦或一下,所以可以写一起
    flag += chr(data[i] ^ check2[i] ^ ord(check1[i%13]))
print(flag)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I Am Rex

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值