【re】 watevrCTF2019_Repyc

本文介绍了在watevrCTF2019中遇到的一个涉及Python pyc文件的逆向工程挑战。通过uncompyle工具将pyc反编译为py源码,发现在Python3中存在非ASCII字符。分析发现代码定义了一个包含大量if语句和运算符的函数,疑似虚拟机代码。作者进行了代码简化,以便于阅读和分析。通过对虚拟机的逐条指令解析,揭示了其功能——输入值经过异或和减法操作后与特定字符串比较,决定是否输出授权信息。最后,作者讨论了逆向此类编码处理的难点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题给了个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)

这题难点还是在对这种非常陌生的编码处理上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值