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