CTF show 数学不及格

拿到题目先查一下壳,看一下信息

发现是一个ELF文件,64位的

用IDA Pro 64 打开这个文件

然后点击F5进行伪代码转换

可以看到有五个if判断,第一个argc != 5这个判断并没有起太大作用,主要是下面四个if判断

根据题目,其实可以判断出来,这个就是一道数学题

现在开始逐步分析一下代码

赋值操作:

strtol函数,作用是把字符串转成长整型,具体解释看这个C 库函数 -- strtol() | 菜鸟教程

然后将v4传入f函数,剩下的v10,v11,v12和v4一样的操作,这里主要就是f函数

然后下面这几个if判断,可以理解为几个方程

假设x = v4,y = v9, a = v10,b = v11, c = v12,那么就有下面几个方程:

y - a = 151381742876(这里将十六进制转换成十进制了,下面的类同)

y - b = 117138004530

y - c = 155894355749

x + a + b + c = 1349446086540

很明显,五个未知数,四个方程解不出来的,这里还有一个点就是v9是通过v4得出的,也就是v9和v4还有关联,只要求出来一个,所有的都可以解出来了

现在查看一下f函数的内容

可以看到传进去的v4也就是这个局部变量的a1,是有限制的,即,1 < a1 <= 200

所以就知道了v4的取值范围也是(1-200]

那就根据这些条件,话不多说直接上脚本

cpp 复制代码
#include <stdio.h>
#include <windows.h>
#include <inttypes.h>

uint64_t y(int var_24);

int main() 
{
	uint64_t v10, v11, v12 ,argv = 0;
	uint64_t dbNumber = 0;
	for (int v4 = 1; v4 < 200; ++v4)
	{
		dbNumber = y(v4);
		v10 = dbNumber - 151381742876;
		v11 = dbNumber - 117138004530;
		v12 = dbNumber - 155894355749;
		argv = v4 + 25923;
		if (v4 + v12 + v11 + v10 == 1349446086540)
		{
			printf("v9=%" PRIX64 ",v10=%" PRIX64 ",v11=%" PRIX64 ",v12=%" PRIX64 ",v4=%X,argv=%" PRIX64 "\r\n", dbNumber, v10, v11, v12, v4,argv);
			printf("%" PRIX64 "%" PRIX64 "%" PRIX64 "%" PRIX64 "\r\n", v10, v11, v12, argv);
		}
	}
	system("pause");
}

uint64_t y(int var_24)
{
	uint64_t *ptr;
	uint64_t var_10;
	uint64_t var_14;
	if (var_24 <= 1)
	{
		return 0;
	}
	else if (var_24 <= 200)
	{
		ptr = (uint64_t *)malloc(var_24 * 8);
		ptr[0] = 1;
		ptr[1] = 1;
		var_10 = 0;
		for (var_14 = 2; var_14 < var_24; ++var_14)
		{
			ptr[var_14] = ptr[var_14 - 1] + ptr[var_14 - 2];
			var_10 = ptr[var_14];
		}
		free(ptr);
		return var_10;
	}
}

下面开始分析这个脚本的作用,以及如何写成的

首先,其中定义的变量都用了uint64_t,原因是,在我最开始写这个脚本的时候,用的long long型定义的,发现还是放不下其中的数值,数值貌似是5000亿,所以这里将所有的变量都改为uint64_t,不过用uint64_t的时候,需要包含头文件inttypes.h

类型 位数 是否有符号 等效传统类型 备注
uint64_t 64 无符号 unsigned long long 保证64位
unsigned long long 至少64 无符号 - 可能比64位更大(依赖平台)
size_t 平台相关 无符号 - 通常用于表示内存大小
uint32_t 32 无符号 unsigned int 32位无符号

然后接着往下分析,整体代码中除了主函数(main)还有一个y函数,这个等同于IDA中的f函数,也就是我将f函数的伪代码转换成C语言了,也就是用来计算IDA中v9的值

然后我main函数中,有一个for循环,这里我的思路是爆破v4的值,然后前面分析也知道了v4的值在(1,200]之间,所以利用一个for循环遍历v4,并将v4传入y函数中,用dbNumber接收返回值,这里dbNumber等同于IDA中的v9

然后v10、v11、v12的值都是通过dbNumber求出来的,也就是根据前面列的方程求

然后再加了一个if语句,是为了判断v4的值是否正确,也就是看看当前根据爆破出来的v4值求出来的v10、v11、v12是否正确,如果正确,那就全部输出出来

最后这个printf的用法,跟正常使用的时候不一样,这是为啥呢,因为我们定义的变量都是uint64_t,而printf 系列函数中,能正确格式化输出 uint64_t 类型的变量的就是PRIX64

  • 宏名称PRIx64

    • PRI:表示 "print"(格式化输出)

    • x:表示十六进制小写输出(X 表示大写十六进制)

    • 64:表示64位宽度

脚本的所有地方都解释清楚了,直接运行

可以看到,第一行是当时为了调试,看看所有变量有没有正确输出,第二行才是真正的flag,也就是将所有变量拼接起来,拼接顺序是v10、v11、v12、argv,为什么呢,因为在IDA中,赋值的地方就看到了v10是argv[1],v11是argv[2],v12是argv[3],v4是argv[4] - 25923,所以argv[4]=v4+25923,也就是我脚本中的argv变量

最后将得到的一串十六进制数复制到厨子中进行十六进制解密,就得到flag了


最后多说一句

如果师傅们还需要更多的资料,欢迎进入泷羽Sec资源库,里面不仅包含了各种面试题,还有各种网课资源,各种源码分享

泷羽Sec资料库,加入泷羽Sec帮会,享受各种IT资源,资源持续更新中

加入帮会-发现更有料的网安圈

相关推荐
以太Yitaai40 分钟前
TryHackMe“Smol”CTF挑战赛
安全·web安全
rocksun2 小时前
需要尽早知道的容器安全知识
安全·容器·kubernetes
中新赛克2 小时前
解读《网络安全法》最新修订,把握网络安全新趋势
安全·web安全
恰薯条的屑海鸥2 小时前
SQL注入篇-sqlmap的配置和使用
数据库·sql·安全·web安全·渗透测试·网络安全学习
网硕互联的小客服2 小时前
如何排查 Docker 容器资源占用过高的问题?
运维·服务器·网络·安全·docker·容器
CYRUS_STUDIO4 小时前
一文搞懂 SO 脱壳全流程:识别加壳、Frida Dump、原理深入解析
android·安全·逆向
Bruce_Liuxiaowei4 小时前
深度剖析OpenSSL心脏滴血漏洞与Struts2远程命令执行漏洞
struts·安全·web安全
科技小E8 小时前
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
人工智能·安全·智能手机
行云流水剑10 小时前
【学习记录】使用 Kali Linux 与 Hashcat 进行 WiFi 安全分析:合法的安全测试指南
linux·学习·安全
KKKlucifer10 小时前
加密通信 + 行为分析:运营商行业安全防御体系重构
网络·安全·重构