def show_risk_code(self, level): result = Color.red('===== Risk Codes =====\n') for k, v in RISKS.items(): if v['lvl'] < level: continue kflag = True for sf in self.smali_dir: for mtd in sf.get_methods(): mflag = True lines = re.split(r'\n\s*', mtd.get_body()) for idx, line in enumerate(lines): for ptn in v['code']: if re.search(ptn, line): if kflag: result += Color.magenta('---' + k + '---\n') kflag = False if mflag: result += Color.green(' ' + str(mtd)) + '\n' mflag = False result += ' ' * 3 + str(idx) + line + '\n' break return result
def _process_mtd(self, mtd, ptn): # if get_value('DEBUG_MODE'): print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 arg_pos, cname, mname, rtn_name = item.groups() cname = cname[1:].replace('/', '.') # 通过参数位置获取参数值 rex = arg_pos + '\s*.array-data 1([\w\W\s]+?).end array-data' ptn_arr = re.compile(rex, re.MULTILINE) bjson = [] for it in ptn_arr.finditer(body): arr = it.groups() for i in arr[0].split("\n"): i = i.strip() if i == "": continue bjson.append(int(i.replace('t', ''), 16)) arguments = ['[B:' + str(bjson)] print(Color.green(cname) + " " + str(arguments)) json_item = self.get_json_item(cname, mname, arguments) self.append_json_item(json_item, mtd, old_content, rtn_name)
def test_keep_tags(): """Test keep_tags keyword arg.""" assert_both = partial(assert_both_values, kind="Color color") instance = Color("{red}Test{/red}", keep_tags=True) assert_both(instance, "{red}Test{/red}", "{red}Test{/red}") assert_both(instance.upper(), "{RED}TEST{/RED}", "{RED}TEST{/RED}") assert len(instance) == 15 instance = Color("{red}\033[41mTest\033[49m{/red}", keep_tags=True) assert_both(instance, "{red}Test{/red}", "{red}\033[41mTest\033[49m{/red}") assert_both(instance.upper(), "{RED}TEST{/RED}", "{RED}\033[41mTEST\033[49m{/RED}") assert len(instance) == 15
def _process_mtd(self, mtd, ptn): if DEBUG_MODE: print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 # arg: 解密参数 # cname:解密类 # mname:解密方法 # rtn_name:最后返回的字符串寄存器,new String的寄存器名字 arg, cname, mname, rtn_name = item.groups() # 转化解密参数 arguments = [self.convert_args('Ljava/lang/String;', arg)] import smafile cname = smafile.smali2java(cname) json_item = self.get_json_item(cname, mname, arguments) mid = json_item['id'] self.append_json_item(json_item, mtd, old_content, rtn_name) if mid in self.results: # 如果同样的ID存在,那么无需解密 continue self.decode(mid)
def process_item(item): text = '' perm = item.get('@android:permission', '') if '_DEVICE' not in perm: return text if pflag: text += Color.red('===== Risk Permissions =====\n') text += perm + item.get('@android:name') + '\n'
def show_risk_perm(self): result = '' if not self.apk.get_manifest(): return result risk_perms = [ '_SMS', '_CALL', '_DEVICE_ADMIN', '_AUDIO', '_CONTACTS' ] ps = set() pflag = True for item in self.apk.get_manifest().get('uses-permission', []): for perm in risk_perms: if perm not in item.get('@android:name'): continue if pflag: result += Color.red('===== Risk Permissions =====\n') pflag = False name = item.get('@android:name') if name in ps: continue result += name + '\n' ps.add(name) app = self.apk.get_manifest().get('application') recs = app.get('receiver') def process_item(item): text = '' perm = item.get('@android:permission', '') if '_DEVICE' not in perm: return text if pflag: text += Color.red('===== Risk Permissions =====\n') text += perm + item.get('@android:name') + '\n' if isinstance(recs, dict): text = process_item(item) if text: result += text pflag = False elif isinstance(recs, list): for item in recs: text = process_item(item) if text: result += text pflag = False break if not pflag: result += '\n' return result
def _process_mtd(self, mtd, ptn): if DEBUG_MODE: print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() # TODO 优化,根据每列来匹配 # 执行之前,没有返回值,赋值等操作的语句,执行,其他都不执行。 for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 # print(old_content) # args: 解密参数 # cname:解密类 # mname:解密方法 # rtn_name:最后返回的字符串寄存器,new String的寄存器名字 part, args, cname, mname, rtn_name = item.groups() snippet = part.split('\n') tmp = [] for item in snippet: if not item: continue if ':try_start' in item: # print(old_content) old_content = old_content.split(item) # print(old_content) tmp.clear() tmp.append(item.strip()) # print(old_content) # print(tmp) # 模拟执行代码片段 # continue self.emu.call(tmp, args=self.global_variables, cv=True, thrown=True) # 转化解密参数 ans = self.argument_names(args) v1 = self.emu.vm.variables.get(ans[0], None) v2 = self.emu.vm.variables.get(ans[1], None) v3 = self.emu.vm.variables.get(ans[2], None) if v1 is None or v2 is None or v3 is None: continue arguments = [self.convert_args('S', v1), self.convert_args('I', v2), self.convert_args('S', v3)] import smafile cname = smafile.smali2java(cname) json_item = self.get_json_item(cname, mname, arguments) mid = json_item['id'] if mid in self.results: # 如果同样的ID存在,那么无需解密 continue self.append_json_item(json_item, mtd, old_content, rtn_name) self.decode(mid)
def proccess(self): for sf in self.smalidir: for mtd in sf.get_methods(): if 'Lcom/cmcc/papp/a/a;->b(Context, String)V' not in str(mtd): continue if DEBUG: from colorclass.color import Color print() print(Color.red(str(mtd))) self._process_mtd(mtd) self.optimize() self.clear()
def _process_mtd(self, mtd, ptn): if DEBUG_MODE: print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 print(old_content) # args: 解密参数 # cname:解密类 # mname:解密方法 # rtn_name:最后返回的字符串寄存器,new String的寄存器名字 part, args, cname, mname, rtn_name = item.groups() snippet = part.split('\n\n') # TODO 自动初始化,静态变量,静态数组等等。后续用于片段计算,用到。 # TODO 模拟执行代码片段 self.emu.call(snippet, args={'Lo/r/g/ন$Ⅱ;->ᖬ:I': 0}, cv=True, thrown=True) # 转化解密参数 ans = self.argument_names(args) v1 = self.emu.vm.variables.get(ans[0], None) v2 = self.emu.vm.variables.get(ans[1], None) v3 = self.emu.vm.variables.get(ans[2], None) if v1 is None or v2 is None or v3 is None: continue arguments = [ self.convert_args('I', v1), self.convert_args('I', v2), self.convert_args('I', v3) ] import smafile cname = smafile.smali2java(cname) json_item = self.get_json_item(cname, mname, arguments) mid = json_item['id'] self.append_json_item(json_item, mtd, old_content, rtn_name) if mid in self.results: # 如果同样的ID存在,那么无需解密 self.json_list.clear() continue self.decode(mid)
def process_perm_item(item): for perm in risk_perms: if perm not in item.get('@android:name'): continue if pflag: result += Color.red('===== Risk Permissions =====\n') pflag = False name = item.get('@android:name') if name in ps: continue result += name + '\n' ps.add(name)
def _process_mtd(self, mtd, ptn): if get_value('DEBUG_MODE'): print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 arg, cname, mname, rtn_name = item.groups() arguments = ['java.lang.String:' + arg] json_item = self.get_json_item(cname, mname, arguments) self.append_json_item(json_item, mtd, old_content, rtn_name)
def _process_mtd(self, mtd, ptn): if get_value('DEBUG_MODE'): print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) body = mtd.get_body() for item in ptn.finditer(body): old_content = item.group() # 匹配到的内容,用来替换 # base解密的字符串,base64解密 # 得到结果再次解密, # rtn_name:最后返回的字符串寄存器,new String的寄存器名字 arg, cname, mname, rtn_name = item.groups() # base64解密 arguments = [self.convert_args('Ljava/lang/String;', arg), 'I:2'] json_item = self.get_json_item('android.util.Base64', 'decode', arguments) mid = json_item['id'] self.append_json_item(json_item, mtd, old_content, rtn_name) arg0 = None if mid not in self.results: # 如果同样的ID存在,那么无需解密 self.decode(mid) arg0 = self.results[mid] old_mid = mid # arg1 = 'fmsd1234' # 这个是一个固定值 # 解密得到的结果 # 进行第二次解密 import smafile cname = smafile.smali2java(cname) arguments = ['[B:' + arg0, 'java.lang.String:fmsd1234'] # print(cname, mname, arguments) json_item = self.get_json_item(cname, mname, arguments) mid = json_item['id'] self.append_json_item(json_item, mtd, old_content, rtn_name) if mid in self.results: self.json_list.clear() continue self.decode(mid) x = self.results[mid] try: result = bytes(eval(x)).decode('utf-8') self.results[old_mid] = result print(result) except Exception as e: print(result, e)
def print_matches(key_path, match_dict): ''' example matches dict [{ 'tags': ['foo', 'bar'], 'matches': True, 'namespace': 'default', 'rule': 'my_rule', 'meta': {}, 'strings': [(81L, '$a', 'abc'), (141L, '$b', 'def')] }] ''' print(Color.green("[*] {}".format(key_path))) for tags in sorted(match_dict): values = ', '.join(sorted(match_dict[tags])) print(" |-> {} : {}".format(tags, values))
def __process(self): for sf in self.smalidir: for mtd in sf.get_methods(): if DEBUG_MODE: print(mtd) # if 'com/android/internal/wrapper/NativeWrapper;->' not in str(mtd): # continue # if 'eMPGsXR()Ljava/lang/Class;' not in str(mtd): # continue if DEBUG_MODE: print(Color.red(mtd)) if self.skip_mtd(mtd): continue self._process_mtd(mtd) # 强制更新 for sf in self.smalidir: sf.update()
def show_risk_children(self, flag=False): result = '' pflag = True self.apk.get_files().sort(key=lambda k: (k.get('type'), k.get('name'))) for item in self.apk.get_files(): if flag: print(item.get('type'), item.get('name')) continue if item.get('type') not in ['dex', 'apk', 'elf']: continue if pflag: result = Color.red('\n===== Risk Files =====\n') pflag = False result += item.get('type') + ' ' + item.get('name') + '\n' return result
def test_keep_tags(): """Test keep_tags keyword arg.""" assert_both = partial(assert_both_values, kind='Color color') instance = Color('{red}Test{/red}', keep_tags=True) assert_both(instance, '{red}Test{/red}', '{red}Test{/red}') assert_both(instance.upper(), '{RED}TEST{/RED}', '{RED}TEST{/RED}') assert len(instance) == 15 instance = Color('{red}\033[41mTest\033[49m{/red}', keep_tags=True) assert_both(instance, '{red}Test{/red}', '{red}\033[41mTest\033[49m{/red}') assert_both(instance.upper(), '{RED}TEST{/RED}', '{RED}\033[41mTEST\033[49m{/RED}') assert len(instance) == 15
def _process_mtd(self, mtd): if DEBUG: from colorclass.color import Color print('\n', '+' * 100) print('Starting to decode ...') print(Color.green(mtd)) # 如果存在数组 array_data_content = [] arr_res = self.arr_data_ptn.search(mtd.get_body()) if arr_res: array_data_content = re.split(r'\n\s', arr_res.group()) lines = re.split(r'\n\s*', mtd.get_body()) old_body = lines.copy() # 存放原始方法体 new_body = [] # 存放解密后的方法体 snippet = [] # 存放smali代码,用于模拟执行 args = {} # 存放方法参数,用于smaliemu执行 index = -1 # 用于计数 for line in lines: snippet.append(line) new_body.append(line) # 解密结果,直接放后面即可 index += 1 if 'invoke-' not in line and 'iget-' not in line: continue from smafile import SmaliLine # 函数有两种类型: # 1. 字符串内置类型 - smaliemu能直接执行 # 2. 其他类型 - 需要发射调用 if DEBUG: print('LINE:', Color.red(line)) if 'Ljava/lang/String;->' in line: if '<init>' not in line: continue if DEBUG: print(Color('{autoyellow}process new string...{/yellow} ')) # 如果是字符串函数,参数为[B/[C/[I,则考虑 rtn_name, rnames = SmaliLine.parse_string(line) if not rnames: continue # 直接执行emu解密 try: ll = args[rnames[1]] # print(ll) except KeyError: continue if not isinstance(ll, list): continue no_str = False for i in ll: if i < 0: no_str = True break if no_str: continue result = ''.join(chr(x) for x in ll) if DEBUG: print(result) # 更新寄存器 args[rtn_name] = result # 更新代码 new_line = 'const-string {}, "{}"'.format(rtn_name, result) new_body = new_body[:-1] new_body.append(new_line) self.make_changes = True mtd.set_modified(True) continue elif 'invoke-static' in line: # 获取函数相关信息 cname, mname, ptypes, rtype, rnames = SmaliLine.parse_invoke_static( line) if cname in ['Ljava/lang/reflect/Method;']: print(cname, 'will skip') continue # 返回值不能其他引用类型 if rtype[0] == 'L' and rtype != 'Ljava/lang/String;': continue if rtype in ['V', 'Z']: continue flagx = False for i in [ 'Landroid/content/Context;', 'Landroid/app/Activity;' ]: if i in ptypes: flagx = True break if flagx: continue elif 'iget-object' in line: # iget-object v3, p0, Lcom/fmsd/a/d;->q:Ljava/lang/String; # 这种情况,需要直接通过反射获取 # clz_name, field_name, rname = cname, fname, rtype, rname = SmaliLine.parse_iget_object(line) if rtype != 'Ljava/lang/String;': continue self.json_list = {'type': 'field', 'data': []} json_item = {'className': cname, 'fieldName': [fname]} # print(json_item) self.json_list['data'].append(json_item) result = self.get_field_value() if not result: continue value = result[fname] args[rname] = value continue else: continue # print('>', cname) # print('>', mname) # print('>', ptypes) # print('>', rnames) # print(">", 'return Type:', rtype) # 参数名(寄存器的名),类名,方法名,proto(简称) # register_name, class_name, mtd_name, ptypescc # ('v1, v2, v3', 'Lcom/game/pay/sdk/y', 'a', 'ISB') # 解密参数的寄存器名 # 初始化所有寄存器 del snippet[-1] snippet.extend(array_data_content) try: args.update(self.pre_process(snippet)) except TIMEOUT_EXCEPTION: pass try: # for lx in snippet: # print(lx) self.emu.call(snippet, args=args, cv=True, thrown=False) registers = self.emu.vm.variables # registers = self.get_vm_variables(snippet, args, rnames) # print('smali执行后,寄存器内容', registers) # args = registers if registers else args if registers: for k, v in registers.items(): if v is None: continue args[k] = v registers = args except TIMEOUT_EXCEPTION: snippet.clear() continue # print('更新寄存器内容', args) # if not registers: # registers = args obj_flag = False if len(ptypes) == 1 and ptypes[0][0] == 'L' and ptypes != [ 'Ljava/lang/String;' ]: # 单独处理参数为对象的情况 obj_flag = True # 已经执行过的代码,不再执行 snippet.clear() if not registers and not obj_flag: continue # print('----->>>>>>>>>>') # 从寄存器中获取对应的参数 # 参数获取 "arguments": ["I:198", "I:115", "I:26"]} arguments = [] # args = {} # the parameter of smali method if not obj_flag: ridx = -1 for item in ptypes: ridx += 1 rname = rnames[ridx] if rname not in registers: break value = registers[rnames[ridx]] argument = self.convert_args(item, value) if argument is None: break arguments.append(argument) else: arguments.append('Object:' + self.smali2java(ptypes[0])) # print('参数类型', ptypes) # print('参数值', arguments) if len(arguments) != len(ptypes): continue json_item = self.get_json_item(cname, mname, arguments) # print('生成json item') # {id}_{rtn_name} 让这个唯一化,便于替换 old_content = '# %s' % json_item['id'] # 如果 move_result_obj 操作存在的话,解密后一起替换 find = self.move_result_obj_ptn.search(lines[index + 1]) # 必须要找到返回值操作,用于更新寄存器 if not find: # print('找不到返回寄存器') continue rtn_name = find.groups()[0] # 为了避免 '# abc_v10' 替换成 '# abc_v1' old_content = old_content + '_' + rtn_name + 'X' self.append_json_item(json_item, mtd, old_content, rtn_name) # print(json_item) result = self.get_result(rtype) # print("解密结果", result) self.json_list.clear() if result: new_body = new_body[:-1] else: continue if not args: args = {} if rtype == 'Ljava/lang/String;': result = list(result.values())[0][0] # 更新寄存器 args[rtn_name] = result # 更新代码 new_line = 'const-string {}, "{}"'.format(rtn_name, result) new_body.append(new_line) self.make_changes = True # print(args) mtd.set_modified(True) elif rtype.startswith('['): # print("返回值为数组,更新寄存器内容") # print(result) args[rtn_name] = result # print(args) else: print("返回值并非字符串,也不是B/C数组") # print('-' * 100) mtd.set_body('\n'.join(new_body))
def test_windows_stream(): """Test class.""" # Test error. if windows.IS_WINDOWS: stream = windows.WindowsStream(windows.init_kernel32()[0], windows.INVALID_HANDLE_VALUE, StringIO()) assert stream.colors == (windows.WINDOWS_CODES['white'], windows.WINDOWS_CODES['black']) stream.colors = windows.WINDOWS_CODES['red'] | windows.WINDOWS_CODES[ 'bgblue'] # No exception, just ignore. assert stream.colors == (windows.WINDOWS_CODES['white'], windows.WINDOWS_CODES['black']) # Test __getattr__() and color resetting. original_stream = StringIO() stream = windows.WindowsStream(MockKernel32(), windows.INVALID_HANDLE_VALUE, original_stream) assert stream.writelines == original_stream.writelines # Test __getattr__(). assert stream.colors == (windows.WINDOWS_CODES['white'], windows.WINDOWS_CODES['black']) stream.colors = windows.WINDOWS_CODES['red'] | windows.WINDOWS_CODES[ 'bgblue'] assert stream.colors == (windows.WINDOWS_CODES['red'], windows.WINDOWS_CODES['bgblue']) stream.colors = None # Resets colors to original. assert stream.colors == (windows.WINDOWS_CODES['white'], windows.WINDOWS_CODES['black']) # Test special negative codes. stream.colors = windows.WINDOWS_CODES['red'] | windows.WINDOWS_CODES[ 'bgblue'] stream.colors = windows.WINDOWS_CODES['/fg'] assert stream.colors == (windows.WINDOWS_CODES['white'], windows.WINDOWS_CODES['bgblue']) stream.colors = windows.WINDOWS_CODES['red'] | windows.WINDOWS_CODES[ 'bgblue'] stream.colors = windows.WINDOWS_CODES['/bg'] assert stream.colors == (windows.WINDOWS_CODES['red'], windows.WINDOWS_CODES['black']) stream.colors = windows.WINDOWS_CODES['red'] | windows.WINDOWS_CODES[ 'bgblue'] stream.colors = windows.WINDOWS_CODES['bgblack'] assert stream.colors == (windows.WINDOWS_CODES['red'], windows.WINDOWS_CODES['black']) # Test write. stream.write(Color('{/all}A{red}B{bgblue}C')) original_stream.seek(0) assert original_stream.read() == 'ABC' assert stream.colors == (windows.WINDOWS_CODES['red'], windows.WINDOWS_CODES['bgblue']) # Test ignore invalid code. original_stream.seek(0) original_stream.truncate() stream.write('\x1b[0mA\x1b[31mB\x1b[44;999mC') original_stream.seek(0) assert original_stream.read() == 'ABC' assert stream.colors == (windows.WINDOWS_CODES['red'], windows.WINDOWS_CODES['bgblue'])
Example usage: echo "{red}Red{/red}" |python -m colorclass """ from __future__ import print_function import fileinput import os from colorclass.color import Color from colorclass.toggles import disable_all_colors from colorclass.toggles import enable_all_colors from colorclass.toggles import set_dark_background from colorclass.toggles import set_light_background from colorclass.windows import Windows TRUTHY = ('true', '1', 'yes', 'on') if __name__ == '__main__': if os.environ.get('COLOR_ENABLE', '').lower() in TRUTHY: enable_all_colors() elif os.environ.get('COLOR_DISABLE', '').lower() in TRUTHY: disable_all_colors() if os.environ.get('COLOR_LIGHT', '').lower() in TRUTHY: set_light_background() elif os.environ.get('COLOR_DARK', '').lower() in TRUTHY: set_dark_background() Windows.enable() for LINE in fileinput.input(): print(Color(LINE))
def test_colorize_methods(): """Test colorize convenience methods.""" assert Color.black('TEST').value_colors == '\033[30mTEST\033[39m' assert Color.bgblack('TEST').value_colors == '\033[40mTEST\033[49m' assert Color.red('TEST').value_colors == '\033[31mTEST\033[39m' assert Color.bgred('TEST').value_colors == '\033[41mTEST\033[49m' assert Color.green('TEST').value_colors == '\033[32mTEST\033[39m' assert Color.bggreen('TEST').value_colors == '\033[42mTEST\033[49m' assert Color.yellow('TEST').value_colors == '\033[33mTEST\033[39m' assert Color.bgyellow('TEST').value_colors == '\033[43mTEST\033[49m' assert Color.blue('TEST').value_colors == '\033[34mTEST\033[39m' assert Color.bgblue('TEST').value_colors == '\033[44mTEST\033[49m' assert Color.magenta('TEST').value_colors == '\033[35mTEST\033[39m' assert Color.bgmagenta('TEST').value_colors == '\033[45mTEST\033[49m' assert Color.cyan('TEST').value_colors == '\033[36mTEST\033[39m' assert Color.bgcyan('TEST').value_colors == '\033[46mTEST\033[49m' assert Color.white('TEST').value_colors == '\033[37mTEST\033[39m' assert Color.bgwhite('TEST').value_colors == '\033[47mTEST\033[49m' assert Color.black( 'this is a test.', auto=True) == Color('{autoblack}this is a test.{/autoblack}') assert Color.black('this is a test.') == Color( '{black}this is a test.{/black}') assert Color.bgblack( 'this is a test.', auto=True) == Color('{autobgblack}this is a test.{/autobgblack}') assert Color.bgblack('this is a test.') == Color( '{bgblack}this is a test.{/bgblack}') assert Color.red('this is a test.', auto=True) == Color('{autored}this is a test.{/autored}') assert Color.red('this is a test.') == Color('{red}this is a test.{/red}') assert Color.bgred( 'this is a test.', auto=True) == Color('{autobgred}this is a test.{/autobgred}') assert Color.bgred('this is a test.') == Color( '{bgred}this is a test.{/bgred}') assert Color.green( 'this is a test.', auto=True) == Color('{autogreen}this is a test.{/autogreen}') assert Color.green('this is a test.') == Color( '{green}this is a test.{/green}') assert Color.bggreen( 'this is a test.', auto=True) == Color('{autobggreen}this is a test.{/autobggreen}') assert Color.bggreen('this is a test.') == Color( '{bggreen}this is a test.{/bggreen}') assert Color.yellow( 'this is a test.', auto=True) == Color('{autoyellow}this is a test.{/autoyellow}') assert Color.yellow('this is a test.') == Color( '{yellow}this is a test.{/yellow}') assert Color.bgyellow( 'this is a test.', auto=True) == Color('{autobgyellow}this is a test.{/autobgyellow}') assert Color.bgyellow('this is a test.') == Color( '{bgyellow}this is a test.{/bgyellow}') assert Color.blue( 'this is a test.', auto=True) == Color('{autoblue}this is a test.{/autoblue}') assert Color.blue('this is a test.') == Color( '{blue}this is a test.{/blue}') assert Color.bgblue( 'this is a test.', auto=True) == Color('{autobgblue}this is a test.{/autobgblue}') assert Color.bgblue('this is a test.') == Color( '{bgblue}this is a test.{/bgblue}') assert Color.magenta( 'this is a test.', auto=True) == Color('{automagenta}this is a test.{/automagenta}') assert Color.magenta('this is a test.') == Color( '{magenta}this is a test.{/magenta}') assert Color.bgmagenta( 'this is a test.', auto=True) == Color('{autobgmagenta}this is a test.{/autobgmagenta}') assert Color.bgmagenta('this is a test.') == Color( '{bgmagenta}this is a test.{/bgmagenta}') assert Color.cyan( 'this is a test.', auto=True) == Color('{autocyan}this is a test.{/autocyan}') assert Color.cyan('this is a test.') == Color( '{cyan}this is a test.{/cyan}') assert Color.bgcyan( 'this is a test.', auto=True) == Color('{autobgcyan}this is a test.{/autobgcyan}') assert Color.bgcyan('this is a test.') == Color( '{bgcyan}this is a test.{/bgcyan}') assert Color.white( 'this is a test.', auto=True) == Color('{autowhite}this is a test.{/autowhite}') assert Color.white('this is a test.') == Color( '{white}this is a test.{/white}') assert Color.bgwhite( 'this is a test.', auto=True) == Color('{autobgwhite}this is a test.{/autobgwhite}') assert Color.bgwhite('this is a test.') == Color( '{bgwhite}this is a test.{/bgwhite}')
def test_colorize_methods(): """Test colorize convenience methods.""" assert Color.black("TEST").value_colors == "\033[30mTEST\033[39m" assert Color.bgblack("TEST").value_colors == "\033[40mTEST\033[49m" assert Color.red("TEST").value_colors == "\033[31mTEST\033[39m" assert Color.bgred("TEST").value_colors == "\033[41mTEST\033[49m" assert Color.green("TEST").value_colors == "\033[32mTEST\033[39m" assert Color.bggreen("TEST").value_colors == "\033[42mTEST\033[49m" assert Color.yellow("TEST").value_colors == "\033[33mTEST\033[39m" assert Color.bgyellow("TEST").value_colors == "\033[43mTEST\033[49m" assert Color.blue("TEST").value_colors == "\033[34mTEST\033[39m" assert Color.bgblue("TEST").value_colors == "\033[44mTEST\033[49m" assert Color.magenta("TEST").value_colors == "\033[35mTEST\033[39m" assert Color.bgmagenta("TEST").value_colors == "\033[45mTEST\033[49m" assert Color.cyan("TEST").value_colors == "\033[36mTEST\033[39m" assert Color.bgcyan("TEST").value_colors == "\033[46mTEST\033[49m" assert Color.white("TEST").value_colors == "\033[37mTEST\033[39m" assert Color.bgwhite("TEST").value_colors == "\033[47mTEST\033[49m" assert Color.black("this is a test.", auto=True) == Color("{autoblack}this is a test.{/autoblack}") assert Color.black("this is a test.") == Color("{black}this is a test.{/black}") assert Color.bgblack("this is a test.", auto=True) == Color("{autobgblack}this is a test.{/autobgblack}") assert Color.bgblack("this is a test.") == Color("{bgblack}this is a test.{/bgblack}") assert Color.red("this is a test.", auto=True) == Color("{autored}this is a test.{/autored}") assert Color.red("this is a test.") == Color("{red}this is a test.{/red}") assert Color.bgred("this is a test.", auto=True) == Color("{autobgred}this is a test.{/autobgred}") assert Color.bgred("this is a test.") == Color("{bgred}this is a test.{/bgred}") assert Color.green("this is a test.", auto=True) == Color("{autogreen}this is a test.{/autogreen}") assert Color.green("this is a test.") == Color("{green}this is a test.{/green}") assert Color.bggreen("this is a test.", auto=True) == Color("{autobggreen}this is a test.{/autobggreen}") assert Color.bggreen("this is a test.") == Color("{bggreen}this is a test.{/bggreen}") assert Color.yellow("this is a test.", auto=True) == Color("{autoyellow}this is a test.{/autoyellow}") assert Color.yellow("this is a test.") == Color("{yellow}this is a test.{/yellow}") assert Color.bgyellow("this is a test.", auto=True) == Color("{autobgyellow}this is a test.{/autobgyellow}") assert Color.bgyellow("this is a test.") == Color("{bgyellow}this is a test.{/bgyellow}") assert Color.blue("this is a test.", auto=True) == Color("{autoblue}this is a test.{/autoblue}") assert Color.blue("this is a test.") == Color("{blue}this is a test.{/blue}") assert Color.bgblue("this is a test.", auto=True) == Color("{autobgblue}this is a test.{/autobgblue}") assert Color.bgblue("this is a test.") == Color("{bgblue}this is a test.{/bgblue}") assert Color.magenta("this is a test.", auto=True) == Color("{automagenta}this is a test.{/automagenta}") assert Color.magenta("this is a test.") == Color("{magenta}this is a test.{/magenta}") assert Color.bgmagenta("this is a test.", auto=True) == Color("{autobgmagenta}this is a test.{/autobgmagenta}") assert Color.bgmagenta("this is a test.") == Color("{bgmagenta}this is a test.{/bgmagenta}") assert Color.cyan("this is a test.", auto=True) == Color("{autocyan}this is a test.{/autocyan}") assert Color.cyan("this is a test.") == Color("{cyan}this is a test.{/cyan}") assert Color.bgcyan("this is a test.", auto=True) == Color("{autobgcyan}this is a test.{/autobgcyan}") assert Color.bgcyan("this is a test.") == Color("{bgcyan}this is a test.{/bgcyan}") assert Color.white("this is a test.", auto=True) == Color("{autowhite}this is a test.{/autowhite}") assert Color.white("this is a test.") == Color("{white}this is a test.{/white}") assert Color.bgwhite("this is a test.", auto=True) == Color("{autobgwhite}this is a test.{/autobgwhite}") assert Color.bgwhite("this is a test.") == Color("{bgwhite}this is a test.{/bgwhite}")
def _process_mtd(self, mtd): # if DEBUG_MODE: # print('\n', '+' * 100) # print('Starting to decode ...') # print(Color.green(mtd)) # 如果存在数组 array_data_content = [] arr_res = self.arr_data_ptn.search(mtd.get_body()) if arr_res: array_data_content = re.split(r'\n\s', arr_res.group()) lines = re.split(r'\n\s*', mtd.get_body()) old_body = lines.copy() # 存放原始方法体 new_body = [] # 存放解密后的方法体 snippet = [] # 存放smali代码,用于模拟执行 args = {} # 存放方法参数,用于smaliemu执行 index = -1 # 用于计数 xget_opcodes = {'iget', 'iget-object', 'sget', 'sget-object'} block_args = {'first': {}} # 保存所有分支的执行结果 last_block_key = 'first' # 上一个分支-关键字 this_block_key = 'first' # 当前分支,默认第一分支 keys = ['first'] # 默认执行第一分支 for line in lines: index += 1 if not line: continue new_body.append(line) # 解密结果,直接放后面即可 # if DEBUG_MODE: # print(Color.blue(line)) parts = line.split() opcode = parts[0] # smali 代码分块执行 # 命中下述关键字,则表示当前分支结束 # 并根据上一个分支的情况,判断之前的分支是否可用 if 'if-' in opcode: # if DEBUG_MODE: # print('>' * 10, opcode) # print('this_block_key', this_block_key) # print('last_block_key', last_block_key) # print('block_args', block_args) # 存在两种情况 # 1. 当前代码片段(if语句之前的代码),还没执行;全部执行一次 # 2. 当前代码片段,已经执行了一部分,因为解密;从执行后的地方开始执行 pre_args = {} if this_block_key in last_block_key: for key in reversed(keys): if this_block_key not in key: pre_args = block_args[key].copy() break else: pre_args = block_args[last_block_key].copy() if this_block_key in block_args: pre_args.update(block_args[this_block_key]) snippet.extend(array_data_content) self.emu.call(snippet, args=pre_args, cv=True, thrown=False) block_args[this_block_key] = self.emu.vm.variables snippet.clear() last_block_key = this_block_key this_block_key = 'if' + parts[-1] # 表示接下来跑的代码块是这个语句的 keys.append(this_block_key) # if DEBUG_MODE: # print('block_args - 运行后', block_args) continue elif 'goto' in opcode: # 跳转语句,直接跳过 continue elif opcode.startswith(':cond_')\ or opcode.startswith(':try_start')\ or opcode.startswith('.catch_'): # if DEBUG_MODE: # print('>' * 10, opcode) # print('this_block_key', this_block_key) # print('last_block_key', last_block_key) # print('block_args', block_args) # 存在两种情况 # 1. 当前代码片段,还没执行;全部执行一次 # 2. 当前代码片段,已经执行了一部分,因为解密;从执行后的地方开始执行 pre_args = block_args[last_block_key].copy() if this_block_key in block_args: pre_args.update(block_args[this_block_key]) snippet.extend(array_data_content) self.emu.call(snippet, args=pre_args, cv=True, thrown=False) block_args[this_block_key] = self.emu.vm.variables snippet.clear() last_block_key = this_block_key this_block_key = opcode # 表示接下来跑的代码块是这个语句的 keys.append(this_block_key) # if DEBUG_MODE: # print('block_args - 运行后', block_args) continue elif opcode.startswith(':try_start'): pass elif '.catch_' in opcode: # 前面代码当成一块处理 continue snippet.append(line) is_static = True if opcode == 'invoke-static': result = self.process_invoke_static_statement(line) if result: cname, mname, ptypes, rtype, rnames = result else: continue # elif opcode == 'invoke-virtual': # TODO 实例方法,目前只考虑无参实例化。 # result = self.process_invoke_static_statement(line) # if result: # cname, mname, ptypes, rtype, rnames = result # print(result) # # 判断类的构造函数是否为<init>()V # clz = self.smalidir.get_method( # java2smali(cname), '<init>()V') # if not clz: # continue # is_static = False # else: # continue elif opcode in xget_opcodes: self.process_xget_statement(line) continue elif 'Ljava/lang/String;-><init>([B)V' in line: if 'move-result-object' in snippet[0]: snippet = snippet[1:] self.emu.call(snippet, args=args, cv=True, thrown=False) if not self.emu.vm.result: continue # 如果有结果,则替换 vx, _ = SmaliLine.parse(line) new_line = 'const-string {}, "{}"'.format( vx, self.emu.vm.result) del new_body[-1] new_body.append(new_line) self.make_changes = True mtd.set_modified(True) snippet.clear() continue else: continue # 模拟执行,获取解密参数 del snippet[-1] snippet.extend(array_data_content) try: snippet = self.process_if_statement(snippet) # if DEBUG_MODE: # print(Color.red('开始处理解密参数 {}'.format(line))) # for l in snippet: # print(Color.red(l)) # print('args', args) # print(block_args) # print(keys) # print(this_block_key) # print('-' * 80) pre_args = block_args[last_block_key].copy() args.update(pre_args) if this_block_key in block_args: args.update(block_args[this_block_key]) args.update(self.fields) self.emu.call(snippet, args=args, cv=True, thrown=False) registers = self.emu.vm.variables block_args[this_block_key] = registers # if DEBUG_MODE: # print(snippet) # print('args:', args) # print('smali执行后,寄存器内容', registers) if registers: for k, v in registers.items(): if v is None: continue args[k] = v registers = args except TIMEOUT_EXCEPTION: snippet.clear() continue print(Color.red('->')) obj_flag = False if len(ptypes) == 1 and ptypes[0][0] == 'L' and ptypes != [ 'Ljava/lang/String;' ]: # 单独处理参数为对象的情况 obj_flag = True snippet.clear() # 已经执行过的代码,不再执行 if not registers and not obj_flag: continue print(Color.red('->>')) # 从寄存器中获取对应的参数 # 参数获取 "arguments": ["I:198", "I:115", "I:26"]} arguments = [] # args = {} # the parameter of smali method if not obj_flag: ridx = -1 for item in ptypes: ridx += 1 rname = rnames[ridx] if rname not in registers: break value = registers[rnames[ridx]] argument = self.convert_args(item, value) if argument is None: break arguments.append(argument) else: arguments.append('Object:' + smali2java(ptypes[0])) # if DEBUG_MODE: # print(Color.red('->>')) # print('参数类型', ptypes) # print('参数值', arguments) if len(arguments) != len(ptypes): print(Color.red('->> 参数对不上')) continue json_item = self.get_json_item(cname, mname, arguments) print(json_item) # print('生成json item') # {id}_{rtn_name} 让这个唯一化,便于替换 old_content = '# %s' % json_item['id'] # 如果 move_result_obj 操作存在的话,解密后一起替换 find = self.move_result_obj_ptn.search(lines[index + 1]) print(Color.red('->> not fount')) # 必须要找到返回值操作,用于更新寄存器 if not find: print('找不到返回寄存器') continue print(Color.red('->>>')) rtn_name = find.groups()[0] # 为了避免 '# abc_v10' 替换成 '# abc_v1' old_content = old_content + '_' + rtn_name + 'X' self.append_json_item(json_item, mtd, old_content, rtn_name) result = self.get_result(rtype) # if DEBUG_MODE: # print("解密结果", result) self.json_list.clear() if result: new_body = new_body[:-1] else: continue if not args: args = {} if rtype == 'Ljava/lang/String;': result = list(result.values())[0][0] # 更新寄存器 args[rtn_name] = result # 更新代码 new_line = 'const-string {}, "{}"'.format(rtn_name, result) new_body.append(new_line) self.make_changes = True mtd.set_modified(True) elif rtype.startswith('['): args[rtn_name] = result # 把结果保存到当前分支 else: print("返回值并非字符串,也不是B/C数组") if args: block_args[this_block_key].update(args) # 把结果保存到当前分支 # if DEBUG_MODE: # print(block_args) # print('*' * 100) # print('last_block_key', last_block_key) # print('this_block_key', this_block_key) # # pre_args = block_args[last_block_key].copy() # if this_block_key in block_args: # pre_args.update(block_args[this_block_key]) # block_args[this_block_key] = mtd.set_body('\n'.join(new_body))