2025/2/15

xx

exe文件,运行一下,发现什么都没有

查壳,无壳,64位文件

拖入ida,看main,像c++,掏出ai分析一波

int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rbx
  __int64 v4; // rax
  __int128 *v5; // rax
  __int64 v6; // r11
  __int128 *v7; // r14
  int v8; // edi
  __int128 *v9; // rsi
  char v10; // r10
  int v11; // edx
  __int64 v12; // r8
  unsigned __int64 v13; // rcx
  __int64 v14; // rcx
  unsigned __int64 v15; // rax
  unsigned __int64 i; // rax
  __int64 v17; // rax
  size_t v18; // rsi
  _BYTE *v19; // rbx
  _BYTE *v20; // r9
  int v21; // r11d
  char *v22; // r8
  __int64 v23; // rcx
  char v24; // al
  __int64 v25; // r9
  __int64 v26; // rdx
  __int64 v27; // rax
  size_t Size; // [rsp+20h] [rbp-48h] BYREF
  __int128 v30; // [rsp+28h] [rbp-40h] BYREF
  int v31; // [rsp+38h] [rbp-30h]
  int v32; // [rsp+3Ch] [rbp-2Ch]
  int Code[4]; // [rsp+40h] [rbp-28h] BYREF
  int v34; // [rsp+50h] [rbp-18h]

  *(_OWORD *)Code = 0i64;
  v34 = 0;
  sub_1400018C0(std::cin, argv, Code);
  v3 = -1i64;
  v4 = -1i64;
  do
    ++v4;
  while ( *((_BYTE *)Code + v4) );
  if ( v4 != 19 )
  {
    sub_140001620(std::cout, "error\n");
    _exit((int)Code);
  }
  v5 = (__int128 *)operator new(5ui64);
  v6 = *(_QWORD *)&::Code;
  v7 = v5;
  v8 = 0;
  v9 = v5;
  do
  {
    v10 = *((_BYTE *)v9 + (char *)Code - (char *)v5);
    v11 = 0;
    *(_BYTE *)v9 = v10;
    v12 = 0i64;
    v13 = -1i64;
    do
      ++v13;
    while ( *(_BYTE *)(v6 + v13) );
    if ( v13 )
    {
      do
      {
        if ( v10 == *(_BYTE *)(v6 + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < v13 );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(v6 + v14) );
    if ( v11 == v14 )
      _exit(v6);
    v9 = (__int128 *)((char *)v9 + 1);
  }
  while ( (char *)v9 - (char *)v5 < 4 );
  *((_BYTE *)v5 + 4) = 0;
  do
    ++v3;
  while ( *((_BYTE *)Code + v3) );
  v15 = 0i64;
  v30 = *v7;
  while ( *((_BYTE *)&v30 + v15) )
  {
    if ( !*((_BYTE *)&v30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )
    *((_BYTE *)&v30 + i) = 0;
  v17 = sub_140001AB0(Code, v3, &v30, &Size);
  v18 = Size;
  v19 = (_BYTE *)v17;
  v20 = operator new(Size);
  v21 = 1;
  *v20 = v19[2];
  v22 = v20 + 1;
  v20[1] = *v19;
  v20[2] = v19[3];
  v20[3] = v19[1];
  v20[4] = v19[6];
  v20[5] = v19[4];
  v20[6] = v19[7];
  v20[7] = v19[5];
  v20[8] = v19[10];
  v20[9] = v19[8];
  v20[10] = v19[11];
  v20[11] = v19[9];
  v20[12] = v19[14];
  v20[13] = v19[12];
  v20[14] = v19[15];
  v20[15] = v19[13];
  v20[16] = v19[18];
  v20[17] = v19[16];
  v20[18] = v19[19];
  v20[19] = v19[17];
  v20[20] = v19[22];
  v20[21] = v19[20];
  v20[22] = v19[23];
  for ( v20[23] = v19[21]; v21 < v18; ++v22 )
  {
    v23 = 0i64;
    if ( v21 / 3 > 0 )
    {
      v24 = *v22;
      do
      {
        v24 ^= v20[v23++];
        *v22 = v24;
      }
      while ( v23 < v21 / 3 );
    }
    ++v21;
  }
  *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;
  v25 = v20 - (_BYTE *)&v30;
  *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = -939386845;
  v32 = -95004953;
  do
  {
    if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );
  v27 = sub_140001620(std::cout, "You win!");
  std::ostream::operator<<(v27, sub_1400017F0);
  return 0;
}
*(_OWORD *)Code = 0i64;
  v34 = 0;
  sub_1400018C0(std::cin, argv, Code);
  v3 = -1i64;
  v4 = -1i64;
  do
    ++v4;
  while ( *((_BYTE *)Code + v4) );
  if ( v4 != 19 )
  {
    sub_140001620(std::cout, "error\n");

输入的明文长度必须是19位

do
{
    v10 = *((_BYTE *)v9 + (char *)Code - (char *)v5);
    v11 = 0;
    *(_BYTE *)v9 = v10;
    v12 = 0i64;
    v13 = -1i64;
    do
        ++v13;
    while ( *(_BYTE *)(v6 + v13) );
    if ( v13 )
    {
        do
        {
            if ( v10 == *(_BYTE *)(v6 + v12) )
                break;
            ++v11;
            ++v12;
        }
        while ( v11 < v13 );
    }
    v14 = -1i64;
    do
        ++v14;
    while ( *(_BYTE *)(v6 + v14) );
    if ( v11 == v14 )
        _exit(v6);
    v9 = (__int128 *)((char *)v9 + 1);
}
while ( (char *)v9 - (char *)v5 < 4 );
*((_BYTE *)v5 + 4) = 0;

输入的内容检查 是否在 Code 中出现过,并记录其位置

简单来说就是输入的必须是qwertyuiopasdfghjklzxcvbnm1234567890中的字符

  v5 = (__int128 *)operator new(5ui64);
  v6 = *(_QWORD *)&::Code;
  v7 = v5;
  v8 = 0;
  v9 = v5;
  do
  {
    v10 = *((_BYTE *)v9 + (char *)Code - (char *)v5);
    v11 = 0;
    *(_BYTE *)v9 = v10;
    v12 = 0i64;
    v13 = -1i64;
    do
      ++v13;
    while ( *(_BYTE *)(v6 + v13) );
    if ( v13 )
    {
      do
      {
        if ( v10 == *(_BYTE *)(v6 + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < v13 );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(v6 + v14) );
    if ( v11 == v14 )
      _exit(v6);
    v9 = (__int128 *)((char *)v9 + 1);
  }
  while ( (char *)v9 - (char *)v5 < 4 );
  *((_BYTE *)v5 + 4) = 0;
  do
    ++v3;
  while ( *((_BYTE *)Code + v3) );
 

这一部分是最难懂的,我看别人的是取前4位(作为后面加密的key),验证这4位都在‘qwertyuiopasdfghjklzxcvbnm1234567890‘中

 v15 = 0i64;
  v30 = *v7;
  while ( *((_BYTE *)&v30 + v15) )
  {
    if ( !*((_BYTE *)&v30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )
    *((_BYTE *)&v30 + i) = 0;

用0将key填充到16位

v17 = sub_140001AB0(Code, v3, &v30, &Size)

sub_140001AB0跟进后是xxtea加密

 v20[1] = *v19;
  v20[2] = v19[3];
  v20[3] = v19[1];
  v20[4] = v19[6];
  v20[5] = v19[4];
  v20[6] = v19[7];
  v20[7] = v19[5];
  v20[8] = v19[10];
  v20[9] = v19[8];
  v20[10] = v19[11];
  v20[11] = v19[9];
  v20[12] = v19[14];
  v20[13] = v19[12];
  v20[14] = v19[15];
  v20[15] = v19[13];
  v20[16] = v19[18];
  v20[17] = v19[16];
  v20[18] = v19[19];
  v20[19] = v19[17];
  v20[20] = v19[22];
  v20[21] = v19[20];
  v20[22] = v19[23];

加密后的结果位置互换

 for ( v20[23] = v19[21]; v21 < v18; ++v22 )
  {
    v23 = 0i64;
    if ( v21 / 3 > 0 )
    {
      v24 = *v22;
      do
      {
        v24 ^= v20[v23++];
        *v22 = v24;
      }
      while ( v23 < v21 / 3 );
    }
    ++v21;
  }
  *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;
  v25 = v20 - (_BYTE *)&v30;
  *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = -939386845;
  v32 = -95004953;
  do
  {
    if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );
  v27 = sub_140001620(std::cout, "You win!");
  std::ostream::operator<<(v27, sub_1400017F0);
  return 0;
}

最后就是异或和比较

脚本是别人的

import struct

_DELTA = 0x9E3779B9


def _long2str(v, w):
    n = (len(v) - 1) << 2
    if w:
        m = v[-1]
        if (m < n - 3) or (m > n): return ''
        n = m
    s = struct.pack('<%iL' % len(v), *v)
    return s[0:n] if w else s


def _str2long(s, w):
    n = len(s)
    m = (4 - (n & 3) & 3) + n
    s = s.ljust(m, b"\0")
    v = list(struct.unpack('<%iL' % (m >> 2), s))
    if w: v.append(n)
    return v


def encrypt(str, key):
    if str == '': return str
    v = _str2long(str, True)
    k = _str2long(key.ljust(16, b"\0"), False)
    n = len(v) - 1
    z = v[n]
    y = v[0]
    sum = 0
    q = 6 + 52 // (n + 1)
    while q > 0:
        sum = (sum + _DELTA) & 0xffffffff
        e = sum >> 2 & 3
        for p in  range(n):
            y = v[p + 1]
            v[p] = (v[p] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
            z = v[p]
        y = v[0]
        v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff
        z = v[n]
        q -= 1
    return _long2str(v, False)


def decrypt(str, key):
    if str == '': return str
    v = _str2long(str, False)
    k = _str2long(key.ljust(16, b"\0"), False)
    n = len(v) - 1
    z = v[n]
    y = v[0]
    q = 6 + 52 // (n + 1)
    sum = (q * _DELTA) & 0xffffffff
    while (sum != 0):
        e = sum >> 2 & 3
        for p in range(n, 0, -1):
            z = v[p - 1]
            v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
            y = v[p]
        z = v[n]
        v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
        y = v[0]
        sum = (sum - _DELTA) & 0xffffffff
    return _long2str(v, True)
tg=[0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B, 0x20, 0x20, 0x91, 0xF7, 0x02, 0x35,
    0x23, 0x18, 0x02, 0xC8, 0xE7, 0x56, 0x56, 0xFA ]
order=[2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
flag=[0]*24
for i in range(23,-1,-1):
    for j in range(i//3):
        tg[i]^=tg[j]
print('逆异或操作后:'+' '.join(map(hex,tg)))
for i in range(24):
    flag[order[i]]=tg[i]
print('逆加密字符串替换后:'+' '.join(map(hex,flag)))
x=decrypt(bytes(flag),'flag'.encode())
print(x)

seven

下载附件,sys文件,很少见,查一下,

.sys 文件是 Windows 操作系统中的系统文件,通常用于存储设备驱动程序、系统设置和核心功能

直接拖入ida,(拖入后能发现是64位)

函数是比较少的,先查找一下字符串

看到星星和点,第一反应可能是迷宫题

跟进看一下代码

__int64 __fastcall sub_1400012F0(__int64 a1, __int64 a2)
{
  __int64 v3; // rsi
  unsigned __int64 v4; // rdx
  int v5; // ecx
  __int16 *v6; // rdi
  __int64 v7; // rbp
  __int16 v8; // dx
  char v9; // dl
  const CHAR *v10; // rcx

  if ( *(int *)(a2 + 48) >= 0 )
  {
    v3 = *(_QWORD *)(a2 + 24);
    v4 = *(_QWORD *)(a2 + 56) / 0xCui64;
    if ( (_DWORD)v4 )
    {
      v5 = dword_1400030E4;
      v6 = (__int16 *)(v3 + 2);
      v7 = (unsigned int)v4;
      while ( *(_WORD *)(v3 + 4) )
      {
LABEL_30:
        v6 += 6;
        if ( !--v7 )
          goto LABEL_31;
      }
      aO[v5] = 46;
      v8 = *v6;
      if ( *v6 == 17 )
      {
        if ( (v5 & 0xFFFFFFF0) != 0 )
        {
          v5 -= 16;
          goto LABEL_13;
        }
        v5 += 208;
        dword_1400030E4 = v5;
      }
      if ( v8 != 31 )
        goto LABEL_14;
      if ( (v5 & 0xFFFFFFF0) == 208 )
        v5 -= 208;
      else
        v5 += 16;
LABEL_13:
      dword_1400030E4 = v5;
LABEL_14:
      if ( v8 == 30 )
      {
        if ( (v5 & 0xF) != 0 )
          --v5;
        else
          v5 += 15;
        dword_1400030E4 = v5;
      }
      if ( v8 == 32 )
      {
        if ( (v5 & 0xF) == 15 )
          v5 -= 15;
        else
          ++v5;
        dword_1400030E4 = v5;
      }
      v9 = aO[v5];
      if ( v9 == 42 )
      {
        v10 = "-1s\n";
      }
      else
      {
        if ( v9 != 55 )
        {
LABEL_29:
          aO[v5] = 111;
          goto LABEL_30;
        }
        v10 = "The input is the flag!\n";
      }
      dword_1400030E4 = 16;
      DbgPrint(v10);
      v5 = dword_1400030E4;
      goto LABEL_29;
    }
  }
LABEL_31:
  if ( *(_BYTE *)(a2 + 65) )
    *(_BYTE *)(*(_QWORD *)(a2 + 184) + 3i64) |= 1u;
  return *(unsigned int *)(a2 + 48);
}

ai分析一下,v5只能是17, 31, 30, 32,最后并遍历检验了一下

  • 如果 v942,输出 "-1s\n"
  • 如果 v955,输出 "The input is the flag!\n",并将 dword_1400030E4 设为 16

十六进制17-->w; 31-->s; 30-->a; 32-->d

分别对应上,下,左,右。

能走点,不能走*

分析完毕,看地图

为了便于移动和字母大小一样,我改了下字母,理论上通过代码可以分析出迷宫的长和宽,但我不想看了,就这样简单弄了一下,已经能看出迷宫的大致样子

hctf{ddddddddddddddssaasasasasasasasasas}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值