def get_result(self, audio_path): def softmax(x): e_x = np.exp(x - np.max(x)) return e_x / e_x.sum(axis=0) print('Generate side channel...') y_s = utils.get_side(audio_path) print('Rendering spectrum...') utils.get_spectrum(y_s, 0, 'temp', max=20) spectrum_list = utils.get_file_list('temp') print('Valid samples...') fin = np.zeros(4) for i_idx in range(len(spectrum_list)): norm_img = self.img_preprocess(spectrum_list[i_idx]) result = self.session.run([], {self.model_input: norm_img})[0][0] result = softmax(result) fin[np.argmax(result)] += 1 print( f'Sample {i_idx+1} -> {self.r_map[np.argmax(result)]}, Prob:{np.max(result)*100:.3f}%' ) if fin[0] != len(spectrum_list): fin[0] = 0 print(f'Final result: {self.r_map[np.argmax(fin)]}') else: print('Final result: Lossless')
def __split_bc_into_lines(self, codes: list, lnotab: list): #PASS 2019/7/4 ''' code : 字节码对 lnotab : co_lnotab 字段 !!! 暂不支持出现单行增量大于 255 的行号表 ''' tab = list(lnotab[2:]) #去除第一个偏移增量对(起始行) tab = utils.get_side(utils.to_pairs(tab)) #将行号表结成对取一边 tab.append(len(codes) * 2 - sum(tab)) #增加最后一行的偏移增量 tl = [] #总字节码序列 ttl = [] #总序列中的子序列 ofsi = tp = 0 #ofsi : 偏移增量 tp : 增量表的指针 for cp in codes + [None]: #加一个None, 防止越界 if ofsi == tab[tp]: tl.append(ttl.copy()) ttl = [] tp += 1 #得到一行, 指针右移 ofsi = 0 #将偏移增量设置为0 ttl.append(cp) ofsi += 2 #将偏移增量增加 2 个 '字节' (一个PyByteCode占一个字节) return tl
def is_def_attr(self, codes: list): ''' codes: 字节码对 ''' scodes = utils.get_side(codes) if opmap['STORE_ATTR'] in scodes and opmap["SETUP_LOOP"] not in scodes: return True return False
def is_store_subscr_expr(self, code: list): ''' codes: 字节码对 ''' scodes = utils.get_side(code) if opmap['STORE_SUBSCR'] in scodes: return True return False
def is_import_expr(self, code: list): ''' codes: 字节码对 ''' scodes = utils.get_side(code) if opmap['IMPORT_NAME'] in scodes: return True return False
def is_def_var(self, codes: list): ''' codes: 字节码对 ''' codes = utils.get_side(codes) if (opmap['STORE_NAME'] in codes or opmap['STORE_FAST'] in codes) \ and opmap['IMPORT_NAME'] not in codes and opmap["SETUP_LOOP"] not in codes: return True return False
def is_return_expr(self, codes: list): ''' codes: 字节码对 ''' scodes = utils.get_side(codes) if codes[-2:] == [(100, 0), (83, 0)] and len(codes) > 2: #为了排除隐式 return return False if scodes[-1] != opmap['RETURN_VALUE']: #return 语句的 RETURN_VALUE 在最后 return False return True
def is_assert_expr(self, codes: list): ''' codes: 字节码对 ''' #accert 无论如何都会压入一个AssertionError对象 scodes = utils.get_side(codes) if opmap['LOAD_GLOBAL'] in scodes: tc = scodes[::-1] #翻转,寻找最靠后的LOAD_GLOBAL ei = tc.index(opmap['LOAD_GLOBAL']) #寻找最靠后的LOAD_GLOBAL的地址 ti = codes[::-1][ei][1] #颠倒字节码对数组,寻找目标字节码对,取出参数 if self.__load_name(ti) == 'AssertionError': return True return False
def is_if_expr(self, codes: list): ''' codes: 字节码对 !!!暂不支持单行 if 语句 ''' #fest = self.__find_jump_fastest(codes) #寻找最远的偏移量 ''' python 的 and or 表达式经过了很好的优化,但是,对于反编译来说,这是个噩梦!!! 我甚至用了2天的时间来找python对于and or语句的规律,例如整个表达式的结束。 但值得我欣慰的是,它只是一个表达式!!!! ''' scodes = utils.get_side(codes) if opname[scodes[-1]] in ('POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE'): #如果最后是 POP_JUMP_IF_FALSE 或 POP_JUMP_IF_TRUE,就判断是 if 语句 return True return False
def __find_jump_fastest(self, codes: list): ''' 寻找在 POP_JUMP 中跳得最远的偏移量 codes : 需要用来判断的字节码对 ''' scodes = utils.get_side(codes) cp = 0 #字节码对指针 fest = 0 #最远的偏移量 for c in scodes: if opname[c] in ('POP_JUMP_IF_TRUE', 'POP_JUMP_IF_FALSE', 'JUMP_IF_TRUE_OR_POP', 'JUMP_IF_FALSE_OR_POP'): if codes[cp][1] > fest: #如果现偏移量大于原偏移量 fest = codes[cp][1] cp += 1 if fest <= 0: raise error.DecomplierError('The jump target can not be 0') return fest
def __make_line(self, codes: list): ''' codes : 所有已经分行的字节码对 将反编译出来的行写入文件 ''' ln_index = 0 #行号索引 for ln in codes: #codes: 整个已分行co_code, ln : 每行 if self.__reco.is_return_expr(ln): #如果是 return expr beh = 'return {0}' #开始处理 POP_TOP 以下, RETURN_VALUE 以上的字节码 if opmap['POP_TOP'] in utils.get_side(ln): #寻找行里是否有POP_TOP lln = ln[::-1] #将该字节码颠倒,开始寻找最靠后的POP_TOP pti = lln.index(opmap['POP_TOP']) #寻找最靠后的一个 POP_TOP lln = lln[1:pti - 1][::-1] #得到RETURN_VALUE ~ POP_TOP之间的字节码,并翻转 else: #一般来说,如果没有POP_TOP, 那么这个return表达式就是独立的 lln = ln[:-1] expr = self.__make_expr(lln) #生成return之后的表达式 self.__add_line(beh.format(expr)) #将结果添加到源码文件 elif self.__reco.is_assert_expr(ln): beh = 'assert {0}' hsn = False #如果assert后面出现了not #开始处理 LOAD_GLOBAL 以上的字节码对 sc = utils.get_side(ln)[::-1] #取出一边,并颠倒 try: ci = sc.index(opmap['POP_JUMP_IF_TRUE']) #如果assert后面出现not,则应该是POP_JUMP_IF_FALSE except ValueError: hsn = True ci = ci = sc.index(opmap['POP_JUMP_IF_FALSE']) ci += 1 #不包括POP_JUMP_IF_XXXX 指令 cs = ln[::-1][ci:][::-1] #截取 POP_JUMP_IF_FALSE 以上的字节码对 cond = self.__make_expr(cs) #取得表达式 self.__add_line(beh.format(('not ' if hsn else '') + cond)) #将结果添加至源码行中,如果hsn,则将'not '加入 elif self.__reco.is_def_var(ln): isf = False #如果是STORE_FAST beh = '{0} = {1}' #处理STORE_XXX以上的字节码 rc = utils.get_side(ln) #取出一边 try: ci = rc.index(opmap['STORE_NAME']) #找到STORE_NAME的位置 except ValueError: #当是STORE_FAST的时候 isf = True ci = rc.index(opmap['STORE_FAST']) #找到STORE_FAST的位置 exprcs = ln[:ci] #截取STORE_XXX以上的字节码 expr = self.__make_expr(exprcs) #生成表达式 argv = ln[ci][1] #得到 STORE_XXX 的参数 if not isf: name = self.__load_name(argv) #根据参数,得到变量名 else: name = self.__load_fast(argv) #根据参数,得到变量名 self.__add_line(beh.format(name, expr)) elif self.__reco.is_def_attr(ln): #处理LOAD_NAME/LOAD_FAST,STORE_ATTR之间的字节码 beh = '{0}.{1} = {2}' scs = utils.get_side(ln)[::-1] #取一边,并颠倒 si = scs.index(opmap['STORE_ATTR']) loni = lofi = logi = 0xffffffff #先设置得很大,然后再比较那个小 #因为是取最小值,而且也不能保证LOAD三家族都存在 try: loni = scs.index(opmap['LOAD_NAME']) #寻找最近的LOAD_NAME except: pass try: lofi = scs.index(opmap['LOAD_FAST']) #寻找最近的LOAD_FAST except: pass try: logi = scs.index(opmap['LOAD_GLOBAL']) #寻找最近的LOAD_FAST except: pass #比较loni 和 lofi的大小,取最小,因为当LOAD_NAME/LOAD_FAST没有时,不代表没有LOAD_FAST/LOAD_NAME loi = min(logi, lofi, loni) pexprc = ln[::-1][ si + 1:loi + 1][::-1] #截取LOAD_NAME/LOAD_FAST以下STORE_ATTR以上的字节码,并回正 pexpr = self.__make_expr(pexprc) #接着,再将loi以上的字节码截取,作为属性值 vexprc = ln[::-1][loi + 1:][::-1] #截取loi以上的字节码 vexpr = self.__make_expr(vexprc) pname = self.__load_name(ln[::-1][si][1]) #获取属性名称 self.__add_line(beh.format(pexpr, pname, vexpr)) elif self.__reco.is_import_expr(ln): behn = 'import {0}' #简单import behf = 'from {0} import {1}' #from import has = False #是否拥有as hsf = False #是否是from import isfast = False #如果是LOAD_FAST ''' as 其实不用省略,因为 import os => import os as os 但是为了人性化,还是选择省略 ''' #处理 STORE_NAME 以上的字节码 sln = utils.get_side(ln)[::-1] try: ci = sln.index(opmap['STORE_FAST']) #如果是在函数/方法里面import except ValueError: ci = sln.index(opmap['STORE_NAME']) #在global域import cs = ln[::-1][ci + 1:][::-1] #截取ci以上的字节码,然后回正 scs = utils.get_side(cs) #开始处理ci以上的字节码 if opmap['IMPORT_STAR'] in scs: #如果是from xx import * #尽管 from xx import * 不允许出现在函数中 imp_ni = scs.index(opmap['IMPORT_NAME']) imp_name = self.__load_name(ln[imp_ni][1]) self.__add_line(behf.format(imp_name, '*')) elif opmap['IMPORT_FROM'] in scs: #如果是 from xx import xx的样式 #最开头的IMPORT_FROM是from的位置 fi = scs.index(opmap['IMPORT_NAME']) imp_pos = self.__load_name(ln[fi][1]) #from的位置 imp_nbr = self.__load_const( ln[fi - 1][1]) #再往前就是import的内容,应该是一个元祖 imp_nbn = len( imp_nbr ) * 2 #元祖的长度*2为下面 IMPORT_NAME STORE_NAME 的数量,用于生成 __ as __ imp_nbrl = ln[fi + 1:fi + imp_nbn + 1] #得到import的成员和其别名(as xxx) imp_ol = [ self.__load_name(op[1]) for op in imp_nbrl if op[0] == 109 ] #原成员名字 imp_nl = [ self.__load_fast(op[1]) for op in imp_nbrl if op[0] in [125, 90] ] #现成员名字 if len(imp_ol) != len(imp_nl): raise error.DecomplierError( 'len(imp_ol) != len(imp_nl)!\nimp_ol:' + str(imp_ol) + '\nimp_nl:' + str(imp_nl)) onp = utils.merge(imp_ol, imp_nl) ons = [ '{0}{1}'.format(o, (f' as {n}' if o != n else '')) for o, n in onp ] #生成的 xx as xx列表 如果o, n同名,则取o self.__add_line(behf.format(imp_pos, ', '.join(ons))) else: ci = scs.index(opmap['IMPORT_NAME']) #获取最开头的IMPORT_NAME位置 imp_n = self.__load_name(ln[ci][1]) #获取import名称 imp_as = self.__load_name(ln[ci + 1][1]) #import对象的as名称 if imp_n != imp_as: #如果导入对象原名称不等于现名称 self.__add_line(behn.format(imp_n + ' as ' + imp_as)) #将as加在后面 return self.__add_line(behn.format(imp_n)) #不加as elif self.__reco.is_store_subscr_expr(ln): beh = '{0}[{1}] = {2}' scs = utils.get_side(ln) si = scs.index(opmap['STORE_SUBSCR']) #得到STORE_SUBSCR的位置 vli = [] #用于生成索引的表达式 sv = { opmap['LOAD_NAME']: lambda i: self.__load_name(i), opmap['LOAD_GLOBAL']: lambda i: self.__load_name(i), opmap['LOAD_FAST']: lambda i: self.__load_fast(i), }.get( scs[si - 1], lambda i: error.DecomplierError( 'Un know opcode:{0}'.format(opname[scs[si - 1]])))( ln[si][1]) #根据字节码类型,得到对应解决方案 else: #单独表达式 expr = self.__make_expr(ln) self.__add_line(expr) ln_index += 1
def do(src_path, dst_path, idx, noise=True): y_s = utils.get_side(src_path) if noise: utils.get_spectrum(y_s, idx, dst_path, noise=[0.001, 0.01]) else: utils.get_spectrum(y_s, idx, dst_path)