学习一下动调

[NSSCTF 2nd]MyBase

die查一下

用ida64打开

main函数里面没有什么信息,接着追一下函数,内容在test函数里面

函数会对我们输入的内容进行base64加密,这段逻辑也很简单,就是将加密后的字符串和目标字符串依次进行比较,一样就输出成功,那么我们是不是可以直接把这段字符串解码一下,然后直接启动程序输入解码内容就可以了,当然不是,看一下解码之后的内容

直接乱码了,原因是这个base_64encode不是base64加密,是一个自定义的函数,我们追踪看看

_BYTE *__fastcall base64_encode(__int64 a1, unsigned __int64 a2, size_t *a3)
{__int64 v4; // rax__int64 v5; // raxint v6; // eax__int64 v7; // raxint v8; // eax__int64 v9; // raxunsigned int v10; // [rsp+28h] [rbp-28h]int v11; // [rsp+30h] [rbp-20h]int v12; // [rsp+34h] [rbp-1Ch]_BYTE *v13; // [rsp+38h] [rbp-18h]__int64 v14; // [rsp+40h] [rbp-10h]unsigned __int64 v15; // [rsp+48h] [rbp-8h]*a3 = 4 * ((a2 + 2) / 3);v13 = malloc(*a3);if ( !v13 )return 0i64;v15 = 0i64;v14 = 0i64;while ( v15 < a2 ){v4 = v15++;v12 = *(unsigned __int8 *)(a1 + v4);if ( v15 >= a2 ){v6 = 0;}else{v5 = v15++;v6 = *(unsigned __int8 *)(a1 + v5);}v11 = v6;if ( v15 >= a2 ){v8 = 0;}else{v7 = v15++;v8 = *(unsigned __int8 *)(a1 + v7);}v10 = (v11 << 8) + (v12 << 16) + v8;v13[v14] = base64_table[v8 & 0x3F];v13[v14 + 1] = base64_table[(v10 >> 6) & 0x3F];v13[v14 + 2] = base64_table[(v10 >> 12) & 0x3F];v9 = v14 + 3;v14 += 4i64;v13[v9] = base64_table[(v10 >> 18) & 0x3F];if ( !setjmp(env) )exception_handler();}if ( a2 % 3 == 1 ){v13[*a3 - 1] = 61;}else if ( a2 % 3 != 2 ){goto LABEL_18;}v13[*a3 - 2] = 61;
LABEL_18:v13[*a3] = 0;return v13;
}

这个代码是简单的还原了反方向的base64加密过程,参杂了base64_table,区别于一般的base64加密这边是属于自己创建了码表,所以我们还要去获得这个码表,直接追踪可以看到一个码表

但是程序又不止有这个码表,可以看到上面的test函数中在base64加密进程后面还有一个函数exception_handler(),点进去这个函数

发现接收的函数时码表,接着追踪这个函数

char *__fastcall generate_base64_table(const char *a1)
{size_t v1; // rbxsize_t v2; // raxint v3; // eaxchar v5; // [rsp+27h] [rbp-59h]char *Destination; // [rsp+30h] [rbp-50h]char *v7; // [rsp+40h] [rbp-40h]int i; // [rsp+4Ch] [rbp-34h]v7 = (char *)malloc(0x41ui64);srand(*a1);v1 = strlen("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");v2 = strlen(a1);Destination = (char *)malloc(v1 + v2 + 1);strcpy(Destination, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");strcat(Destination, a1);for ( i = 63; i > 0; --i ){v3 = rand();v5 = Destination[v3 % (i + 1)];Destination[v3 % (i + 1)] = Destination[i];Destination[i] = v5;}strncpy(v7, Destination, 0x40ui64);v7[64] = 61;v7[65] = 0;free(Destination);strcpy(base64_table, v7);return base64_table;
}

这个函数就是对码表的一个处理,从在里面可以看到,码表在一定条件下会发生变化,具体怎么发生变化要和base64的加密原理联合起来理解,这个函数接收一个参数a1,采用随机数进行计算去作为码表对应字符的下角标,历遍整个码表依次和随机数计算得到的下角标进行替换。给了一个字符集,后面的destination是由这个字符集和a1组成的,组成之后会用上面说到的方法对这个destination进行打乱,之后输出形成一个新的码表。

到这里我们只知道码表怎么生成的,那跳转总共会生成几个码表呢,又或者说进行base64加密的过程中会用到几个码表呢,所以要结合base64加密的原理来理解,也就是这部分代码

    v4 = v15++;v12 = *(unsigned __int8 *)(a1 + v4);if ( v15 >= a2 ){v6 = 0;}else{v5 = v15++;v6 = *(unsigned __int8 *)(a1 + v5);}v11 = v6;if ( v15 >= a2 ){v8 = 0;}else{v7 = v15++;v8 = *(unsigned __int8 *)(a1 + v7);}

按3字节一组读取字符,每进行3个字节的加密之后都会重新更新一次码表,那么我们还要知道加密之前的字符串由多长,但是我们只知道加密之后的字符串也就是YkLYv1Xj23X7N0E5eoFgUveKeos1XS8K9r4g有36位,按照base64加密的原理25~27位字符组成的字符串加密之后会变成36位的字符串,原因是可能后面会有两个=的填充,这边元字符串的长度就是3的倍数也就是27。

也就是我们要得到9个码表,我们在更换码表的函数上面下断点

进入动调

这边要写入充分多的字符才能得到足够的码表,输入之后这边是第一个码表

f9继续动调可以获得第二个码表

重复上面的操作就可以获得9个码表

接着就是写代码去解密,但是写完之后发现理解的不是特别到位,被上面说到的提取3个字符之后换一次码表误导了,3个是加密之前的字符串,对应加密之后的应该是4个然后每4个进行一轮解密对应一个码表,上面也说到是反向的base64加密,这边的反向也不是把一整个字符串反转过来,而是,每一轮加密也就是每4个字符串进行一次反转,所以单独提取出来4个字符之后进行一次反转,之后也不是单纯的base64解密,而是通过映射字符串和码表,因为是自定义的码表。

def custom_base64_decode(encoded_strings, key):# 初始化flagflag = ''# 标准base64字符表standard_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"# 遍历每个编码字符串for i in range(len(encoded_strings)):# 从key中提取4个字符并反转if i*4+4 > len(key):breakstr1 = key[i*4:i*4+4][::-1]# 获取当前的编码表current_table = encoded_strings[i]# 创建从自定义表到标准表的映射trans_table = str.maketrans(current_table, standard_base64)# 转换编码字符串decoded_chunk = str1.translate(trans_table)# 进行base64解码try:# Python的base64模块要求输入是4的倍数,如果不是,添加'='填充padding_needed = (4 - len(decoded_chunk) % 4) % 4decoded_chunk += '=' * padding_needed# 解码并添加到flagflag += base64.b64decode(decoded_chunk).decode('utf-8')except:# 如果解码失败,跳过这个块continuereturn flag# 导入base64模块
import base64# 定义要解密的数据
a = ["+86420ywusqomkigecaYWUSQOMKIGECABDFHJLNPRTVXZbdfhjlnprtvxz13579/", "YsVO0tvT2o4puZ38j1dwf7MArGPNeQLDRHUK+SChbFanmklWEcgixXJIq6y5B/9z", "xDfpNE4LYH5Tk+MRtrlv1oFbQm0gP37eqIajh2syUnZcSV8iBK6O/XWuzdCwA9GJ", "YvHeOZECmTyg0Mw2i7PIGKblsfF59rzUk6p3hVdW1qaQ+xRANnXLj48BcJDotS/u", "xDfpNE4LYH5Tk+MRtrlv1oFbQm0gP37eqIajh2syUnZcSV8iBK6O/XWuzdCwA9GJ", "YvHeOZECmTyg0Mw2i7PIGKblsfF59rzUk6p3hVdW1qaQ+xRANnXLj48BcJDotS/u", "xDfpNE4LYH5Tk+MRtrlv1oFbQm0gP37eqIajh2syUnZcSV8iBK6O/XWuzdCwA9GJ", "YvHeOZECmTyg0Mw2i7PIGKblsfF59rzUk6p3hVdW1qaQ+xRANnXLj48BcJDotS/u", "xDfpNE4LYH5Tk+MRtrlv1oFbQm0gP37eqIajh2syUnZcSV8iBK6O/XWuzdCwA9GJ"]b = 'YkLYv1Xj23X7N0E5eoFgUveKeos1XS8K9r4g'# 解密并打印结果
decrypted_flag = custom_base64_decode(a, b)
print("解密后的flag:", decrypted_flag)

[SWPUCTF 2023 秋季新生赛]IDA动态调试

die查一下

ida打开看主函数

输出一个东西之后直接停止程序了,接着追踪看看其他的

看到类似flag设置的地方,这边还有一个函数,后面是对这个函数的结果的验证,给了给if语句后面会释放内存,我们接着看这个函数

这段代码返回的是v2的地址,但是声明v2的地方也就是这个函数,当这个函数执行完成之后v2分配的内存会被自动收回,所以这边会导致一个程序的错乱,我们不妨执行一下这个程序看看

直接这就是空白,纵观整个程序问题就是出在这里,所以我们在这边下一个断点,调试看看,直接追踪v2的值,因为我们是在返回v2处也就是v2被删除的时候下的断点,所以我们这是后看v2的值是在的,也就是上面异或的结果

结果就是flag

[HNCTF 2022 WEEK3]Help_Me!

die查一下

ida打开,直接去看main函数看不到什么东西,这题要去看strings

直接追踪到为函数这边是func函数

这边有提示信息输出flag的格式所以我们要达成整个函数的条件,我们可以运行一下程序

就是在一定条件下选择这几个课,得到最高分,至于选择的逻辑就是要逆向去找了,还是在string里面去找,可以找到真的main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{__int64 v3; // rbx__int64 v4; // r8__int64 v5; // rdxint v6; // ebxint v7; // esiunsigned int v8; // ediint v10; // [rsp+28h] [rbp-F0h]int v11; // [rsp+2Ch] [rbp-ECh]int v12[24]; // [rsp+30h] [rbp-E8h]int v13[34]; // [rsp+90h] [rbp-88h]v3 = 0i64;_main();puts("Welc0me T0 HNCTF!");puts(&byte_488020);puts(&byte_488050);puts(&byte_488093);v4 = 26i64;v12[0] = 26;v12[1] = 59;v12[2] = 30;v12[3] = 19;v12[4] = 66;v12[5] = 85;v12[6] = 94;v12[7] = 8;v12[8] = 3;v12[9] = 44;v12[20] = 0;v12[10] = 5;v12[11] = 1;v12[12] = 41;v12[13] = 82;v12[14] = 76;v12[15] = 1;v12[16] = 12;v12[17] = 81;v12[18] = 73;v12[19] = 32;v13[0] = 71;v13[1] = 34;v13[20] = 0;v13[2] = 82;v13[3] = 23;v13[4] = 1;v13[5] = 88;v13[6] = 12;v13[7] = 57;v13[8] = 10;v13[9] = 68;v13[10] = 5;v13[11] = 33;v13[12] = 37;v13[13] = 69;v13[14] = 98;v13[15] = 24;v13[16] = 26;v13[17] = 83;v13[18] = 16;v13[19] = 26;while ( 1 ){v5 = (unsigned int)v3++;printf("(%d).%d\n", v5, v4);if ( v3 == 20 )break;v4 = (unsigned int)v12[v3];}puts(&byte_4880AF);std::istream::operator>>(refptr__ZSt3cin);puts(&byte_4880BF);if ( v10 <= 0 ){v7 = 1;}else{v6 = 0;v7 = 1;v8 = 0;do{++v6;std::istream::operator>>(refptr__ZSt3cin);v8 += v13[v11];v7 *= v12[v11];}while ( v10 > v6 );if ( v8 > 200 ){printf(aAnd1);exit(0);}}if ( (unsigned int)func(v7) )printf(aOi);elseprintf(aScore);return 0;
}

可以看看到不能超过200,所以重要的还是上面提到的func函数,经过了解这是一个类似背包问题的一种算法,简单来说就是要在一定条件下,使得得到的分数最高,这边的条件就是总共的重量不能超过两百,价值就是v12数组,重量就是v13数组

扔给ai就可以解决

def knapsack_01(values, weights, capacity):n = len(values)# DP表:dp[i][w] 表示前i个物品在容量w下的最大价值dp = [[0] * (capacity + 1) for _ in range(n + 1)]for i in range(1, n + 1):for w in range(1, capacity + 1):if weights[i-1] <= w:# 可以选择拿或不拿当前物品dp[i][w] = max(dp[i-1][w], values[i-1] + dp[i-1][w - weights[i-1]])else:# 当前物品太重,不能拿dp[i][w] = dp[i-1][w]# 回溯找出选了哪些物品selected = []w = capacityfor i in range(n, 0, -1):if dp[i][w] != dp[i-1][w]:selected.append(i-1)w -= weights[i-1]return dp[n][capacity], selected# 给定的数据
v12 = [26, 59, 30, 19, 66, 85, 94, 8, 3, 44,5, 1, 41, 82, 76, 1, 12, 81, 73, 32
]
v13 = [71, 34, 82, 23, 1, 88, 12, 57, 10, 68,5, 33, 37, 69, 98, 24, 26, 83, 16, 26
]
capacity = 200max_value, selected_items = knapsack_01(v12, v13, capacity)print("最大价值:", max_value)
print("选择的物品索引:", selected_items)
print("选择的物品价值:", [v12[i] for i in selected_items])
print("选择的物品重量:", [v13[i] for i in selected_items])
print("总重量:", sum([v13[i] for i in selected_items]))

但是直接用程序又不行,输入之后会直接退出程序,所以还要下断点动调

断点下在跳出之前即可,执行之后慢慢用f8调试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97389.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97389.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java试题-选择题(22)

Java试题-选择题&#xff08;22&#xff09; 题目以下对JDBC事务描述错误的是 &#xff1f; A) JDBC事务属于JAVA事务的一种 B) JDBC事务属于容器事务类型 C) JDBC事务可以保证操作的完整性和一致性 D) JDBC事务是由Connection发起的&#xff0c;并由Connection控制要通过可滚动…

蓝牙5.3核心技术架构解析:从控制器到主机的无线通信设计

蓝牙5.3核心技术架构解析&#xff1a;从控制器到主机的无线通信设计在无线通信领域&#xff0c;蓝牙技术如何通过精巧的架构设计实现设备间的高效互操作&#xff1f;答案在于其分层架构与标准化的接口定义。蓝牙5.3核心规范作为现代无线通信的重要标准&#xff0c;其系统架构设…

android View#performClick() 和 View#callOnClick() 的差异

文章目录performClick()callOnClick()关键区别对比总结在 Android 中&#xff0c;View.performClick() 和 View.callOnClick() 都是用于触发视图点击事件的方法&#xff0c;但它们的设计目的和执行逻辑存在细微差异&#xff0c;具体区别如下&#xff1a;performClick() 核心作…

PHP单独使用phinx使用数据库迁移

可以独立使用的迁移包对比后&#xff0c;感觉phinx更接近PHP的使用习惯。 为什么要单独用&#xff1f; 因为我不想数据库的迁移文件依赖于某种框架。本来是可以在框架里直接安装这个包的&#xff0c;但是发现这个包依赖cakephp&#xff0c;而cakephp的函数与thinkphp的env()函…

从零开始学习单片机18

使用STM32CubeMX创建工程选择对应芯片后创建工程&#xff0c;首先设置时钟源内部时钟源包括LSI&#xff08;低速时钟&#xff09;和HSI&#xff08;高速时钟&#xff09;&#xff0c;使用内部时钟源就需要将图中的一二处勾选HCLK是芯片运行时的评率&#xff0c;虽然下面标的最大…

如何使用 DeepSeek 帮助自己的工作?

技术文章大纲&#xff1a;利用 DeepSeek 提升工作效率 了解 DeepSeek 的基本功能 DeepSeek 的核心能力&#xff1a;文本生成、代码辅助、数据分析支持的平台与访问方式&#xff08;网页端/API/集成工具&#xff09;适用场景&#xff1a;技术文档撰写、自动化流程设计、数据处理…

计算机毕设javayit商城 基于SSM框架的校园二手交易全流程管理系统设计与实现 Java+MySQL的校园二手商品交易与供需对接平台开发

计算机毕设 javayit 商城uwd1i9 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09;本套源码可以先看具体功能演示视频领取&#xff0c;文末有联xi 可分享随着校园二手物品流通需求增长&#xff0c;传统校园二手交易依赖线下摆摊、社群发布的模式&#xff0c;存在信息分…

Java函数式编程之【流(Stream)性能优化】

Java函数式编程之【流&#xff08;Stream&#xff09;性能优化一、流&#xff08;Stream&#xff09;性能优化的预备知识&#xff08;一&#xff09;并行与并发的区别&#xff08;二&#xff09;Stream操作特性分类&#xff08;三&#xff09;Stream流管道的相关知识二、流&…

Cybero: 1靶场渗透

Cybero: 1 来自 <Cybero: 1 ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.168.23.139 3&#xff0c;对靶机进行端口服务探…

【学习笔记】非异步安全函数(禁止在信号处理中调用)

非异步安全函数&#xff08;禁止在信号处理中调用&#xff09; 一、测试 在信号处理函数&#xff08;Signal Handler&#xff09;中&#xff0c;只有异步信号安全函数&#xff08;async-signal-safe functions&#xff09; 可以安全调用。这类函数的特点是&#xff1a;不使用全…

【K8s】整体认识K8s之K8s的控制器

作用&#xff1a;控制器的作用就是持续监控k8s集群的状态&#xff0c;让它处于我们期望的状态&#xff0c;常见的控制器有replicaset、deployment、daemonset、statefulset 、job 、cronjobReplicaset控制一组pod的副本数&#xff0c;始终与预设的值相同&#xff0c;会持续监视…

R ggplot2学习Nature子刊一张图,换数据即可用!

本次使用R语言复现Nature Communications上的1张组合图,这张图兼具颜值+节约版面! Fig. 1 b原图 ❤️复现效果图-b图❤️ ✅读入测试数据! ✅关键代码, # 关键代码 library(ggplot2) library(dplyr) library(cowplot)# --- 外圈图 --- p_outer <- ggplot(data_aug, aes…

迷你电脑用到什么型号的RJ45网口

迷你电脑常用的 RJ45 网口主要有标准 RJ45 网口和 Mini RJ45 网口两种。标准 RJ45 网口是最常见的类型&#xff0c;遵循 IEEE 802.3i 标准&#xff0c;采用 8P8C&#xff08;8 Position 8 Contact&#xff0c;8 位 8 触点&#xff09;连接器&#xff0c;有 T568A 和 T568B 两种…

网络安全 | 保护智能家居和企业IoT设备的安全策略

网络安全 | 保护智能家居和企业IoT设备的安全策略 一、前言 二、智能家居和企业 IoT 设备面临的安全威胁 2.1 设备自身安全缺陷 2.2 网络通信安全隐患 2.3 数据隐私风险 2.4 恶意软件和攻击手段 三、保护智能家居和企业 IoT 设备的安全策略 3.1 设备安全设计与制造环节的考量 3…

优化器全指南:从原理到调优实战

本文将带你轻松理解深度学习中的“导航系统”——优化器。我们会避开复杂的数学公式,用大量的比喻和图示,让你彻底明白 Adam、AdamW、LAMB 是怎么回事,并学会如何调节它们的关键参数。 第一部分:核心概念:优化器是什么? 一个简单的比喻: 想象你在一座大雾弥漫的山里(…

Notepad++使用技巧1

1.打开官方参考代码经常看到下图这种行尾很多空格的代码&#xff0c;一点都不合符华为的书写规范&#xff0c;阅读起来容易让人烦躁不安。初学者建议看看华为的代码书写规范&#xff0c;你将少走很多弯路&#xff0c;终生受益。2.快速去掉行尾很多空格方法点击顶部菜单栏“宏”…

AIoT云边协同方式

随着物联网&#xff08;IoT&#xff09;与人工智能&#xff08;AI&#xff09;的深度融合&#xff0c;AIoT&#xff08;人工智能物联网&#xff09;作为一种新兴技术范式&#xff0c;正在推动智能设备与产业的快速发展。AIoT通过云边协同的方式&#xff0c;将边缘侧的IoT设备、…

MIT 6.5840 (Spring, 2024) 通关指南——Lab 1: MapReduce

MIT 6.5840 (Spring, 2024) – Lab 1: MapReduce &#x1f468;‍&#x1f4bb; Charles &#x1f517; 实验手册&#xff1a; 6.5840 Lab 1: MapReduce &#x1f4c3; MapReduce 论文原文&#xff1a; mapreduce-osdi04.pdf ✍️ 本系列前文&#xff1a; MIT 6.5840 (Spring, …

吴恩达机器学习作业五:神经网络正向传播

数据集在作业一正向传播正向传播&#xff08;Forward Propagation&#xff09;是神经网络计算过程中的核心步骤&#xff0c;指的是将输入数据通过神经网络的各层依次传递&#xff0c;最终得到输出结果的过程。核心原理在神经网络中&#xff0c;信息从输入层流入&#xff0c;经过…

网络编程(4)

【0】复习 sockfdsocket(); //指定网络信息 bind(); listen(); //创建表 fd_set rfds,tempfds; FD_ZERO(); FD_SET(sockfd); max sockfd while(1) {tempfdsrfds;select(max1,&tempfds)if(FD_ISSET(scokfd,&tempfds)){acceptfdaccept();FD_SET(acceptfd,&rfds);if(m…