南邮平台逆向题目

前面几题太基础就不写了。

WxtVM1

IDA打开直接查看主函数,可以看到flag的长度为24,经过一个函数调用后,与密文进行对比。

那么关键点就是sub_4005B6函数了,内部是这样的,

这个流程说明它是个虚拟机,字节码存在byte_6010C0中,一共有15000个字节,3个字节为一条指令,第1个字节决定操作符,第2个字节决定flag的偏移,第3个字节作为值与flag对应偏移的字节进行运算,不过这个虚拟机并不是汇编级别的,且流程不复杂,所有运算可逆,所以可以直接当作加密函数逆向,写出解密函数即可,然后把密文解密即可得到flag,脚本如下,

f = open('WxyVM1', 'rb')

f_conten = f.read()

tmp = f_conten[0x1060:0x1060+24*4]

m_data = f_conten[0x10c0:0x10c0+15000]

tmp = list(tmp)

m_data = list(m_data)

box = []



for i in range(0, len(tmp), 4):

num = 0

for j in range(4):

num += tmp[i+j] << j*8

box.append(num)



i = 14997

while i >= 0:

v0 = m_data[i]

v3 = m_data[i+2]

result = v0

if v0 == 1:

result = m_data[i+1]

box[result] -= v3

elif v0 == 2:

result = m_data[i+1]

box[result] += v3

elif v0 == 3:

result = m_data[i+1]

box[result] ^= v3

elif v0 == 4:

result = m_data[i+1]

box[result] /= v3

elif v0 == 5:

result = m_data[i+1]

box[result] ^= box[m_data[i+2]]

box[result] &= 0xff

i -= 3



for j in range(len(box)):

box[j] = chr(box[j])

print(''.join(box))

maze

迷宫问题是逆向的一种解题模式,有点游戏的性质。通常程序构造了一个二维数组,以这个二维数组为迷宫的地图,其中不同字符元素代表不同意义,找出正确路径后构造出相应的输入值即可解决问题。

进入主函数大概浏览一下,可以看到几条if语句

跟进其中的几个函数,都是++和--之类的,且v4正好与输入有关,所以猜测这是迷宫进行移动的各种方向,前两个函数和后两个函数的功能是相同的,不同的只是参数,前两个是(int)&v9+1后两个是&v9。继续往下看,在结尾处可以看到字节的比较

然后是不远处调用的函数

v9是一个64位的数据,SHIDWORD(v9)表示取其高32位作为整数,(signed int)v9表示取其低32位作为整数,再结合之前if语句内函数的参数,可以得到结论,v9的低32位是当前所在行数,v9的高32位是当前所在的列数,而每行一共有8列,asc_601060以每行8个元素打印出来就是迷宫,以#结束。

跟进sub_400690可以看到,空格和井号表示正确,而星号表示失败,为了好看,我把正确的路用+表示o表示错误,然后#结束

根据前面几条if语句找到各个方向对应的字符,然后按着迷宫的加号走到井号就得到flag了

WxyVM2

IDA打开后看到主函数非常长,有几万行吧,f5等了半天,反编译出来后发现有许多异或操作,仔细观察发现,这些异或操作对输入根本没有影响,因为输入只有25字节,这些异或影响的都是25字节之后的数据,即是花指令,可以写一个脚本除这些花指令,机器码的模式为:

8B ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 31 ?? 89 ?? ?? ?? ?? ??

只要匹配到关键的操作码,就将这20字节的数据全部换为90

脚本如下:

content = open('WxyVM2', 'rb').read()

content_new = content[0x66e:0x92d30]

content_new = list(content_new)

for i in range(len(content_new)):

content_new[i] = chr(content_new[i])

i = 0

while i < len(content_new):

if content_new[i] == '\x8b' and content_new[i+6] == '\x8b' \

and content_new[i+12] == '\x31' and content_new[i+14] == '\x89':

for j in range(i,i+20):

content_new[j] = '\x90'

i += 20

else:

i += 1

for i in range(len(content_new)):

content_new[i] = ord(content_new[i])

content_new = bytes(content_new)

content = content.replace(content[0x66e:0x92d30], content_new)

print(content[0x66e:0x66e+20])

print(content_new[:20])

f = open('WxyVM2.patch', 'wb')

f.write(content)

f.close()

除去花指令后用IDA重新打开文件,反编译后发现该程序对输入还是进行了非常多的加减异或运算来加密输入。如果看作虚拟机的话,byte_694100里面就是机器码吧,不过IDA反编译结果太清晰了,可以暴力一点,嘿嘿

直接复制下来,逆序后编译成C程序执行,也可以直接用python的exec来执行字符串,这里用python,将复制下来的表达式先逆序,然后将减法和加法互换,异或不变,然后读取这个文件,执行表达式,脚本:

byte_694100 = [0xFFFFFFC0, 0xFFFFFF85, 0xFFFFFFF9, 0x0000006C, 0xFFFFFFE2, 0x00000014, 0xFFFFFFBB, 0xFFFFFFE4,

0x0000000D, 0x00000059, 0x0000001C, 0x00000023, 0xFFFFFF88, 0x0000006E, 0xFFFFFF9B, 0xFFFFFFCA,

0xFFFFFFBA, 0x0000005C, 0x00000037, 0xFFFFFFFF, 0x00000048, 0xFFFFFFD8, 0x0000001F, 0xFFFFFFAB,

0x00FFFFA5]



instr = open('ret.txt', 'r').readlines()

for s in instr:

exec(s)

print(byte_694100)

for i in range(len(byte_694100)):

byte_694100[i] = chr(byte_694100[i]&0xff)



print ''.join(byte_694100)

得到flag

single

各个流程看一下,关注几个check函数,发现是个数独游戏,找到初始值去网上直接解即可

480小时精通C++

这个题真的迷,它没有任何输入点,只是打印了一堆东西,不过不管怎么样还是用IDA打开它吧,在函数列表中找到了StringEncryptFunction函数,而输出的正好是

难道是直接逆向这个加密函数并写出解密函数来解出这个密文吗?但是这个函数是这样的

wtf???orz

于是直接瞎猫碰死耗子直接将密文作为函数参数传进去,因为有些加密算法本身也是解密算法,结果。。。还真是,这特喵什么玩意儿

先在lea rax, [rbp-0x50]下断点,

加密函数的第1个参数为密文,第二个参数为长度,而调用方式为fastcall,所以这里使

rdi = rax,rsi = 36,rip = 0x04224F6,在该函数结尾下断点然后直接执行就可以在栈中找到flag

HomuraVM

。。。待续未完

猜你喜欢

转载自blog.csdn.net/qq_35713009/article/details/86603755
今日推荐