這題給了個pyc。先用uncompyle反編譯成py。
uncompyle6 3nohtyp.pyc >>sss.py
打開,然後驚了。
# uncompyle6 version 3.6.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.0 (default, Oct 23 2019, 18:51:26)
# [GCC 9.2.0]
# Embedded file name: circ.py
# Compiled at: 2019-12-14 02:29:55
# Size of source mod 2**32: 5146 bytes
佤 = 0
侰 = ~佤 * ~佤
俴 = 侰 + 侰
def 䯂(䵦):
굴 = 佤
굿 = 佤
괠 = [佤] * 俴 ** (俴 * 俴)
궓 = [佤] * 100
괣 = []
while 䵦[굴][佤] != '듃':
굸 = 䵦[굴][佤].lower()
亀 = 䵦[굴][侰:]
#print(괠 )
#print(궓 )
if 굸 == '뉃':
괠[亀[佤]] = 괠[亀[侰]] + 괠[亀[俴]]
elif 굸 == '렀':
괠[亀[佤]] = 괠[亀[侰]] ^ 괠[亀[俴]]
elif 굸 == '렳':
괠[亀[佤]] = 괠[亀[侰]] - 괠[亀[俴]]
elif 굸 == '냃':
괠[亀[佤]] = 괠[亀[侰]] * 괠[亀[俴]]
elif 굸 == '뢯':
괠[亀[佤]] = 괠[亀[侰]] / 괠[亀[俴]]
elif 굸 == '륇':
괠[亀[佤]] = 괠[亀[侰]] & 괠[亀[俴]]
elif 굸 == '맳':
괠[亀[佤]] = 괠[亀[侰]] | 괠[亀[俴]]
elif 굸 == '괡':
괠[亀[佤]] = 괠[亀[佤]]
elif 굸 == '뫇':
괠[亀[佤]] = 괠[亀[侰]]
elif 굸 == '꼖':
괠[亀[佤]] = 亀[侰]
elif 굸 == '뫻':
궓[亀[佤]] = 괠[亀[侰]]
elif 굸 == '딓':
괠[亀[佤]] = 궓[亀[侰]]
elif 굸 == '댒':
괠[亀[佤]] = 佤
elif 굸 == '묇':
궓[亀[佤]] = 佤
elif 굸 == '묟':
괠[亀[佤]] = input(괠[亀[侰]])
elif 굸 == '꽺':
궓[亀[佤]] = input(괠[亀[侰]])
elif 굸 == '돯':
print(괠[亀[佤]])
elif 굸 == '뭗':
print(궓[亀[佤]])
elif 굸 == '뭿':
굴 = 괠[亀[佤]]
elif 굸 == '뮓':
굴 = 궓[亀[佤]]
elif 굸 == '뮳':
굴 = 괣.pop()
elif 굸 == '믃':
if 괠[亀[侰]] > 괠[亀[俴]]:
굴 = 亀[佤]
괣.append(굴)
continue
elif 굸 == '꽲':
괠[7] = 佤
for i in range(len(괠[亀[佤]])):
if 괠[亀[佤]] != 괠[亀[侰]]:
괠[7] = 侰
굴 = 괠[亀[俴]]
괣.append(굴)
elif 굸 == '꾮':
괢 = ''
for i in range(len(괠[亀[佤]])):
괢 += chr(ord(괠[亀[佤]][i]) ^ 괠[亀[侰]])
print(괢 )
괠[亀[佤]] = 괢
elif 굸 == '꿚':
괢 = ''
for i in range(len(괠[亀[佤]])):
괢 += chr(ord(괠[亀[佤]][i]) - 괠[亀[侰]])
괠[亀[佤]] = 괢
elif 굸 == '떇':
if 괠[亀[侰]] > 괠[亀[俴]]:
굴 = 괠[亀[佤]]
괣.append(굴)
continue
elif 굸 == '뗋':
if 괠[亀[侰]] > 괠[亀[俴]]:
굴 = 궓[亀[佤]]
괣.append(굴)
continue
elif 굸 == '똷':
if 괠[亀[侰]] == 괠[亀[俴]]:
굴 = 亀[佤]
괣.append(굴)
continue
elif 굸 == '뚫':
if 괠[亀[侰]] == 괠[亀[俴]]:
굴 = 괠[亀[佤]]
괣.append(굴)
continue
elif 굸 == '띇':
if 괠[亀[侰]] == 괠[亀[俴]]:
굴 = 궓[亀[佤]]
괣.append(굴)
continue
굴 += 侰
䯂([
[
'꼖', 佤, 'Authentication token: '],
[
'꽺', 佤, 佤],
[
'꼖', 6, 'á×äÓâæíäàßåÉÛãåäÉÖÓÉäàÓÉÖÓåäÉÓÚÕæïèäßÙÚÉÛÓäàÙÔÉÓâæÉàÓÚÕÓÒÙæäàÉäàßåÉßåÉäàÓÉÚÓáÉ·Ôâ×ÚÕÓÔɳÚÕæïèäßÙÚÉÅä×ÚÔ×æÔÉ×Úïá×ïåÉßÉÔÙÚäÉæÓ×ÜÜïÉà×âÓÉ×ÉÑÙÙÔÉâßÔÉÖãäÉßÉæÓ×ÜÜïÉÓÚÞÙïÉäàßåÉåÙÚÑÉßÉàÙèÓÉïÙãÉáßÜÜÉÓÚÞÙïÉßäÉ×åáÓÜÜ\x97ÉïÙãäãÖÓ\x9aÕÙÛ\x99á×äÕà©â«³£ï²ÕÔÈ·±â¨ë'],
[
'꼖', 俴, 俴 ** (3 * 俴 + 侰) - 俴 ** (俴 + 侰)],
[
'꼖', 4, 15],
[
'꼖', 3, 侰],
[
'냃', 俴, 俴, 3],
[
'뉃', 俴, 俴, 4],
[
'괡', 佤, 俴],
[
'댒', 3],
[
'꾮', 6, 3],
[
'꼖', 佤, 'Thanks.'],
[
'꼖', 侰, 'Authorizing access...'],
[
'돯', 佤],
[
'딓', 佤, 佤],
[
'꾮', 佤, 俴],
[
'꿚', 佤, 4],
[
'꼖', 5, 19],
[
'꽲', 佤, 6, 5],
[
'돯', 侰],
[
'듃'],
[
'꼖', 侰, 'Access denied!'],
[
'돯', 侰],
[
'듃']])
# okay decompiling 3nohtyp.pyc
發現了很多非ascii字符,由於是python3,所以是可以有非ascii字符的,如:
In [2]: chr(256)
Out[2]: 'Ā'
In [3]: chr(243)
Out[3]: 'ó'
In [4]: chr(336)
Out[4]: 'Ő'
先不管編碼,看這個py,有一個函數,下面是函數調用,函數裏都是if語句,還有±*/&|這些操作,很像是一個VM,那麼下面的函數調用的列表參數就是這個VM的代碼。
嘗試修改這個py文件,用ascii字符進行替換,讓其可讀,刪除一些沒有執行到的代碼以及反編譯時候可能存在的錯誤。
# uncompyle6 version 3.6.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.8.0 (default, Oct 23 2019, 18:51:26)
# [GCC 9.2.0]
# Embedded file name: circ.py
# Compiled at: 2019-12-14 02:29:55
# Size of source mod 2**32: 5146 bytes
a = 0
b = 1
c = 2
def fun1 (arg):
A= a
M= [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
C= [a] * 100
K= []
while arg[A][a] != '12':
#print(M)
opcode= arg[A][a].lower()
opn = arg[A][b:]
#print(opn)
if opcode== '4':
M [opn[a]] = M [opn[b]] + M[opn[c]]
elif opcode== '3':
M [opn[a]] = M [opn[b]] * M[opn[c]]
elif opcode== '5':
M [opn[a]] = M [opn[a]]
elif opcode== '1':
M[opn[a]] = opn[b]
elif opcode== '11':
M[opn[a]] = C[opn[b]]
elif opcode== '6':
M[opn[a]] = a
elif opcode== '2':
C[opn[a]] = input(M[opn[b]])
elif opcode== '10':
print(M[opn[a]])
elif opcode== '9':
M[7] = a
for i in range(len(M[opn[a]])):
print( M[opn[a]], M[opn[b]])
if M[opn[a]] != M[opn[b]]:
M[7] = b
A= M[opn[c]]
K.append(A)
elif opcode== '7':
s= ''
for i in range(len(M[opn[a]])):
s+= chr(ord(M[opn[a]][i]) ^ M[opn[b]])
print(s)
M[opn[a]] = s
elif opcode== '8':
s= ''
for i in range(len(M[opn[a]])):
#print(M[opn[a]][i],M[opn[b]])
s+= chr(ord(M[opn[a]][i]) - M[opn[b]])
M[opn[a]] = s
A+= b
fun1([
[
'1', 0, 'Authentication token: '],
[
'2', 0, 0],
[
'1', 6, 'á×äÓâæíäàßåÉÛãåäÉÖÓÉäàÓÉÖÓåäÉÓÚÕæïèäßÙÚÉÛÓäàÙÔÉÓâæÉàÓÚÕÓÒÙæäàÉäàßåÉßåÉäàÓÉÚÓáÉ·Ôâ×ÚÕÓÔɳÚÕæïèäßÙÚÉÅä×ÚÔ×æÔÉ×Úïá×ïåÉßÉÔÙÚäÉæÓ×ÜÜïÉà×âÓÉ×ÉÑÙÙÔÉâßÔÉÖãäÉßÉæÓ×ÜÜïÉÓÚÞÙïÉäàßåÉåÙÚÑÉßÉàÙèÓÉïÙãÉáßÜÜÉÓÚÞÙïÉßäÉ×åáÓÜÜ\x97ÉïÙãäãÖÓ\x9aÕÙÛ\x99á×äÕà©â«³£ï²ÕÔÈ·±â¨ë'],
[
'1', 2, c ** (3 * c + b) - c ** (c + b)],
[
'1', 4, 15],
[
'1', 3, b],
[
'3', 2, 2, 3],
[
'4', c, c, 4],
[
'5', a, c],
[
'6', 3],
[
'7', 6, 3],
[
'1', 0, 'Thanks.'],
[
'1', 1, 'Authorizing access...'],
[
'10', 0],
[
'11', a, a],
[
'7', a, 2],
[
'8', a, 4],
[
'1', 5, 19],
[
'9', 0, 6, 5],
[
'10', 1],
[
'12'],
[
'1', b, 'Access denied!'],
[
'10', 1],
[
'12']])
# okay decompiling 3nohtyp.pyc
接下來開始分析虛擬機,每個opcode handler都比較簡單,直接給出分析結果。
操作碼分析如下
opcode operation
1 mov M[op1] op2
2 read M[op1] stdin
3 M[op1]=M[op2]+M[op3]
4 M[op1]=M[op2]*M[op3]
5 M[op1]=M[op1]
6 M[op1]=0
7 M[op1]中每個字符異或M[op2]
8 M[op1]中每個字符減去M[op2]
9 jnp M[op1] M[op2]
10 write M[op1] stdout
11 mov M[op1] C[op2]
12 exit
代碼序列分析後發現就是將輸入和某值異或再和某值(可通過動態調試得到)相減之後與字符串比較,相同輸出Authorizing access…不同輸出Access denied!
寫逆算法
s='á×äÓâæíäàßåÉÛãåäÉÖÓÉäàÓÉÖÓåäÉÓÚÕæïèäßÙÚÉÛÓäàÙÔÉÓâæÉàÓÚÕÓÒÙæäàÉäàßåÉßåÉäàÓÉÚÓáÉ·Ôâ×ÚÕÓÔɳÚÕæïèäßÙÚÉÅä×ÚÔ×æÔÉ×Úïá×ïåÉßÉÔÙÚäÉæÓ×ÜÜïÉà×âÓÉ×ÉÑÙÙÔÉâßÔÉÖãäÉßÉæÓ×ÜÜïÉÓÚÞÙïÉäàßåÉåÙÚÑÉßÉàÙèÓÉïÙãÉáßÜÜÉÓÚÞÙïÉßäÉ×åáÓÜÜ\x97ÉïÙãäãÖÓ\x9aÕÙÛ\x99á×äÕà©â«³£ï²ÕÔÈ·±â¨ë'
flag=''
for i in range(len(s)):
flag+=chr((ord(s[i])+15)^135)
print(flag)
這題難點還是在對這種非常陌生的編碼處理上。