攻防世界 reverse-box

reverse-box

C语言

  • 题目下载下来,弄半天始终觉得有问题。百度发现题目少给了输出字符串。

  • 开始再次看题,被自己坑惨了。。。因为生成数据表的函数中自己只看到了生成的随机数赋值了给了数据表的第一次元素,那整个题就有点奇怪了。看了又看,才发先最后用到了随机数生成数据的,只是屏幕容不下了。。。
    在这里插入图片描述

  • 另外就是先将每次生成索引值 v7 用C语言写出来后打印看看, 但大多数是负数,很大的数。这显然不对的,因为我们运行程序时输入的参数都是可打印字符 (ASCII: 32-127),伪代码不靠谱,果断去看看了汇编。
    在这里插入图片描述

  • 其次就是 伪代码中的 __ROR__了,看了汇编知道了 ror 指令,将数据想右位移动指定的位数。以为只是简单的 >> ,就这样写了整个题的爆破代码。但是始终不对,花了很时间,不甘心,就ida中动调,C语言中调试,每个步骤对比结果,才找到是 ror 这里错了。。。 原来 ror 是右移动位后会把多余的位移动到最左边,即一个圆圈转。

  • exp:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> 
    
    void generate(int a, int *result)
    {
    	int v7 = 1, v2 = 0, v3 = 0, temp = 0;
    	int v4 = 0, v5 = 0, v8 = 1, v9 = 0;
    	result[0] = a;
    	do
    	{
    		v2 = v7 ^ 2 * v7;
    		if((v7 & 0x80) == 0)
    			v3 = 0;
    		else
    			v3 = 27;
    		v7 = v2 ^ v3;
    		v7 = v7 & 0xFF;
    		
        	v4 = (4 * (2 * v8 ^ v8) ^ 2 * v8 ^ v8)&0xff;
    		v9 = ((16 * v4 ^ v4)&0xff);
        	if ( v9 >= 0 && v9 <= 127 )
          		v5 = 0;
        	else
          		v5 = 9;
        	v8 = (v9 ^ v5);
    		if(v7 < 127)
        		result[v7] = (((v8 >> 4) | ((v8 & 0xF) << 4)) ^ ((v8 >> 5) | ((v8&0x1F) << 3)) ^ ((v8 >> 6) | 						   ((v8&0x3F)<<2) ) ^ ((v8 >> 7) | ((v8&0xFF)<<1) ) ^ (v8 ^ a))&0xff;
        		
    	}while(v7 != 1); 
    }
    
    int main(void)
    {
    	int *result = (int *)malloc(sizeof(int)*127);
    	int i = 0, value = 0, j = 0;	
    	char a[] = "95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a";
    	
    	for(i = 1; i < 256; i++)
    	{
    		generate(i, result);
    		
    		if(result[84] == 0x95)
    			break;
    	}
    	
    	for(i = 0; i < strlen(a); i += 2)
    	{
    		if(a[i] >= 48 && a[i] <= 57)
    			a[i] -= 48;
    		else
    			a[i] -= 87;
    		
    		if(a[i+1] >= 48 && a[i+1] <= 57)
    			a[i+1] -= 48;
    		else
    			a[i+1] -= 87;
    			
    		value = a[i+1] | a[i]*16;
    		
    		for(j = 32; j < 127; j++)
    		{
    			if(result[j] == value)
    			{
    				printf("%c", j);
    				break;
    			}
    		
    		} 
    	}	
    } 
    

在这里插入图片描述

python

  • 做完去看了看网上的 writeup, 发现都是用gdb写脚本搞的,然后去学习了下。

  • 使用 gdb的 define 命令可以定义一系列的gdb指令。首先找到要下断点地址,这个在ida中很容易。

    这里有2中方法,执行gdb脚本,一:直接输入defien命令,输入指令,最后执行。二:单独写成一个脚本文件使用 source 来执行。

  • 这里直接写的脚本文件使用 source执行。

    while($i<$total)
      b *0x80485b4
      b *0x8048707
      run T
      set $i=$i+1
      set *(char*)($ebp-0xc)=$i
      continue
      if ($eax==0x95)
        print $i
        x/127xb $esp+0x1c  #这里有一个知识点,最后总结。
        set $i=256
      stop
    end
    

在这里插入图片描述

  • 因为可打印字符的ASCII: 32-127,所以我们打印出前128个数据即可。最后解密。python确实方便,各种方法直接调用即可。

    list =  [0xd6,0xc9,0xc2,0xce,0x47,0xde,0xda,0x70
    	,0x85,0xb4,0xd2,0x9e,0x4b,0x62,0x1e,0xc3
    	,0x7f,0x37,0x7c,0xc8,0x4f,0xec,0xf2,0x45
    	,0x18,0x61,0x17,0x1a,0x29,0x11,0xc7,0x75
    	,0x02,0x48,0x26,0x93,0x83,0x8a,0x42,0x79
    	,0x81,0x10,0x50,0x44,0xc4,0x6d,0x84,0xa0
    	,0xb1,0x72,0x96,0x76,0xad,0x23,0xb0,0x2f
    	,0xb2,0xa7,0x35,0x57,0x5e,0x92,0x07,0xc0
    	,0xbc,0x36,0x99,0xaf,0xae,0xdb,0xef,0x15
    	,0xe7,0x8e,0x63,0x06,0x9c,0x56,0x9a,0x31
    	,0xe6,0x64,0xb5,0x58,0x95,0x49,0x04,0xee
    	,0xdf,0x7e,0x0b,0x8c,0xff,0xf9,0xed,0x7a
    	,0x65,0x5a,0x1f,0x4e,0xf6,0xf8,0x86,0x30
    	,0xf0,0x4c,0xb7,0xca,0xe5,0x89,0x2a,0x1d
    	,0xe4,0x16,0xf5,0x3a,0x27,0x28,0x8d,0x40
    	,0x09,0x03,0x6f,0x94,0xa5,0x4a,0x46]
    
    flag = ""
    s = "95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a";
    for i in range(0, len(s), 2):
        s1 = int(s[i:i+2], 16)
        flag += chr(list.index(s1))
    print (flag)
    
  • 总结:这道题收获还是很大。1:对ida中汇编语言的解读更熟悉了些,注意各种 al 取最低字节数据。 2:ror指令的了解,及对他的C语言用法:如 ror a,3 那C语言为:((a>>3)| ((a&7) << 5))。 3:使用gdb写脚本。

    gdb脚本中的 查看内存内容的方法:x/<n/f/u> n、f、u是可选的参数。

    n:显示的内存单元的个数,f:表示显示的格式,其中:s:字符串显示,x:按十六进制格式显示,d:按十进制格式显示变量

    u:按十六进制格式显示无符号整型,t:按二进制格式显示, o:按八进制格式显示,c:按字符格式显示变量。

    最后的u表示每个单元的大小,其中:b表示单字节,h表示双字节,w表示四字 节,g表示八字节。

    那上面脚本写的 x/127xb 表示将 127个的单字节单元的数据按16进制格式显示出来。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值