CTF逆向-[安洵杯 2019]game-使用deflat对主要混淆脱混淆后常规逻辑判断

来源:https://buuoj.cn/

内容:无

附件: https://pan.baidu.com/s/1qq_64SNIRnnTTCNqNIKOiw?pwd=1iz9 提取码:1iz9

答案:KDEEIFGKIJ@AFGEJAEF@FDKADFGIJFA@FDE@JG@J

总体思路

判断和输入相关的函数,然后对这些函数使用deflat.py对程序扁平化处理。

反向编写脚本得到答案

详细步骤

  • 检查文件信息

  • 打开general_inspection以及trace等自定义方法的,程序发现控制流特别大,可能是进行了混淆

使用deflat.py(见附件),在ida中查看main方法的地址为0x4006F0,分别deflat掉对输入有操作的函数,check1check3check2

  • check3函数中套了一个check2,该函数中是判断用户的输入值是否与全局变量相同,双击点开sodokuD0g3变量,shift+e按如图设置得到地图。其中D0g3变量会接收变更后的input值,即使得用户输入与其sodoku变量相同即可

  • 其中check1函数的实现是转换v_input:

    • v_input的0-len/2-1len/2-len互换
    • v_input[2n]和v_input[2n+1]互换
    • v_input[k] = (v_input[k] & 0xF3 | ~v_input[k] & 0xC) - 20
  • 通过使用z3创建一个 0-9的映射,即将每个数字都得到原来的输入

    • from typing import List
      import z3
      import structdef convert(raw: str) -> List[int]:raw = bytearray.fromhex(raw)raw = [raw[x*4:(x+1)*4] for x in range(int(len(raw)/4))]raw = [struct.unpack('<I', x)[0] for x in raw]return rawv_sudo = '010000000400000005000000030000000200000007000000060000000900000008000000080000000300000009000000060000000500000004000000010000000200000007000000060000000700000002000000080000000100000009000000050000000400000003000000040000000900000006000000010000000800000005000000030000000700000002000000020000000100000008000000040000000700000003000000090000000500000006000000070000000500000003000000020000000900000006000000040000000800000001000000030000000600000007000000050000000400000002000000080000000100000009000000090000000800000004000000070000000600000001000000020000000300000005000000050000000200000001000000090000000300000008000000070000000600000004000000'
      v_d0g3 = '010000000000000005000000030000000200000007000000000000000000000008000000080000000000000009000000000000000500000000000000000000000200000000000000000000000700000000000000000000000100000000000000050000000000000003000000040000000900000000000000010000000000000000000000030000000000000000000000000000000100000000000000000000000700000000000000090000000000000006000000070000000000000003000000020000000900000000000000040000000800000000000000000000000600000000000000050000000400000000000000080000000000000009000000000000000000000004000000000000000000000001000000000000000300000000000000000000000200000001000000000000000300000000000000070000000000000004000000'
      v_sudo = convert(v_sudo)
      v_d0g3 = convert(v_d0g3)
      print(f'v_sudo:{v_sudo}')
      print(f'v_d0g3:{v_d0g3}')
      s = z3.Solver()
      v_result = [index + 48 for index, x in enumerate([0] * 10)]  # 初始化数字的ascii
      v_input = [0] * len(v_result)
      v_input = [z3.BitVec(str(index), 16) for index, x in enumerate(v_input)]def exp(index: int):x = v_input[index]r = v_result[index]return (x & 0xf3 | ~x & 0xc) - 20 == rdef get_result(index: int) -> int:r = Nones.add(exp(index))result = s.check()if result == z3.sat:rs = s.model()r = rs[0]  # 获取最后结果keyr = rs[r].as_long()  # 转换为valueelse:print(f'fail on {index}')s.reset()return rkey_mapper = [get_result(index) for index, x in enumerate(v_result)]
      print(f'key_mapper:{key_mapper}')
      
  • 得到 key_mapper:[72, 73, 74, 75, 68, 69, 70, 71, 64, 65]

  • 发现在最后的input判断中是只判断当前数组中为0的项的,即输入的值是v_sudo和v_d0g3不一致的值

    • # 只填入d0g3中为0的位置,使得v_sudo == v_d0g3
      is_invalid = -1
      v_encoded = [v_sudo[index] if x == 0 else is_invalid for index,x in enumerate(v_d0g3)]  # 转换为输入
      v_encoded = list(filter(lambda x: x != is_invalid, v_encoded))
      v_encoded = [key_mapper[x] for x in v_encoded]
      v_encoded = [chr(x) for x in v_encoded]
      print(f'v_encoded:{v_encoded}')
      
    • 得到转换后的v_input v_encoded:['D', 'F', 'A', 'K', 'F', 'D', 'I', 'G', 'F', 'J', '@', 'A', 'D', 'F', '@', 'E', 'G', 'J', 'J', '@', 'D', 'K', 'E', 'E', 'F', 'I', 'K', 'G', 'J', 'I', 'A', '@', 'G', 'F', 'J', 'E', 'E', 'A', '@', 'F']

  • 最后将其通过key_mapper后,按:

    • v_input的0-len/2-1len/2-len互换
    • v_input[2n]和v_input[2n+1]互换
  • 最终的exp为

    • from typing import List
      import z3
      import structdef convert(raw: str) -> List[int]:raw = bytearray.fromhex(raw)raw = [raw[x*4:(x+1)*4] for x in range(int(len(raw)/4))]raw = [struct.unpack('<I', x)[0] for x in raw]return rawv_sudo = '010000000400000005000000030000000200000007000000060000000900000008000000080000000300000009000000060000000500000004000000010000000200000007000000060000000700000002000000080000000100000009000000050000000400000003000000040000000900000006000000010000000800000005000000030000000700000002000000020000000100000008000000040000000700000003000000090000000500000006000000070000000500000003000000020000000900000006000000040000000800000001000000030000000600000007000000050000000400000002000000080000000100000009000000090000000800000004000000070000000600000001000000020000000300000005000000050000000200000001000000090000000300000008000000070000000600000004000000'
      v_d0g3 = '010000000000000005000000030000000200000007000000000000000000000008000000080000000000000009000000000000000500000000000000000000000200000000000000000000000700000000000000000000000100000000000000050000000000000003000000040000000900000000000000010000000000000000000000030000000000000000000000000000000100000000000000000000000700000000000000090000000000000006000000070000000000000003000000020000000900000000000000040000000800000000000000000000000600000000000000050000000400000000000000080000000000000009000000000000000000000004000000000000000000000001000000000000000300000000000000000000000200000001000000000000000300000000000000070000000000000004000000'
      v_sudo = convert(v_sudo)
      v_d0g3 = convert(v_d0g3)
      print(f'v_sudo:{v_sudo}')
      print(f'v_d0g3:{v_d0g3}')
      s = z3.Solver()
      v_result = [index + 48 for index, x in enumerate([0] * 10)]  # 初始化数字的ascii
      v_input = [0] * len(v_result)
      v_input = [z3.BitVec(str(index), 16) for index, x in enumerate(v_input)]def exp(index: int):x = v_input[index]r = v_result[index]return (x & 0xf3 | ~x & 0xc) - 20 == rdef get_result(index: int) -> int:r = Nones.add(exp(index))result = s.check()if result == z3.sat:rs = s.model()r = rs[0]  # 获取最后结果keyr = rs[r].as_long()  # 转换为valueelse:print(f'fail on {index}')s.reset()return rkey_mapper = [get_result(index) for index, x in enumerate(v_result)]
      print(f'key_mapper:{key_mapper}')
      # 只填入d0g3中为0的位置,使得v_sudo == v_d0g3
      is_invalid = -1
      v_encoded = [v_sudo[index] if x == 0 else is_invalid for index,x in enumerate(v_d0g3)]  # 转换为输入
      v_encoded = list(filter(lambda x: x != is_invalid, v_encoded))
      v_encoded = [key_mapper[x] for x in v_encoded]
      v_encoded = [chr(x) for x in v_encoded]
      print(f'v_encoded:{v_encoded}')result = v_encoded
      vel = len(result)  # result_len
      vehl = int(vel / 2) # result_half_lenfor i in range(vehl):(result[i], result[i+vehl]) = (result[i+vehl], result[i])for i in range(0, vel-1, 2):(result[i], result[i+1]) = (result[i+1], result[i])print(''.join(result))
    • 得到答案 KDEEIFGKIJ@AFGEJAEF@FDKADFGIJFA@FDE@JG@J

其他文档

  • CTF逆向-常用的逆向工具 提取码:pnbt

  • 常见用法

    • 使用python快捷处理加密算法(RSA、AES、DES、3DES、XXTEA、blowfish)
    • Python使用struct库的用法
  • B站教程中国某省队CTF集训(逆向工程部分)

    • 中国某省队CTF集训(逆向工程部分)(已授权)(一)
    • 基础加密方式例如 XXTEABase64换表
    • Python库 Z3 方程式、不定式等的 约束求解
    • 基础的假跳转花指令(脏字节)
    • 非自然程序流程
      • 扁平化程序控制流
      • OLLVM程序流程(虚拟机壳) 很难一般不考
      • ida里面按X键跟踪,寻找所有Tyw的引用(即类型是写入的),通常就是关键位置
    • 中国某省队CTF集训(逆向工程部分)(已授权)(二)
    • ollydb动调去壳,upx为例子
    • python的逆向和自定义虚拟指令
      • 使用pycdc 提取码:dorr 解密python编译的exe或者pyc
      • 逐条去解析用py字典手动实现的指令调用
      • C++编译的程序的逆向
    • 中国某省队CTF集训(逆向工程部分)(已授权)(三)
      • 简单模运算加密
      • base58 寻找一下特别大的数,这种数通常是算法的标识,或者ida7.7版本以上自带的find crypt插件ctrl+alt+f
      • 常见的关键位置是有新的内存分配的地方通常是关键地方,或者函数中间突然return的地方也是
      • 迷宫题 注意绘制出来就好
      • 动调题
        • 注意观察会执行的反调试分支,例如出现int 3,需要跳过去
  • 基本知识

    • 大小端序

更多CTF逆向题通用性做法和常用工具下载参考该博文内容:CTF逆向Reverse题的玩法

相关逆向CTF题

  • Python

    • Python反汇编方法 Python的pyc字节码反编译反汇编相关知识
    • [CTF逆向-羊城杯 2020]Bytecode-WP-Python字节码反编译
  • 远程调试汇编

    • CTF逆向-[watevrCTF 2019]Timeout-WP-远程调试和修改程序当前运行位置RIP
    • CTF逆向-[watevrCTF 2019]esreveR-看似复杂流程,发现核心逻辑,按64位架构导出栈中和寄存器中的值得到结果
  • 流程控制

    • CTF逆向-Dig the way Interesting Pointer-通过栈溢出方式覆盖变量以达到修改执行流程的目的
  • 逆向思维

    • [CTF逆向-NPUCTF2020]Baby Obfuscation-逆向思维编写脚本以及函数含义的逻辑理解
    • [CTF逆向-MRCTF2020]EasyCpp - C++类型的逆向通用操作方法
    • [CTF逆向-SUCTF2018]babyre-WP-cpp简单迭代并按表输出值的爆破
  • 安卓

    • [CTF逆向-网鼎杯 2020 青龙组]bang-安卓脱壳逆向:frida-dexdump导出得到源码
  • 虚拟机

    • [CTF逆向-GWCTF 2019]babyvm-WP-虚机模拟流程反向编码和z3约束求解器解方程工具的使用
    • [CTF逆向-WMCTF2020]easy_re-WP_虚机-perl加载器截取
  • 反调试和SMC

    • [CTF逆向-SCTF2019]creakme-WP-基于AES加密算法下的保护:反调试及except_handler和SMC
    • CTF逆向-[FlareOn1]Shellolololol-栈上执行,多层smc的动调得到最终结果
  • 加密

    • Python 基于pycryptodome,实现对AES、DES、3DES、RSA等常用加密算法的使用,文末附各种加密的源码示例
    • [CTF逆向-FlareOn2]very_success-WP_rol循环位移加密
    • base64换表
      • [CTF逆向-CISCN2018]2ex-WP_mips-32架构以及base64换表
      • [CTF逆向-De1CTF2019]Re_Sign-简单脱壳和base64换表编码的深度算法跟踪
  • 花指令

    • [CTF逆向-SCTF2019]babyre-WP_简单去花指令和流程识别
    • CTF逆向-[MRCTF2020]VirtualTree-恒成立的jz花指令去除及smc变换原执行流程在二叉树上的应用,通过逆向思维编写脚本以解决
  • 流程混淆的扁平化处理

    • [CTF逆向-RoarCTF2019]polyre-WP_控制流扁平化去混淆idcpy去指令
    • CTF逆向-[SUCTF2019]hardcpp-使用优化过的deflat.py处理混淆的控制流并将cpp的lambda解析得到实际处理逻辑
  • c/cpp基础

    • [CTF逆向-b01lers2020]little_engine-cpp基本函数用法和byte类型要点

CTF逆向-[安洵杯 2019]game-使用deflat对主要混淆脱混淆后常规逻辑判断相关推荐

  1. BUUCTF [安洵杯 2019]easy_serialize_php

    考点: 变量覆盖.反序列化中的对象逃逸 题目地址:BUUCTF在线评测 源码如下: <?php$function = @$_GET['f'];function filter($img){$fil ...

  2. [安洵杯 2019]iamthinking

    /www.zip下载源码审计 通过README可以看到是ThinkPHP6.0. 当前只能访问到/public/index.php, 关于这个框架的index.php [thinkphp6源码分析一 ...

  3. 【BUUCTF】[安洵杯 2019]吹着贝斯扫二维码

    题目链接:[安洵杯 2019]吹着贝斯扫二维码. 下载压缩包解压得到这么一些文件,可以看到一堆未知类型文件和一个flag.zip 老规矩,把这些没有拓展名的文件用010Editor打开,发现都是jpg ...

  4. [安洵杯 2019]吹着贝斯扫二维码

    [安洵杯 2019]吹着贝斯扫二维码 压缩包解压后得到一些无后缀文件,和一个flag.zip 查看flag.zip内容发现尾部有类似base32的数据,先不管去看那些文件(这题其实可以用不到其他文件) ...

  5. BUUCTF:[安洵杯 2019]不是文件上传

    这题和攻防世界XCTF:upload有点像,看似上传却都不是上传是上传图片的文件名注入 参考:安洵杯2019 官方Writeup 获取源码 在网站首页存在一些信息 在gihtub找得到源码 BUU也给 ...

  6. 第二届安洵杯2019部分writeup

    Web easy_web 参数可疑:?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= TXpVek5UTTFNbVUzTURabE5qYz0进行两次base64解密, ...

  7. 【安洵杯 2019】easy-web

    涉及内容:base64解码.代码审计.MD5强类型注入.命令注入绕过 打开控制器,查看源代码,可以看到md5 is funny,可知这题应该会出现MD5 其余信息一无所获后,看到网站: 看到img=T ...

  8. [安洵杯 2019]Attack (详细解析)

    (*本文使用工具,均为windows系统,这些工具kali系统自带,有的人不喜欢用kali系统,主页有windows下载资源) 题目链接: https://buuoj.cn/challenges#[% ...

  9. BUUCTF:[安洵杯 2019]吹着贝斯扫二维码

    题目地址:https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]%E5%90%B9%E7%9D%80%E8%B4%9D%E6% ...

  10. [安洵杯 2019]easy_web 1

    打开环境 源码中只有一个md is funny 然后URL有一个img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= 先试试模板注入发现不行,然后伪协议也不行,再爆破目录也 ...

最新文章

  1. Spring第二弹—–搭建与测试Spring的开发环境
  2. IOS学习笔记之十七 (NSDate、NSDateFormatter、NSCalendar、NSDateComponents、NSTimer)
  3. vmware服务器虚拟化实施文档,VMware服务器虚拟化
  4. C#简单的生成随机数
  5. 61.Linux/Unix 系统编程手册(下) -- SOCKET: 高级主题
  6. 威纶和s7200通讯线_威纶触摸屏与西门子S7200通讯实例
  7. lsass.exe是什么?
  8. springboot+宿舍管理小程序 毕业设计-附源码171008
  9. 计算机自我介绍英语范文,计算机面试英文自我介绍范文
  10. 论文阅读笔记:Intriguing properties of neural networks
  11. JS-对象,包装类--渡一教育(视频笔记)
  12. java jsp 获得网页源代码三种方式
  13. 百度 Apollo 轨迹规划技术分享笔记
  14. 【Matlab WSN通信】A_Star改进LEACH多跳传输协议【含源码 487期】
  15. 2020Android手机专业摄影,华为拍照手机排行榜2020_华为拍照最好的是哪款
  16. 基于51单片机智能停车场管理车位引导系统蓝牙手机通信proteus仿真原理图PCB
  17. 初学 STM32 (从 51 过度到 STM32 ,初学 STM32 必须了解的知识)
  18. iOS开发中的UDID和UUID详解
  19. XGBoost和GBDT
  20. 【GaussDB数据库----连接】

热门文章

  1. 安徽农业大学计算机考研分数线,安徽农业大学考研录取分数线
  2. R语言作图——Lollipop chart(棒棒糖图)
  3. Windows Server 2016-Win Ser 2016已删减内容
  4. 【蓝桥杯】:奇怪的分式
  5. 下载Idea以及破解使用至2100年
  6. PhalApi框架新手脱坑笔记(一)
  7. Akka Actors入门案例解析
  8. 计算机系微电子专业大学排名,2021年微电子科学与工程专业大学排名
  9. 绘本“深阅读’’的教学探索
  10. 仿支付宝实现密码框输入