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资源,资源持续更新中

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

相关推荐
Web极客码16 分钟前
如何为你的WordPress网站选择合适的安全插件
网络·安全
一只鹿鹿鹿1 小时前
【网络安全】信息网络安全建设方案(WORD)
人工智能·安全·spring·web安全·低代码
卓码软件测评1 小时前
软件测评中网站类测评测试使用的BurpSuite-Web安全测试流程
测试工具·安全·web安全
爱学习的大牛1231 小时前
网络安全专业知识体系:成为专家需要做的
安全·web安全
DS小龙哥4 小时前
基于单片机汽车少儿安全预警系统
单片机·安全·汽车
菲路普科技4 小时前
国产芯+单北斗防爆终端:W5-D防爆智能手机,助力工业安全通信升级
安全·智能手机
m0_738120725 小时前
Solar月赛(应急响应)——攻击者使用什么漏洞获取了服务器的配置文件?
运维·服务器·安全·web安全·网络安全
网络研究院9 小时前
从内部保护你的网络
网络·安全·风险·成本·措施
wanhengidc11 小时前
高防服务器租用:保障数据安全
服务器·网络·安全
一只鹿鹿鹿15 小时前
【网络安全】等级保护2.0解决方案
运维·安全·web安全·架构·信息化