2015-ctf-32C3-blobberry(PiOS)
逆了下这道题的算法,在img文件中重要的文件就是这个bootcode.bin,伙伴搜到了相应ida可用的cpu的python文件,于是直接用IDA反汇编这个程序即可由于不能反编译,只能看汇编代码,不过程序逻辑还算简单,逆起来比较轻松。
1. 确定输出函数。
由于查到0x31b的位置是banner信息,而0x2b2的位置是提示信息,能够确定0x62e位置的函数是类似于puts的含数。0x5c6的代码几乎只是一个循环,我将其命名为延时函数。
由于提示了输入flag的信息后,直接调用了0x5da函数,这个就是一个read函数。根据错误和正确的信息都能找到相应的位置,前面的函数几乎就是判定的主逻辑函数,命名后的逻辑如下:
2. 在main_logic函数里面几乎是初始化一下串口之类的操作,并且以r6寄存器为计数器的一个循环,重点在于0x87c函数。
在0x87c函数中分三步:r6=0,r6=1,r6>1三种情况,如下:
由于这三个地方都是标号(不是函数),而且返回都是b lr,所以直接返回到函数调用位置,即0x87c调用的位置,只有在r0和r10都为0的地方采用了pop r6,lr,这时候返回到了主逻辑里面,打印结果信息。
3. 根据其那面的分析,来逆向代码,就比较容易了。根据逆向的逻辑发现,最终的r0和r10只与三个文件内地址出的值有关,从0~255,0x7d6~0x7d6+255,0x31b~而中间某些内存值在中途改变,由于0x31b处是输入的值所在的位置。所以是可变的,而其他地方,如果在允许过程中与该位置没有运算,那么即使改变,也可以认为是定值(因为与输入无关)。通过打印改变各个值的位置以及参与改变运算的值的位置发现,均不属于0x31b~0x31b+0x28,所以此时可以认定,判定结果处的r0和r10只是输入值与一些定值之间进行直接的运算(不会受多次修改影响)。
r1^ = r0
r13 ^= r1
r10 |= r13
最终可转换成{r10 |= 定值 ^ 输入值[i] ^ 定值}的形式,由于当时考虑的比较复杂,所以觉得用z3求解器来求解,于是在逆向代码中生成约束条件,总的逆向以及约束生成代码如下:
memory = [0] * 0x200
file_r = open("./bootcode.bin", 'rb')
memory = file_r.read()
file_r.close()
memory = [ord(c) for c in memory]
r = [0] * 16
g_length = 0x28
def func0(memory):
r[10] = 0
r[9] = 0
for r[9] in range(0, 0x100):
r[7] = 0
r[7] += r[9]
memory[r[7]] = r[9] & 0xff
def func1(memory):
r[12] = 0
r[9] = 0
for r[9] in range(0, 0x100):
r[7] = 0
r[7] += r[9]
#print "r[7]:", hex(r[7])
r[13] = memory[r[7]]
r[12] += r[13]
r[15] = r[9]
r[15] &= 0x0f
r[15] += 0x204
#print "r[15]:", hex(r[15])
r[15] = memory[r[15]]
r[12] += r[15]
r[12] &= 0xff
r[14] = 0
r[14] += r[12]
#print "r[14]:", hex(r[14])
if (r[7] > 0x31b or r[15] > 0x31b or r[14] > 0x31b):
print hex(r[7]), hex(r[15]), hex(r[14])
r[15] = memory[r[14]]
memory[r[14]] = r[13] & 0xff
memory[r[7]] = r[15] & 0xff
r[12] = 0
content = []
def func_next(memory):
r[9] = r[6]
r[9] -= 1
r[9] &= 0xff
r[7] = 0
r[7] += r[9]
#print hex(r[9]), hex(r[7])
r7_back = r[7]
r[13] = memory[r[7]]
r[12] += r[13]
r[12] &= 0xff
r[14] = 0
r[14] += r[12]
#print hex(r[14])
r14_back = r[14]
r[15] = memory[r[14]]
memory[r[7]] = r[15]
memory[r[14]] = r[13]
r[13] += r[15]
r[13] &= 0xff
r[13] += 0
#print hex(r[13])
r13_back = r[13]
r[13] = memory[r[13]]
r[0] = 0x31a
r[0] += r[9]
#print hex(r[0])
r0_back = r[0]
r[0] = memory[r[0]]
r[1] = 0x7d6
r[1] += r[9]
#print hex(r[1])
r1_back = r[1]
r[1] = memory[r[1]]
r1_value = r[1]
r13_value = r[13]
r[1] ^= r[0]
r[13] ^= r[1]
r[10] |= r[13]
print "r0 = memory_%s"%hex(r0_back)[2:]
print "r1 = memory_%s"%hex(r1_back)[2:]
print "r13 = memory_%s"%hex(r13_back)[2:]
print "r7 = memory_%s"%hex(r7_back)[2:]
print "r14 = memory_%s"%hex(r14_back)[2:]
print ""
#print "r10 |= %d ^ r0 ^ %d"%(r[1], r[13])
#content.append("r0 = memory_%s\n"%hex(r0_back)[2:])
content.append("r10 |= %d ^ memory_%s ^ %d\n"%(r1_value, hex(r0_back)[2:], r13_value))
if r0_back != 0x31b + g_length - 1:
content.append("s.add(memory_%s >= 0x20 and memory_%s < 0x80)\n"%(hex(r0_back)[2:], hex(r0_back)[2:]))
#print r[0], r[10]
#print ""
if r[0] == 0:
r[0] = r[10]
if r[0] == 0:
print "right"
def sub_87c(memory):
if r[6] == 0:
func0(memory)
#print memory[0:0x200]
elif r[6] == 1:
func1(memory)
else:
func_next(memory)
#main
r[6] = 0
while r[6] < g_length + 2:
r[0] = 0x7d2
r[7] = r[6]
r[7] &= 0x3
r[0] += r[7]
r[0] = memory[r[0]]
r[0] = 0
sub_87c(memory)
r[6] += 1
def print_memory(memory, range_begin, range_size):
for i in range(range_begin, range_begin + range_size):
if i % 16 == 0:
print ""
print "%2s"%hex(i)[2:],
print "%2s"%hex(memory[i])[2:],
#print_memory(memory, 0x2b0, 0x1000)
#print_memory(memory, 0x5C0, 0x40)
#print [hex(c) for c in memory[0x5A0:0x5A0 + 0x40]]
#print [hex(c) for c in memory[0x5C0:0x5C0 + 0x40]]
file_w = open("./solver.py", 'w')
file_w.write("from z3 import *\n")
#file_w.write("r0 = BitVec('r0', 32)\n")
file_w.write("r10 = BitVec('r10', 32)\n")
for i in range(0x31b, 0x31b + g_length):
file_w.write("memory_%s = BitVec('memory_%s', 32)\n"%(hex(i)[2:], hex(i)[2:]))
file_w.write("s = Solver()\n")
file_w.write("".join(content))
file_w.write("s.add(r10 == 0)\n")# and r0 == 0)\n")
file_w.write("s.add(memory_%s == 0)\n"%hex(0x31b + g_length - 1)[2:])
file_w.write("print s.check()\n")
info = []
for i in range(0x31b, 0x31b + g_length):
info.append("s.model()[memory_%s]"%hex(i)[2:])
info = ", ".join(info)
file_w.write("print " + info)
file_w.close()
生成的z3求解约束代码如下:
from z3 import *
r10 = BitVec('r10', 32)
memory_31b = BitVec('memory_31b', 32)
memory_31c = BitVec('memory_31c', 32)
memory_31d = BitVec('memory_31d', 32)
memory_31e = BitVec('memory_31e', 32)
memory_31f = BitVec('memory_31f', 32)
memory_320 = BitVec('memory_320', 32)
memory_321 = BitVec('memory_321', 32)
memory_322 = BitVec('memory_322', 32)
memory_323 = BitVec('memory_323', 32)
memory_324 = BitVec('memory_324', 32)
memory_325 = BitVec('memory_325', 32)
memory_326 = BitVec('memory_326', 32)
memory_327 = BitVec('memory_327', 32)
memory_328 = BitVec('memory_328', 32)
memory_329 = BitVec('memory_329', 32)
memory_32a = BitVec('memory_32a', 32)
memory_32b = BitVec('memory_32b', 32)
memory_32c = BitVec('memory_32c', 32)
memory_32d = BitVec('memory_32d', 32)
memory_32e = BitVec('memory_32e', 32)
memory_32f = BitVec('memory_32f', 32)
memory_330 = BitVec('memory_330', 32)
memory_331 = BitVec('memory_331', 32)
memory_332 = BitVec('memory_332', 32)
memory_333 = BitVec('memory_333', 32)
memory_334 = BitVec('memory_334', 32)
memory_335 = BitVec('memory_335', 32)
memory_336 = BitVec('memory_336', 32)
memory_337 = BitVec('memory_337', 32)
memory_338 = BitVec('memory_338', 32)
memory_339 = BitVec('memory_339', 32)
memory_33a = BitVec('memory_33a', 32)
memory_33b = BitVec('memory_33b', 32)
memory_33c = BitVec('memory_33c', 32)
memory_33d = BitVec('memory_33d', 32)
memory_33e = BitVec('memory_33e', 32)
memory_33f = BitVec('memory_33f', 32)
memory_340 = BitVec('memory_340', 32)
memory_341 = BitVec('memory_341', 32)
memory_342 = BitVec('memory_342', 32)
s = Solver()
r10 |= 18 ^ memory_31b ^ 33
s.add(memory_31b >= 0x20 and memory_31b < 0x80)
r10 |= 157 ^ memory_31c ^ 175
s.add(memory_31c >= 0x20 and memory_31c < 0x80)
r10 |= 75 ^ memory_31d ^ 8
s.add(memory_31d >= 0x20 and memory_31d < 0x80)
r10 |= 99 ^ memory_31e ^ 80
s.add(memory_31e >= 0x20 and memory_31e < 0x80)
r10 |= 89 ^ memory_31f ^ 6
s.add(memory_31f >= 0x20 and memory_31f < 0x80)
r10 |= 55 ^ memory_320 ^ 67
s.add(memory_320 >= 0x20 and memory_320 < 0x80)
r10 |= 234 ^ memory_321 ^ 130
s.add(memory_321 >= 0x20 and memory_321 < 0x80)
r10 |= 30 ^ memory_322 ^ 123
s.add(memory_322 >= 0x20 and memory_322 < 0x80)
r10 |= 104 ^ memory_323 ^ 26
s.add(memory_323 >= 0x20 and memory_323 < 0x80)
r10 |= 135 ^ memory_324 ^ 226
s.add(memory_324 >= 0x20 and memory_324 < 0x80)
r10 |= 73 ^ memory_325 ^ 58
s.add(memory_325 >= 0x20 and memory_325 < 0x80)
r10 |= 219 ^ memory_326 ^ 132
s.add(memory_326 >= 0x20 and memory_326 < 0x80)
r10 |= 116 ^ memory_327 ^ 21
s.add(memory_327 >= 0x20 and memory_327 < 0x80)
r10 |= 162 ^ memory_328 ^ 204
s.add(memory_328 >= 0x20 and memory_328 < 0x80)
r10 |= 147 ^ memory_329 ^ 204
s.add(memory_329 >= 0x20 and memory_329 < 0x80)
r10 |= 87 ^ memory_32a ^ 54
s.add(memory_32a >= 0x20 and memory_32a < 0x80)
r10 |= 242 ^ memory_32b ^ 128
s.add(memory_32b >= 0x20 and memory_32b < 0x80)
r10 |= 68 ^ memory_32c ^ 41
s.add(memory_32c >= 0x20 and memory_32c < 0x80)
r10 |= 5 ^ memory_32d ^ 90
s.add(memory_32d >= 0x20 and memory_32d < 0x80)
r10 |= 69 ^ memory_32e ^ 43
s.add(memory_32e >= 0x20 and memory_32e < 0x80)
r10 |= 133 ^ memory_32f ^ 224
s.add(memory_32f >= 0x20 and memory_32f < 0x80)
r10 |= 195 ^ memory_330 ^ 187
s.add(memory_330 >= 0x20 and memory_330 < 0x80)
r10 |= 141 ^ memory_331 ^ 249
s.add(memory_331 >= 0x20 and memory_331 < 0x80)
r10 |= 68 ^ memory_332 ^ 27
s.add(memory_332 >= 0x20 and memory_332 < 0x80)
r10 |= 96 ^ memory_333 ^ 20
s.add(memory_333 >= 0x20 and memory_333 < 0x80)
r10 |= 225 ^ memory_334 ^ 142
s.add(memory_334 >= 0x20 and memory_334 < 0x80)
r10 |= 44 ^ memory_335 ^ 115
s.add(memory_335 >= 0x20 and memory_335 < 0x80)
r10 |= 243 ^ memory_336 ^ 135
s.add(memory_336 >= 0x20 and memory_336 < 0x80)
r10 |= 249 ^ memory_337 ^ 145
s.add(memory_337 >= 0x20 and memory_337 < 0x80)
r10 |= 23 ^ memory_338 ^ 114
s.add(memory_338 >= 0x20 and memory_338 < 0x80)
r10 |= 183 ^ memory_339 ^ 232
s.add(memory_339 >= 0x20 and memory_339 < 0x80)
r10 |= 46 ^ memory_33a ^ 77
s.add(memory_33a >= 0x20 and memory_33a < 0x80)
r10 |= 158 ^ memory_33b ^ 238
s.add(memory_33b >= 0x20 and memory_33b < 0x80)
r10 |= 73 ^ memory_33c ^ 60
s.add(memory_33c >= 0x20 and memory_33c < 0x80)
r10 |= 43 ^ memory_33d ^ 43
s.add(memory_33d >= 0x20 and memory_33d < 0x80)
r10 |= 71 ^ memory_33e ^ 71
s.add(memory_33e >= 0x20 and memory_33e < 0x80)
r10 |= 73 ^ memory_33f ^ 73
s.add(memory_33f >= 0x20 and memory_33f < 0x80)
r10 |= 31 ^ memory_340 ^ 31
s.add(memory_340 >= 0x20 and memory_340 < 0x80)
r10 |= 76 ^ memory_341 ^ 76
s.add(memory_341 >= 0x20 and memory_341 < 0x80)
r10 |= 229 ^ memory_342 ^ 229
s.add(r10 == 0)
s.add(memory_342 == 0)
print s.check()
print s.model()[memory_31b], s.model()[memory_31c], s.model()[memory_31d], s.model()[memory_31e], s.model()[memory_31f], s.model()[memory_320], s.model()[memory_321], s.model()[memory_322], s.model()[memory_323], s.model()[memory_324], s.model()[memory_325], s.model()[memory_326], s.model()[memory_327], s.model()[memory_328], s.model()[memory_329], s.model()[memory_32a], s.model()[memory_32b], s.model()[memory_32c], s.model()[memory_32d], s.model()[memory_32e], s.model()[memory_32f], s.model()[memory_330], s.model()[memory_331], s.model()[memory_332], s.model()[memory_333], s.model()[memory_334], s.model()[memory_335], s.model()[memory_336], s.model()[memory_337], s.model()[memory_338], s.model()[memory_339], s.model()[memory_33a], s.model()[memory_33b], s.model()[memory_33c], s.model()[memory_33d], s.model()[memory_33e], s.model()[memory_33f], s.model()[memory_340], s.model()[memory_341], s.model()[memory_342]求得结果,在计算输入:
a = "51 50 67 51 95 116 104 101 114 101 115 95 97 110 95 97 114 109 95 110 101 120 116 95 116 111 95 116 104 101 95 99 112 117 0 0 0 0 0 0"
a = a.split(' ')
content = ""
for i in a:
if i != "0":
content += chr(int(i))
print content 最终结果:

这篇博客详细介绍了作者在32C3 CTF挑战中遇到的Blobberry (PiOS)问题。作者通过逆向工程分析了程序,识别了关键函数,如puts类似函数、read函数和主逻辑函数。文章强调了在0x87c函数中的三个步骤,指出最终的解决方案依赖于输入值与一些固定值之间的特定运算。作者使用Z3求解器生成约束并求解出输入,从而解决挑战。
1739

被折叠的 条评论
为什么被折叠?



