reverse-daily(1)-audio_visual_receiver_code

Posted on 2016-09-11 19:38  LOMOoO  阅读(336)  评论(0编辑  收藏  举报

本人第一篇随笔,就以一篇CTF逆向分析的文章开始吧!

链接:http://pan.baidu.com/s/1eS6xFIa 密码:u14d

因为re的分析比较琐碎,所以主要就挑一些重点东西来说。

据说这道题是谷歌的一道题目,然而我觉得题目不算很好,有很大程度上要靠猜测出题人的意图,有为了出题而出题的嫌疑,不过还是首先来上手分析吧

1.首先拿到程序用ida载入,会发现这是一个elf文件,程序的主体结构很简单,首先进入main函数,看到read_button函数,进入

2.简单分析一下read_button函数可得到这样一个对应关系

  U/u >0;   D/d>1;   L/l>2;   R/r>3;   A/a>4;   B/b>5

3.再回到main函数看到

v3 = read_button();
(*(&buttons + v3))();

而如图:

可知输入不同值分别对应运行up,down,left,right,a,b各个程序

4.再对up,down,left,right,a,b几个函数分别进行分析,在a函数中看到有out_flag函数,进入后发现这是一个输出flag的函数:

5.然后就是对各个函数算法漫长的分析了,由分析可以得到这样一个简化版本,

db check
db state=5
1.down:  check^=state
             state=state>>1*8-state>>1
2.up:    check^=state
            state=3state
3.left:  check^=state
            state=2state
4.right: check^=state
            state=state>>3 循环右移
5.b:     check^=state
           state=~state
6.a:     check^=state
          state=state>>4 循环右移
          if(*cross_ptr==check)
           check=0
           cross_ptr++

6.初始时pos=&buffer,state=5,每运行left,right等其中的一个程序,就会首先将_int8 state的值放入buffer数组中pos所对应的位置,然后pos++,接着是对state的演算变化,现在来看check,可以看到a函数中要想运行out_flag函数的最重要的一个条件就是:if ( *(_BYTE *)cross_ptr == check ),而cross_ptr所对应的值如下:

7.而check在bss段中,由分析有每运行一次a,b等函数,首先做的就是check^=state,所以check的值实际上就是运行到当前时所有state值异或的结果,而如果a中

if ( *(_BYTE *)cross_ptr == check )这样一个条件成立的话,首先check=0,即对check清零,然后cross_ptr++

 

8.然后每个函数中都有这样一个判断

if ( (_BYTE *)pos - (_BYTE *)&buffer > 32 )
pos = &buffer;

即当buffer长度>32时即对其进行重写

 

9.a中最后一重判断:

if ( (_BYTE *)pos - (_BYTE *)&buffer > 29 )
output_flag();

即buffer到pos所指位置处长度>29时输出,由于条件8的存在所以输入字符串的长度其实并没有限制

 

10.再看out_flag函数,可以看到输出结果为flag数组和buffer各位异或的输出,而flag长度为30位:

 

11.这样一来,整个程序的结构就很清楚了,这道题的重点并不在程序的逆向,而主要在于算法的逆向分析,分析到这里,我就卡住了很久很久,因为就我的分析来看,这道题目基本无解,因为首先程序的输入长度就不能确定,其次对程序的爆破也不可行

 

12,坑爹的地方来了,我的一个学长这时候提醒我,注意各个函数的名称,我看了看,上下左右ab,这不是魂斗罗的大招吗,上上下下左右左右ba,因为flag长度为30

所以我就尝试了下uuddlrlrbauuddlrlrbauuddlrlrba,结果正是:

 

13,当然并不只有这样一种方法,如果揣测出题人意图的话,会发现,cross数组长度为3,而flag长度为30,而要想输出的话,最后以为肯定是a字符,这样一来,可以推测出这样一个关系:字符串长度为30,第十,二十,三十个字符分别为a,这样一来可以分十组,分别进行爆破,结合输出的ascii的范围,可以进一步缩小范围,以下的python代码是由我得学长所写,因为是他提供的第二种思路,我自己也尝试用c来写了下,当然c的话是很不好写,最好用python,有时间我会贴上自己的c代码

 

14.这道题目的确是不大好,如我开始所说,很大一部分要靠冒着很大风险来猜测,如果是打比赛如果我忘记了魂斗罗的大招的话,我肯定是不会做这道题的,当然这道题还是有很意义的,首先,加强了我算法分析的能力,这道题的算法还是有一定算法复杂度的,其次,python的编写,python绝对是最好用的脚本语言之一,我还在学习用好它的路上,最后,揣测出题人的意图,有时候能事半功倍,当然不要为了做题而做题

 

15.就写到这里吧!写篇随笔真的很耗时间。。。

 

  1 alp = '1234567890_{ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz}'
  2 flag = [0x46,0x5b,0x6b,0xe1,0x6f,0x5e,0xa3,0xd3,0xa2,0x1c,0x82,0xed,0x62,0x24,0x67,0x71,0xdd,0x6d,0xf3,0x20,0x83,0x8d,0xca,0x3e,0x33,0xc8,0x75,0x5a,0x68,0x87]
  3 cross = [0x25,0x68,0xef]
  4 cross_ptr = 0
  5 Buf = [0 for i in xrange(30)]
  6 State = 5
  7 Pos = 0
  8 Check = 0
  9 find = 0
 10 
 11 def up(pos,state,check,buf):
 12     buf[pos] = state
 13     pos += 1
 14     pos %= 33
 15     check ^= state
 16     state *= 3
 17     state &= 0xff
 18     return pos,state,check,buf
 19 
 20 def down(pos,state,check,buf):
 21     buf[pos] = state
 22     pos += 1
 23     pos %= 33
 24     check ^= state
 25     state >>= 1
 26     tmp = state
 27     state *= 8
 28     state -= tmp
 29     state &= 0xff
 30     return pos,state,check,buf
 31 
 32 def left(pos,state,check,buf):
 33     buf[pos] = state
 34     pos += 1
 35     pos %= 33
 36     check ^= state
 37     state *= 2
 38     state &= 0xff
 39     return pos,state,check,buf
 40 
 41 def right(pos,state,check,buf):
 42     buf[pos] = state
 43     pos += 1
 44     pos %= 33
 45     check ^= state
 46     tmp = 32*state
 47     state >>= 3
 48     state |= tmp
 49     state &= 0xff
 50     return pos,state,check,buf
 51 
 52 def b(pos,state,check,buf):
 53     buf[pos] = state
 54     pos += 1
 55     pos %= 33
 56     check ^= state
 57     state ^= 0xff
 58     state &= 0xff
 59     return pos,state,check,buf
 60 
 61 def a(pos,state,check,buf):
 62     global cross
 63     global cross_ptr
 64     buf[pos] = state
 65     pos += 1
 66     pos %= 33
 67     check ^= state
 68     tmp = state >> 4
 69     state *= 16
 70     state |= tmp
 71     state &= 0xff
 72     correct = 0
 73     if cross[cross_ptr] == check:
 74         check = 0
 75         correct = 1
 76         cross_ptr += 1
 77         if pos == 30:
 78             output_flag(buf)
 79     return pos,state,check,buf,correct
 80 
 81 def output_flag(buf):
 82     global flag
 83     s = ''
 84     for i in xrange(30):
 85         s += chr(flag[i]^buf[i])
 86     print s
 87 
 88 func = [up,down,left,right,b]
 89 
 90 def force(pos,state,check,buf):
 91     global find
 92     global flag
 93     global alp
 94     if find == 1:
 95         return
 96     if (pos+1)%10 == 0:
 97         pos,state,check,buf,c = a(pos,state,check,buf)
 98         if c == 0:
 99             return 
100         if pos == 30:
101             find = 1
102             return 
103     for v in func:
104         tmp1,tmp2,tmp3,tmp4 = v(pos,state,check,buf)
105         tmp = chr(flag[tmp1]^tmp2)
106         if tmp in alp:
107             force(tmp1,tmp2,tmp3,tmp4)
108 
109 force(Pos,State,Check,Buf)
110                 
111         
112