CTF逆向-[安洵杯 2019]game-使用deflat对主要混淆脱混淆后常规逻辑判断
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掉对输入有操作的函数,check1
、check3
、check2
check3
函数中套了一个check2
,该函数中是判断用户的输入值是否与全局变量相同,双击点开sodoku
和D0g3
变量,shift+e按如图设置得到地图。其中D0g3
变量会接收变更后的input值,即使得用户输入与其sodoku
变量相同即可其中
check1
函数的实现是转换v_input:- v_input的
0
-len/2-1
与len/2
-len
互换 - v_input[2n]和v_input[2n+1]互换
- v_input[k] = (v_input[k] & 0xF3 | ~v_input[k] & 0xC) - 20
- v_input的
通过使用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-1
与len/2
-len
互换 - v_input[2n]和v_input[2n+1]互换
- v_input的
最终的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集训(逆向工程部分)(已授权)(一)
- 基础加密方式例如
XXTEA
、Base64
换表 - Python库
Z3
方程式、不定式等的约束求解
- 基础的假跳转花指令(脏字节)
- 非自然程序流程
- 扁平化程序控制流
- OLLVM程序流程(虚拟机壳) 很难一般不考
- ida里面按
X
键跟踪,寻找所有Ty
为w
的引用(即类型是写入的),通常就是关键位置
- 中国某省队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对主要混淆脱混淆后常规逻辑判断相关推荐
- BUUCTF [安洵杯 2019]easy_serialize_php
考点: 变量覆盖.反序列化中的对象逃逸 题目地址:BUUCTF在线评测 源码如下: <?php$function = @$_GET['f'];function filter($img){$fil ...
- [安洵杯 2019]iamthinking
/www.zip下载源码审计 通过README可以看到是ThinkPHP6.0. 当前只能访问到/public/index.php, 关于这个框架的index.php [thinkphp6源码分析一 ...
- 【BUUCTF】[安洵杯 2019]吹着贝斯扫二维码
题目链接:[安洵杯 2019]吹着贝斯扫二维码. 下载压缩包解压得到这么一些文件,可以看到一堆未知类型文件和一个flag.zip 老规矩,把这些没有拓展名的文件用010Editor打开,发现都是jpg ...
- [安洵杯 2019]吹着贝斯扫二维码
[安洵杯 2019]吹着贝斯扫二维码 压缩包解压后得到一些无后缀文件,和一个flag.zip 查看flag.zip内容发现尾部有类似base32的数据,先不管去看那些文件(这题其实可以用不到其他文件) ...
- BUUCTF:[安洵杯 2019]不是文件上传
这题和攻防世界XCTF:upload有点像,看似上传却都不是上传是上传图片的文件名注入 参考:安洵杯2019 官方Writeup 获取源码 在网站首页存在一些信息 在gihtub找得到源码 BUU也给 ...
- 第二届安洵杯2019部分writeup
Web easy_web 参数可疑:?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= TXpVek5UTTFNbVUzTURabE5qYz0进行两次base64解密, ...
- 【安洵杯 2019】easy-web
涉及内容:base64解码.代码审计.MD5强类型注入.命令注入绕过 打开控制器,查看源代码,可以看到md5 is funny,可知这题应该会出现MD5 其余信息一无所获后,看到网站: 看到img=T ...
- [安洵杯 2019]Attack (详细解析)
(*本文使用工具,均为windows系统,这些工具kali系统自带,有的人不喜欢用kali系统,主页有windows下载资源) 题目链接: https://buuoj.cn/challenges#[% ...
- 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% ...
- [安洵杯 2019]easy_web 1
打开环境 源码中只有一个md is funny 然后URL有一个img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= 先试试模板注入发现不行,然后伪协议也不行,再爆破目录也 ...
最新文章
- Spring第二弹—–搭建与测试Spring的开发环境
- IOS学习笔记之十七 (NSDate、NSDateFormatter、NSCalendar、NSDateComponents、NSTimer)
- vmware服务器虚拟化实施文档,VMware服务器虚拟化
- C#简单的生成随机数
- 61.Linux/Unix 系统编程手册(下) -- SOCKET: 高级主题
- 威纶和s7200通讯线_威纶触摸屏与西门子S7200通讯实例
- lsass.exe是什么?
- springboot+宿舍管理小程序 毕业设计-附源码171008
- 计算机自我介绍英语范文,计算机面试英文自我介绍范文
- 论文阅读笔记:Intriguing properties of neural networks
- JS-对象,包装类--渡一教育(视频笔记)
- java jsp 获得网页源代码三种方式
- 百度 Apollo 轨迹规划技术分享笔记
- 【Matlab WSN通信】A_Star改进LEACH多跳传输协议【含源码 487期】
- 2020Android手机专业摄影,华为拍照手机排行榜2020_华为拍照最好的是哪款
- 基于51单片机智能停车场管理车位引导系统蓝牙手机通信proteus仿真原理图PCB
- 初学 STM32 (从 51 过度到 STM32 ,初学 STM32 必须了解的知识)
- iOS开发中的UDID和UUID详解
- XGBoost和GBDT
- 【GaussDB数据库----连接】