*CTF2022 Re复现

死了活

Simple File System

Simple File System程序挂载flag文件加密,需要找到加密函数进行解密。
找到加密函数sub_21B2((__int64)ptr, v8);,下图地址不同是因为动调
在这里插入图片描述

进行动调,得到v4 = 0xDEEDBEEF,
并且在该处sub_1e16中 a3=1为上述的加密函数,而为2时是随机值
在这里插入图片描述

在这里插入图片描述

所以只有一组正确的数据存于image.flag ,其余均为随机值,并且每个数据间隔0x1000h,
使用加密函数得到*CTF{加密后的值
data[] = {0x2a, 0x43, 0x54, 0x46, 0x7b};
搜索找到加密后的值
在这里插入图片描述

脚本

然后直接爆破

#include <stdio.h>
int main()
{
    unsigned char v5 = 0;
    unsigned char data[32] = {
        0x00, 0xd2, 0xFC, 0xD8, 0xA2, 0xDA, 0xBA, 0x9E, 0x9C, 0x26, 0xF8, 0xF6, 0xB4, 0xCE, 0x3C, 0xCC, 0x96, 0x88, 0x98, 0x34, 0x82, 0xDE, 0x80, 0x36, 0x8A, 0xD8, 0xC0, 0xF0, 0x38, 0xAE, 0x40, 0};
    for (int n = 0; n < 31; n++)
    {
        for (int i = 0; i < 0xff; i++)
        {
            v5 = i;
            v5 = (v5 >> 1) | (v5 << 7);
            v5 ^= 0xef;
            v5 = (v5 >> 2) | (v5 << 6);
            v5 ^= 0xbe;
            v5 = (v5 >> 3) | (32 * v5);
            v5 ^= 0xed;
            v5 = (v5 >> 4) | (16 * v5);
            v5 ^= 0xde;
            v5 = (v5 >> 5) | (8 * v5);
            if (v5 == data[n])
            {
                printf("%c", i);
                break;
            }
        }
    }
    return 0;
}
// *CTF{Gwed9VQpM4Lanf0kEj1oFJR6}

NaCl

找到主函数

__int64 __fastcall sub_8001775(__int64 a1, char a2)
{
  int v2; // edx
  int v3; // ecx
  int v4; // r8d
  int v5; // r9d
  __int64 result; // rax
  char v7[40]; // [rsp+20h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+48h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  sub_8010B50("input:");
  sub_8001940(0LL, v7, 32LL);
  sub_8080900(v7);
  if ( (unsigned int)v7 == 1 )
    sub_800A380((unsigned int)"*CTF{%s}\n", (unsigned int)v7, v2, v3, v4, v5, a2);
  else
    sub_8010B50("failed\n");
  result = 0LL;
  if ( __readfsqword(0x28u) != v8 )
    sub_8047FA0();
  return result;
}

动调了好久,花指令
在这里插入图片描述
nop指令不知道是啥,去掉。
然后 r15寄存器实现了类似堆栈的作用。
将返回地址(sub_8080760)压入r15-8中,然后jmp跳转,可以直接nop掉这三个指令,然后将jmp改为call
在这里插入图片描述
有好几处,都改一下,IDC脚本不太会。。。
在这里插入图片描述
将r15-8的值给edi,然后跳转,类似pop操作,直接改为retn
在这里插入图片描述

xtea ,

__int64 __fastcall sub_8080100(int a1, __int64 a2)
{
  __int64 v2; // r13
  __int64 v3; // r15
  __int64 result; // rax

  *(_DWORD *)(v3 - 36) = a1;
  *(_QWORD *)(v3 - 48) = a2;
  *(_QWORD *)(v3 - 24) = &unk_80AFB40;
  *(_DWORD *)(v3 - 8) = *(_DWORD *)(v2 + (unsigned int)*(_QWORD *)(v3 - 48));
  *(_DWORD *)(v3 - 12) = *(_DWORD *)(v2 + (unsigned int)*(_QWORD *)(v3 - 48) + 4);
  *(_DWORD *)(v3 - 16) = 0;
  *(_DWORD *)(v3 - 28) = 0x10325476;
  for ( *(_DWORD *)(v3 - 4) = 0; *(_DWORD *)(v3 - 4) < *(_DWORD *)(v3 - 36); ++*(_DWORD *)(v3 - 4) )
  {
    *(_DWORD *)(v3 - 8) += (((*(_DWORD *)(v3 - 12) >> 5) ^ (16 * *(_DWORD *)(v3 - 12))) + *(_DWORD *)(v3 - 12)) ^ (*(_DWORD *)(v2 + 4 * (*(_DWORD *)(v3 - 16) & 3) + (unsigned int)*(_QWORD *)(v3 - 24)) + *(_DWORD *)(v3 - 16));
    *(_DWORD *)(v3 - 16) += *(_DWORD *)(v3 - 28);
    *(_DWORD *)(v3 - 12) += (((*(_DWORD *)(v3 - 8) >> 5) ^ (16 * *(_DWORD *)(v3 - 8))) + *(_DWORD *)(v3 - 8)) ^ (*(_DWORD *)(v2 + 4 * ((*(_DWORD *)(v3 - 16) >> 11) & 3) + (unsigned int)*(_QWORD *)(v3 - 24)) + *(_DWORD *)(v3 - 16));
  }
  *(_DWORD *)(v2 + (unsigned int)*(_QWORD *)(v3 - 48)) = *(_DWORD *)(v3 - 8);
  result = *(unsigned int *)(v3 - 12);
  *(_DWORD *)(v2 + (unsigned int)*(_QWORD *)(v3 - 48) + 4) = result;
  return result;
}

还有费斯托加密,动调可以得到需要的key

unsigned int dword_80AFB60[44] = {
        0x04050607, 0x00010203, 0x0C0D0E0F, 0x08090A0B, 0xCD3FE81B, 0xD7C45477, 0x9F3E9236, 0x0107F187,
        0xF993CB81, 0xBF74166C, 0xDA198427, 0x1A05ABFF, 0x9307E5E4, 0xCB8B0E45, 0x306DF7F5, 0xAD300197,
        0xAA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0xC6CB1E7D, 0x18EB0D7A, 0xD4EC4800, 0xB486F92B,
        0x8737F9F3, 0x765E3D25, 0xDB3D3537, 0xEE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3,
        0x896E10A2, 0x2247F0C0, 0xB84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C,
        0xFC27B826, 0x5FDDDFBC, 0xDE0FC404, 0xB2B30907
};

脚本

最后是小端序

unsigned int dword_80AFB60[44] = {
        0x04050607, 0x00010203, 0x0C0D0E0F, 0x08090A0B, 0xCD3FE81B, 0xD7C45477, 0x9F3E9236, 0x0107F187,
        0xF993CB81, 0xBF74166C, 0xDA198427, 0x1A05ABFF, 0x9307E5E4, 0xCB8B0E45, 0x306DF7F5, 0xAD300197,
        0xAA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0xC6CB1E7D, 0x18EB0D7A, 0xD4EC4800, 0xB486F92B,
        0x8737F9F3, 0x765E3D25, 0xDB3D3537, 0xEE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3,
        0x896E10A2, 0x2247F0C0, 0xB84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C,
        0xFC27B826, 0x5FDDDFBC, 0xDE0FC404, 0xB2B30907
};

DWORD xtea_key[4] = { 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C };

void decipher(unsigned int num_rounds, DWORD v[2], DWORD key[4]) {
        unsigned int i;
        DWORD v0 = v[0], v1 = v[1], delta = 0x10325476, sum = delta * num_rounds;
        for (i = 0; i < num_rounds; i++) {
                v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
                sum -= delta;
                v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        }
        v[0] = v0; v[1] = v1;
}

void enc11(DWORD* v)
{
        for (int i = 0; i < 44; i++)
        {
                DWORD tmp = v[0];
                v[0] = (LeftRotate(v[0], 1) & LeftRotate(v[0], 8)) ^ LeftRotate(v[0], 2) ^ v[1] ^ dword_80AFB60[i];
                v[1] = tmp;
        }
        DWORD tmp = v[0];
        v[0] = v[1];
        v[1] = tmp;
}

void dec11(DWORD* v)
{
        DWORD tmp = v[0];
        v[0] = v[1];
        v[1] = tmp;
        for (int i = 0; i < 44; i++)
        {
                tmp = v[0];
                v[0] = v[1];
                v[1] = (LeftRotate(v[0], 1) & LeftRotate(v[0], 8)) ^ LeftRotate(v[0], 2) ^ tmp ^ dword_80AFB60[43-i];
        }
}

int main()
{
        DWORD enc[] = { 0xFDF5C266, 0x7A328286, 0xCE944004, 0x5DE08ADC, 0xA6E4BD0A, 0x16CAADDC, 0x13CD6F0C, 0x1A75D936 };

        //input = "1234567890abcdefghijklmn12366666"
        //DWORD enc[] = { 0x4A16D2F5, 0x3995DF74, 0xC0B2BC9A, 0x313495AC, 0x207EAA57, 0x5C46F1CB, 0x9AB2B6D3, 0xF0E536C3 };
        DWORD rounds[] = { 2, 4, 8, 16 };
        for (int i = 0; i < 8; i += 2)
        {
                decipher(rounds[i / 2], &enc[i], xtea_key);
                dec11(&enc[i]);
        }
        char* flag = (char*)enc;

        for (int i = 0; i < 32; i += 4)
        {
                printf("%c", flag[i+3]);
                printf("%c", flag[i + 2]);
                printf("%c", flag[i + 1]);
                printf("%c", flag[i]);
        }
        return 0;
}
// mM7pJIobsCTQPO6R0g-L8kFExhYuivBN

jump没看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值