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

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所需的输入格式如下:

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

这些信息也是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的输出如下:

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

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

信息提取

Constants、Names和Varnames

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

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

不过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的其他参数默认元组。

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

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

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

如下是一个关键字参数的函数示例:
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

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

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

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

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

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时会以元组的形式列出:

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

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

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

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:

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

但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
然后手动生成:

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

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

例题

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

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

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

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

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

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

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

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

恢复结果:
# 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的dis反汇编提取代码对象部分信息

版权声明:admin 发表于 2024年5月15日 下午12:29。
转载请注明:利用Python的dis反汇编提取代码对象部分信息 | CTF导航

相关文章