【UNCTF】逆向WriteUp以及出题笔记
WriteUp
re_checkin
IDA打开,搜索字符串
查看交叉引用,定位到主函数
可以看到直接比较字符串
由于Str2在IDA中没有出现明文值,因此直接x64dbg打开,主函数下断,即可看到flag
反编译
这道题…有意思???
正规解题步骤参照下面的babypy,不过这道题据说运行就有flag?!
babypy
ExeinfoPe打开,发现是pyinstaller打包的,用网上的脚本解包
将解包出来的struct的前16字节添加到babypy文件头部,改名为babypy.pyc,用uncompyle6反编译,得到.py文件
import os, libnum, binascii
flag = 'unctf{*******************}'
x = libnum.s2n(flag)
def gen(x):
y = abs(x)
while 1:
if y > 0:
yield y % 2
y = y >> 1
else:
if x == 0:
yield 0
l = [i for i in gen(x)]
l.reverse()
f = '%d' * len(l) % tuple(l)
a = binascii.b2a_hex(f.encode())
b = int(a, 16)
c = hex(b)[2:]
print(c)
os.system('pause')
再结合tip.txt,很容易写出逆向算法
flag = '313131303130313031313031313130303131303030313130313131303130303031313030313130303131313130313130313031303130303031313031303030303130303030303030313131303130303031303131313131303131303130303130313131303031313031303131313131303131313030313030313130303130313031313030303031303031313030303130303131303030313031313131303031303130313131313130313130303031313030313130303030303031313030303030303131303030313031313131313031'
n = 0
for i in flag:
if i == '1':
n = (n << 1) + 1
elif i == '0':
n = n << 1
s = libnum.n2s(n)
print(s)
easyMaze
IDA打开,标准的迷宫题
检查输入格式
输入wasd控制方向,Dst处是迷宫地图
根据交叉引用定位
迷宫是10x10的,这样看着不直观,而且是反的,倒过来换成每行10个稍微直观了一点
Oo00oD00SD
0oooo0Dooo
o0D0oD0o00
ooooo00o00
oD0D0ooooo
o00o0o0o0o
oDoooooDDD
o00o00oooo
oD0D0000oD
oooooooooD
很容易看出来走出迷宫的路径:dsdddssaaaassssssddddddddwwaawawwddwwwdw
ICU
IDA打开,明文对比字符串
看似好像是先处理一遍然后依次对单个字符进行处理,动态调试看看情况
输入123456下断查看第一次处理的结果,6位变8位,看起来像base64,IDA搜索字符串可以看到base64的变表
单步即可看到第二次处理的结果
最终解密脚本
import base64
table = 'UyOPef2ghvwx3ABdT7856QSijuCDFGst0LKER4ZabckHIJMNnopqrlmz1VWXY9+/'
origin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
t = 'HSWEH2vXHmRtGZRJvSmKviwtviv4Ga5rD25Mvl:u6ewBUKg9'
f = ''
odd = True
for i in t:
if odd:
f += chr(ord(i) - 1)
else:
f += i
odd = not odd
flag = f.translate(str.maketrans(table, origin))
print(base64.b64decode(flag))
ezRust
通过试错可以发现需要2个额外的命令行参数
x64dbg打开,给2个假的命令行参数“1234”和“5678”,一路F8,遇到Error输出就F7,最后进入下面的函数
这一行会把第一个命令行和“YLBNB”入参,“1234”的情况下执行完call后rax等于0
尝试把第一个命令行换成“YLBNB”,rax等于1
返回0会直接输出Error,返回1会进行第二次判断,同理得到第二个命令行为“RUSTPROGRAMING”
运行直接出flag(IDA也能找到对应的地方)
base_on_rust
(做题环境忘了保存,口头说一下做法)
这题我是动调出来的,但是我想站在上帝视角教大家一个简单的办法
程序需要一个额外的命令行输入,我们假设输入123456,会发现它会输出一段base64,将其解码,发现疑似base32,再解,发现是313233343536,正好是输入的字符的ascii码的十六进制拼起来
IDA的F5里面很多JUMPOUT,在汇编窗口手动修一下(没有解析的代码C一下,C不行的话就nop,再U整个函数,再P),可以看到疑似比较的操作,把待比较的数据dump下来,解码一下,跑脚本出flag
s = ''
f = '756E6374667B6261736536345F6261736533325F6261736531365F656E636F64655F5F5F7D'
i = 0
while i < len(f):
c = f[i:i + 2]
s += chr(int(c, 16))
i += 2
print(s)
Trap
IDA打开,发现输入的flag s1和dest各留一份,在sub_400CBE后s1与s2比较
跟进函数内部,异或后会开启线程
这个程序有很多地方不能正常反编译,手动修一下汇编就好了
比如说sub_400C13,一开始F5后看不懂,修好以后发现是个简单递归
跟进另一个函数,这个函数里面本来是有反调试的,被我nop掉了
对s1 s2的算法都很简单,很容易求出输入的是 941463c8-2bcb-
运行的时候输入正确的flag会异或解密整个动态链接库文件,然后写入文件并调用jo_enc函数对接下来的输入进行检查
我的Ubuntu20不知道为什么调用动态库会失败,于是在/tmp中找到文件直接静态分析
也是进行运算操作后和固定值比较,逆向脚本还算好写
cipher = [1668, 1646, 1856, 4118, 1899, 1752, 640, 2000, 4412, 1835, 820, 984, 968, 1189, 4353, 1646, 4348, 4561, 1564,
1566, 5596, 1525]
input1 = ''
input2 = '941463c8-2bcb-'
a = [i * 2 for i in range(128)]
b = [i * 2 + 1 for i in range(128)]
c = [16 * ord(input2[m % 14]) ^ cipher[m] for m in range(22)]
for d in c:
for n in range(128):
j = 0
if not n % 2:
for i in range(0, n, 2):
j += a[i]
else:
for i in range(0, n, 2):
j += b[i]
if j == d:
input1 += chr(n)
print('unctf{' + input2 + input1 + '}')
ezre
IDA打开,发现有混淆,根据字符串定位到主函数,flag有18位
整个函数充满着混淆后的junk代码,自己调一调就能明白这些代码什么意思
前面写了用来对比的数据,此处就是check的代码
2张截图之间的160多行代码就是具体的算法了,下面给出化简后的代码
v1 = v45[0];
v42 = 0;
v2 = 9;
while (1)
{
v3 = v45[v2];
if (v1 + v3 < 128)
{
v43[v42] = 128 - v3;
v43[v42 + 9] = 2 * v3 + v1 - 128;
}
else
{
if (v1 + v3 == 128)
{
v43[v42] = v1;
v43[v42 + 9] = v3;
}
else
{
v43[v42] = 2 * v1 + v3 - 128;
v43[v42 + 9] = 128 - v1;
}
}
if (++v42 == 9)
break;
v1 = v45[v42];
v2 = v42 + 9;
}
用python写一个爆破脚本跑出flag
def chk(a, b):
x = a + b
if x < 128:
y = 128 - b
a, b = y, x - y
elif x == 128:
a = a
b = b
else:
y = 128 - b
a, b = x - y, y
return a, b
flag = [141, 99, 177, 201, 161, 205, 177, 177, 203, 51, 62, 33, 19, 31, 12, 24, 33, 23]
flag_pre = ''
flag_post = ''
for i in range(0, 9):
for j in range(0, 256):
for k in range(0, 256):
if chk(j, k) == (flag[i], flag[i + 9]):
flag_pre += chr(k)
flag_post += chr(j)
print(flag_pre + flag_post)
ezvm
IDA打开,就是一个VM
一开始程序对VM进行了初始化
根据初始化代码,自建一个结构体
分析每条指令作用的时候有几个地方需要注意
将opcode提取出来,并写出伪代码
-9 -15 6 3 -15 7 0 * -15 5 0 -8 -15 2