强网杯2019逆向 just re lebel:string2hex(string2decimal是atoi) / ida识别字符串有点小Bug? / rdtsc / 3DES(可PEiD插件识别)

静态分析

定位关键函数

通过字符串定位到关键函数,输入为flag{}括号里的值,长度应该为26
注意到函数指针byte_4018A0,联想到了SMC,会有写入它的地方

  if ( sub_401610((int)&v1, (int)&savedregs) 
  	&& ((int (__thiscall *)(char *))byte_4018A0)(&v1) )
  {
    puts("congrats!");
    sub_401CA0("flag{%.26s}\n\n", &v1);
    result = 0;
  }

找与输入相关的地方

  index1 = 0;
  while ( 1 )
  {
    v5 = *(_BYTE *)(index1 + input);
    if ( v5 >= '0' && v5 <= '9' )               // 输入为数字
    {
      v6 = v5 - 0x41;
      goto LABEL_6;
    }
    v6 = v5 - 0x41;                             // A-F转为0-5
    if ( (unsigned __int8)(v5 - 0x41) > 0x19u ) // v5 > 0x5a,输入为a-z
      break;
LABEL_6:
    v3 *= 16;
    if ( (unsigned __int8)(v5 - 0x30) <= 9u )   // 输入为数字
    {
      v7 = v3 - 0x30;
LABEL_10:
      v3 = v5 + v7;
      goto LABEL_11;
    }
    if ( v6 <= 25u )                            // A-Z
    {
      v7 = v3 - 0x37;                           // A-F转为10-15
      goto LABEL_10;
    }
LABEL_11:
    if ( ++index1 >= 8 )                        // 循环8次
    {
      v8 = 1;
      goto LABEL_14;
    }
  }

又是熟悉的输入范围判断,追一遍流程就行
根据 0-9减0x30,A-F减0x37,v3 *= 16 推出应是对前8位进行了string2hex
后面有对第9和第10个数进行操作的代码,分析了一下应该也是判断范围,没什么特别的

找return 1

  v9 = _mm_shuffle_epi32(_mm_cvtsi32_si128(v3), 0);

  ..............
  
  v18 = _mm_cvtsi32_si128((char)v11);
  v19 = _mm_unpacklo_epi8(v18, v18);
  v27 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v19, v19), 0);
  if ( v17 )
  {
    v20 = 0;
    if ( dword_4053C4 >= 2 )
    {
      v20 = 16;
      v21 = _mm_mullo_epi32(_mm_cvtepu8_epi32(_mm_cvtsi32_si128(v27.m128i_u32[0])), (__m128i)xmmword_404380);
      xmmword_405018 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32((__m128i)xmmword_404340, v9),
                                   _mm_add_epi32(v21, (__m128i)xmmword_405018));
      xmmword_405028 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404350, (__m128i)xmmword_404340), v9),
                                   _mm_add_epi32(v21, (__m128i)xmmword_405028));
      xmmword_405038 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404360, (__m128i)xmmword_404340), v9),
                                   _mm_add_epi32(v21, (__m128i)xmmword_405038));
      xmmword_405048 = (__int128)_mm_xor_si128(
                                   _mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404370, (__m128i)xmmword_404340), v9),
                                   _mm_add_epi32(v21, (__m128i)xmmword_405048));
    }
    do
    {
      *((_DWORD *)&xmmword_405018 + v20) = (v20 + v3) ^ (0x1010101 * v11 + *((_DWORD *)&xmmword_405018 + v20));
      ++v20;
    }
    while ( v20 < 24 );
    v22 = 0;
    while ( *((_BYTE *)&xmmword_405018 + v22) == *((_BYTE *)&loc_404148 + v22) )
    {
      if ( ++v22 >= 96 )
      {
        v28 = 0;
        v23 = __rdtsc();
        if ( HIDWORD(v23) > HIDWORD(v26) || (v28 = v23 - v26, (unsigned int)(v23 - v26) >= 0xFFFFFF) )
          MEMORY[0] = 0;
        v24 = GetCurrentProcess();
        WriteProcessMemory(v24, &byte_4018A0, &xmmword_405018, 96u, 0);
        return 1;
      }
    }
  }
  return 0;
}

参与xmmword运算的v9和前8位有关,v21和9,10位有关

while ( *((_BYTE *)&xmmword_405018 + v22) == *((_BYTE *)&loc_404148 + v22) )
*((_DWORD *)&xmmword_405018 + v20) = (v20 + v3) ^ (0x1010101 * v11 + *((_DWORD *)&xmmword_405018 + v20))

25510约为107数量级
v3是int,v11是byte,爆破范围v3为0x10000000-0xFFFFFFFF,v11为0-0xFF
不过自己确实没搞懂爆破这一步…略过
在这里插入图片描述

v24 = GetCurrentProcess();
WriteProcessMemory(v24, &byte_4018A0, &xmmword_405018, 96u, 0);

写入byte_4018A0,写入的96字节只是真个函数的一部分

3DES(可PEiD插件识别)

OWORD输入的后16位

  v1 = *(_OWORD *)(a1 + 10);

xmmword处,正常来说正确的结果应该是ida识别的字符串的倒序
在这里插入图片描述
在这里插入图片描述
&v23存了Src的24个Byte,再结合&v21为三个函数参数,v23,v25,v27相差八个字节,这里很像3个Key,那么就是三重DES

  Src = xmmword_4041A8;
  v2 = strlen((const char *)&Src);
  memcpy(&v23, &Src, v2);
  memset((char *)&v23 + v2, 0, 24 - v2);
  v21 = v23;
  v22 = v24;
  sub_401000(&v21, &v20);
  v21 = v25;
  v22 = v26;
  sub_401000(&v21, &v19);
  v21 = v27;
  v22 = v28;
  sub_401000(&v21, &v18);

/8说明输入长度最好为8的倍数,正常明文是64位8字节,这里正好得16,16是加密轮数
DES循环左移 [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
3DES循环左移{ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0 };

然后到这,v21应该是明文,同时可得到加密后的结果应该要为v12

v21 = ((unsigned __int8)*(&v32 + v5) << 24) | ((unsigned __int8)*(&v31 + v5) << 16) | ((unsigned __int8)*(&v30 + v5) << 8) | (unsigned __int8)*(&Dst + v5);
.........
sub_401500((unsigned int *)&v21, (int)&v20, (int)&v19, (int)&v18);
*(&v37 + v5) = v21;
........
  *(_QWORD *)&v12 = 0xFACE0987E6A97C50i64;
  v10 = 0;
  *((_QWORD *)&v12 + 1) = 0x6C97BB90CF0DD520i64;
  v13 = -1326018416;
  v14 = -391862661;
  while ( *((_BYTE *)&v12 + v10) == *(&v37 + v10) )
  {
    if ( ++v10 >= 16 )
      return 1;
  }

1 0 1像3DES解密的的EDE,a2 a3 a4对应三个Key

  sub_401250(a2, this, 1);
  sub_401250(a3, v4, 0);
  sub_401250(a4, v4, 1);

进入sub_401250
函数内跟踪1 0 1分析其代表的是加密模式还是解密模式
因为DES解密密钥要反过来,所以跟踪第一个参数 密钥 的变化
在if(a3)内v17 += 4; else里v18 -= 4;所以1为加密,0为解密

解题脚本

from Crypto.Cipher import DES
s = '\x50\x7C\xA9\xE6\x87\x09\xCE\xFA\x20\xD5\x0D\xCF\x90\xBB\x97\x6C'
des0 = DES.new('AFSAFCED', DES.MODE_ECB)
des1 = DES.new('YCXCXACN', DES.MODE_ECB)
des2 = DES.new('DFKDCQXC', DES.MODE_ECB)
#加密是E(0)D(1)E(2)所以解密D(2)E(1)D(0)
text = des0.decrypt(des1.encrypt(des2.decrypt(s)))
print text

其它一些点

rdtsc可用来获得程序或者一段代码运行的时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

q1uTruth

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

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

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

打赏作者

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

抵扣说明:

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

余额充值