社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

利用Python的dis反汇编提取代码对象部分信息

山石网科安全技术研究院 • 7 月前 • 163 次点击  
CTF比赛中,Reverse方向经常能遇见一种(可能是唯一一种)只给文本附件的题目,这种题目基本是靠人工阅读理清逻辑、并解出藏在其中的flag,费时费力又不难,因此广受各位出题人的喜爱。
这种题目就是经典的Python字节码文本(通常使用Python自带的dis输出)题,常作为各种比赛的签到题出现。
本文开发了一种手撕字节码工具,从Python的dis反汇编中提取出代码对象所需的信息,并结合xasm工具(https://github.com/rocky/python-xasm/tree/master/xasm)将字节码文本恢复为pyc,从而可以使用成熟的pyc反编译工具(如decompyle3/uncompyle6/pycdc等)获得字节码文本的Python源码。
工具已开源至github:https://github.com/c10udlnk/dis2xasm

手撕字节码

xasm输入的文本格式

PyCodeObject对象的属性在Python代码保护技术及其破解中有介绍,这里针对xasm所需的必要信息进行提取。
经过测试,xasm所需的输入格式如下:

这些信息也是xasm必要的信息,如果缺失会直接导致反编译程序报错退出;其余信息如文件名、firstlineno等为非必要信息,缺失可能导致恢复出的pyc信息有遗漏、进而导致反编译结果不够准确,但测试下来也差别不大。
xasm目前仅支持3.9及以下版本的字节码的汇编,故该工具主要也是针对这些版本的字节码进行信息提取,暂未适配3.10+版本中新增的字节码特性。

dis反汇编输出的文本格式

而Python自带的dis反汇编输出会剔除很多信息,只有主体的字节码部分,主打一个给人类阅读,不在乎机器能否解析,这也是很多出题人喜欢考它的原因。
Python 3.7+版本的dis新增了_disassemble_recursive(),可以递归反汇编co_consts中的代码对象,因此题目通常使用Python 3.7+版本的python3 -m dis temp.py反汇编整个文件的输出作为文本附件。与上文同一个函数,dis的输出如下:

第一行"Disassembly of..."中包含了该函数的函数名、代码对象ID、所属文件名和firstlineno,而剩下就只有字节码的反汇编了,对于其他xasm所需的信息都没有明显地列出。
因此,该工具的主要功能即通过字节码反汇编提取/推断出Constants、Names、Varnames、Positional arguments、Free variables和Cell variables信息

信息提取

Constants、Names和Varnames

这三个元组的提取相对简单,通过Python自带的opcode可以拿到使用这些元组索引的字节码:

不过opcode模块只能获取当前运行的Python版本的信息,而有些时候字节码文本是不知道具体版本的,需要跨版本爆破,所以这里采用xdis(https://github.com/rocky/python-xdis)获取跨版本的opcode信息,在遍历字节码的过程中直接匹配提取即可:
# 匹配形同"LOAD_CONST      1 (3)"的反汇编行PTN_ARG = r"([A-Z_]+)\s+(\d+)\s+\((.+)\)" 
for i in range(len(asm)): # 遍历字节码 reobj = re.search(PTN_ARG, asm[i]) if reobj is not None: opcode, idx, arg = reobj.groups() idx = int(idx) if op.opmap[opcode] in op.hasconst: co[CONSTS].update({idx: arg}) elif op.opmap[opcode] in op.hasname: co[NAMES].update({idx: arg}) elif op.opmap[opcode] in op.haslocal: co[VARNAMES].update({idx: arg})

Positional arguments

对于位置参数的识别主要包括两个部分:参数的识别,位置参数和关键字参数的区分。Varnames中按顺序依次包含三种变量名:位置参数、关键字参数和函数中新定义的局部变量(下文中简称局部变量)。所以可以先将Varnames中的参数识别出来,再通过定义和调用函数的字节码区分出关键字参数,剩下的就是位置参数了。
函数中的参数一般是外部传值进来的,不会像局部变量那样在使用之前一定会有STORE,所以我们可以在遍历的时候加一个判断,判断这个局部变量在使用时有没有STORE过,如果没有那说明很大概率就是函数参数,由于在Varnames中两种参数一定在局部变量前,所以记录这样检测出来的索引最大值即可:
for i in range(len(asm)):    reobj = re.search(PTN_ARG, asm[i])    if reobj is not None:        opcode, idx, arg = reobj.groups()        idx = int(idx)        # ...        elif op.opmap[opcode] in op.haslocal:            co[VARNAMES].update({idx: arg})            if "STORE" in opcode:                varState.append(idx)            elif idx not in varState: # 使用时检查该变量是否存储过                co[ARGMAX] = max(co[ARGMAX], idx)
同时为了提高推断的准确度,也会记录局部变量的索引最小值,已赋值的变量很大概率是局部变量(如果函数中重新赋值了参数,那相当于参数原本的值被覆盖了,此时可以看作是局部变量)。
co[LOCMIN] = min(varState) if varState else -1
正常情况下,参数索引最大值ARGMAX与局部变量索引最小值LOCMIN相差1(Varnames中参数和局部变量依次排列)。但如果参数或局部变量没有在函数中使用过,那么会有一部分索引对应的数据无法提取,也就无法精准地确定出参数个数,只能通过取max(ARGMAX, LOCMIN-1)来推断。值得注意的是,如果函数的参数直接被传入闭包中(而没有在函数中进行任何的调用),也会导致Varnames中参数索引对应的数据缺失。一般的Python程序也不会创建无用变量,所以此处推断的参数个数正常情况下还是很准的;且至于缺失的数据,只能用随机名暂代,可以在反编译后人工纠正。
参数的个数获取以后,接下来是关键字参数的区分。关键字参数会在两个地方出现:
  1. 如果关键字参数有设置默认值,那么在MAKE_FUNCTION时标志位会设置0x02位:

    在运行栈中,TOS是函数的限定名称,TOS1是函数体的常量,TOS2开始就是标志位标识的常量,顺序为0x08的自由变量元组(下文分辨freevars和cellvars时同理)、0x04的标注字典、0x02的关键字参数默认值字典和0x01的其他参数默认元组。

  2. 没有设置默认值的关键字参数,调用时一定需要指明变量名,所以可以寻找该函数被调用时的字节码,找到 CALL_FUNCTION_KW前面指定的关键字参数名:

如下是一个关键字参数的函数示例:
def f(a, b: int, h: int, i=9, *, c: str = "1", f, g=11):    # ...    return
查看dis反汇编,MAKE_FUNCTION标志位为7,即被设置了0x04、0x02、0x01。那就是往上数三个栈元素,偏移80的LOAD_CONST是TOS,偏移78的LOAD_CONST是TOS1,我们需要的关键字参数默认值字典是TOS3(设置0x04的标注字典在TOS2)。在这个默认值字典中,最后一次LOAD_CONST是涉及的关键字变量名,这里可以获得一部分关键字参数cg

该函数被调用时,CALL_FUNCTION_KW上方的元组就是关键字参数名,这里可以获得剩下的关键字参数fc重复):

通过这种方法,我们可以记录函数的关键字参数,把他们的个数从参数个数中减去即可:

argidx = max(co[ARGMAX], co[LOCMIN] - 1)if fn in self.fkwDict.keys():    # ...    argidx -= len(self.fkwDict[fn])co[POSARGS] = argidx

Free variables和Cell variables

在字节码中cellvars和freevars位于同一索引列表(该索引列表为cellvars+freevars拼接而成),可以使用xdis中对应版本opcode的hasfree属性筛选出所有的freevars和cellvars:

for i in range(len(asm)):    reobj = re.search(PTN_ARG, asm[i])    if reobj is not


    
 None:        opcode, idx, arg = reobj.groups()        idx = int(idx)        # ...        elif op.opmap[opcode] in op.hasfree:            co[CELLVARS].update({idx: arg}) # cellvars and freevars

freevars是传进闭包函数中供其使用的外部变量,在MAKE_FUNCTION时会以元组的形式列出:

因此只要遍历到MAKE_FUNCTION的标志位设置了0x08位,那么在TOS2就是组成了freevars的元组,例如这里的(b2, b3, a3, c)是函数ccc的freevars。

freevars确定以后,就可以将其从cellvars中区分出来:
if fn in self.fvDict.keys():    idx_list = [next(k for k, v in co[CELLVARS].items() if v == fv) for fv in self.fvDict[fn]]    idx = min(idx_list)    for k, v in list(co[CELLVARS].items()):        if k >= idx:            co[FREEVARS][k-idx] = v            del co[CELLVARS][k]

处理字节码

xasm的字节码格式同dis的相比有一些不同,主要是把同名的函数加了ID做区分(这也导致反编译以后程序可能不能正常运行),去除每行前的偏移值,跳转的">>"符号也被去除,其余差别不影响后续的汇编和反编译,这里简单调整即可:
def _adjust_asm(self, asm):    def repl(o):        name, addr = o.groups()        s = list(o.group())        if addr in self.funcMap.keys():            assert name == self.funcMap[addr][0]            name = self.funcMap[addr][1]            ib, ie = [t[1]-t[0] for t in zip(o.regs[0], o.regs[1])]            s[ib:ie] = name        return ''.join(s)    newAsm = asm.replace(">>", "  ")    newAsm = re.sub(PTN_CO, repl, newAsm)    newAsm = re.sub(PTN_LNO, lambda o: f"\n{o.group(1)}:\n", newAsm)    newAsm = re.sub(PTN_BOFF, "\n", newAsm)    return newAsm.strip("\n")

汇编

xasm工具做的是将这些信息整合起来,最后生成一个CodeType:

但xasm优秀的地方在于其版本之间的兼容做得非常好,例如Python不同版本之间的CodeType属性不同,如果自己写只能这样,用各个版本的opcode生成对应版本的版本信息,在运行时再读取:
try:    with open('version_{}_{}_info.txt'.format(_v[0], _v[1]), 'r') as f:        data = f.read().strip()    def _get_info():        for l in data.split('\n'):            yield l    info = _get_info()    self.argnames = literal_eval(next(info))    attrs = ['hascompare', 'hasconst', 'hasfree', 'hasjabs', 'hasjrel', 'haslocal', 'hasname', 'hasnargs', 'HAVE_ARGUMENT', 'opmap']    for x in attrs:        setattr(self, x, literal_eval(next(info)))    self.stackeffects = literal_eval(next(info))    return Trueexcept FileNotFoundError:    print("[-] Cannot find 'version_{}_{}_info.txt', parsing exits.".format(_v[0], _v[1]))    return False
然后手动生成:

(这是该工具的旧版本)版本之间的兼容非常痛苦,还有数不清的bug。
决定重启这个项目的原因也是因为发现了uncompyle6的作者R. Bernstein的仓库中有这么个小汇编器,但是只支持固定的输入格式,所以对旧版本的手撕字节码工具进行了重构,调用了xasm的轮子,专注信息的提取即可。

例题

这里拿L3HCTF上的一道字节码题目DAG做例子:

这是一个4400+的字节码文本(虽然前面有不少重复部分),很显然是dis反汇编出来的。
由于中间偏移值可以看到有被人为删除的痕迹(64-110),偏移值一般是连续的:

手动添加相反效果的两条字节码补全:(decompyle3反编译时无法识别NOP,所以退而求其次用其他的补,总之把缺的偏移补全就行)

然后使用这个工具生成pyc并使用反编译工具反编译:

恢复结果:
# decompyle3 version 3.9.1# Python bytecode version base 3.8.0 (3413)# Decompiled from: Python 3.11.4 (main, Jan  5 2024, 15:17:54) [Clang 17.0.6 ]# Embedded file name: unknown# Compiled at: 2024-05-07 15:51:53import random
def func1(lss, i, j): if arr[i * len(lss) + j] != -1L: return arr[i * len(lss) + j] s1, s2 = list(lss[i]), list(lss[j]) l1, l2 = len(s1), len(s2) flag = True n = 0L if l1 - l2 == 1L: for m in range(l1): if s1[m] != s2[n]: if flag: flag = False else: arr[i * len(lss) + j] = 0L return arr[i * len(lss) + j] else: n += 1L if n == l2: break
else: arr[i * len(lss) + j] = 0L return arr[i * len(lss) + j] arr[i * len(lss) + j] = 1L return 1L

def abc(lss, i): if abcarray[i] > 0L: return abcarray[i] m = 1L for (index, word) in enumerate(lss): if func1(lss, i, index) == 1L: m = max(m, abc(lss, index) + 1L) abcarray[i] = m return m

def solution(lss): global abcarray global arr abcarray = [ -1L] * len(lss) arr = [ -1L] * (len(lss) * len(lss)) ans = 1L for i in range(len(lss)): ans = max(ans, abc(lss, i))
return ans

def func2(n): (a, b) = (1L, 1L) for i in range(n - 1L): a, b = b, a + b
return a

def calc(nums): num1, num2, num3 = nums[0L], nums[1L], nums[2L] num1 = 2023L + (num1 & 15L) - (num1 & 240L) num2 = func2(num2 + 7L) random.seed(num3) flag = f"{num1}{num2}{num3}{random.gauss(num2, 0.2)}" flag = flag.replace(".", "x") print("flag=", flag) return flag

def encode(s): ret = [] ls = list(s) for i in range(0L, len(ls), 2L): num1 = ord(ls[i]) num2 = ord(ls[i + 1L]) numa = (num1 & 248L) >> 3L numb = (num1 & 7L) << 3L | (num2 & 240L) >> 4L numc = num2 & 15L ret = ret + [numa, numb, numc]
return ret

if __name__ == "__main__": ### 原文中缺失的部分 assert encode(str1) == [12L, 22L, 1L] assert encode(str2) == [12L, 14L, 2L] assert encode(str3) == [12L, 22L, 3L] assert encode(str4) == [12L, 30L, 2L] assert encode(str5) == [12L,22L,4L,12L,30L,1L] assert encode(str6) == [12L,22L,1L,12L,30L,4L] assert encode(str7) == [12L,22L,2L,12L,22L,2L] assert encode(str8) == [12L,14L,3L,12L,38L,2L] assert num1 == solution(["a",str1,str2,str3,str4,"bda",str5,str6,str7,str8,"bcdef","aabcc","acbac","bdcaa","bbbbcc","babccc","abaccc"]) assert num2 == solution(["klmnowx","abcdefgiklmno","fgij","bcfghijklmno","fgjpqrst","uy","abceklmnouvw","pqrstuwy","fghijlno","mnouvwxy","klmnopqt","klmnopqrstuy","aeuvw","muvw","abcdeklmnow","fhijpqrst","mpqrst","klmnoprt","fghijklno","abcdelmo","klnuvwxy","klmnopst","abcdeklmnov","fghj","luvwxy","ghklmnopqrst","pqrstwx","abcdklmno","cdefghij","pqrs","efghijklmno","fghjklmno","adeklmno","rs","kuvwxy","ghij","befghijklmno","ln","hijklmnopqrst","ghpqrst","fgiklmnopqrst","pqrtuvwxy","pqrsty","jklmnopqrst","lnouvwxy","klmnoqsuvwxy","abcdeghklmno","fi","fghijlnpqrst","abdklmnouvw","uwx","abcdekln","klmno","abcdekn","abcdemuvw","pqs","fghijpqt","klmnopqrstuw","n","nopqrstuvwxy","abcdefghj","fghiklmnopqrst","klmnorst","abcdemnouvw","fgh","pqt" ,"abfghij","o","nouvw","abcdklmnouvw","abeklmno","abcden","klmnopqrstwxy","q","fghijklmnoprt","klmnovx","abceuvw","klmnopsuvwxy","hj","abcdefgh","fhjklmno","klmnoquvwxy","wxy","klmnopqrstuvwy","kln","abcdegklmno","mno","gklmno","klnouvw","fghijklmnoqr","fghijpqrst","mnuvwxy","ghipqrst","klmnoqrtuvwxy","acdfghij","uwy","fghjklmnopqrst","mnpqrstuvwxy","abcdeknouvw","abcdefghijklmno","klmnorsuvwxy","abcdeh","klmnost","iklmnopqrst","abcdegijklmno","fghijklmopqrst","fghijklmnors","pqrstux","abcdefghijlm","abcdem","klmn","opqrst","ghjklmnopqrst","cdfghij","kluvwxy","ceklmno","abcdeghijklmno","lmo","bklmno","fghijs","cdeklmnouvw","abcdeknuvw","cdklmnouvw","abcdeklmnovw","klmnopr","fghijklmnopqrst","klmnopqtuvwxy","abcdefhijklmno","abcdeuv","abcdefhklmno","x","abcdeouvw","fjklmno","a","klmnopqrstuv","abdklmno","fghijlm","bcefghijklmno","quvwxy","fghi","klmnopqrstuwx","r","klmnuvw","kn","abcdeklmn","abcdeklmno","ps","klmnoqrt","pstuvwxy","klmnopqrsty","lmn","d","abcdefghijmo","fghijmnopqrst","ghiklmno","mouvwxy","abcdeghj","fghijklmnopr","kmnouvwxy","fghijklmnopqst","klmnox","nouvwxy","adefghijklmno","kmo","klmnovy","klmnopqrstuvwxy","cde","y","klmnouy","fgklmnopqrst","nuvwxy","kluvw","abcdefghijkno","abcdekl","fghijno","ceuvw","abcdelo","bcdklmno","gij","abcdeijklmno","klmnopqrt","abcdeklm","pqruvwxy","klnuvw","fijklmno","knpqrstuvwxy","fghijklmnor","ace","abcdekluvw","deklmnouvw","lpqrstuvwxy","abcdefhiklmno","fijpqrst","klmnopqrstvwy","mn","kmpqrst","ipqrst","fghijkmnpqrst","uvxy","bklmnouvw","fghijkmnopqrst","fghijklnopqrst","kopqrstuvwxy","pqrstuwxy","abdeuvw","acefghij","jklmno","k","fghijqs","abcdefghijno","fghijklmnort","adeuvw","vwx",0L,"hi","abcdefghijm","nuvw","fklmnopqrst","abcdehklmno","fghijklmnoqrt","klmnoruvwxy","abcdemnuvw","klmnovw","klmnopqrstvw","klmnoqtuvwxy","klmnoy","wx","ouvwxy","lmopqrst","fghjpqrst","lnuvwxy","vy","abdfghijklmno","kmnouvw","uvy","klmnoqst","klmnort","pqrstuxy","qs","lopqrstuvwxy","mnouvw","abdeklmno","abcdelnouvw","pruvwxy","qrsuvwxy","cklmno","bc","acdfghijklmno","j","fghijpqs","fghijknopqrst","fgijklmno","fghijnopqrst","mpqrstuvwxy" ,"knopqrst","acdeuvw","lnouvw","fghijklmn","klmnouvxy","abcdefghiklmno","abcdefghij","hij","abcdekuvw","klmnopqs","aklmnouvw","acdefghijklmno","cfghij","fghijpqst","cfghijklmno","abcdefhi","kmouvwxy","pquvwxy","pqrstuy","pqrstuwx","ce","klmnopqrstv","deklmno","klmnouvw","abcdeno","fghijkmo","knouvwxy","fpqrst","hklmno","fghijkmopqrst","abcdefghjklmno","kmpqrstuvwxy","dklmnouvw","abcdefghijkmo","abcdel","giklmnopqrst","buvw","klmo","klmnoqrsuvwxy","uvwy","abcdeluvw","klmnostuvwxy","bceklmno","fghijm","defghijklmno","ijklmno","pqr","abcduvw","fghijklmnopqt","hijklmno","klmnoprsuvwxy","aeklmno","lo","klmnouxy","cdklmno","fghijpr","muvwxy","lmnouvwxy","abce","kmnopqrst","pt","klmnoptuvwxy","abde","abcdeghiklmno","klmnopqsuvwxy","klmnouvx","efghij","klmnouwy","bceklmnouvw","klmnuvwxy","ad","klmnoux","gjpqrst","abcdegij","fghijkpqrst","fghijlmnopqrst","abcdefj","fghijklmnops","fghijklmnoqs","ghi","fghijqst","abcdemo","abcdefghijkl","fghklmnopqrst","no","klmnopqrstuwxy","klmnopqrstvwx","abcdeklmnou","abdefghijklmno","klmnopqrstxy","acfghij","pqrstuvwy","kuvw","abcdehi","de","fghijpq","lmuvwxy","abcdelmouvw","abdfghij","knuvwxy","acde","cuvw","uw","kmopqrstuvwxy","abcfghij","fghij","abcdeklmo","abcdehij","abcdek","fghijklmnoqrst","pqrstvx","klmnopqrstvx","abc","klmnoqrstuvwxy","acklmnouvw","afghijklmno","abcdeklmnuvw","abcdei","fgiklmno","klmnopqrstuvw","abcklmnouvw","abcdelmnuvw","abcdehj","abcdefghijlo","fghpqrst","acfghijklmno","abcdeg","klpqrst","klmouvw","bdfghijklmno","aefghijklmno","fijklmnopqrst","fghijps","fghijklnpqrst","fghijklmnop","fklmno","klmnopqrstw","abcdfghijklmno","fj","lnopqrst","fghijkmpqrst","fghijlnopqrst","ux","fgjklmno","fghijklmnopqr","abcdeghjklmno","abcdefghijkmn","abcdegiklmno","abcdefiklmno","acdeklmno","klmnops","fghijklmnopqrt","fghijklmnoqt","abcdegj","acdklmno","abcdeghi","abcdelmuvw","abcdefg","fghijkl","gjklmnopqrst","hipqrst","klmnopqstuvwxy","lnuvw","ghijpqrst","pqrstuvwxy","klmnovwx","klmnoqstuvwxy","bcklmnouvw","abdeklmnouvw","fghijklmnopq","abcdefghijk","abcdefghijklno","fiklmnopqrst","klmnopq","npqrstuvwxy","klmnopqrstwx","abcdefi","lpqrst","ghijklmnopqrst","bd","bcuvw","hjklmnopqrst","adfghijklmno","klmnosuvwxy","louvwxy", "bce","gpqrst","fghijklmnot","wy","pqrstvwxy","fghijkln","lmouvw","gi","fghijn","fhklmnopqrst","ghj","klpqrstuvwxy","abcdefgklmno","fghijlmo","fghijo","fhpqrst","klmnoprs","abcefghij","abcdeklno","abcdefghijlmno","kmnpqrst","fghijklmnoq","abcdefhij","fghijklmnopt","klmnopt","abcdefklmno","abcdelno","pqrstw","fghijlopqrst","bfghij","abuvw","abcdefghijln","hi","aefghij","prs","lmnopqrstuvwxy","abcdefghijn","klmnopqrstux","luvw","giklmno","kpqrst","jpqrst","fghijrt","fghijlo","abcdefij","fghijklmnorst","fghijqrst","tuvwxy","fghijlmopqrst","klmnouwxy","bdeuvw","fghijprt","klmnoprst","pqrstuvy","fghijpqrt","fgj","pqrstvxy","abdefghij","abcdegh","abefghij","lno","klmnopuvwxy","klmnouvwxy","fghijrst","cd","euvw","hijpqrst","pqrst","klopqrst","gijpqrst","klmnopqrs","fghijk","klopqrstuvwxy","rtuvwxy","klmnorstuvwxy","stuvwxy","abcdevw","cdefghijklmno","bdeklmno","pqstuvwxy","fghipqrst","fghijpst","kmn","mo","abcdeuw","qst","fghijklmnost","klnopqrst","abcdekm","abcdefgj","klmnopqrstuvy","kouvw","abcdelmnouvw","abefghijklmno","fgipqrst","klm","klmnopstuvwxy","abcdekmno","fghijmno","pqrstvw","kmouvw","cdeklmno","st","fij","fhiklmno","abcdefghklmno","lmnuvwxy","klmnovwy","klmnow","mnuvw","fghijklmnpqrst","klmnoxy","fghklmno","b","lopqrst","pqrstuvw","abcdekmouvw","abcdeklmnouw","acduvw","klmnoq","bde","pqrstxy","qrs","bcdeklmnouvw","abcdekmo","abcdefghijkn","kno","abcdefghijklm","abcdefgij","kmopqrst","kmnuvwxy","pqrstuvwx","fghijkmn","acdefghij","fghijmn","qr","l","kmnopqrstuvwxy","abcdefghijl","afghij","auvw","abcdew","klmnopqrstwy","adfghij","abcdeghij","lmopqrstuvwxy","abcdefghijklmn","uvx","km","abcdefijklmno","abcdeij","pq","lnpqrst","bdfghij","abcdefhj","mopqrstuvwxy","fghijklmnopqs","fghijqt","ade","abcdejklmno","fghijklmpqrst","pqrstuvxy","mouvw","mopqrst","lmnopqrst","abcdefhjklmno","acdklmnouvw","bcklmno","nopqrst","qrt","fghijlmnpqrst","pqrstuv","klmnos","pqrstwxy","fgjklmnopqrst","pqrstuw","klmnopqrstuvxy","fhijklmno","abcdekmnuvw","ghjklmno","klmnoprtuvwxy","abcdefghijlmn","klmouvwxy","abcdegjklmno","p","hiklmnopqrst","rstuvwxy","gh","cdfghijklmno" ,"klmnou","iklmno","klmnopqrstvxy","lmpqrstuvwxy","prtuvwxy","klmnovwxy","pqst","klmnortuvwxy","lmnpqrstuvwxy","fghijmpqrst","ghiklmnopqrst","klmpqrst","klmnoprstuvwxy","ghklmno","fghijopqrst","klmnoqruvwxy","abcdeklmouvw","ae","abcfghijklmno","vw","fghijr","kmnpqrstuvwxy","fghijklpqrst","vwxy","uxy","cklmnouvw","abcdefghijkm","uvw","bcd","bcefghij","abcdeiklmno","klmnot","cduvw","fghijmo","eklmnouvw","klmnopqrstuwy","kmnuvw","lmouvwxy","abcdefghijlmo","cefghij","klmnoqs","klmnouwx","kmuvwxy","ceklmnouvw","fghijklmnoqrs","abduvw","abceklmno","ghijklmno","abcdefghijmn","bcdfghij","pqrstvwx","fghijlpqrst","gijklmnopqrst","abcdelnuvw","pqrstvwy","pr","fghijklmnos","c","fghijklmno","abcdefghijkmno","abcuvw","abcdev","abeuvw","pqrstuvx","klo","fghijln","klmnpqrstuvwxy","abcdefghijlno","fghijklmnopst","acd","gipqrst","w","abcdenuvw","deuvw","abcdeklmnouvw","fg","cdeuvw","lmnuvw","abcdenouvw","klmnoqt","hklmnopqrst","klmnouvwy","gijklmno","klmnopqrst","fghijmopqrst","kmno","f","uv","fhij","knuvw","klmnor","klnouvwxy","bcdeuvw","bdklmno","abklmnouvw","abcdehjklmno","bcde","fghijklmo","abcdefghijklmo","aefghij","abcdeklmuvw","bcdefghijklmno","beuvw","qstuvwxy","aeklmnouvw","h","t","kmuvw","fhi","fjklmnopqrst","hiklmno","fhipqrst","qrtuvwxy","abcdeklnuvw","fghijqrt","pqrstx","bdefghijklmno","gj","abcdelmno","abcdefjklmno","fhjpqrst","klnpqrst","fgijklmnopqrst","abcdelm","fghijrs","klmnouw","fhklmno","abcdeln","fgijpqrst","fghijklmnoqst","abeklmnouvw","klmuvw","i","lmno","fghijklo","fghijkm","g","adklmnouvw","be","abcdefgjklmno","prst","puvwxy","qrstuvwxy","klmnov","klmnopqrstuvwx","acefghijklmno","fghijpqrs","fhj","abklmno","abcd","fiklmno","ijpqrst","fghijnpqrst","lmnouvw","suvwxy","knouvw","duvw","fghijkmno","bdefghij","aceklmno","fgklmno","fghijst","adefghij","fghijklmnopqrs","bcdefghij","abcdefghijko","klmnotuvwxy","klmnopruvwxy","klmnovxy","qtuvwxy","fhjklmnopqrst","klmnoqrst","prt","fghijt","uvwx","abcdekmnouvw","dfghij","abcdehiklmno","klmnopqrstu","adeklmnouvw","abcdefghijmno","klmnopquvwxy","abcdefghijkln","mnpqrst","fghijlmn","lnopqrstuvwxy","pqrt","fghijpt" ,"abcde","ij","bcdklmnouvw","fghijkn","pst","bdklmnouvw","abcdeko","fh","fjpqrst","fghijqr","beklmno","fghijklopqrst","lmuvw","klouvw","fghijpqr","abcdegi","psuvwxy","klnopqrstuvwxy","abcdelmn","fhiklmnopqrst","fghijprst","lnpqrstuvwxy","qruvwxy","aduvw","abcdekmuvw","adklmno","abcdeu","cefghijklmno","lm","hjklmno","abcdefghijklo","klmnoqrs","fghijko","ouvw","pqrstu","mnopqrst","louvw","prsuvwxy","abcdekno","klmnopqruvwxy","kpqrstuvwxy","abcdefgijklmno","klmnors","abcdefghijo","npqrst","knopqrstuvwxy","vx","fghijqrs","klmnopqrstuxy","u","aceuvw","klmnopqrtuvwxy","uvwxy","fipqrst","klmnowxy","befghij","gklmnopqrst","abe","mnopqrstuvwxy","fghijklmnoprs","abcdeo","eklmno","fgi","fghijlmpqrst","qt","abcdefghi","bcduvw","bduvw","klouvwxy","kouvwxy","fghiklmno","abcdemno","pqsuvwxy","ab","klmnopqrstvwxy","pqrstv","abfghijklmno","beklmnouvw","fghijklm","pqrsuvwxy","acdeklmnouvw","vwy","ghjpqrst","fghijl","klmnopqrstvy","abcdelouvw","fhijklmnopqrst","klmpqrstuvwxy","abcdef","bcfghij","fghijkno","kopqrst","rsuvwxy","abcdekmn","aklmno","dfghijklmno","abcdeklouvw","klmnpqrst","abcdeklmnouv","knpqrst","aceklmnouvw","kl","fghijprs","rt","klmnopqrsuvwxy","bfghijklmno","klmnouv","abcdefh","s","klmnouvwx","fghijp","uwxy","fghijq","klmnoqr","vxy","fgpqrst","fghijlmno","defghij","pqtuvwxy","dklmno","klno","klmnowy","abcdemn","abcdeklnouvw","ptuvwxy","abcdehijklmno","acuvw","bcdfghijklmno","abcdemouvw","abcdefgi","opqrstuvwxy","v","lmpqrst","abcdeuvw","abcdekouvw","qrst","klmopqrstuvwxy","prstuvwxy","lmnpqrst","pqrstvy","abcdfghij","klmnop","ijklmnopqrst","klnpqrstuvwxy","klmnopqr","xy","abcdeklo","abd","klmnouvy","klmuvwxy","abcefghijklmno","fghijkopqrst","fghijklmnoprst","ruvwxy","m","e","abcdej","hpqrst","bceuvw","fghijmnpqrst","pqrstwy","klmnopqrstx","qsuvwxy","fghijknpqrst","bcdeklmno","klmopqrst","bdeklmnouvw","klmnopqst","abcdeklmuvw","acklmno","hjpqrst","abcklmno","rst"]) assert num3 == solution(["ysvydhncudvxqgub","jxomzgqmpccovmyy","hxiwwqdowwbdzrql","zqfykhyqgxpuedhx","vhszanyizlocrcta","dthywqimclejyrxf","pxvnsacefcaeqwpn","eibroystpzgkhwkt","efioczniyhzlkgxx","jbafyifjrdsevjlt","noggsbrxuzxxxpnv","usxugdobkxyvebgp" ,"omppygjbdzvfncoh","lszhxcyfyhbezqpl","sywbjmfmigsrdhbe","kmitesfpzturedvn","fhccayoplynamcmf","xwkxxvmngwdkktcq","bkdetlrdtrvxtwnm","otbqjkibazuiuzjc","bvdlpsuozpxykhso","sfkdemywenvutigi","zlsgexavkjlbniyz","omvmljrelegkrnly","ncfqxwbgspmmxequ","nsnusovrqfyjqcmi","xmfltlmbucykoygu","znevkwdmcjkxazvx","qmmlumphgweyuqll","vvwllhnjjilkkfbr","tfczebbrmcwkijpy","dyqudxtooxmzaivg","qabmbvkkacpipzwv","ousivmwzqkzowbsf","wiajbnzcyczvdkme","jtvkqglawuiitvne","hynkguvzlahiaweu","dcdhzutcxsrwhtiu","sjkbkfbzcltyhkzc","vmtoulenvyzgmzph","hhpjlqospgyrpjnr","trxsiqvzjdsumnbx","ifmzrmfjlfbxrspp","zuybbnxweoodzrcp","dqselcmauqpdbvji","ucdmjxlnodsqbtpf","yxqxoqyqsuxbvvwh","jifmvnffunc2jlgdux","fttypgxftlzhrjhu","rzmkqtaejgzrwvht","fylzmnvoslrjeuhu","xxhmsywcfchxybtz","nivviopjjkilmfnt","vlvtonhigprfttuk","cwgnurrfabcfotdmj","erjxfseyzaygaujp","nrcqdwczglmcvinq","dqbyglmywihtexid","vqggccuiimjqqpuz","wbvvklwhouxxcbzg","jxstdmcbouqvysje","envdnanmuewgheqr","oxjeneckyoxdypwq","ityoxogkfmlasgfq","tgpkcweywtqopjnc","hepoijpjgvckkqzc","ubppuzmagmjgmjnf","snvaiqinphtkbxtc","wvdwymqejrygisbn","kmbwjynfbwyablvs","rsscpinfcegvnulj","oplzudhvjaumtavx","oionhndcrjvfexir","cxxlrudrixtmjsgw","sfngfbrksewwbwuo","wngezcjkxlftmure","xgkmmsvjjvtlwyko","dfaihamfjrwobkai","ybzlbmtejcbhkbqn","yvgttkpmodjrdjaj","wsfkdifjxsisyazp","btdahuinzvvmyuti","sppdjjphoadtnxqz","idikaxmkupaaeyvd","bxmusrwhsuglelsa","wllftkyuyjwumzfz","lsrfakcruqfghhqr","oitbsfztaayzgttw","qvdaclqbkxzxtvji","hqtnylqopcuyitvv","dovrsivynjuycgob","zbeexmgffbvgyukt","jnyrkwuketocbnlp","kesivzsfimkupknz","fvctuhkhcsxgpnlc","geyiflxobsqqgysp","vdhnckkljiwiylkc","jxixmpjvkuisogjx","ggmgthlqqfjzvsiv","nkdbbqswrytidodb","cvnxasfxcyyprwky","msptawajcgigotxx","lggqfreicrrzgqug","pywexuvmpapzhhmk","yjfzlaazckdxqhpk","gxopiqnejwahizvy","rwptjuqhjshtosim","zhszbxltmwjfbcnn","hznbmqrhucjlhtev","repwvulbjzulzqlm","juemhyiaujdhjwda","iphegtklhgyiabcof","tpqxoalgjntzhxph","ahnrxtoyzqrqrxce","ljsunmfpleczezfi","flqbbwjpvmpiagkm","enxrdnasgsrczncm","setirvmdopdbgqqi","uuyoeqtcgvygmlbd","gznmxhdzpgclmmce","wrqmvtilsmjrfruj","nzbqahmftsbygrje","nodxqfwosevxikai","ynzmckxtfampkdcb","ishsysxcjavxukfq","mbwcnmktksqoptdx","ybpgwitxuarhyuud","odkhmislpnpjltvc","imlknoihasmgbjle","autoweexfbmsnamc","pzddxvvmnmujzovy","zbklmwsqltyiqjaq","wsfezmwlwnovzfnq","ipvtflaxlabczbjwg","xmeypiupgboeikma","qmhxpnusoafktsrp","akbzwaoevusmqhjy","ptnrluxfiaoedirs","fkkujjetvujaffev","iqlaebkqlabcuugvd","tvfazupnodyxyegj","cxxbmckkoocwwmkv","eiinwggrnufbuefm","jbajzgyvabcjrpirb","anotitqeflusqkmx","kkyyjfyqfwuyphvs","mkxxxgmewnnfmtgw","rfzfkowvhlbuptnn","yihacnrktjrrbupi","ljbfbmrxivbqhvgn","kelkifhcummieqec","qwglfqmlgtufeggt","ztdsjupiobdswepc","nxxrjnqebfrtztab","zwuijitgzkamuohu","skctyqbrtdlybrad","ftvbzzqisluhwvoj","tkyzlbdwikxwxtfm","yqzbwtibgyhezefc","ugmtditxujqhzdjk","pzqfxlcsbyiayoqn","mvuvmubzxoapqlwq","wxydvrxojyifgild","gaubuvvoncoahhqs","arrqgidasqpyozqo","hlktmcpfqmqunsiw","hpshspcjtkvjtyfc","xwdjpdyqbgkvbbto","dnipqamvliabetfk","zrptncovohuprjfj","zykerhdnpwqnklnp","wehvwpjsjmlhbxme","qhabvcixedhtacnm","nzbonhjtiragsjxu","piktfsxlejzjpmxa","kpgluxplomivhups" ,"utbqkkbmdakmajvb","pbosjdvammowabof","hwwpavjyghyogxiz","qixjbuehpllqwbir","watokwdhqrlthmyt","fiuvnmucwsfhvirt","efjbktqktzylkzym","eyagoufvrlrbukvi","dbebcdxywrceoioj","dmejkiuqtpzkvtil","irxxxrbxjvvisefx","ezacasyffovrewri","zfoernjrzvxkzqjn","krrmkfftxdxqxrjf","xexiopshwbkipjdw","cnuiizhcocljycvu","idsxihqjacgtwiuu","nwjjtbiketrqdvxb","avmxhxabcxhflzcbs","uqxjgosfyjcbxshz","gwybdcsgvjjacjoq","zokabcujdqyhfvvve","dudqkxdyvnmzxbal","duurelhvlvlwtisc","vvduznkfxsydjjsu","jvohyxbezkxdybjk","tecmjpqvbqdfgbch","wmiwtqmxlipobteb","bzhfoutsommbeahv","pzxilyvfyokfmsmr","fvptnoujoahvjljv","nntjwlzvtlwjijtq","iiahigptxppvjwwh","fiwxrfkvznhngctp","hljuecxsqwhfhooj","kpgylifngxbybkwm","ckxgbjjygzkystat","anxjpmmadenhxunx","kztzbysfhebhkxhw","qeywqntlveiebhos","jlbvhtvumiyxwqlo","ubsttmdcjigfizes","tifeodqhusljfhxl","xhtrvehthwvsxkmj","slytykltdhwruorn","ettsedvbbxttpkwg","znlstbcrbxxyauvt","zvxkminzbadeyxpn","vkeqpqwrdrzvrdkg","lmgvnrmbwermpsxx","wpcihvumyumoljws","sqqleapevuisjovs","xrtefpneewlrlvwd","mmbabccilwfyvvjak","mqebclxzlkierkjf","cuytrwygyntgajgm","fhodjnmtmzrqzszj","kmgwmlnfykcuvqnl","aopjewaqievtqdct","tjouxksorchkworv","ncirabcozpldzewjz","sucivpgmovkfqxpn","akhusibommljkvfb","cdxrtkejlxftegjn","pcykwqocqfjcpygs","ddgipyltjxtthplq","uqtqauyppkzzztxr","byziilqifrkefnmx","pihmqvosbrmfwvgj","zcrokjgwuujlsqzk","midiigvhwxuuxdoj","quzizelifvrqgiqy","qoizxtjfeiykktbh","kopvmoiueozhbxfe","rabczignulcwpsobz","acklmno","cwknucjbjropshgm","xrkvscqbnuofxbbd","lfhexistfbnypjxb","qtvceoxufqerkgcd","nvqnrbzmizbmenoj","vaxeseydjahzmeqv","kkhvyzvdlupbekot","ghkdrqrrufndvlab","puuorkmgkyjrrfzm","qdojlkfsajazdbtr","trunvamzxxtruqqk","wyfqiycmuaxnwdmj","tehftxcnimfcgulv","xideohbursltsyaw","zukuxtscehugrlwz","tqyowyifdxmlekmi","gktvxxotbobtzjhz","sbrdswxuitwshrql","vjxkqyvipqlevbhk","xupvseicxsjlvprl","zzvgmaspjzobbbai","umqxughwbhxrbgnv","necgnedkdtsxllws","kfzhgtbffdkcmemk","jygmwohqgxytdabcc","xubntcuzhakycmhb","nykkvobihcvcbsom","jmpfjbgethlvegac","rcrkrqlqszizkuwn","mkvtjvezpqntwsor","vavxnwabzsvbxrta","wxjtawscbrqldboj","ukqyxnzmmregydtj","bzdoqdhyfxjhrtca","zwwifjejxilnlncq","zbhinfwhbsewmmnj","wpatetlrcetrwygn","qijjqtjtkjldjzpv","wizlmxgtbqokdive","gjowgwgtfyoyvakj","dutziyzhjwwdwbmh","hhxlvaslalqnjfez","nftbzbqrrdhpbvel","rawgbwriyffuvwea","qelvbxvcmyipiyux","gpvbmgzpjpvmfjou","edysbthmpzewjmhq","gimdgabewrjfmouq","kabamudmytcvskgz","jnbqnbtzepeettut","ubycgxbczobyuvty","ncqlwqzzlurrfurm","mqdliidaptajnque","aqkislhbhutlmskx","kqgowgleasjmgjro","anzasevxbinscrwy","mligzlmekbqjtlkz","acjwzeaariolohth","lewbaeswgtsegzgf","bkaleiidkzgtyukg","griqeggfgygajdxr","tiqtuoakcxhsppug","djwebkqgutgcqjkq","mtdquygxxpcnmxvg","lzbitojuuxxhrcms","wkqdzfkdeoxlrrrv","qdkvpynqxmqizxfh","rsypvochupieijuw","zhjqkrovsdewbwrg","cojrovhotitqglxf","vupizqllrxepdyej","rrcescgfpodyqgqj","enyhpwibqizxzxlf","ysgpfnkxewxpunmc","qqayjdiwesfhjqdj","vvxsqmsxkwlowkaz","vhbgvteemnjcjzjn","pjvysfsrgpzeefgi","hjpqwdkuxpvojlrb","qdviqqkpfpmusqku","zekclapatdchkkuu","ushhsykosapkwfvn","qlwhigtykfafzwkf","ueeemzyxxionuzvh","uxidcslniryrlkfr","wjrqpxvnjwnzvhaw","sfufkmlseobjehmb","viqcfxqgzfgjlwyn" ,"vfffdaynlllgflud","xgbzqwuziammugee","juwviucofrqykbph","nfhofnyrvpgnrncr","xwnrmtztbduhaxzm","qwjuwencytcviddt","zgtzokhuophlklax","yhhhyqbivjulhxzz","qjlrmtnkpezzxbip","csjtxagscqzcyxgw","gibiwnkxfwmdypdb","zwuqefypxjswiqnr","rvwoomgislxnjiku","avtzjpgdqkrswwil","tybnjxlyeppveuln","hvjlkwgdbzjuthio","uwmvnynpvcrtjaoi","tazibajxbbektuny","eydtgcsqrjeudusa","cjvzwcgypecfudux","oovnezznsbbuzage","jjeciyognokzoavb","ewwzxbjfxgyrwdnz","mqtotsnaejvwsfxv","hewhemklxufjlxds","qfgrjckxuvxppffa","xrkanxmmdhjnrpms","ugszqiazpribuhin","hhtlbstnuebaovan","wmerwupitfwffwjq","cfhlftbplljrdnmt","iwgvszqjzoutyofq","rfddyjwanuajwfms","glcpwdgghxjjlbhl","opyabchjxtqeaqluw","zqrzsgsurxcablbp","tlzsuhpazrgyftra","hfbywjxrjvfyfjor","xfuisoaqkhitaneo","jbmpkilwrfevuabc","riftearjllxbsrpg","visatalbyphvpcqn","tezwyeuynxiqceny","gmllnngsknyuqfyg","jcptptnztjtczgin","sfslwzsttdrouqmi","oprcoelsndlnehzv","cfmhxjwgozohudcf","mhxzekxwbbccbumx","qeqyvhpujfgrmiop","gtqtcpovarcorjrf","aloszdzbbywgchfd","dknbhpmmjnuehczn","ebkeuntykvvfywib","nlgiglojmpbxhafl","uswobtqjlbukbjdo","deinrxindafjewms","bgkkntzoayoycmii","ibgusyotlezfhixr","jhduofjmetuvulfv","ncomoknshtsctgif","oeqgwqzgiuxzwnbo","kfqhheuvmfwtbokw","iqsoqygphhfktibu","bobacxbmnfzanumt","knnwtzpjwzujuuxw","vfnlobdgwymhcgun","gsvqncqugmzlvkcc","fqnfjzhlmmsjzvxx","isynioqvlkzdhldw","ysyenabcioynjgrzo","mgarisubmmtmxaqu","tlkplxdwjvivozqu","uumvkpkfqckauzpy","jqzzndmsdwuznmii","cqqaephdukcklkkh","arqsbqajtlzbxspv","fpwnogjkszhusmqn","arkauhwcnzyhgzgp","mmlbhlqmmpxdsjpr","hxsyiwgylwvfxvqf","fmgsmcxhczkblvrr","jfsbaiqqmrcqziyh","yonriirnykgcqqoa","loqnbxhvnqhefnzc","vnrwfrtawnjzmzpr","nwvmixbdevbawgcb","ssoscjougdkdgwzy","tdotnfxymskkechy","gdqyqjahcohateim","nmpingpzculglnzq","oshxfncaghkzfflo","brqucwymtbtbpkmg","dlbolallmawftyne","zaygaqdomkdndypz","frynwfgjeyczjiyj","fkrmnqytsxookgtf","ztsuspdffprgefji","urmvtcqxbzqlfenp","jtqnervrgeqgltma","mxazffkgorgqvasd","ohxmmsvrbcbakvtz","gvgbadnzvabrkajj","ytxszlngumxdrxgs","uyrufyweypbkrbcg","ylelxbcmvwdqlsst","fnqgyqxovwwitolz","nmrqcgovdmaregoh","jabcyxscsxpdwhduv","agyjbfjdrxsdxcbz","rsxthmvbbfsbapza","bnulsywwhvtckkmm","oetgshifgdhknjen","fdacdxgrjnfqhbgl","ltrpuqvqvaaijmix","aalhlxvddlhxsyev","qubggjexevkjzapf","qffkqkgvbxyrncum","ouebeyqrrbwluaiu","bsmvockhhfxdvwnn","wzyrusboriskzetg","qtkohvlnoxldzkhe","sknqielwtnmdozdk","hueabhcqpsziqofs","qvdcptldvpyzwbwt","gmcsgkgfgdzvdywo","whcybgsdsunkkpqd","zouenychsloywadi","ofnixothejurjqwx","baurihhbpsuzaxdz","odnxgsawwegaqqsk","avnvjxfrofflpnfl","fpeejbcasyuuirri","lnqcckixeovoabad","ogzfwbnpmoqzdxqb","lsfpkmktczfkgase","ckfkwbmenshnuzrk","puuxkxfbbtdttkec","oxplgbgxocgwayuc","tgxfplgbhcjubdtg","cpcwhsckcdfhbwmp","huaukdwwqenjsnbr","hvofxghsjlfhswhp","vnwbsvtnpfpwatiw","mcbkpsbgywhqxsix","zksceqawvnemisil","ojpmvjelrldcqflk","ppfxcvjrjywbkaci","vkkkabrzumejtwdr","jzzvegddqgtogyel","fvwxxwbukfrbazxg","rpvgsjrcsunopqja","ngjxvxsqxcboieeo","xgrdakguxugvngjr","zlixckrlsfjnvwiw","kqqahdzvaovwrarw","zeqmlrqvcymohkfc","fkdmammoniaqeaei","ktrvrgxstgvttftq","skujpfmasgqboljm","ydenwjcdlcdtodqp","hgsuqywmnwmyfotr","waufauuijgxaqceu", "gbudfydfhbvoamth","afskwqlszmvafeqm","nbsjuuyfqbhqajok","iiawyxcdikosbwsx","cwknucjbjropshgm","icqcdxpedlxpvgms","wpxzbdlhhvarycks","wkwdjgkzzrmuhuol","swsgbdcrbhqhfcci","kgmkgeiryynvhwah","cmpvksdyjvmbdfhj","uglxrzjgijfcvhbx","bgevfvpmocxgausz","uqojyggipoyuwkby","avlnovzpuzubuuss","eyghurrorndubcsm","zdnntbwcugnykdti","lchrlndexvovoznd","cpnizzfmpzinymlk","hskvkurwexwqasxt","xprysdqnfmvifwjy","ngzdbejzpatoixnp","zxomsbqlfuhemazl","iqvuegauwclhvqma","tzdgvyptuayjvktt","zvhbvljserqbcbir","mukwzypdxlegwipe","uslhhogibvwqzhyz","rylrlapnfsdogovl","impmhoqumkogchoq","zarlqxhzfwhqjsms","ymxpexvboiwzkomy","nhgexfzvunjnosgb","wslojqmvusvumclp","uufkkyrchehmokjr","uadbebqfwaewmzdk","wwzazyhamqhdwjzc","yrwrqxhvmzfeiqpa","gycblakmiqqoioke","gpyfmbzhhhtuysyf","agtyhlalmwzmpnes","jhbfquwnkzzmmrqg","xahekbixkfaidgkb","njiajqrymsbxsfyj","xrhkzoerfwjjjvyv","mojaewgjwmmxmmcj","mcimexhcqqptnotx","lshefqasobmbuxdd","srgglcluxgheudmy","cgxocmkqzjagwgmm","iyreabcwxbnkpsjoa","zaljaqjvfvvqdays","gskeygtjgbijvkjn","smpslnyxjvbhjyvh","raeaxhedueaayvlp","vbzqcqhzdaptsdts","enurfjqxyapakpyu","xesnqtvzlkjudkgx","kjwfyrasqtafiyri","bsbavcxzjuaksbld","hstmbonbgsleppae","exyhezlohmqkhxlr","rqmhckbvtfyqwsxh","wfnvwsffbdliqsll","eaqnrvadjaojgfsm","rhocxroqdqrervjn","mzdczcvbrhjwcdve","yxlrftymqxqtbvso","baunrbrfzrapqzit","oipmrdynelruxvry","khppolojdkojxwqv","umwgrzharatzdqjb","jbabfxajhdducgsw","ohtxxfqthypvhbca","knwjiwadhywkwlsz","qteikhwuuasdyvpn","ytdeibtvnlysssfj","bdcflvlghfonjfik","eactaiaqtgrhwkbn","evfodntmumnmpltz","zklhlzjiueabafnz","zrsbbgkjcseqeang","cbvthkbgywxvjkhh","gykehthvmdzklzmm","bhrydwsdwtqaxyhu","abchczaihcevacgzx","yonhiezjoqwosrwx","lpwsvvjbtimkqkaz","tibcufriphwxwzhj","kqxnnvmxdyubsyma","jdjdalrfdvtzjzzf","qzijzvthlydyayby","xsmhbxalbihmkgmr","ickheeqdhkhfvagy","zgancfyzdspdikye","rglysjgxdhtlirpe","xwmvbwnbknuynzms","rtggytyubuthyvdu","hjfqzmmiqdopyduc","yyeixxunfkstmdly","stccdhodaeauqskv","bsemgaskpcgvmcgd","todqxrxzpksoowqy","wqpfgvkppuehavdx","oecawvidnbencfzv","ocpbksbgdutggshn","hvfvfvhuwftqdtys","raqymywkbzpjsomo","mnsgyltrdguifeom","zrtwkfvmrxgmebpc","esnlddvhmlycfnzm","ujmrrippyxxaitjd","cjqopvqjmwdwrhtc","axterdjcgvvkvjmt","wsfjhyhiwcskrnzl","excxprrgtvsdstkq","bqpvnpcbqbjeorfs","zgrbyxqcahdirxzz","ibruhcuhiwpsndjo","dmningijzetvgssq","vsbnskosiigyjwhd","gvbexrsmzefdfjra","rnjdwommvluzgmiw","qfnpnioafynmfnch","iutdykdyrnjbijim","yybpzynyyvqsibqw","ukcumxubdajklbow","qpfhjabesozcqxnt","ogpjowmcxjvltaei","nmmgxxpblhyvjcza","rsdicjpuitrhjhoo","rougghrsdcuhaxkb","ccoubobkldovhdha","heeysansiaiqecsy","txyzgixqzbqoyddo","zgonqkaonzusldmu","ksvocdxauzvzaqej","tthfhimluvparxna","jrfaqfteargbowaq","vwgdxfzukfkbwmoi","kxaxverroublhnkg","hxcyocruwhxerkwv","waaywxwtrwpnwcxe","kbrwbedcrxacnfzn","heqhjudnrfmpgffr","zoninmtmgfzwfivy","nhdjsbedakglczfb","eyklkfsriufgdeta","cdtcihvzlfrxcqkk","nszlmuisqibdhuij","frfwwwunnpwouryl","bahmwsfifpehpvlm","xinovuwjryvjderk","stdxirugdjwsxdrf","ukzsodimorlbassb","dcqdmnpirlwetexz","lnkkravbrdzuaixf","iqhikikqgoabcupoz","tqqnskydlxxyeloy","hoqhujloveotexob","tafrmbzoiiyxkrpv","gedftcwddbvqbcbp","tmlvgfxezfqhqlro","omkqddentowyusgs", "uvmoywmfgcxprcob","wxaexnkxfscqpbvn","arouwkkwzmpxcraq","oshuiowfgoxvscum","wlcbjlvtpwbizxkk","pqdqfcardhablnlm","hncftotfykwkmcwc","ilbkfisyjvqmmjox","mjziuevwvgazkmrr","qxftpuleqzgeoxkn","qwfbcoulervauwzy","hzzahmyatnakmfkm","atlkeburbqttzgdv","chctjbylvaqivhnu","kljxzdlufmjsakrn","ldqznwrdmigxmplj","jnzsugujwghliiyj","davvfzptwjezrtut","ayvxlihyfxjghbnj","damnybtgbouyhgvm","xycclwykeleqgqbz","xcexkuimhauveeep","alawhglfqmrpujdu","ucqkzhnxzfmhrscm","giqfhrubpvulkbcz","ibjyvrczdfvorhxe","qbwwxgvtphqitwrc","nznctodxeivfdauc","gcelouuuaxwxmvsw","rqelrfgexnkdnazl","fbepvxtrhujvrdfc","iczbfakdstudncnv","qwyjcjokwchroxbr","ycjrzaetiivrrdkc","hjaflkntduxbssgu","rwfrleciyxwvxygj","pfkodbjvlrgvryzh","fyvawqjluonvjjxc","nzkedkvundnsfmnm","zkvlbpsldcyafkpj","hrnjhejkhdkcmnmh","sydwdkxfjjkvvbfk","ydznqbenlyrstgmu","katzotudzcpwwvkb","xucadxwemqvixtva","nnbzlmlmesntwwhh","sidmvrqryepebkda","zqlfnaleybermqpx","kduaxanohkcebsaj","jajuaudbrkkcnyyq","rhtefiqjirzhpjwt","tgbyhnyxxivxpebp","oqqwgmpqimqnjrxz","tptopmpejaaaxokz","rglhbkxoupbeqxhn","diannxikfirreuin","ilkjfpwdabcorejuk","tzygwhlicpqhsxsm","ednqyfigrhjjsixi","ichtvcqqxhzvwyrk","ckyoxfbufktqznpj","xoskspafepfgeeit","jcbtyhklimaasdfu","cfkabckzjghzapvxx","owdyarpowhkunwhy","etnyrgssgohswpva","ccdzytrxkxrfobiv","vxmwodlmkjmnanqf","lfoyuzoffzuzknom","avpouwwwczpcsixm","befuilgwreabcsjqn","wwlkjupnpinaskti","wuaufrnozwrcwrux","ddmlqscfylvvlqet","ngtehvarjqltinad","hxilufvmpbmybqse","sxckpnkpctadurmj","tkauepahazlgunce","wdnczbubbvaeugur","blbtvambkabhgfmt","hscywaqlqpzmajlw","kqbcyrflffoyrrde","swatgwoezppbhzrz","wncpezwknhwlkyfa","fxoalqugauheullc","yfejaqfwodcbvjxo","srdidycbfudekvry","wbmqrnpsbwvajyst","eojhwvsjkhruoihy","lebgsqpfytyfljzy","nlfrksicpahzoyzs","vwfuihhrcdfzahuq","zxossokxsiilrhwn","nnogzvnyavbajgxg","xudcsovkwdigfykp","oxnernpkebnwtzgk","icqcdxpedlxpvgms","xwmoythsnnalagrd","bwxqduzhwponwuxh","tvqujorvigsrzqra","ruhirwfwnudvhndi","yigakwntqrddbxel","doyelkmwfiqrcvwf","nqepgxvwmpczbqmp","euwsrbwhhaosbuxv","qybvertwzftjmsbo","ovrxezhfnplztkrf","zhsklztsgdxqqlos","hjkalxuedegqevxf","acqcmxxnvxiyiarj","irfjxvnxvcwfggyf","ivjlvhotuhyjrbqi","ybowwazfbqnlxhix","rwldwkwiuokthyvd","emeoryhhzmchkcaf","wkjtfktltlxrpodu","zozxqufosbvhvzmk","kejjywawtflpnzxq","tgjqeqqyflstgyfn","edodalhdkbpbvbbi","svvbrdqtivcocuok","jqycfyojmcojaike","uysmgvolzqhvrjcg","jepqutdjnzdxpuis","htypdjotmvugsqrn","ruanlnsslyvcmloa","rmguapshfylrqcyw","idmrozfesprjyydi","igiijxxuaewkngez","mmfbpbxhjbbtaktl","wbryhbistnsnxcre","eyypsgultocxkddt","hmgsapmnlbhkldjy","srdiuczmorzzmqmx","jydlzvjtvssbiriv","xyxlubdngtpamnie","hzxhqmvdfeelavey","dnmkfxoqikbpnncm","uvykqjhcbjrkhwws","hcouhxnefskqtsmj","tlzdfixqvzmpnxey","bqthxadcjbuoihjb","amqcryxqrquugjds","kazopbofkzigbrjf","yoazjvgcjnuynogm","cekiuyvsxvnhllot","skaakenhygficler","vyyblxbztgjdxemi","cwijfnzpasohsysb","vxshtpkflepkegsv","dqlajjejvwkljffm","pdrurythrunegiyt","wyniiprlwdxayecx","onzimmmmwsczxrud","wahjycyykcusbzkh","pmxfomqplrchaeji","cuiofjxjmfwmwjpo","mqeyxhbjjhtyiqax","vxjtwryiiaiqmgxc","rpxhygecrrxsorep","pdhcrtkvutpxkjqk","xghqzhfjrcskksay","llatzvkvpehtkmlp","evcdafiqhelayolh", "wnpjllgpnngclefg","cplkciggvoivrdrk","rwzojlohceoksqei","ibblbsqbtieahuip","rxymbuhpxlybbpwj","oufytsooclpjthdt","ladsdwyczkhlprsk","lqglakcncwvhbmdq","pvffqrafetpcnonv","ltxqocyoaqwqlclh","ujleyjgijrzxpohv","hdliszkijxjfdhuz","uerwlwcboltvibyv","frnvgotjrsmsvdrv","kprkmutaqpumileg","dyfntcyriixrbzpu","pljixloqwehtiyju","guvbkiuixwtllbyh","aywoiniduriovexc","xkhsubtnkyitnjuu","orgjwbnwirxnlvkv","tbnfpmbwrdvlcids","ljptwryckhaervnt","piklsbpqrpcwtkax","btjqiwzsjhtyrabp","xaqhoeyrofnixysd","ildloryxoleksykm","tpkrvszvlfvhpgua","uomslwptxjarrgtp","qfawaceubqhtfqia","xvsatjnexaphrcsq","chlowdcammoiqswp","vryqjuplbwlaomsw","zkndhkyqnmooseqy","oehmlodyfkbgwggc","ygicydiozmvrkjov","vffghaadldklcvpa","dudkmcpnwktzabcyc","cgpwhbxlqbydfial","xkeqyrbppiqzzdtc","aywomxmmicyapqry","qxrfswxmtgqwiaiu","ogesstqnbrqzcike","quvgbtgtjtgxrqez","ilrohxbbjzdyifwb","mwbgfsetpneteejs","awvqavqersnsgvym","lslutwvxqsgrasxf","hujsniqoktvleeph","tbibnfjtibcusfqc","jkeeyrhwuudkrzmx","rckpwpavcgvgmbqn","drzbjsuvjgfxgpzx","kmdsvposrrdokxzu","lapmakjdxbobqslx","awqhcznyrcbreinx","sgtrrbfxpgcdmlfi","hjvvuazaydvuqzfl","ukvueksttoovtqnx","fjcjtxrbzsrxelui","ynxnlswchgyljfah","ueznbslrhcswvlvg","ixvfnmhdbnowsido","tnvrbemiduyabcpgf","xicjxbvnripjquxk","pnguepiandvkkjgm","fmjuyijqtflklzrz","wowbwesqdjgbnfza","bzhqulhhfrmvlikt","xwwbxkpqwzuvbfcc","tzfeejglmxpjfiob","ttvlzzgyydwznuuj","zsaqdcbxiivqeibj","jqhivhimzrbhfjye","woxtmnynlehbynso","tweacunvvzvxvkhe","wvjiwrdllmbrzyzh","kpawpohuffukizip","culggzusblbzrbvp","rfiaujemuathqnrg","txcebmnimvozhnbq","lbpnqjkgkmqepuca","rqfueobyxicwpkao","rggegjcjqzhrkjqn","xbxlktpwwsergaut","lhowgnysedqhcquk","oqldregahyfprwsi","dizcwcthvgopgnwx","bzpodvsqzlmeakvy","vclpieckqkxhblhl","lnvngowxjpgdkwfv","yvkdxviywwowawba","zxymzgtfqsshclgz","boqkrbmnsxvbiema","hoeexawhwjrohbxe","luocnssrsnrlbmyi","tduuyggdvgbfgmhw","frvhgulszabsrunb","vcsontpzpacsgobo","kaiqymcnijuixgvp","vgfugfulxkppkurw","foudqjgejntrwhke","abldoxtbpltfnsni","kqxvgbgkkoakfeaj","rdkjzlwcpygzkshq","qfjxzlkyrpmuvlrf","depydkicbtuwrbuf","vmpfhqfgcyreyqdl","oneokdfkplafayzn","fjcerifwgajithlr","gtlxawvwmlmqsuuu","wgfxdchxqlzdxcpr","ajdrspwucswacivi","wjzhtgddolhaahmo","hbyrafvgohzefptw","roxblqysntdnkfqx","rmvrjdkeppblcmvy","xzgbkvnyxljluccp","dvvwfjxmydfdzqyt","kxxjltlgbaiguihx","rahukefeaibeekpq","spsdfgpofpoanurm","pjmewktbcytjsvrs","nhtbcrwqzoxbhkyi","eanjdepcqzqdeoea","ujhvaizclocaksng","tkucqzszyktwvyjq","dnummodkocgrdhbx","bzvvgfxvgzqjshji","ddctbuygjncstchf","mrpciqjmowzdjvsm","qhdgxhopljagfbfi","ksnimciprjexohfu","sdfgsfcwgaknzrqt","keiywmjuavometzf","pxdzshicopwmofxl","xdwlukdaxhwjojeq","krnlgjtxhnuntwsa","bpnrhdwfkagaubka","beoyleogpryyjcmv","rrhlmtgpyfszchsi","ozdknlljectjisdg","wdobdazbwjecqcep","jfxjpbzonkvxltib","fwcffctkbvpkgexm","gornbkdvwuqirrlk","yyiqngwrxevbwchf","ggyqhxvbjwyzuxwf","ixhwkhgotdmkamtj","dbqqdygrhtysgxgw","mzwmkjfknwfhulgv","xtngfkkjuaonbemi","vghhkblxwbijsqwi","fkfulljgmpkmvxwn","kqdckewxfcwyjkuo","msaxmgcjerovxgqo","bswhhcxiljhjeivr","lwllrzomgnjzjqxh","gugxbiwfpjbtscyw","mmqsxwrnsiprrmyv","pdjccwbewqxbhgzn","mshemwgzytwmqljx","moezekitiafkvsqr","edthrvvafeypjypw" ,"qspowcqalsukqhhy","wasrmlhgjgalcbrb","dglyfamnfpqkmteh","xgpvsclrqskbjnao","iawgyqoqnmxmwtrk"]) s = calc([num1, num2, num3])
# okay decompiling xasm_bytecode.pyc
恢复结果跟官方的出题源码(https://hust-l3hsec.feishu.cn/docx/MZ8SdwSoPo3cBTxOxbGcuUBun4c#CHFYdpr8roKZzcxfBdGc2HdtnBZ)相比已经很相似了,除了原代码中被删除的flag相关的常量赋值外近乎一摸一样。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/170129
 
163 次点击