吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7138|回复: 27
收起左侧

[CTF] 2018nctf几道逆向题

  [复制链接]
姚小宝 发表于 2018-11-25 22:34
本帖最后由 yechen123 于 2019-2-9 15:55 编辑

这两天比赛挺多了  

利用空余时间看了下题目
发个帖子记录一下

上传题目  别的两道题目没有存有。。
nctf.rar (56.01 KB, 下载次数: 14)

南邮杯的 题目大部分都不怎么难

0.后门后门后门

没啥技术含量
hereisyourflag();  里边就是flag



1.基本操作
看代码
[Asm] 纯文本查看 复制代码
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 result; // rax

  puts("Input flag:");
  __isoc99_scanf("%64s", &byte_601100);
  dword_601064 = 0;
  sub_400666(0LL);
  if ( !strcmp(&s1, "bcec8d7dcda25d91ed3e0b720cbb6cf202b09fedbc3e017774273ef5d5581794") )
  {
    memset(&s1, 0, 0x80uLL);
    dword_601064 = 0;
    sub_4006BE(0LL, 0LL);
    if ( !strcmp(&s1, "7d8dcdcaed592e1dcb07e02c36bcb2f0bf9e0bdcb0e13777237e25fd48515974") )
      printf("TQL! TQL! flag: nctf{%s}\n", &byte_601100);
    else
      puts("Emmmm.....");
    result = 0LL;
  }
  else
  {
    puts("GG!");
    result = 0LL;
  }
  return result;
}

输入字符串后经过变换后
再跟字符串比较得到就是flag
看变换函数
[Asm] 纯文本查看 复制代码
__int64 __fastcall sub_400666(signed int a1)
{
  int v1; // eax
  __int64 result; // rax

  if ( a1 <= 63 )
  {
    v1 = dword_601064++;
    *(&s1 + v1) = byte_601100[a1];
    sub_400666((unsigned int)(2 * a1 + 1));
    result = sub_400666((unsigned int)(2 * (a1 + 1)));
  }
  return result;
}

懒得写脚本
直接按照ascii码生成一串有序字符串
然后再看如何变换
[Asm] 纯文本查看 复制代码
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\\]^
_`abcdefghijklmn

变换之后
[Asm] 纯文本查看 复制代码
0137?OnP@QR8ASTB
UV49CWXDYZ:E[\F\
]25;G^_H`a<IbcJd
e6=KfgLhi>MjkNlm

看变换之后的字符串
[Asm] 纯文本查看 复制代码
bcec8d7dcda25d91
ed3e0b720cbb6cf2
02b09fedbc3e0177
74273ef5d5581794

逆推得到flag
[Asm] 纯文本查看 复制代码
bc2e3b4c2eb03258c5102bf9de77f57dddad9edb70c6c20febc01773e5d81947

1.png


2.Some Boxes
[Asm] 纯文本查看 复制代码
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int v3; // eax
  int i; // [rsp+8h] [rbp-8h]
  int len; // [rsp+Ch] [rbp-4h]

  sub_4007D9();
  read(0, buf, 1000uLL);
  len = strlen(buf);
  for ( i = 0; i < len; ++i )
  {
    v3 = buf[i];
    if ( v3 == 52 )                             // 4
    {
      sub_400C62();                             //
      goto LABEL_14;
    }
    if ( v3 > 52 )
    {
      if ( v3 == 53 )                           // 5
      {
        sub_400D5D();                           // 下
        goto LABEL_14;
      }
      if ( v3 == 87 )                           // W
      {
        sub_400B67();                           // 上
        goto LABEL_14;
      }
    }
    else if ( v3 == 48 )                        // 0
    {
      sub_400A6C();                             // 右
      goto LABEL_14;
    }
    puts("error!");
LABEL_14:
    sub_400E58();
  }
  return 0LL;
}

题目显示play a game  

题目会允许输入1000个字符
但是只能是4 5 W 0 是控制方向的  否则报错
先看看判断成功的函数
[Asm] 纯文本查看 复制代码
__int64 sub_400E58()
{
  __int64 result; // rax

  result = (unsigned __int8)byte_6020A0[16 * flag_one_hang + flag_one_lie];
  if ( (_BYTE)result == 20 )
  {
    result = (unsigned __int8)byte_6020A0[16 * flag_two_hang + flag_two_lie];
    if ( (_BYTE)result == 20 )
    {
      puts(&byte_4018EE);
      system("cat flag");
      exit(0);
    }
  }
  return result;
}

最终要这两个值返回20
看一下迷宫
[Asm] 纯文本查看 复制代码
08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 
08 08 00 00 08 08 08 08 08 08 08 08 00 00 08 08 
08 08 00 00 00 00 00 08 00 00 00 00 00 00 08 08 
08 08 00 08 08 00 00 00 00 00 08 08 08 00 00 08 
08 08 00 08 08 00 08 08 00 00 08 14 00 00 00 08 
08 08 00 00 08 00 00 00 00 00 08 08 08 08 08 08 
08 08 00 00 08 08 08 08 00 08 08 08 08 08 08 08 
08 08 00 08 08 08 08 08 00 08 08 00 00 00 08 08 
08 00 00 08 14 08 00 08 00 00 00 00 08 00 08 08 
08 00 00 00 00 00 00 00 00 08 08 08 08 00 08 08 
08 00 00 00 00 08 08 08 00 08 00 00 00 00 08 08 
08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 08 

在看一下方向控制函数 看看是一个什么游戏
[Asm] 纯文本查看 复制代码
__int64 sub_400C62()
{
  __int64 result; // rax

  result = (unsigned __int8)byte_6020A0[16 * hang - 1 + lie];
  if ( (_BYTE)result != 8 )                     // 如果是通路
  {
    if ( lie - 1 != flag_one_lie || hang != flag_one_hang )// 
    {
      if ( lie - 1 == flag_two_lie && hang == flag_two_hang )// 需要和2冲突
      {
        if ( byte_6020A0[16 * flag_two_hang - 1 + flag_two_lie] == 8 )// 如果二左移撞墙
          ++lie;                                // 那主键就不移动
        else
          sub_400A1C(&flag_two_lie);            // 否则二左移
      }
    }
    else if ( byte_6020A0[16 * flag_one_hang - 1 + flag_one_lie] == 8 )// 如果此时一左移撞墙
    {
      ++lie;                                    // 主键不移动
    }
    else                                        // 如果冲突了 
    {
      sub_400A1C(&flag_one_lie);                // one_lie左移
    }
    result = (unsigned int)(lie-- - 1);
  }
  return result;
}

说明 控制自己是主要的  另外还有两个值也在迷宫中
当主键移动时候 如果主键碰到强 也就是08  那就不移动 如果碰到另外两个值
如果另外两个值向着相同方向移动会碰墙 那就不移动
最终要使两个值推到0x14的方格中
那就是推箱子了
看看初始化位置
[Asm] 纯文本查看 复制代码
void sub_400796()
{
  lie = 8;
  hang = 5;
  flag_one_lie = 5;
  flag_one_hang = 2;
  flag_two_lie = 8;
  flag_two_hang = 7;
}

ok
4代表左 5是下 0是右 W是上
2.png
得到
WW44W444W45555555450050W0000WWWWW5444WW00050W4W0000W0550544
3.png

4.VM VM题目基本没怎么做过 只是了解一点加密过程  可能会有错误

一个vm程序
看主要代码
[Asm] 纯文本查看 复制代码
__int64 sub_400DAB()
{
  int v1; // [rsp+Ch] [rbp-54h]
  void *liuchengbiao; // [rsp+10h] [rbp-50h]
  char *v3; // [rsp+18h] [rbp-48h]
  int *v4; // [rsp+20h] [rbp-40h]
  int *v4_one; // [rsp+28h] [rbp-38h]
  int *v4_two; // [rsp+30h] [rbp-30h]
  int *v4_three; // [rsp+38h] [rbp-28h]
  char *v8; // [rsp+40h] [rbp-20h]
  char *v9; // [rsp+48h] [rbp-18h]
  _DWORD *v10; // [rsp+50h] [rbp-10h]
  unsigned __int64 v11; // [rsp+58h] [rbp-8h]

  v11 = __readfsqword(0x28u);
  v1 = 0;                                       // 
  liuchengbiao = malloc(0x200uLL);              // 1653010
  v3 = (char *)malloc(0x1400uLL);               // 1653220
  memset(&v4, 0, 48uLL);
  memcpy(liuchengbiao, &unk_6021C0, 0x190uLL);
  v4 = (int *)malloc(0x38uLL);                  // 1654630
  v4_one = v4 + 1;                              // 可能是寄存器
  v4_two = v4 + 2;
  v4_three = v4 + 3;
  v8 = v3 + 5120;
  v9 = v3 + 5120;
  v10 = liuchengbiao;
LABEL_26:
  while ( *v10 )
  {
    switch ( (char)*v10 )
    {
      case 8:
        sub_40082B((&v4)[v10[1] - 1], v10[2], &v10);// 把v10[2]的值放到 第v10[1]-1块寄存器 
        goto LABEL_26;
      case 9:
        sub_40096D((&v4)[v10[1] - 1], (_DWORD **)&v8, &v10);// v8值赋值给寄存器
        goto LABEL_26;
      case 0xA:
        sub_400927((&v4)[v10[1] - 1], &v8, &v10);// 寄存器值复制给v8 两个相差不远
        goto LABEL_26;
      case 0xB:
        input_flag(v4, &v10);                   // flag存到寄存器中 每次就存一个字符
        goto LABEL_26;
      case 0xC:
        sub_4009E5(v4, &v10);
        goto LABEL_26;
      case 0xD:
        sub_400B5D(&v1, (&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);// 比较两个操作寄存器大小 并操作v1的值 下一个函数(F)会根据v1的值跳转
        goto LABEL_26;
      case 0xE:
        sub_400A34(&v10, v10[1], (__int64)liuchengbiao);// 根据v10[1]决定跳转到liucjhengbiao哪个个值
        goto LABEL_26;
      case 0xF:
        sub_400AAF(v1, (signed __int64 *)&v10, v10[1], (__int64)liuchengbiao);// 跳转
        goto LABEL_26;
      case 0x10:
        sub_400A61(v1, (signed __int64 *)&v10, v10[1], (__int64)liuchengbiao);
        goto LABEL_26;
      case 0x11:
        sub_400AFD((&v4)[v10[1] - 1], &v10);    // 寄存器自增
        goto LABEL_26;
      case 0x12:
        sub_400B2D((&v4)[v10[1] - 1], &v10);
        goto LABEL_26;
      case 0x13:
        sub_400C0E((&v4)[v10[1] - 1], v10[2], &v10);// 让寄存器一加上流程表的值
        goto LABEL_26;
      case 0x14:
        sub_400C43((&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);// 寄存器1减去寄存器2
        goto LABEL_26;
      case 0x15:
        sub_400C7C((&v4)[v10[1] - 1], v10[2], &v10);// 让寄存器的值^上流程表的值
        goto LABEL_26;
      case 0x16:
        sub_400CB1((&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);
        goto LABEL_26;
      case 0x17:
        sub_400CEA((&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);
        goto LABEL_26;
      case 0x19:
        sub_400858((&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);// 寄存器赋值
        goto LABEL_26;
      case 0x1A:
        sub_400889((&v4)[v10[1] - 1], (unsigned __int64)(&v4)[v10[2] - 1], &v10);
        goto LABEL_26;
      case 0x1B:
        sub_4008BA((&v4)[v10[1] - 1], (unsigned int *)(&v4)[v10[2] - 1], &v10);// 把寄存器二的值作为地址指向的值给寄存器1
        goto LABEL_26;
      case 0x1C:
        sub_4008EF((unsigned int *)(&v4)[v10[1] - 1], (&v4)[v10[2] - 1], &v10);// 把寄存器一的值赋值给第二个寄存器所指向的地址
        goto LABEL_26;
      case 0x1D:
        sub_400D23((&v4)[v10[1] - 1], v10[2], &v10);// 让第一个寄存器乘以v10[2]也就是流程表的值
        goto LABEL_26;
      case 0x64:
        return sub_400D59((__int64)v9);
      default:
        sub_400A17(&v10);
        break;
    }
  }
  return 1LL;
}


memcpy(liuchengbiao, &unk_6021C0, 0x190uLL);  申请流程表 程序会根据里边的值加密程序

[Asm] 纯文本查看 复制代码
  v4_one = v4 + 1;                              // 可能是寄存器
  v4_two = v4 + 2;
  v4_three = v4 + 3;
  v8 = v3 + 5120;

v4_one 这几块内存 模拟 寄存器 其中v4_three会储存一个常数0x46  也就是输入的字符串长度
v8指的是一块内存 存储输入的字符串 一个字符一个字符的存 每次存完就会自动减四
看流程表
[Asm] 纯文本查看 复制代码
 08 00 00 00 01 00 00 00  00 00 00 00 08 00 00 00
 03 00 00 00 46 00 00 00  0E 00 00 00 15 00 00 00
 0A 00 00 00 01 00 00 00  09 00 00 00 02 00 00 00
 0B 00 00 00 0A 00 00 00  01 00 00 00 0A 00 00 00
 02 00 00 00 09 00 00 00  01 00 00 00 11 00 00 00
 01 00 00 00 0D 00 00 00  01 00 00 00 03 00 00 00
 0F 00 00 00 08 00 00 00  08 00 00 00 01 00 00 00
 00 00 00 00 08 00 00 00  03 00 00 00 47 00 00 00
 0E 00 00 00 46 00 00 00  0A 00 00 00 01 00 00 00
 1A 00 00 00 02 00 00 00  06 00 00 00 1D 00 00 00
 01 00 00 00 04 00 00 00  14 00 00 00 02 00 00 00
 01 00 00 00 19 00 00 00  01 00 00 00 02 00 00 00
 1B 00 00 00 01 00 00 00  01 00 00 00 1D 00 00 00
 01 00 00 00 6E 00 00 00  13 00 00 00 01 00 00 00
 63 00 00 00 15 00 00 00  01 00 00 00 74 00 00 00
 13 00 00 00 01 00 00 00  66 00 00 00 1C 00 00 00
 02 00 00 00 01 00 00 00  09 00 00 00 01 00 00 00
 11 00 00 00 01 00 00 00  0D 00 00 00 01 00 00 00
 03 00 00 00 0F 00 00 00  22 00 00 00 64 00 00 00

其中比较重要的是
[Asm] 纯文本查看 复制代码
 0D 00 00 00  01 00 00 00 03 00 00 00

这样的流程
0d表示比较寄存器
当字符计数寄存器大于另一个寄存器时候 跳转  也就是判断读取长度 要读够0x46个字符
然后后边的
0F 00 00 00 08 00 00 00
跳转
读取完了跳转到后边加密
5.png
当到了后边加密时候
会从内存中一个字符地读数据 放到最左边的寄存器中加密

加密完了在放回去  最右边的是一个计数寄存器 判断循环次数
而上边的内存就是存储输入的数据

再看看最后的判断代码
[Asm] 纯文本查看 复制代码
signed __int64 __fastcall sub_400D59(__int64 a1)
{
  signed int i; // [rsp+14h] [rbp-4h]

  for ( i = 0; i <= 69; ++i )
  {
    if ( dword_6020A0[i] != *(_DWORD *)(4LL * i - 280 + a1) )
      return 0LL;
  }
  return 1LL;
}

最后就是比较了  读出最后加密过的代码
[Asm] 纯文本查看 复制代码
i = [14035, 11007, 10955, 11157, 11157, 11157, 5791, 6253, 6359, 5649, 6359, 11157, 11299, 11433, 5649, 5649, 6359, 11007, 6217, 6395, 10955, 10865, 5941, 6359, 5649, 10955, 5597, 6359, 11299, 5791, 5597, 11157, 5791, 5483, 6253, 11007, 5649, 5649, 5597, 11007, 11299, 10955, 5597, 5597, 6253, 6217, 11157, 5483, 5941, 6395, 6395, 10865, 11007, 5941, 11299, 5597, 6359, 10865, 6359, 6359, 11299, 11007, 5483, 11299, 5791, 13743, 11433, 12981, 11007, 12345]

刚上面的加密算法是
((输入的值*6e)+0x63)^0x74+0x66
不建议逆推 涉及小数点问题
直接爆破
[Asm] 纯文本查看 复制代码
i = [14035, 11007, 10955, 11157, 11157, 11157, 5791, 6253, 6359, 5649, 6359, 11157, 11299, 11433, 5649, 5649, 6359, 11007, 6217, 6395, 10955, 10865, 5941, 6359, 5649, 10955, 5597, 6359, 11299, 5791, 5597, 11157, 5791, 5483, 6253, 11007, 5649, 5649, 5597, 11007, 11299, 10955, 5597, 5597, 6253, 6217, 11157, 5483, 5941, 6395, 6395, 10865, 11007, 5941, 11299, 5597, 6359, 10865, 6359, 6359, 11299, 11007, 5483, 11299, 5791, 13743, 11433, 12981, 11007, 12345]

flags = ""
for q in range(len(i)):
        for u in range(32, 126):
                if (((((u*0x6e)+0x63)^0x74)+0x66)==i[q]):
                        flags += chr(u)
print flags
flag = ""
u = len(flags)
for u in range(len(flags)):
        flag += flags[q-u]
print flag

得到最终flag
[Asm] 纯文本查看 复制代码
nctf{3e1ce77b70e4cb9941d6800aec022c813d03e70a274ba96c722fed72783dddac}

6.png

免费评分

参与人数 9威望 +2 吾爱币 +14 热心值 +8 收起 理由
肖望舒 + 1 我很赞同!
一筐萝卜 + 1 + 1 我很赞同!
Hmily + 2 + 8 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
oka010203 + 1 + 1 谢谢@Thanks!
lihaohua + 1 + 1 我很赞同!
Assissant + 1 用心讨论,共获提升!
simplex + 1 + 1 用心讨论,共获提升!
ghugyul + 1 用心讨论,共获提升!
我是新手123 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

YenKoc 发表于 2020-1-11 16:11
那个基本操作中的,比较字符串,那块变换没看懂,能详细解答一下吗
我是新手123 发表于 2018-11-25 23:03
虽然不能一次性看明白,正在学习逆向破解中。。。
13无奇不有 发表于 2018-11-26 07:58 来自手机
simplex 发表于 2018-11-26 09:24
学习学习
starain2000 发表于 2018-11-26 09:37
厉害了,学习学习!
zjlzhok 发表于 2018-11-26 10:56
谢谢分享。
52pojiezorroman 发表于 2018-11-26 12:33
看不懂了,哈哈哈
头像被屏蔽
pjchangew 发表于 2018-11-26 12:42
提示: 作者被禁止或删除 内容自动屏蔽
乞铭星 发表于 2018-11-26 13:00
厉害,不明觉厉!!
one_last 发表于 2018-11-26 14:12
感谢分享,学习学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表