2020XCTF天津垓问题求解

1.天津垓

有一些反调试措施和加壳的保护,但是总体逻辑非常简单

1.1 “Authorize:”求解

核心逻辑是:
在这里插入图片描述

v39是一个数组,长度为14,具体值为:
arrlist = [0x52,0x69,0x73,0x69,0x6e,0x67,0x5f,0x48,0x6f,0x70,0x70,0x65,0x72,0x21]
其中*(&v39+i%14)就是 arrlist[i%14]
v1也是一个数组,长度为18,具体值为:
target = [17,8,6,10,15,20,42,59,47,3,47,4,16,72,62,0,7,16]
其中*(&v1+i)就是target[i]
那么,str[i]就可以通过遍历可视字符[0x20~0x7f]来求解,只要满足v43==target[i]即可,代码如下:

def main():
	arrlist = [0x52,0x69,0x73,0x69,0x6e,0x67,0x5f,0x48,0x6f,0x70,0x70,0x65,0x72,0x21]
	target = [17,8,6,10,15,20,42,59,47,3,47,4,16,72,62,0,7,16]
	idx = 0
	flag1 = ""
	for idx in range(0,18):
		for c in range(0x0,0xff):
			t = ~(c & arrlist[idx%14]) & (c|arrlist[idx%14])
			if t== target[idx]:
				print(idx,chr(c))
				flag1 += chr(c)
	print(flag1)

得出flag1 = Caucasus@s_ability

1.2 壳

相关逻辑如下:
在这里插入图片描述
地址0x164d是被加壳的内容,大小为1045。sub_1506函数在解壳,之后在第5行即可直接调用unk_164d()函数。

解壳的逻辑如下:
在这里插入图片描述
其中第18行就是解码过程,其中*(lpAddress+i)就是unk_164d[i],然后*(v8+i%18)就是str[i%18],可以先把解码之后的内容dump出来,代码如下:

import idc
from binascii import *
s = "Caucasus@s_ability"
def main():
	count = 1045
	start = 0x10040164D
	addr = start
	fp = open('origin','wb')
	for i in range(0,1045):
		c = s[i%18]
		addr = start + i;
		res = idc.Byte(addr)
		res ^= ord(c)
		fp.write(a2b_hex(hex(res)[2:].rjust(2,'0')))
	fp.close()
if __name__ == '__main__':
	main()

用ida打开origin文件,发现不能反编译函数,如下
在这里插入图片描述
很明显,解码是正确的,符合函数的特征,尤其是第一个push指令,现在想要反编译这个代码,方便分析逻辑,于是直接将内容patch到原始exe文件上,代码如下:

def rewrite():
	fp = open('tjh.exe','rb')
	fp2 = open('origin','rb')
	data2 = fp2.read()
	data=fp.read()
	idx = data.find('\x16\x29\xf4\x8f') #是地址0x164d的内容,找到index,可以准确替换
	out_data = data[:idx]
	for i in range(0,1045):
		out_data+=data2[i]
	out_data += data[idx+1045:]
	fp3 = open('out.exe','wb')
	fp3.write(out_data)
	fp3.close()

最后用IDA打开out.exe文件,可以看到反编译成功了,逻辑如下:
在这里插入图片描述
flag是51个字符,验算过程和Authorize类似,这里就不重复说明了,代码如下:

s=r"""
v9 = 2007666;
v10 = 2125764;
v11 = 1909251;
v12 = 2027349;
v13 = 2421009;
v14 = 1653372;
v15 = 2047032;
v16 = 2184813;
v17 = 2302911;
v18 = 2263545;
v19 = 1909251;
v20 = 2165130;
v21 = 1968300;
v22 = 2243862;
v23 = 2066715;
v24 = 2322594;
v25 = 1987983;
v26 = 2243862;
v27 = 1869885;
v28 = 2066715;
v29 = 2263545;
v30 = 1869885;
v31 = 964467;
v32 = 944784;
v33 = 944784;
v34 = 944784;
v35 = 728271;
v36 = 1869885;
v37 = 2263545;
v38 = 2283228;
v39 = 2243862;
v40 = 2184813;
v41 = 2165130;
v42 = 2027349;
v43 = 1987983;
v44 = 2243862;
v45 = 1869885;
v46 = 2283228;
v47 = 2047032;
v48 = 1909251;
v49 = 2165130;
v50 = 1869885;
v51 = 2401326;
v52 = 1987983;
v53 = 2243862;
v54 = 2184813;
v55 = 885735;
v56 = 2184813;
v57 = 2165130;
v58 = 1987983;
v59 = 2460375;
"""
def solve():
	res = s.split('\n')
	n_list = []
	for item in res[1:-1]:
		number = item.split('=')[1].strip(';')
		n_list.append(int(number))
	v61 = 19683
	v62 = 0x8000000b
	flag = ""
	for i in range(0,51):
		for c in range(0x20,0x7f):
			t = v61 * (c%v62)
			if t == n_list[i]:
				flag += chr(c)
	print(flag)

最后解出flag为flag{Thousandriver_is_1000%_stronger_than_zero-one}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值