IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [ctf.show.reverse] 摆烂杯 简单的逆向 -> 正文阅读

[C++知识库][ctf.show.reverse] 摆烂杯 简单的逆向

困扰我好几天,今天华为的本到货了,安上系统拿它来练手。

这个程序流程很简单,输入64字节的flag然后每4字节会去做个200多行异或移位XXX的加密后生成20字节的密文,与已知密文比较。由于每次只有4字节而且加密过于复杂,所以方向应该是爆破。一直也搜不到wp,还真想给它爆出来。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __m128i si128; // xmm0
  __int64 v4; // rdx
  __int64 v5; // r8
  int *v6; // rcx
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rdi
  signed __int64 v10; // rbx
  int v11; // eax
  __int64 v12; // r8
  int *v13; // rax
  const char *v14; // rdx
  _BYTE v16[256]; // [rsp+20h] [rbp-118h] BYREF

  si128 = _mm_load_si128((const __m128i *)&xmmword_1400046A0);
  dword_140006730 = 2043430169;
  dword_140006734 = 2043430169;
  dword_140006738 = 2043430169;
  dword_14000673C = 2043430169;
  dword_140006740 = 2043430169;
  dword_140006744 = 2043430169;
  dword_140006748 = 2043430169;
  dword_14000674C = 2043430169;
  dword_140006750 = 2043430169;
  dword_140006754 = 2043430169;
  dword_140006758 = 2043430169;
  dword_14000675C = 2043430169;
  dword_140006760 = 2043430169;
  dword_140006764 = 2043430169;
  dword_140006768 = 2043430169;
  dword_14000676C = 2043430169;
  stru_140006770[0] = si128;
  dword_140006710 = 1937774191;
  stru_140006770[1] = si128;
  dword_140006714 = 1226093241;
  stru_140006770[2] = si128;
  dword_140006718 = 388252375;
  stru_140006770[3] = si128;
  dword_14000671C = -628488704;
  stru_140006770[4] = si128;
  dword_140006720 = -1452330820;
  stru_140006770[5] = si128;
  dword_140006724 = 372324522;
  stru_140006770[6] = si128;
  dword_140006728 = -477237683;
  stru_140006770[7] = si128;
  dword_14000672C = -1325724082;
  stru_140006770[8] = si128;
  stru_140006770[9] = si128;
  stru_140006770[10] = si128;
  stru_140006770[11] = si128;
  sub_140001DE0(std::cout, "emm~~~ flag please:\n", envp);
  memset(v16, 0, sizeof(v16));
  sub_140002080(std::cin, v4, v16);
  v6 = (int *)v16;
  v7 = -1i64;
  do
    ++v7;
  while ( v16[v7] );
  if ( v7 == 64 )
  {
    v9 = 0i64;
    v10 = &unk_140004480 - (_UNKNOWN *)&dword_140006710;
    while ( 2 )
    {
      qword_140006864 = 0i64;
      *(__int64 *)((char *)&qword_140006864 + 4) = 0i64;
      v11 = *(_DWORD *)&v16[v9];
      xmmword_140006834 = 0i64;
      dword_140006830 = v11;
      xmmword_140006844 = 0i64;
      LOBYTE(xmmword_140006834) = 0x80;
      xmmword_140006854 = 0i64;
      dword_14000686C = 0x20000000;
      sub_1400011A0(v6);
      v13 = &dword_140006710;
      do
      {
        v6 = (int *)*(unsigned int *)((char *)v13 + v10);
        if ( *v13 != (_DWORD)v6 )
        {
          v14 = "hehe~~~\n ";      //第2个patch点,把这改为jmp 到开始实现循环
          goto LABEL_12;
        }
        ++v13;
      }
      while ( (__int64)v13 < (__int64)&dword_140006730 );
      v9 += 4i64;
      v10 += 32i64;
      if ( v9 < 64 )       //第1个patch点,每次改到比已知大4,爆破4字节
        continue;
      break;
    }
    v14 = "VeryGood!\nNow,\nYou know who is the best houdaode Propositioner le~~~\n ";
LABEL_12:
    sub_140001DE0(std::cout, v14, v12);
  }
  else
  {
    v8 = sub_140001DE0(std::cout, "hehe~~~\n ", v5);
    std::basic_ostream<char,std::char_traits<char>>::operator<<(v8, sub_140001FB0);
  }
  return 0;
}

但是win程序每次调起太麻烦,所以导致无法爆破。后来终于想到个办法(没机子也没闲着),把程序patch两个地方。

  1. 第1处在长度比较的位置,每次改为比已爆出长度大4,用来爆下4个字节;
  2. 第2处在不正确时返回hehe时,这里字节比较长改为jmp 0xfffffd8d 跳到开始1a09,这样程序在这里成一个循环不再退出,时间成百倍的节省。

然后用subprocess调起程序(后来有个问题,写回原程序时会发生无权写入,所以每次新生成一个文件)

from subprocess import *
import string


data = list(open('cppc.exe', 'rb').read())

letter = ''
letter+= '_{}'
letter+= string.ascii_lowercase
letter+= string.ascii_uppercase
#letter+= string.digits
#flag = 'ctfshow{as_we_all_know_AFox_is_the_most_houdaode_Propositioner_}'
flag = ''
def getflag(i):
    global flag
    for i in letter:
        for j in letter:
            for k in letter:
                for l in letter:
                    tflag = flag+i+j+k+l+'0'*(64-4-len(flag)) +'\n'
                    p.stdin.write(tflag)
                    p.stdin.flush()
                    retstr = p.stdout.readline()
                    if 'VeryGood!' in retstr:
                        flag += i+j+k+l  
                        print(flag)
                        p.stdout.close()
                        p.stdin.close()
                        return True 

for i in range(len(flag ),64,4):
    data[0x106b] = i+4
    open(f'cppc_{i}.exe', 'wb').write(bytes(data))
    p = Popen(f'.\cppc_{i}.exe', stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True )
    p.stdout.readline()
    p.stdout.flush() 
    if getflag(i) :
        print(flag)

因为这里大部分flag都是小字字母,所在在不的成功的时候再把大写加进来会省不少时间。64字符多恶心呀。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 10:59:30  更:2022-05-05 11:02:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 3:29:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码