攻防世界 reverse asong

asong

算是小白第一次接触逆向真正算法的题吧. 吃了算法的亏, 逆向这个算法想了半天🤣

0x1分析
  • 下载下来三个文件, 但这不是我以前遇到的那种同一个题给不同的版本.

  • 依次看了下, 一个64位elf文件无壳, 2个文本文件. 打开文本文件后,没有头绪. 将elf文件载入ida.

  • 整个流程开始看不清楚做什么, 多看几次明白了. 先输入字符串, 打开一个that_girl文件读信息, 最后向out文件写信息. 但这怎么和flag联系起来呢. 其实那个out文件里的就是密文, 我们找到逆向算法, 通过密文求出明文(即我们的输入, 也是flag)

  • 下面具体分析每个函数. 第一函数: sub_400B4C 由于很简单, 直接给出函数功能.

在这里插入图片描述

  • sub_400B4C: 先判断, 再取 { } 之间的内容.

在这里插入图片描述

  • 下面就是我遇到的难点 1: v4哪里来的及 ++*(_DWORD *)(4LL * v2 + v4);语句的作用

在这里插入图片描述

  • 第一次遇到, 没有经验, 后来才想到通过汇编的查看, v4即是我们传了参数 a2(也就是主函数的v3), 这是通过寄存器传递. 64位与32位程序的区别吧. 但该语句功能还不是很清楚.在这里插入图片描述在这里插入图片描述

  • 继续看一个函数,sub_400E54: 看到这里, 就很清晰了, 就是先通过统计that_girl文件中每个字符出现的次数, 然后按照一定的顺序输入字符, 把每个字符出现的次数按一定顺序给下面的 v5 数组赋值. 那 sub_400936转换字符函数我们是不用管的.

在这里插入图片描述

  • 下面是2个加密函数, 我算法太菜, 逆算法想半天😅, 首先sub_400D33((unsigned __int8 *)v5);

在这里插入图片描述

  • 然后 sub_400DB4(v5, v4); 解释起来有点抽象…注意是一个字节, 所以多出的位要舍弃在这里插入图片描述
  • 举个例子:在这里插入图片描述
  • 最后一个函数: **sub_400CC0((__int64)v5, “out”, v4);**将加密后的值写入 out文件.
0x2逆向解密
  • 直接exp:

    #include <stdio.h>
    
    int main(void)
    {
    	union
    	{
    		unsigned char ida[152];
    		int change[38];
    	}A = {
       			22,   0,   0,   0,   0,   0,   0,   0,   6,   0, 
       			0,   0,   2,   0,   0,   0,  30,   0,   0,   0, 
       			24,   0,   0,   0,   9,   0,   0,   0,   1,   0, 
       			0,   0,  21,   0,   0,   0,   7,   0,   0,   0, 
       			18,   0,   0,   0,  10,   0,   0,   0,   8,   0, 
        		0,   0,  12,   0,   0,   0,  17,   0,   0,   0, 
       			23,   0,   0,   0,  13,   0,   0,   0,   4,   0, 
        		0,   0,   3,   0,   0,   0,  14,   0,   0,   0, 
      			19,   0,   0,   0,  11,   0,   0,   0,  20,   0, 
        		0,   0,  16,   0,   0,   0,  15,   0,   0,   0, 
        		5,   0,   0,   0,  25,   0,   0,   0,  36,   0, 
        		0,   0,  27,   0,   0,   0,  28,   0,   0,   0, 
       			29,   0,   0,   0,  37,   0,   0,   0,  31,   0, 
        		0,   0,  32,   0,   0,   0,  33,   0,   0,   0, 
      			26,   0,   0,   0,  34,   0,   0,   0,  35,   0, 
       			0,   0
    				};
    	
    	int i = 0, j = 0, a[100] = {0}, temp = 0, lenth = 0;
    	unsigned char b[100] = {0}, c[2000] = {0};
    	int count[127] = {0}, change_[38] = {0};
    	char flag[100] = {0};
    	
    	FILE *fp = NULL;
    	
    	fp = fopen("out", "rb");			//先从文件读取密文
    	lenth = fread(b, 1, 100, fp);		//返回读取成功个数, 确定字符个数
    	fclose(fp);
    		
        
        									//第一层解密
    	temp = b[lenth-1]&7;			    //&7  取后三位数据.
    	for(i = 0; i < lenth; i++)						
    	{									//从整体来看就是将整个数据右移动3位
    		a[i] = (b[i] >> 3) | (temp << 5);
    		temp = b[i]&7;
    	} 
    	
    	fp = fopen("that_girl", "rb"); //打开that_girl, 统计字符数.
    	fread(c, 1, 1742, fp);
    	fclose(fp); 
    	
    	for(i = 0; i < sizeof(c); i++)
    	{
    		if(c[i] >= 65 && c[i] <= 90)  
    			c[i] += 32;					//因为不区分大小写, 都转换为小写
    			
    		count[c[i]]++; 
    	} 
    	
    	i = 0, j = 0;
    	while(A.change[i]) 
    	{
    		change_[j++] = A.change[i];  //统计每个字符出现次数
    		i = A.change[i];  
    	}
    	j -= 1;
    
    	temp = a[0], a[0] = a[change_[j]];   //第二层解密
    	for(i = 0; i < lenth-2; i++)		 //按照给定赋值找到一个未变的值, 倒序赋值回去即可
    	{
    		a[change_[j]] = a[change_[--j]];
    	}
    	a[change_[j]] = temp; 
    	
    	 
    	for(i = 0; i < lenth; i++) //第三层解密, 比对每个字符出现的次数的顺序,进而确定输入顺序
    	{
    		for(j = 0; j < 127; j++)
    		{
    			if(a[i] == count[j])
    			{
    				flag[i] = j; 
    				break;
    			}
    		} 
    	} 
    	
    	printf("QCTF{%s}", flag);   //得到flag.
    	
    	return 0; 
    } 
    

在这里插入图片描述

  • 总结: (1)算法还是太重要. 算法稍微好点的话, 这道题就轻松很多. (2)注意64位程序的传递参数的方式(3)要习惯看汇编代码
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值