小众语言逆向

笔记

BrainFuck-Compiler.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
def shrinkBFCode(code):
cPos2Vars = {} #位置对应的变量
cPos2Change = {} #位置中 + 号 增加的值
varPos = 0
nCode = []
incVal = 0
lc = None
dataChangeOp = set(['+', '-'])
dataShiftOp = set(['>', '<'])
for i in range(len(code)):
c = code[i]
if c not in dataChangeOp and lc in dataChangeOp:
cPos2Change[len(nCode)] = incVal
cPos2Vars[len(nCode)] = varPos
nCode.append('+')
incVal = 0
if c == '>':
varPos += 1
elif c == '<':
varPos -= 1
else:
if c in dataChangeOp:
incVal += 1 if c == '+' else -1
else:
#if lc == '>' or lc == '<':
# cPos2Vars[len(nCode)] = varPos
cPos2Vars[len(nCode)] = varPos
nCode.append(c)
lc = c

return ''.join(nCode), cPos2Vars, cPos2Change
def generatePyCode(shellCode, pVars, pChange):
pyCodes = []
bStacks = []
whileVarCache = {}
for i, c in enumerate(shellCode):
d_pos = i if i not in pVars else pVars[i]
d_change = 1 if i not in pChange else pChange[i]
indentLevel = len(bStacks)
indentStr = ' '*(4*indentLevel)
if c == '[':
pyCodes.append('{}while data[{}] != 0:'.format(indentStr, d_pos))
bStacks.append((c, i))
whileVarCache[i] = {}
elif c == ']':
if bStacks[-1][0] != '[':
raise Exception('miss match of {}] found between {} and {}'.format(bStacks[-1][0], bStacks[-1][1], i))
cNum = i-bStacks[-1][1]
if cNum == 2:
del pyCodes[-1]
del pyCodes[-1]
d_pos_l = i-1 if i-1 not in pVars else pVars[i-1]
pyCodes.append('{}data[{}] = 0'.format(' '*(4*(indentLevel-1)), d_pos_l))
whileCode = shellCode[bStacks[-1][1]+1 : i]
if cNum>2 and '[' not in whileCode and not '%' in whileCode: # nested loop is a bit complicated, just skip
loopCondvar = bStacks[-1][1]
d_pos_l = loopCondvar if loopCondvar not in pVars else pVars[loopCondvar]
whileVars = whileVarCache[bStacks[-1][1]]
cVarChange = whileVars[d_pos_l]
# remove statement of same indent
while len(pyCodes)>0 and pyCodes[-1].startswith(indentStr) and pyCodes[-1][len(indentStr)]!=' ':
pyCodes.pop()
pyCodes.pop()
#del pyCodes[bStacks[-1][1]-i:]
for vPos, vChange in whileVars.items():
if vPos == d_pos_l:
continue
ctimes = abs(vChange / cVarChange)
ctimesStr = '' if ctimes==1 else '{}*'.format(ctimes)
cSign = '+' if vChange > 0 else '-'
pyCodes.append('{}data[{}] {}= {}data[{}]'.format(' '*(4*(indentLevel-1)),
vPos, cSign, ctimesStr, d_pos_l))
pyCodes.append('{}data[{}] = 0'.format(' '*(4*(indentLevel-1)), d_pos_l))
del whileVarCache[bStacks[-1][1]]
bStacks.pop()
elif c == '.':
pyCodes.append('{}print(data[{}])'.format(indentStr, d_pos))
elif c == ',':
pyCodes.append('{}data[{}] = ord(stdin.read(1))'.format(indentStr, d_pos))
elif c == '+':
opSign = '-=' if d_change < 0 else '+='
if pyCodes and pyCodes[-1] == '{}data[{}] = 0'.format(indentStr, d_pos):
pyCodes[-1] = '{}data[{}] = {}'.format(indentStr, d_pos, d_change)
else:
pyCodes.append('{}data[{}] {} {}'.format(indentStr, d_pos, opSign, abs(d_change)))
if bStacks:
whileVarCache[bStacks[-1][1]].setdefault(d_pos, 0)
whileVarCache[bStacks[-1][1]][d_pos] += d_change
elif c == '-':
opSign = '+=' if d_change < 0 else '-='
if pyCodes and pyCodes[-1] == '{}data[{}] = 0'.format(indentStr, d_pos):
pyCodes[-1] = '{}data[{}] = {}'.format(indentStr, d_pos, -d_change)
else:
pyCodes.append('{}data[{}] {} {}'.format(indentStr, d_pos, opSign, abs(d_change)))
if bStacks:
whileVarCache[bStacks[-1][1]].setdefault(d_pos, 0)
whileVarCache[bStacks[-1][1]][d_pos] -= d_change
elif c == '%':
pyCodes.append('{}data[{}] %= data[{}]'.format(indentStr, d_pos, d_pos+1))
return '\n'.join(pyCodes)
shellcode = '...'
shrinkCode, pVars, pChange = shrinkBFCode(shellcode)
print(generatePyCode(shrinkCode, pVars, pChange))

做题

[羊城杯 2023]CSGO

Go语言逆向,找到fkReverse_()函数为Base64加密,但是表不动调出不来…

反调机制,拿SharpOD绕过,发现调飞了。

runtime_memequal()函数附近有密文。直接解失败,推测Base64换表。

易知羊城杯flag前缀为‘DASCTF{’,Base64加密后对着密文猜表:LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJK

结果给猜出来了。

[FBCTF 2019]Go get the flag!

go语言写的elf,找main_main函数,找到第一个命令行传参,然后尝试直接执行decrypt函数。

[GKCTF 2021]Crash

elf带符号的Golang逆向。看到函数main_check中,第一层为AES,main_encrypto的返回值即为密文。Go中加密函数为Encrypt_DesEncrypt,密钥和盐通过json传递,即encoding_json_Unmarshal,第一个传参即为数据。

第二层SHA256爆破,第三层SHA512爆破,第四层没法看伪代码,阅读汇编为MD5爆破。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from Crypto.Cipher import DES3
import base64,itertools,string,hashlib
def des3_cbc_decrypt(secret_key,secret_value,iv):
unpad=lambda s:s[0:-ord(s[-1])]
res=DES3.new(secret_key.encode("utf-8"),DES3.MODE_CBC,iv)
base64_decrypted=base64.b64decode(secret_value.encode("utf-8"))
encrypt_text=res.decrypt(base64_decrypted)
result=unpad(encrypt_text.decode())
return result
def sha256crash(sha256enc):
code=''
strlist=itertools.product(string.ascii_letters+string.digits,repeat=4)
for i in strlist:
code=i[0]+i[1]+i[2]+i[3]
encinfo=hashlib.sha256(code.encode()).hexdigest()
if encinfo==sha256enc:
return code
def sha512crash(sha512enc):
code=''
strlist=itertools.product(string.ascii_letters+string.digits,repeat=4)
for i in strlist:
code=i[0]+i[1]+i[2]+i[3]
encinfo=hashlib.sha512(code.encode()).hexdigest()
if encinfo==sha512enc:
return code
def md5crash(md5enc):
code=''
strlist=itertools.product(string.ascii_letters+string.digits,repeat=4)
for i in strlist:
code=i[0]+i[1]+i[2]+i[3]
encinfo=hashlib.md5(code.encode()).hexdigest()
if encinfo==md5enc:
return code
key="WelcomeToTheGKCTF2021XXX"
iv=b'1Ssecret's
cipher="o/aWPjNNxMPZDnJlNp0zK5+NLPC4Tv6kqdJqjkL0XkA="
part1=des3_cbc_decrypt(key,cipher,iv)
part2=sha256crash("6e2b55c78937d63490b4b26ab3ac3cb54df4c5ca7d60012c13d2d1234a732b74")
part3=sha512crash("6500fe72abcab63d87f213d2218b0ee086a1828188439ca485a1a40968fd272865d5ca4d5ef5a651270a52ff952d955c9b757caae1ecce804582ae78f87fa3c9")
part4=md5crash("ff6e2fd78aca4736037258f0ede4ecf0")
flag="GKCTF{"+part1+part2+part3+part4+"}"
print(flag)

[FSCTF 2023]rrrrust!!!

Rust逆向连蒙带猜。

0x55DB3F0666DF处发现有xor,可能是异或加密,多次动调发现密钥为循环字符串。

找到loc_55DB3F066569处有密文比较过程,dump出来写exp:

1
2
3
4
enc=[0x3E,0x2A,0x27,0x33,0x15,0x03,0x3D,0x77,0x25,0x64,0x03,0x67,0x07,0x32,0x76,0x0B,0x1C,0x21,0x2B,0x32,0x19,0x23,0x5E,0x26,0x69,0x22,0x3B,0xD8,0x9F,0x0B,0x3F,0xDB,0x55]
key="XFFTnT"
for i in range(len(enc)):
print(chr(enc[i]^ord(key[i%6])),end='')

[第五空间 2021]StrangeLanguage

pyinstxtractor+pycdc正常解包,发现逻辑在“brainfuck”里,找到.pyd文件即.dll文件丢IDA,找到BrainFuck代码,用这个在Linux下转Python:https://github.com/rdebath/Brainfuck。

生成800多行Python代码,尝试找网上wp。

盯着中间一坨数据,猜测加密方法可得flag:

1
2
3
4
5
res=[83,15,90,84,80,85,3,2,0,7,86,7,7,91,9,0,80,5,2,3,93,92,80,81,82,84,90,95,2,87,7,52,0]
for i in range(31,-1,-1):
res[i]^=res[i+1]
for i in range(len(res)):
print(chr(res[i]),end='')