安恒6月赛逆向WP

0X01.T0p_Gear

签到,upx的壳,linux环境下脱壳,再换回windows环境,IDA打开,三个函数,判断输入是否正确,三个函数看似有内容,其实与咱们的输入无关,核心在最下面的比较,下断动调,即可得出三段flag。
T0p_Gear
c92bb6a5a6c3009124566d882d4bc7ee

0X02.pyCharm

pyc文件恢复
方法:https://www.52pojie.cn/thread-912103-1-1.html
1
方法相同,找64000000,之前的删掉,修改co_code大小为0x8f就可以反编译了,网站反编译pyc得到Python代码。

import base64
a = 'YamaNalaZaTacaxaZaDahajaYamaIa0aNaDaUa3aYajaUawaNaWaNajaMajaUawaNWI3M2NhMGM='
flag = raw_input('Are u ready?')
c = base64.b64encode(flag)
d = list(c)
for i in range(0, 32):
    d[i] += 'a'
 
ohh = ('').join(d)
if ohh == a:
    print 'great!waht u input is the flag u wanna get.'
else:
    print 'pity!'

YmNlZTcxZDhjYmI0NDU3YjUwNWNjMjUwNWI3M2NhMGM=,base64解码就OK。

0X03.Magia

1
三条限制,可写脚本爆破。

import string
guess_range = string.printable
rule1=[51,0,21,9,11,54,6,12,2,58,44,8,49,11,55,12]
rule2=[76,101,96,114,100,73,112,99,108,69,83,97,78,100,72,97]
rule3=[14,5,0,11,13,9,2,3,12,5,15,1,14,4,15,13,1,8,15,15,9,3,15,14,15,4,15,6,2,5,5,13]
def guess_pos(i):
	for i in range(i, i+1):
		for chr1 in guess_range:
			for chr2 in guess_range:
				num1 = ord(chr1)
				num2 = ord(chr2)
				if (num1^num2==rule1[i]) and (num1&num2==rule2[i]) and (num1&0xF==rule3[i]) and (num2&0xF==rule3[31-i]):
					print (i, chr1,31-i, chr2)
for i in range(0, 16):
	guess_pos(i)

结合题目提示,爆破出来Nep{mircle_and_maho_is_not_free},输入之后是正确的,但It_is_that_true?\n灵魂拷问,接着往下走sub_403000里面全是数据,推测动调起来会改变,于是上x64dbg(Inc ebp–>push ebp),直接flag就跑出了。

0x04.BrainBreaker

IDA 打开,找不到有用的和真正函数,找到right和wrong但是是数据段的,所以动调开始入手。1
到达main函数,div0(程序异常执行会抛出“除0”这种异常信号),直接找SEH链中最先捕获异常的函数就是真正的函数。F8单步往下走。2
这里是反调试技术,比较跳转,如果让它跳转则程序退出,所以nop掉。接着往下走,走到一开始找到的真正的函数那。在这里插入图片描述
这里看对应IDA的地址位置,但IDA里是数据,按C转代码,很明显的switch case模型,vm结构,找三点:要执行的字符,opcode,最终结果。z3可以解决,不用再逆,本身的逻辑用IDA里的创建函数,反编译就可。
膜Baymax.师傅的z3脚本

from z3 import *

a1 = [BitVec('flag%d' % i,9) for i in range(100)]
s = Solver()
a1.reverse()

result = [0xFA,0x2B,0x94,0xEA,0x63,0xA8,0xC4,0x13,0x84,0xE7,0xA7,0xDA,0xD4,0x2D,0xAE,0xBE]

opcode = "****--:~+******^.~+*****:*+++++^.-:///--*^.:///---^.,:~-----^>,:~-/++++++++++++^>,:~+****--^>+*******://++++++++++^:,^>-:///^:,^>+******://-^:,^>-/+://+++++++^:,^>-/----:,^>-/+:/+++++^:,^>-:++****+^:,^>-/+:~+**++^:,^>+****:*^:,^>-:++****++++^:,^>-/---:,^>+*****://+^:,^>-/+:///+^:,^>,"
ax = 0
bx = 0
fin=[0 for i in range(100)]
fin[0] = 1
for i in opcode:
    o = ord(i)
    if o == 60:
        ax -= 1
        # print "dec ax","ax = ",ax
    if o == 62:
        ax += 1
        # print "inc ax","ax = ",ax
    if o == 46:
        continue
        # print "put %c fin[{}]".format(ax)
        # print chr(fin[ax])
    if o == 44:
        fin[ax] = a1.pop()
        # print "get %2x fin[{}]".format(ax)
        # break
    if o == 43:
        # print "inc fin[{}]".format(ax)
        fin[ax] += 1
    if o == 45:
        # print "dec fin[{}]".format(ax)
        fin[ax] -= 1
    if o == 42:
        # print "double fin[{}]".format(ax)
        fin[ax] *= 2
    if o == 47:
        # print "shr fin[{}]".format(ax)
        fin[ax] >>= 1
    if o == 94:
        # print "xor fin[{}],bx".format(ax)
        fin[ax] ^= bx
    if o == 58:
        # print "mov bx,fin[{}]".format(ax)
        bx = fin[ax]
    if o == 126:
        # print "check ax == 32;mov fin[{}],0".format(ax)
        if ax == 32:
            break
        fin[ax] = 0
    fin[ax] &= 0xff
    ax &= 0xff
    bx &= 0xff
        
for i in range(len(result)):
    s.add(result[i] == fin[i])

print (s.check())
answer = s.model()
# flag = "".join([hex(answer[i].as_long())[2:] for i in a1])
# print flag
print (answer)

PS1: 注意python里的符号问题,vm里寄存器操作是无符号的,python直接加减是有符号的,需要&0xff来转换成无符号。
PS2: 由于只有BitVec支持位操作,而BitVec是无符号的,请时刻注意这点。当你发现计算的结果和你预期不符时,可以试着把BitVec扩大一位来解决问题。这个题没碰到这个情况。
PS3:

 if o == 46:  #输出
        continue
        # print "put %c fin[{}]".format(ax)
        # print chr(fin[ax])
    if o == 44:  #输入
        fin[ax] = a1.pop()
        # print "get %2x fin[{}]".format(ax)
        # break

PS4:

a1.reverse()
fin[ax] = a1.pop()

得出的字符按顺序16进制就是flag。

0x05.521

搜字符串,找逻辑,点进去函数1
1是对目标字符串的赋值
2是对输入的处理(2函数点进去,与固定字符串异或,动调下断,固定字符串可以试出来)
1
3是1和2的比较

result=[0x80,0x59,0x23,0x35,0x2a,0x6,0x8c,0x6f,0x27,0x55,0x32,0xe9,0x52,0x54,0x85,0xf,0xc2,0x93,0x2d,0xad,0xf6,0x1a,0x2,0x93,0x22,0x7c,0x16,0x8a,0x29,0x4a,0x1e,0x34,0x72,0x80,0x9f,0x9b,0x22]
tmp=[0x80,0x59,0x23,0x35,0x22,0x73,0x8d,0x1a,0x51,0x5d,0x30,0xe8,0x57,0x26,0xf6,0x7,0xc6,0x92,0x5e,0xdc,0x83,0x1f,0x76,0x92,0x25,0xf,0x65,0xfb,0x2e,0x4d,0x6b,0x45,0x3,0x87,0xe9,0x9f,0x22]
input=['N', 'e', 'p', '{', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '}']
flag=[0 for i in range(37)]
for i in range(37):
	flag[i]=result[i]^(ord(input[i])^tmp[i])
print(''.join(map(chr,flag)))
#Nep{8E1EF8215BC841CAE5D17CCA77EAA7F4}

0x06.DDoll

反调试多,IDA是找不到中文字符的,直接上X64dbg(X64dbg需要安装插件识别中文字符),接下来就是逐步往里跟,搜到中文字符串,这就明了。
1
红框内函数EE1122,IDA反编译,是明文比较,因此找到目标字符而且24位,接着从后往前看,EE12AD生成目标字符串,没啥用,EEA694找不到,EE1055将输入字符与某字符串异或。至此逻辑清楚。模拟输入24位(也没有对前几个字符和最后字符以及字符长度的条件判断,你输100位都没事,有点奇怪,哈哈哈)。

enc = [0xC6,0xA5,0x04,0x53,
0x33,0xC3,0xC8,0x9E,
0x2F,0x8F,0x44,0xE0,
0x9D,0x24,0x2F,0x28,
0xE4,0xDC,0xDB,0x34,
0x78,0xB8,0x4C,0x38]
flag=[0xC6,0xA5,0x04,0x53,
0x17,0xF6,0xCF,0xAA,
0x21,0xAF,0x5C,0xE0,
0x9F,0x17,0x2F,0x74,
0x88,0xA6,0x8B,0x72,
0x3F,0xE5,0x1B,0x38]

dec = "Nep{fuckyouall123456789}"
result=[0 for i in range(24)]
for i in range(24):
	result[i]=enc[i]^(flag[i]^ord(dec[i]))
print(''.join(map(chr,result)))
#Nep{B@d_wOman_1n_Neppen}

感谢Tony Smith师傅的知识补充
补充: ida里的rebase还是挺好用的。od里的地址有时候跟ida里的不一样,直接rebase。
ida edit->segments->rebase program,之后打开od的memory map(alt+m),找pe文件头,ida的base地址直接设成文件头的地址两边地址就能一块用了。
2
在这里插入图片描述

0x07.easy_maze

简单的迷宫题,地图没有变换,ujkh,上下左右清晰,#,终点清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值