NSSCTF [suctf 2019]hardcpp WP 控制流混淆
下载文件,64位主函数非常多循环
去控制流混淆,脚本下载deflat
用法
python 脚本名 文件名 起始地址
例如主函数地址是0x4007E0
python deflat.py hardCpp 0x4007E0
然后就生成了去混淆的文件
主函数非常大,开始分析逻辑
puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?");
输出01abfc750a0c942167651c40d088531d"?
s = getchar();
fgets(v24, 21, stdin);
然后输入字符串,其中第一个值给s,然后再给v24。
if ( y >= 10 && ((((_BYTE)x - 1) * (_BYTE)x) & 1) != 0 )goto LABEL_13;while ( 1 ){v20 = strlen(&s);v34 = v20 != 21;if ( y < 10 || ((((_BYTE)x - 1) * (_BYTE)x) & 1) == 0 )break;
LABEL_13:v20 = strlen(&s);}
这里是个混淆,无论if跳不跳转,v20都等于s长度,注意s前面加了地址符&,
说明是地址,而s和v24的地址是连续的。所以v20本来应该为1,其实为21,不过v20的作用不大。,v34作用不大忽略
while ( 1 ){v19 = 1;if ( y < 10 || ((((_BYTE)x - 1) * (_BYTE)x) & 1) == 0 )break;v19 = 1;}
这里也有混淆,v19就是1
hile ( v19 < 21 ){if ( y >= 10 && ((((_BYTE)x - 1) * (_BYTE)x) & 1) != 0 ){v18 = v21 ^ v24[v19 - 1];v17[0] = main::$_0::operator()(v27, (unsigned int)v18);v16[0] = main::$_1::operator()(v25, (unsigned int)*(&s + v21 + v19 - 1));v8 = main::$_1::operator() const(char)::{lambda(int)#1}::operator()(v16, 7LL);v18 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v17, (unsigned int)v8);v15[0] = main::$_2::operator()(v28, (unsigned int)v18);v14[0] = main::$_2::operator()(v28, (unsigned int)*(&s + v21 + v19 - 1));v9 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v14, 18LL);v13[0] = main::$_3::operator()(v26, (unsigned int)v9);v10 = main::$_3::operator() const(char)::{lambda(char)#1}::operator()(v13, 3LL);v12[0] = main::$_0::operator()(v27, (unsigned int)v10);v11 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v12, 2LL);v18 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v15, (unsigned int)v11);}do{v18 = v21 ^ v24[v19 - 1];v17[0] = main::$_0::operator()(v27, (unsigned int)v18);v16[0] = main::$_1::operator()(v25, (unsigned int)*(&s + v21 + v19 - 1));v3 = main::$_1::operator() const(char)::{lambda(int)#1}::operator()(v16, 7LL);v18 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v17, (unsigned int)v3);v15[0] = main::$_2::operator()(v28, (unsigned int)v18);v14[0] = main::$_2::operator()(v28, (unsigned int)*(&s + v21 + v19 - 1));v4 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v14, 18LL);v13[0] = main::$_3::operator()(v26, (unsigned int)v4);v5 = main::$_3::operator() const(char)::{lambda(char)#1}::operator()(v13, 3LL);v12[0] = main::$_0::operator()(v27, (unsigned int)v5);v6 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v12, 2LL);v18 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v15, (unsigned int)v6);}while ( enc[v19 - 1] != v18 );while ( y >= 10 && ((((_BYTE)x - 1) * (_BYTE)x) & 1) != 0 );++v19;}
接下来来到了重头戏了,共六个函数一个一个分析
main::$_0::operator()
char __fastcall main::$_0::operator()(__int64 a1, char a2)
{return a2;
}
就是返回a2,我们把函数重命名为return_a2
方便后续分析
main::$_1::operator() const(char)::{lambda(int)#1}::operator()
__int64 __fastcall main::$_1::operator() const(char)::{lambda(int)#1}::operator()(char *a1, int a2)
{return (unsigned int)(*a1 % a2);
}
返回a1%a2,这里a2是常数7,命名为return_a1_mod_7
main::$_0::operator() const(char)::{lambda(char)#1}::operator()
__int64 __fastcall main::$_0::operator() const(char)::{lambda(char)#1}::operator()(__int64 a1, char a2)
{int v2; // eaxint v3; // eaxchar *v5; // [rsp+0h] [rbp-40h]int v6; // [rsp+8h] [rbp-38h]int v7; // [rsp+Ch] [rbp-34h]int v8; // [rsp+10h] [rbp-30h]int v9; // [rsp+14h] [rbp-2Ch]char *v10; // [rsp+18h] [rbp-28h]char v11; // [rsp+23h] [rbp-1Dh]int v12; // [rsp+24h] [rbp-1Ch]bool v13; // [rsp+2Ah] [rbp-16h]bool v14; // [rsp+2Bh] [rbp-15h]unsigned int v15; // [rsp+2Ch] [rbp-14h]v13 = ((((_BYTE)x_5 - 1) * (_BYTE)x_5) & 1) == 0;v14 = y_6 < 10;v12 = 1023500310;v11 = a2;v10 = (char *)a1;do{while ( 1 ){while ( 1 ){while ( 1 ){v9 = v12;v8 = v12 + 2037067308;if ( v12 != -2037067308 )break;v5 = v10;*((_BYTE *)&v5 - 16) = v11;v12 = -1418698808;}v7 = v9 + 1418698808;if ( v9 != -1418698808 )break;v3 = -2037067308;v5 = v10;*((_BYTE *)&v5 - 16) = v11;v15 = *((char *)&v5 - 16) + *v5;if ( y_6 < 10 || ((((_BYTE)x_5 - 1) * (_BYTE)x_5) & 1) == 0 )v3 = 1456142001;v12 = v3;}v6 = v9 - 1023500310;if ( v9 != 1023500310 )break;v2 = -2037067308;if ( v14 || v13 )v2 = -1418698808;v12 = v2;}HIDWORD(v5) = v9 - 1456142001;}while ( v9 != 1456142001 );return v15;
核心部分
v11 = a2;v10 = (char *)a1;
v5 = v10;
*((_BYTE *)&v5 - 16) = v11;
v15 = *((char *)&v5 - 16) + *v5;
return v15;
就是返回a1+a2,命名return_a1_add_a2
main::$_2::operator()
核心部分
v12 = a2;
*((_BYTE *)&v5 - 16) = v12;
LOBYTE(v5) = *((_BYTE *)&v5 - 16);
v16 = v5;
return v16;
就是返回v5低位,就是a2re_a22
main::$_2::operator() const(char)::{lambda(char)#1}::operator()
return (unsigned int)(char)(a2 ^ *a1);
命名return_a1_XOR_a2
main::$_3::operator()
v12 = a2;
*((_BYTE *)&v5 - 16) = v12;
LOBYTE(v5) = *((_BYTE *)&v5 - 16);
v16 = v5;
return v16;
命名re_a2222
main::$_3::operator() const(char)::{lambda(char)#1}::operator()
return (unsigned int)(a2 * *a1);
return_a1_x_a2
六个大爹干完了,然后再对逻辑进行分析,就是一直变换,就是解方程
v18=v24[v19-1];v17[0]=v18;//v17[0]=v24[v19-1];v16[0]=s[v19-1];v8=v16%7;//v8=s[v19-1]%7;v18=v17+v8;//v18=v24[v19-1]+s[v19-1]%7;v15[0]=v18;//v15[0]=v24[v19-1]+(s[v19-1]%7);v14[0]=s[v19-1];v9=v14^18;//v9=s[v19-1]^18;v13[0]=v9;//v13[0]=s[v19-1]^18;v10=v13*3;//v10=s[v19-1]^18*3;v12[0]=v10;v11=v12+2;//v11=s[v19-1]^18*3+2;v18=v15^v11;//v18={v24[v19-1]+(s[v19-1]%7)}^{s[v19-1]^18*3+2}
一层一层代入就得到了v18={v24[v19-1]+(s[v19-1]%7)}^{(s[v19-1]^18)*3+2}
然后再与enc[v19 - 1]比较,然后v19加1。继续上述循环。
然后逆过去解方程
v24[v19-1]+(s[v19-1]%7)=v18^(s[v19-1]^18*3+2)
v24[v19-1]=(v18^(s[v19-1]^18*3+2))-(s[v19-1]%7)
这样就能得到每一位了。现在看开头
puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?");
32位,盲猜md5加密,去进行解密,得到符号#,说明第一个字符是#,即知道了s[v19-1],v19=1;.又知道了v18即enc,我们就可以求出第二位,同理得到所有,脚本如下
enc=[0xF3, 0x2E, 0x18, 0x36, 0xE1, 0x4C, 0x22, 0xD1, 0xF9, 0x8C,0x40, 0x76, 0xF4, 0x0E, 0x00, 0x05, 0xA3, 0x90, 0x0E, 0xA5]
lst=[35]
for i in range(len(enc)):lst.append((((enc[i]^((lst[i]^18)*3+2)))-((lst[i]%7)))&0xff)print(lst)
for i in lst:print(chr(i),end='')
这里有个&0xff运算,防止数字溢出
得到flag
#flag{mY-CurR1ed_Fns}
相关文章:

NSSCTF [suctf 2019]hardcpp WP 控制流混淆
下载文件,64位主函数非常多循环 去控制流混淆,脚本下载deflat 用法 python 脚本名 文件名 起始地址例如主函数地址是0x4007E0 python deflat.py hardCpp 0x4007E0然后就生成了去混淆的文件 主函数非常大,开始分析逻辑 puts("func(?…...

计算机毕业论文内容参考|基于神经网络的网络安全态势感知技术研究
文章目录 导文文章重点摘要前言绪论课题背景国内外现状与趋势课题内容相关技术与方法介绍技术分析技术设计技术实现总结与展望导文 基于神经网络的网络安全态势感知技术研究 文章重点 摘要 随着互联网的快速发展,网络攻击的频率和复杂度也在逐年增加。为了更好地保护信息系统…...
Flask框架之Request、Response、Cookies、Session等对象的使用
Request、Response、Cookies、Session等对象的使用 Request对象基本使用参数的获取转换器内置转换器自定义转换器 Response对象基本使用返回模板重定向返回JSON Cookies对象设置cookie获取cookie删除cookie Session会话对象设置SECRET_KEY设置会话获取会话释放会话 Request对象…...

信号与槽机制一
一、信号与槽 1、什么是信号与槽? 信号和槽是用于对象之间的通信,它是Qt的核心机制,在Qt编程中有着广泛的应用。如果想学好Qt,一定要充分掌握信号的槽的概念与使用。 2、信号和槽的代码实例 在Qt中,发送对象、发送的信…...
nodejs 复制文件到指定目录
var fs require(fs), path require(path), exec require(child_process).exec, sourcePath, targetPath; //获取命令行中的路径 process.argv.forEach(function (val, index, array) { if (index 2) { sourcePath val; } if (index 3) { targetPath val; } }); // 定义…...

第八章 使用Apache服务部署静态网站
文章目录 第八章 使用Apache服务部署静态网站一、网站服务程序1、网站服务介绍2、Apache程序介绍 二、配置服务文件参数1、Linux系统中的配置文件2、配置httpd服务程序时最常用的参数以及用途描述 三、SELinux安全子系统1、SELinux介绍2、SELinux服务配置模式3、Semanage命令4、…...

Three——四、几何体、高光网络材质、锯齿模糊以及GUI库的使用
文章: Three——一、初识Three以及基础的前端场景搭建(结尾含源码)Three——二、加强对三维空间的认识Three——三、动画执行、画布大小、渲染帧率和相机适配体验Three——四、几何体、高光网络材质、锯齿模糊以及GUI库的使用Three——五、点线模型对象、三角形概念…...

盲目自学网络安全只会成为脚本小子?
前言:我们来看看怎么学才不会成为脚本小子 目录: 一,怎么入门? 1、Web 安全相关概念(2 周)2、熟悉渗透相关工具(3 周)3、渗透实战操作(5 周)4、关注安全圈动…...
文从字顺|程序员须知,如何编写高质量代码
高质量代码是软件开发中至关重要的一部分。高质量的代码不仅可以提高软件的可维护性和可复用性,还可以增强软件的安全性和稳定性。同时,可以降低软件维护成本,提升开发效率,为用户提供更好的使用体验。 写出高质量代码是每个程序…...

PCIe物理层弹性缓存机制(详细)解析-PCIe专题知识(四)
目录 前言一、简介二、详细解析2.1 实例解析2.2 具体实现过程 三、总结四、其他相关链接1、PCI总线及发展历程总结2、PCIe物理层总结-PCIE专题知识(一)3、PCIe数据链路层图文总结-PCIe专题知识(二)4、PCIe物理层链路训练和初始化总…...
分片上传和断点续传的区别?实现思路是什么?
相同: 分片上传和断点续传都是网络传输中常用的重要技术 不同: 分片上传:将一个大文件切分为多个小文件进行上传。这种方式能够加快上传速度,降低服务器压力,特别适用于大型文件的上传。例如,在云存储系统…...

微前端 qiankun@2.10.5 源码分析(二)
微前端 qiankun2.10.5 源码分析(二) 我们继续上一节的内容。 loadApp 方法 找到 src/loader.ts 文件的第 244 行: export async function loadApp<T extends ObjectType>(app: LoadableApp<T>,configuration: FrameworkConfi…...
08异步请求:何种场景下应该使用异步请求?
异步在计算机科学中早就是一个比较常用的词汇,从操作系统的特性( 并发、共享、虚拟、异步)开始,异步就在处理并发操作中起到很大的作用,不仅如此,在软件层面,异步同样也是解决并发请求的一个关键过程,它可以将瞬时激增的请求进行更加灵活的处理,通过异步请求,客户端可…...
【深度学习 | Transformer】Transformers 教程:pipeline一键预测
文章目录 一、前言二、Computer vision2.1 Image classification2.2 Object detection2.3 Image segmentation2.4 Depth estimation 三、NLP3.1 Text classification3.2 Token classification3.3 Question answering3.4 Summarization3.5 Translation3.6 Language modeling3.6.…...

HTMLCSS
1、HTML 1.1 介绍 HTML 是一门语言,所有的网页都是用HTML 这门语言编写出来的,也就是HTML是用来写网页的,像京东,12306等网站有很多网页。 这些都是网页展示出来的效果。而HTML也有专业的解释 HTML(HyperText Markup Language)…...

【安装Nginx】
Linux上安装Nginx 文章目录 Linux上安装NginxUbuntuCentOS查看已安装的软件 Ubuntu 在 Ubuntu 上安装 Nginx 非常简单。只需按照以下步骤操作: 打开终端,更新软件包索引: sudo apt update安装 Nginx: sudo apt install nginx安…...

VSCode作业1:猜数字游戏和简单计数器(包含完整代码)
目录 猜数字游戏 一、使用‘random’函数获取随机数 二、 分情况讨论输入值大小情况 三、HTML代码 四、CSS样式及运行效果 简单计数器(计时器) 一、使用‘setInterval’函数实现计数效果 二、使用’clearInterval‘函数实现暂停计数和重新计数效果 …...

NANK OE骨传导开放式蓝牙耳机发布,极致体验拉满!
近日,中国专业音频品牌NANK南卡发布了全新一代——骨传导开放式蓝牙耳机NANK OE,耳机采用了传统真无线和骨传导的结合方式,带来更加舒适的佩戴体验和音质升级,同时还支持单双耳自由切换,全新的设计收获了市场的喜爱和认…...

看完这篇文章你就彻底懂啦{保姆级讲解}-----(I.MX6U驱动GPIO中断《包括时钟讲解》) 2023.5.9
目录 前言整体文件结构源码分析(保姆级讲解)中断初始化部分初始化GIC控制器初始化中断向量表设置中断向量表偏移 系统时钟初始化部分使能所有的时钟部分led初始化部分beep初始化部分key初始化部分按键中断初始化部分按键中断服务函数部分 while循环部分 …...

MySql -- 事务
目录 1.概念 2.事务的运用场景 3.事务的四大特点 4.执行事务带来的问题 4.1 脏读 4.2 不可重复度 4.3 幻读 5. MySQL中事务的隔离级别 1.概念 事务就是把若干个独立操作打包成一个整体而诞生的一种功能. 2.事务的运用场景 比如:A——>B 转账500 A的余额-500…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...

sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...

Go 语言中的内置运算符
1. 算术运算符 注意: (自增)和--(自减)在 Go 语言中是单独的语句,并不是运算符。 package mainimport "fmt"func main() {fmt.Println("103", 103) // 13fmt.Println("10-3…...