├── .gitignore ├── README.md ├── commond ├── get_target_binary.sh └── util.js ├── exp.py ├── images ├── YJ_1_1.png ├── YJ_1_2.png ├── YJ_2_1.png ├── YJ_2_2.png ├── YJ_2_3.png ├── YJ_2_4.png ├── YJ_2_5.png ├── YJ_2_6.png ├── YJ_2_7.png ├── YJ_2_8.png ├── YJ_2_9.png ├── image_one.png └── image_two.png ├── model ├── dataSource_hook.js ├── frida_so.js ├── frida_so_64.js ├── heif_to_yuv_hook.js └── hook_exit.js └── style ├── config.json └── layout.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin-debug/ 3 | bin-release/ 4 | [Oo]bj/ 5 | [Bb]in/ 6 | 7 | # Other files and folders 8 | .settings/ 9 | 10 | # Executables 11 | *.swf 12 | *.air 13 | *.ipa 14 | *.apk 15 | 16 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 17 | # should NOT be excluded as they contain compiler settings and other important 18 | # information for Eclipse / Flash Builder. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 前言 2 | 3 | `YJ`是一款基于Frida框架的款`Native`层逆向分析的交互式工具,就像在`GUN-LINUX`上使用`GDB`工具一样,设计`YJ`的灵感来自`GNU-GDB`调试工具,它通过交互命令模式轻松地向展示你想要窥探的内存数据 4 | 5 | `Frida`是一个底层hook工具及框架。提供了hook工具的同时也提供了大量的API操作,基于`Frida`框架的大多都是一些对`Java`代码层的一个Hook集成,而对于`Native`层方面较为全面的分析工具很零碎 6 | 7 | ## 安装 8 | 9 | 首先你得有`Frida`,我在开发和测试阶段分别采用了`frida-15.2.2`和`frida-16.0.0`,而在完成开发的阶段已经发布了`16.0.10`,最后采用`16.0.3`是出于`16.0.0`发布的`snapshots`功能,它能提高`YJ`加载到交互界面的性能,目前该功能还在测试阶段,在不久后将会发布 10 | 11 | ```bash 12 | pip3 install frida==16.0.0 13 | git clone https://github.com/yang-datong/YJ-3.git 14 | ``` 15 | 16 | ## 使用 17 | 18 | 通过`ADB`连接上已经开启了`frida-server`的`Android`手机 19 | 20 | ```bash 21 | cd YJ-3 22 | python3 exp.py [你的目标应用名称] 23 | ``` 24 | 25 | ![iShot_2023-02-20_21.45.30](images/YJ_2_1.png) 26 | 27 | 看起来有点意思,这是一个简单的`内置shell`交互模式 28 | 29 | > 试用了一些`python`的`内置shell`库都感觉不够轻量 30 | 31 | 32 | 33 | `YJ`提供了一些在我用`GDB`调试时的一些常见命令,具体可以看`help`命令的输出文本,默认`YJ`启动的是`attach`模式直接附加到当前的App中: 34 | > 可以通过`python3 exp.py --help`来查看`spawn`模式来调试目标进程,或者通过`load`来加载你的脚本(默认加载脚本为`model/main.js`) 35 | 36 | 37 | - 如果你有明确的逆向分析函数的话你可以直接使用`breakpoint [functionName]`来对目标地址下监控点(breakpoint支持对函数名、lib库名+具体偏移偏移、计算表达式下监控点,然后也可以删除当前监控点,重新监控到另一个地址) 38 | 39 | ![iShot_2023-02-20_22.14.07](images/YJ_2_2.png) 40 | 41 | - 如果没有明确分析具体的函数,那么可使用`watch`命令来监控具体的`lib库`内存,如下: 42 | 43 | ![iShot_2023-02-20_22.20.10](images/YJ_2_3.png) 44 | 45 | 46 | 47 | 如果该`lib库`是个热点库,那么立马会回收到监控的内存空间具体调用信息, 48 | 49 | ![iShot_2023-02-20_22.19.16](images/YJ_2_4.png) 50 | 51 | 52 | 53 | 找到目标地址后,`unwatch`停止内存监控,进入一下操作,通过`breakpoint [address]`对目标地址下入监控点 54 | 55 | ![iShot_2023-02-20_22.32.27](images/YJ_2_5.png) 56 | 57 | 58 | 59 | 当地址被执行时,那么就进入到我们的内存视图(arm64的寄存器非常多,这里一整页已经装不下了) 60 | 61 | ![iShot_2023-02-20_22.26.18](images/YJ_2_6.png) 62 | 63 | ![iShot_2023-02-20_22.36.23](images/YJ_2_7.png) 64 | 65 | 66 | 67 | 现在可以尽情享受了,你可以通过'print'、'hex'、'telescope'、'hexdump'等命令详细的查看指定的内存数据,比如 68 | 69 | ![iShot_2023-02-20_22.41.52](images/YJ_2_8.png) 70 | 71 | ## 无Root 72 | 73 | 对于无root设备`frida`提供了`frida-gadget`库,之前将`gadget.so`用脚本一键注入到目标进行并使`YJ`调试上去的时候发现`apktool`重新打包的性能消耗太严重,考虑到稳定性现在只保留一键注入到`lib库`中,后续的打包以及绕过操作自行处理 74 | 75 | ![iShot_2023-02-20_22.53.33](images/YJ_2_9.png) 76 | 77 | 通过`bash inject.sh [gadgetInteractionType]`可以选择你的gadget执行的模式,如`监听模式`、`脚本模式`具体看https://frida.re/docs/gadget/ 78 | 79 | > 脚本模式中默认使用的脚本为`explore.js` 你可以在`main()`中定义你的规则 80 | 81 | ## 环境问题 82 | 83 | 电脑:目前只支持在`bash`、`python`环境中的机器,大众的来说`Mac OS`、`GUN-Linux`可用,`Windows`不可用(以后会考虑在powershell中实现类bash的功能) 84 | 85 | 手机:目前只支持Android 86 | 87 | 调试目标:目前只支持Android Native层调试,Java层无任何支持 88 | 89 | ## 后续 90 | 91 | - 性能优化:会考虑热点功能函数使用全C实现 92 | - 自定义插件入口:扩展功能编解码器中直接从内存抽帧 93 | - 多平台支持:Windows 94 | - 数据结构详细分析:堆链条、内核结构、更详细完整的内存信息 95 | 96 | ## 开源协议 97 | 98 | !!!免责声明!!! 99 | 100 | 因为设计到了逆向安全领域,所以不得不慎重声明,本项目使用Apache License 2.0开源协议 101 | 102 | 1.授权使用者免费使用个人专利 103 | 104 | 2.使用者必须放置协议说明 105 | 106 | 3.使用者需要对修改部分声明 107 | 108 | 4.禁止用作者的名号进行商业广告 109 | 110 | 5.原作者不承担代码使用后风险 111 | 112 | 本项目仅作为学习使用,一切后果本人概不负责 113 | -------------------------------------------------------------------------------- /commond/get_target_binary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# == 0 ];then 3 | echo "no target binary !!!" 4 | exit 1 5 | elif [ $# == 1 ];then 6 | echo "no lib !!!" 7 | exit 1 8 | fi 9 | 10 | 11 | target_binary_path=$1 12 | lib_name=$2 13 | ROW_NUMBER=$3 14 | OFFSET=$4 15 | 16 | YJ_dir=".YJ" 17 | obj="objdump" 18 | 19 | #Check OS System 20 | if [ "$(uname)" == "Darwin" ];then #Mac 21 | obj="objdumps" 22 | elif [ "$(uname)" == "Linux" ];then #Linux 23 | obj="objdump" 24 | else 25 | echo "Windows has not been tested for the time being" 26 | exit 1 27 | fi 28 | 29 | #Checkout is intall objdump(Must be objdump under linux) 30 | if [ ! -x "$(command -v $obj)" ];then 31 | echo "Please Install Linux objdump,Mac -> (brew install binutils)" 32 | echo "And renamed it to $obj" 33 | exit 1 34 | fi 35 | 36 | #is exist .yj dir? 37 | if [ ! -d "$YJ_dir" ];then 38 | mkdir $YJ_dir 39 | adb pull $target_binary_path $YJ_dir/ 40 | $obj "$YJ_dir/$lib_name" -j .text -S > "$YJ_dir/$lib_name.asm" 41 | exit 1 42 | #is exist lib file? 43 | elif [ ! -f "$YJ_dir/$lib_name" ];then 44 | adb pull $target_binary_path $YJ_dir/ 45 | $obj "$YJ_dir/$lib_name" -j .text -S > "$YJ_dir/$lib_name.asm" 46 | exit 1 47 | #is exist asm file? 48 | elif [ ! -f "$YJ_dir/$lib_name.asm" ];then 49 | $obj "$YJ_dir/$lib_name" -j .text -S > "$YJ_dir/$lib_name.asm" 50 | exit 1 51 | else 52 | grep -C $ROW_NUMBER $OFFSET "$YJ_dir/$lib_name.asm" | awk '{$2="";print 0x$0}' 53 | exit 1 54 | fi 55 | 56 | -------------------------------------------------------------------------------- /commond/util.js: -------------------------------------------------------------------------------- 1 | // -------------------------define------------------------------- 2 | // 配置信息区 3 | let END_LINE_LEN; 4 | let VIEW_MESSAGE; 5 | let VIEW_STACK; 6 | let VIEW_CODE; 7 | let VIEW_TRACE; 8 | let VIEW_REGISTERS; 9 | let CLEAR_TAG; 10 | let TELE_TAG; 11 | let CODE_TAG; 12 | let TRACE_TAG; 13 | let REGISTER_TAG; 14 | let INIT_SEGMENT_ADDRESS_TAG; 15 | let TELE_SHOW_ROW_NUMBER; 16 | rpc.exports.init = mjson => { 17 | END_LINE_LEN = mjson.end_line_len; 18 | VIEW_MESSAGE = mjson.view_message; 19 | VIEW_STACK = mjson.view_stack; 20 | VIEW_CODE = mjson.view_code; 21 | VIEW_TRACE = mjson.view_trace; 22 | VIEW_REGISTERS = mjson.view_registers; 23 | CLEAR_TAG = mjson.clear_tag; 24 | CODE_TAG = mjson.code_tag; 25 | TRACE_TAG = mjson.trace_tag; 26 | TELE_TAG = mjson.tele_tag; 27 | REGISTER_TAG = mjson.register_tag; 28 | INIT_SEGMENT_ADDRESS_TAG = mjson.init_segment_address_tag; 29 | TELE_SHOW_ROW_NUMBER = mjson.tele_show_row_number; 30 | }; 31 | 32 | // 变量区 33 | const message_tag = ' log '; 34 | const _width = 70; 35 | let step = 4; // 默认32bit 36 | let arch; 37 | 38 | const log = (...info) => { 39 | const befor = Array.from({length: _width - END_LINE_LEN - message_tag.length + 1}).join('='); 40 | const end = new Array(END_LINE_LEN).join('='); 41 | console.log(befor + message_tag + end + '\n'); 42 | console.log(...info); 43 | }; 44 | 45 | const dump = (...ptr) => { 46 | if (ptr[1] == undefined) { 47 | return send(hexdump(ptr[0], {offset: 0, length: 0x30, header: true, ansi: true})); 48 | } 49 | 50 | return send(hexdump(ptr[0], {offset: 0, length: ptr[1], header: true, ansi: true})); 51 | }; 52 | // -------------------------init------------------------------- 53 | // 这里是配置信息 需要进行配置上下文对象 往后会对64位so进行支持!!! 54 | /** 55 | send("id->"+Process.id + 56 | "\narch->"+Process.arch + 57 | "\nplatform->"+Process.platform + 58 | "\npageSize->"+Process.pageSize + 59 | "\nisDebuggerAttached->"+Process.isDebuggerAttached()+ 60 | "\ngetCurrentThreadId->"+Process.getCurrentThreadId()+ 61 | "\npointerSize->"+Process.pointerSize ) 62 | */ 63 | // findAll("初始化之前",lib) 64 | // setTimeout((v0,v1) => {findAll(v0,v1)},1700,"初始化之后",lib) 65 | 66 | // -------------------------alias------------------------------- 67 | // 以更简洁的方式调用(设置别名) 68 | function tele(...args) { 69 | show_telescope_view(...args); 70 | } 71 | 72 | function ls(ctx, lib_base) { 73 | show_view(ctx, lib_base); 74 | } 75 | 76 | // -------------------------func------------------------------- 77 | // 监控内存数据 78 | function watch(addr, length, lib) { 79 | MemoryAccessMonitor.enable({base: addr, size: length}, { 80 | onAccess(details) { 81 | send('operation->' + details.operation 82 | + '\nfrom->' + details.from 83 | + '\naddress->' + (details.address) 84 | + '\nrangeIndex->' + details.rangeIndex 85 | + '\npageIndex->' + details.pageIndex 86 | + '\npagesCompleted->' + details.pagesCompleted 87 | + '\npagesTotal->' + details.pagesTotal, 88 | ); 89 | }}); 90 | } 91 | 92 | // 用于Interceptor.attach的封装 93 | function b(...args) { 94 | const addr = args[0]; 95 | const on_enter = args[1]; 96 | const on_leave = args[2]; 97 | const is_clear = args[3]; 98 | 99 | Interceptor.attach(addr, { 100 | onEnter(args) { 101 | if (is_clear != undefined) { 102 | send(CLEAR_TAG); 103 | } 104 | 105 | // Show_view(this.context) 106 | if (on_enter != undefined) { 107 | on_enter(this.context); 108 | } 109 | }, onLeave(returnValue) { 110 | if (on_leave != undefined) { 111 | on_leave(this.context); 112 | } 113 | }, 114 | }); 115 | } 116 | 117 | // 显示一个指针块视图 118 | function show_telescope_view(...args) { 119 | let data = ''; 120 | let addr = args[0]; 121 | let _addr; let ptr; 122 | for (let i = 0; i < TELE_SHOW_ROW_NUMBER; i++) { 123 | _addr = addr.readPointer(); 124 | try { 125 | ptr = _addr.readPointer(); 126 | } catch { 127 | ptr = 0; 128 | } 129 | 130 | data += (addr + '│' + (i * step) + '│' + _addr + '│' + ptr + TELE_TAG); 131 | addr = addr.add(step); 132 | } 133 | 134 | if (args[1] != null) { 135 | send([data, args[1]]); 136 | } else { 137 | send(data); 138 | } 139 | } 140 | 141 | // 寄存器视图 142 | function show_registers(...args) { 143 | const context = args[0]; 144 | let data = ''; 145 | let addr; let ptr; 146 | for (const key in context) { 147 | addr = context[key]; 148 | try { 149 | ptr = addr.readPointer(); 150 | } catch { 151 | ptr = 0; 152 | } 153 | 154 | data += (key + '│' + addr + '│' + ptr + REGISTER_TAG); 155 | } 156 | 157 | send([data, VIEW_REGISTERS]); 158 | } 159 | 160 | // 向python块发送所需块数据 161 | function init_segment_address(context) { 162 | arch = ' code:' + Process.arch + ' '; 163 | step = Process.pointerSize; 164 | const stack = context.sp; 165 | const code = context.pc; 166 | const data = stack + INIT_SEGMENT_ADDRESS_TAG + code + INIT_SEGMENT_ADDRESS_TAG + arch + INIT_SEGMENT_ADDRESS_TAG + step; 167 | send(data); 168 | } 169 | 170 | // 显示所有布局视图 171 | function show_view(context, lib_base) { 172 | init_segment_address(context); 173 | show_registers(context); 174 | show_telescope_view(context.sp, VIEW_STACK); // 栈空间视图 175 | show_code_view(context); 176 | // Show_trace_view(context) //卡顿严重 暂时不开放!!!! 177 | } 178 | 179 | function show_trace_view(ctx) { 180 | const data = Thread.backtrace(ctx, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + TRACE_TAG; 181 | send([data, VIEW_TRACE]); 182 | } 183 | 184 | function show_code_view(ctx) { 185 | // Send("id->"+Process.id + 186 | // "\narch->"+Process.arch + 187 | // "\nplatform->"+Process.platform + 188 | // "\npageSize->"+Process.pageSize + 189 | // "\nisDebuggerAttached->"+Process.isDebuggerAttached()+ 190 | // "\ngetCurrentThreadId->"+Process.getCurrentThreadId()+ 191 | // "\npointerSize->"+Process.pointerSize ) 192 | const lib = Process.getModuleByAddress(ctx.pc); 193 | const name = lib.name; 194 | const base = lib.base; 195 | const path = lib.path; 196 | const offset = ctx.pc - Number.parseInt(base); 197 | const object = {name, 198 | base, 199 | path, 200 | offset}; 201 | 202 | const data = JSON.stringify(object) + CODE_TAG; 203 | send([data, VIEW_CODE + arch]); // 标记为送往code段的数据 204 | } 205 | 206 | // 所有加载的so 207 | function findAll(string_, lib) { 208 | for (const i in lib) { 209 | send(string_ + lib[i] + '-> ' + Module.findBaseAddress(lib[i])); 210 | } 211 | } 212 | 213 | // So层栈回溯 214 | function printStack_so(ctx) { 215 | send('So Stack -> :\n' + Thread.backtrace(ctx, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); 216 | // Log('So Stack -> :\n' +Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); 217 | } 218 | 219 | // Android层栈回溯 220 | function printStack() { 221 | send('Java Stack -> :\n' + Java.use('android.util.Log').getStackTraceString(Java.use('java.lang.Throwable').$new())); 222 | } 223 | 224 | // So的所有导出函数 225 | function export_func(so) { 226 | const exports = Module.enumerateExportsSync(so); 227 | for (const export_ of exports) { 228 | send(export_.name + ': ' + export_.address + ',so->' + so); 229 | b(export_.address.add(1), c => { 230 | send(export_.name); 231 | }); 232 | 233 | if (export_.name == 'ByteVC1_dec_create') { 234 | send(export_.name + ': ' + export_.address + ',so->' + so); 235 | } 236 | } 237 | } 238 | 239 | function import_func(so, target) { 240 | // So的所有导入函数 241 | const exports = Module.enumerateImportsSync(so); 242 | for (const export_ of exports) { 243 | // Send(exports[i].name + ": " + exports[i].address+",so->"+so); 244 | if (export_.name == target) { 245 | send('Find!!!' + so + '->' + export_.name); 246 | } 247 | } 248 | } 249 | 250 | // So的所有导入函数 251 | function hook_libart() { 252 | let GetStringUTFChars_addr = null; 253 | const module_libart = Process.findModuleByName('libart.so'); 254 | const symbols = module_libart.enumerateSymbols(); 255 | for (const symbol_ of symbols) { 256 | const name = symbol_.name; 257 | if ((name.includes('JNI')) 258 | && (!name.includes('CheckJNI')) 259 | && (name.includes('art')) && name.includes('GetStringUTFChars')) { 260 | log(name); 261 | // 获取到指定 jni 方法地址 262 | GetStringUTFChars_addr = symbol_.address; 263 | } 264 | } 265 | } 266 | 267 | // 保存数据到文件 268 | function writeFile(content, file_name) { 269 | const file = new File('/sdcard/' + file_name, 'w+');// A+表示追加内容,此处的模式和c语言的fopen函数模式相同 270 | file.write(content); 271 | file.flush(); 272 | file.close(); 273 | send('-----> save: ' + file_name + ' is done!! <------'); 274 | } 275 | 276 | function calss_methods() { 277 | // Hook类的所有方法 278 | const md5Util = Java.use('com.ss.texturerender.VideoSurfaceTexture'); 279 | const methods = md5Util.class.getDeclaredMethods(); 280 | for (const method of methods) { 281 | var methodName = method.getName(); 282 | console.log(methodName); 283 | 284 | // 这里遍历方法的所有重载 285 | for (let i = 0; i < md5Util[methodName].overloads.length; i++) { 286 | md5Util[methodName].overloads[i].implementation = function () { 287 | for (const argument of arguments) { 288 | console.log(argument); 289 | } 290 | 291 | // 这里需要调用原来的方法,但是原来的方法的参数个数不确定,所以需要使用到arguments 292 | return Reflect.apply(this[methodName], this, arguments); 293 | }; 294 | } 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /exp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: UTF-8 -*- 3 | from style.layout import * 4 | import frida,sys 5 | 6 | 7 | if (len(sys.argv) < 2): 8 | print("\033[31mPlease input script\033[0m, such as ->\033[32m python3 exp.py script.js\033[0m") 9 | exit(0) 10 | 11 | mainFile = sys.argv[1] 12 | 13 | layout = LayoutView() #Init Sytle Theme 14 | 15 | def on_message(message,data): 16 | if message['type'] == 'send': 17 | layout.check_is_view_tag(message) 18 | if(layout.check_is_need_clear_view()==True): 19 | return 20 | if(layout.check_is_init_segment_address() == True): 21 | return 22 | layout.show_line_view() 23 | layout.reset_send_payload(message) 24 | if LayoutView.tele_tag in layout.payload: 25 | layout.show_tele_view() 26 | elif LayoutView.register_tag in layout.payload: 27 | layout.show_registers_view() 28 | elif LayoutView.code_tag in layout.payload: 29 | layout.show_code_view() 30 | elif LayoutView.trace_tag in layout.payload: 31 | layout.show_trace_view() 32 | else: 33 | layout.payload = str(message['payload']) #还原数组 34 | print("\033[31m{0}\033[0m".format(layout.payload)) 35 | else: 36 | print(message) 37 | 38 | 39 | 40 | device = frida.get_usb_device() 41 | process = device.attach('抖音') 42 | process.enable_debugger() 43 | #pid = device.spawn("com.android.providers.downloads.ui", activity="com.android.providers.downloads.ui.DownloadList") #使用挂起调试时才用 44 | 45 | foot = "" 46 | with open(mainFile) as jscode: 47 | foot += jscode.read() 48 | with open("./commond/util.js") as jscode: 49 | foot += jscode.read() 50 | 51 | script = process.create_script(foot,runtime='v8') 52 | script.on('message',on_message) 53 | script.load() 54 | show_head_view_tips_info_color() 55 | script.exports.init(LayoutView.mjson) #对应js脚本的hook函数init() 56 | #device.resume(pid) #对应挂起函数调用 57 | sys.stdin.read() 58 | 59 | -------------------------------------------------------------------------------- /images/YJ_1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_1_1.png -------------------------------------------------------------------------------- /images/YJ_1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_1_2.png -------------------------------------------------------------------------------- /images/YJ_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_1.png -------------------------------------------------------------------------------- /images/YJ_2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_2.png -------------------------------------------------------------------------------- /images/YJ_2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_3.png -------------------------------------------------------------------------------- /images/YJ_2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_4.png -------------------------------------------------------------------------------- /images/YJ_2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_5.png -------------------------------------------------------------------------------- /images/YJ_2_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_6.png -------------------------------------------------------------------------------- /images/YJ_2_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_7.png -------------------------------------------------------------------------------- /images/YJ_2_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_8.png -------------------------------------------------------------------------------- /images/YJ_2_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/YJ_2_9.png -------------------------------------------------------------------------------- /images/image_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/image_one.png -------------------------------------------------------------------------------- /images/image_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yang-datong/YJ/74060d6c7af72eaa68177c2a39891dda5a406d4d/images/image_two.png -------------------------------------------------------------------------------- /model/dataSource_hook.js: -------------------------------------------------------------------------------- 1 | // -------------------------define------------------------------- 2 | // -------------------------mian------------------------------- 3 | Java.perform(() => { 4 | const cls = Java.use('com.ss.ttvideoengine.MediaPlayerWrapper'); 5 | cls.setDataSource.overload('android.content.Context', 'android.net.Uri', 'java.util.Map').implementation = function (v0, uri, map) { 6 | const Uri = Java.use('android.net.Uri'); 7 | send(uri.toString()); 8 | uri = Uri.parse(data); 9 | send(v0.toString()); 10 | let result = ''; 11 | const keyset = map.keySet(); 12 | const it = keyset.iterator(); 13 | while (it.hasNext()) { 14 | const keystr = it.next().toString(); 15 | const valuestr = map.get(keystr).toString(); 16 | result += valuestr; 17 | } 18 | 19 | send(result); 20 | return this.setDataSource(v0, uri, map); 21 | }; 22 | 23 | var data = 'mdl://id78/?rk=7121291048277593344&k=v0d00fg10000cb9ugh3c77u10c2r36k0_bytevc1_540p_1050133&u0=https%3A%2F%2Fv27-a.douyinvod.com%2Ff7b23028be6654b210b818c292c1612c%2F62e3695e%2Fvideo%2Ftos%2Fcn%2Ftos-cn-ve-15c001-alinc2%2Fe8356892580d4779a462d3913da9d919%2F%3Fa%3D1128%26ch%3D10010%26cr%3D3%26dr%3D0%26lr%3Dall%26cd%3D0%7C0%7C0%7C3%26cv%3D1%26br%3D1025%26bt%3D1025%26btag%3D80000%26cs%3D2%26ds%3D6%26ft%3D47IFAjjM95MxrKqoZmCTeK_ScoAwHX~pu6aVJEInv5RCPD%26mime_type%3Dvideo_mp4%26qs%3D14%26rc%3DaDo6NThpOmk7PGc6NGc8NUBpMzl1ZjQ6Zmt4ZTMzNGkzM0AxXzRgXjIuXmIxMS1eLjVhYSNoMC8tcjQwZDZgLS1kLWFzcw%3D%3D%26l%3D20220729115956010158116040170514A5&u1=https%3A%2F%2Fv26.douyinvod.com%2Fbf66f4799622d9ccc05c3ae581a85dc9%2F62e3695e%2Fvideo%2Ftos%2Fcn%2Ftos-cn-ve-15c001-alinc2%2Fe8356892580d4779a462d3913da9d919%2F%3Fa%3D1128%26ch%3D10010%26cr%3D3%26dr%3D0%26lr%3Dall%26cd%3D0%7C0%7C0%7C3%26cv%3D1%26br%3D1025%26bt%3D1025%26btag%3D80000%26cs%3D2%26ds%3D6%26ft%3D47IFAjjM95MxrKqoZmCTeK_ScoAwHX~pu6aVJEInv5RCPD%26mime_type%3Dvideo_mp4%26qs%3D14%26rc%3DaDo6NThpOmk7PGc6NGc8NUBpMzl1ZjQ6Zmt4ZTMzNGkzM0AxXzRgXjIuXmIxMS1eLjVhYSNoMC8tcjQwZDZgLS1kLWFzcw%3D%3D%26l%3D20220729115956010158116040170514A5&u2=https%3A%2F%2Fapi-hl.amemv.com%2Faweme%2Fv1%2Fplay%2F%3Fvideo_id%3Dv0d00fg10000cb9ugh3c77u10c2r36k0%26line%3D0%26file_id%3Dd2891da1074d49e8af175fa5c277b74e%26sign%3D46c441d52c5871b4061a2cc2587cc156%26is_play_url%3D1%26source%3DPackSourceEnum_PUBLISH%26pass-region%3D1%26pass-route%3D1%26iid%3D1535390967150711%26device_id%3D128016083857303%26ac%3Dwifi%26channel%3Ddy_tiny_sem_sogou_pz%26aid%3D1128%26app_name%3Daweme%26version_code%3D200600%26version_name%3D20.6.0%26device_platform%3Dandroid%26os%3Dandroid%26ssmix%3Da%26device_type%3DPixel%203%26device_brand%3Dgoogle%26language%3Dzh%26os_api%3D30%26os_version%3D11%26openudid%3D2cf99247acc688d4%26manifest_version_code%3D200601%26resolution%3D1080%2A2028%26dpi%3D440%26update_version_code%3D20609900%26_rticket%3D1659067289683%26package%3Dcom.ss.android.ugc.aweme%26cpu_support64%3Dtrue%26host_abi%3Darmeabi-v7a%26is_guest_mode%3D0%26app_type%3Dnormal%26minor_status%3D0%26appTheme%3Dlight%26need_personal_recommend%3D1%26is_android_pad%3D0%26ts%3D1659067287%26cdid%3Dfea73398-8399-4945-9f69-2191303fc6fb&ah=5b0'; 24 | }); 25 | -------------------------------------------------------------------------------- /model/frida_so.js: -------------------------------------------------------------------------------- 1 | // -------------------------define------------------------------- 2 | const idx = 0; 3 | let width; let mheight; let mwidth; 4 | let size; 5 | // -------------------------mian------------------------------- 6 | libByteVC1_dec_so('libByteVC1_dec.so'); 7 | // Libttheif_dec_so("libttheif_dec.so") 8 | // 使用Java hook会导致明显延迟!!!!!! 9 | /** 10 | Java.perform(()=>{ 11 | Java.use("com.bytedance.fresco.nativeheif.Heif").toRgba.overload('[B', 'int', 'boolean', 'int', 'int', 'int', 'int', 'int').implementation = function(v0,v1,v2,v3,v4,v5,v6,v7){ 12 | send("java_size->"+v1) 13 | return this.toRgba(v0,v1,v2,v3,v4,v5,v6,v7) 14 | } 15 | }) 16 | */ 17 | // -------------------------func------------------------------- 18 | function libByteVC1_dec_so(so) { 19 | let lib = Module.findBaseAddress(so); 20 | while (lib == null) { 21 | lib = Module.findBaseAddress(so); 22 | } 23 | 24 | hook(lib); 25 | } 26 | 27 | function libttheif_dec_so(so) { 28 | let lib = Module.findBaseAddress(so); 29 | while (lib == null) { 30 | lib = Module.findBaseAddress(so); 31 | } 32 | 33 | // Sava_input_buff(lib) //保存转yuv前的数据 34 | save_output_buff(lib); // 保存转完yuv后的数据 35 | } 36 | 37 | function hook(lib) { 38 | b(lib.add(0x1_FE_70 + 1), ctx => { 39 | ls(ctx); 40 | }, c => {}, 'clear'); 41 | } 42 | 43 | function sava_input_buff(lib) { 44 | b(lib.add(0x7B_A0 + 1), c => { 45 | send('so size->' + Number.parseInt(c.r2)); 46 | dump(c.r1); // Byte!!! 47 | // writeFile(Memory.readByteArray(c.r1,parseInt(c.r2)),"prepare_to_yuv.log") 48 | }); 49 | } 50 | 51 | function save_output_buff(lib) { 52 | const offset = 0x6A_40; 53 | let out_buffer; 54 | let height; 55 | b(lib.add(offset + 1), ctx => { 56 | height = ctx.sp.add(0x00_18).readPointer(); 57 | if (Number.parseInt(height) < 0x60) { 58 | return; 59 | } 60 | 61 | ls(ctx); 62 | send('out_buffer->' + ctx.r1 + '[' + idx + ']'); 63 | send('width->' + ctx.sp.add(0x00_14).readPointer()); 64 | send('height->' + ctx.sp.add(0x00_18).readPointer()); 65 | out_buffer = ctx.r1; 66 | }, ctx => { 67 | if (Number.parseInt(height) < 0x60) { 68 | return; 69 | } 70 | 71 | size = ctx.r0; 72 | send('size->' + size); 73 | // WriteFile(Memory.readByteArray(out_buffer,parseInt(size)),"out_data_yuv.yuv") 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /model/frida_so_64.js: -------------------------------------------------------------------------------- 1 | // -------------------------mian------------------------------- 2 | // java() 3 | hook('libttmplayer.so', 0x10_34_18); 4 | // Hook("libjato.so",0x12B05) 5 | // hooks("libttmplayer.so",0x145384) 6 | // -------------------------func------------------------------- 7 | function java() { 8 | send('1'); 9 | Java.perform(() => { 10 | Java.use('com.ss.ttm.player.TTPlayer').setVideoSurface.overload('android.view.Surface').implementation = function (v1) { 11 | send(String(this.mHandle.value)); 12 | return this.setVideoSurface(v1); 13 | }; 14 | }); 15 | } 16 | 17 | function hook(so, addr) { 18 | let lib = Module.findBaseAddress(so); 19 | while (lib == null) { 20 | lib = Module.findBaseAddress(so); 21 | } 22 | 23 | b(lib.add(addr), c => { 24 | ls(c); 25 | tele(c.x8); 26 | }); 27 | } 28 | 29 | function hooks(so, addr) { 30 | let lib = Module.findBaseAddress(so); 31 | while (lib == null) { 32 | lib = Module.findBaseAddress(so); 33 | } 34 | 35 | send('find!' + so); 36 | Interceptor.attach(lib.add(addr), { 37 | onEnter(args) { 38 | send('1111'); 39 | }, onLeave(returnValue) {}}); 40 | } 41 | 42 | let exitClass = ''; 43 | setImmediate(() => { 44 | Java.perform(() => { 45 | console.log('[*] Hooking calls to System.exit'); 46 | exitClass = Java.use('java.lang.System'); 47 | exitClass.exit.implementation = function () { 48 | console.log('[*] System.exit called'); 49 | }; 50 | 51 | let strncmp; 52 | const imports = Module.enumerateImportsSync('libfoo.so'); 53 | 54 | for (const import_ of imports) { 55 | if (import_.name == 'strncmp') { 56 | strncmp = import_.address; 57 | break; 58 | } 59 | } 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /model/heif_to_yuv_hook.js: -------------------------------------------------------------------------------- 1 | // -------------------------define------------------------------ 2 | const idx = 0; 3 | let width; let mheight; let mwidth; 4 | let size; 5 | // -------------------------mian------------------------------- 6 | // libByteVC1_dec_so("libByteVC1_dec.so") 7 | libttheif_dec_so('libttheif_dec.so'); 8 | 9 | // -------------------------func------------------------------- 10 | 11 | function libByteVC1_dec_so(so) { 12 | let lib = Module.findBaseAddress(so); 13 | while (lib == null) { 14 | lib = Module.findBaseAddress(so); 15 | } 16 | 17 | hook(lib); 18 | } 19 | 20 | function libttheif_dec_so(so) { 21 | let lib = Module.findBaseAddress(so); 22 | while (lib == null) { 23 | lib = Module.findBaseAddress(so); 24 | } 25 | 26 | sava_input_buff(lib); // 保存转yuv前的数据 27 | save_output_buff(lib); // 保存转完yuv后的数据 28 | } 29 | 30 | function hook(lib) { 31 | b(lib.add(0x1_D1_B0 + 1), ctx => { 32 | ls(ctx); 33 | }, c => {}, 'clear'); 34 | } 35 | 36 | function sava_input_buff(lib) { 37 | b(lib.add(0x7B_A0 + 1), c => { 38 | send('so size->' + Number.parseInt(c.r2)); 39 | dump(c.r1); // Byte!!! 40 | writeFile(Memory.readByteArray(c.r1, Number.parseInt(c.r2)), 'prepare_to_yuv.log'); 41 | }); 42 | } 43 | 44 | function save_output_buff(lib) { 45 | const offset = 0x6A_40; 46 | let out_buffer; 47 | let height; 48 | b(lib.add(offset + 1), ctx => { 49 | height = ctx.sp.add(0x00_18).readPointer(); 50 | if (Number.parseInt(height) < 0x60) { 51 | return; 52 | } 53 | 54 | ls(ctx); 55 | send('out_buffer->' + ctx.r1 + '[' + idx + ']'); 56 | send('width->' + ctx.sp.add(0x00_14).readPointer()); 57 | send('height->' + ctx.sp.add(0x00_18).readPointer()); 58 | send('0x00_14->'+Number.parseInt(0x00_14)) 59 | send('0x0014->'+Number.parseInt(0x0014)) 60 | out_buffer = ctx.r1; 61 | }, ctx => { 62 | if (Number.parseInt(height) < 0x60) { 63 | return; 64 | } 65 | 66 | size = ctx.r0; 67 | send('size->' + size); 68 | writeFile(Memory.readByteArray(out_buffer, Number.parseInt(size)), 'out_data_yuv.yuv'); 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /model/hook_exit.js: -------------------------------------------------------------------------------- 1 | let exitClass = ''; 2 | setImmediate(() => { 3 | Java.perform(() => { 4 | console.log('[*] Hooking calls to System.exit'); 5 | exitClass = Java.use('java.lang.System'); 6 | exitClass.exit.implementation = function () { 7 | console.log('[*] System.exit called'); 8 | }; 9 | 10 | let strncmp; 11 | const imports = Module.enumerateImportsSync('libfoo.so'); 12 | 13 | for (const import_ of imports) { 14 | if (import_.name == 'strncmp') { 15 | strncmp = import_.address; 16 | break; 17 | } 18 | } 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /style/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "end_line_len": 4, 3 | "tele_show_row_number": 10, 4 | "code_show_row_number": "5", 5 | 6 | "view_message": " send ", 7 | "view_stack": " stack ", 8 | "view_code": " code ", 9 | "view_trace": " trace ", 10 | "view_registers": " registers ", 11 | 12 | "clear_tag": "$$$$clear_tag$$$$", 13 | "message_tag": "$$$$message_tag$$$$", 14 | "tele_tag": "$$$$tele_tag$$$$", 15 | "code_tag": "$$$$code$$$$", 16 | "trace_tag": "$$$$trace$$$$", 17 | "register_tag": "$$$$register_tag$$$$", 18 | "init_segment_address_tag": "$$$$INIT_SEGMENT$$$$", 19 | 20 | "color_format_value_grey": "0", 21 | "color_format_value_red": "31", 22 | "color_format_value_green": "32", 23 | "color_format_value_yellow": "33", 24 | "color_format_value_bule": "34", 25 | "color_format_value_pink": "35", 26 | "color_format_value_cyan": "36" 27 | } 28 | -------------------------------------------------------------------------------- /style/layout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: UTF-8 -*- 3 | import json,os 4 | 5 | class LayoutView: 6 | def __init__(self): 7 | get_config_info() 8 | self.payload = "" 9 | self.width = int(os.get_terminal_size().columns) 10 | self.stack_base = 0 11 | self.code_base = 0 12 | self.step = 4 13 | 14 | #显示一条分割线 15 | def show_line_view(self): 16 | print("─"*int(self.width - LayoutView.end_line_len - int(len(LayoutView.message_tag))) + "\033[36m"+LayoutView.message_tag+"\033[0m"+"─"*LayoutView.end_line_len+"\n") 17 | 18 | def check_is_need_clear_view(self): 19 | if LayoutView.clear_tag in self.payload: 20 | print("\n"*100) 21 | print("\033[32m{0}\033[0m".format(LayoutView.wecome)) 22 | show_head_view_tips_info_color() 23 | return True 24 | else: 25 | return False 26 | 27 | #检查是否需要改变分割线的标签 28 | def check_is_view_tag(self,message): 29 | self.payload 30 | mtype = type(message['payload']) 31 | if(mtype == list): 32 | self.payload = str(message['payload'][1]) #[1]有值则表示需要改变tag名 33 | elif(mtype == str): 34 | self.payload = message['payload'] 35 | elif(mtype == dict): 36 | self.payload = message['payload'] 37 | else: 38 | self.payload = message['payload'] 39 | self.update_is_view_tag() 40 | 41 | #改变分割线的标签 42 | def update_is_view_tag(self): 43 | if LayoutView.view_registers in self.payload: 44 | LayoutView.message_tag = LayoutView.view_registers 45 | elif LayoutView.view_stack in self.payload: 46 | LayoutView.message_tag = LayoutView.view_stack 47 | elif LayoutView.view_code in self.payload: 48 | LayoutView.message_tag = LayoutView.view_code 49 | elif LayoutView.view_trace in self.payload: 50 | LayoutView.message_tag = LayoutView.view_trace 51 | else: 52 | LayoutView.message_tag = " send " 53 | 54 | #重置数据索引 55 | def reset_send_payload(self,message): 56 | mtype = type(message['payload']) 57 | if(mtype == list): 58 | self.payload = str(message['payload'][0]) ##这里使用数组的数据块 59 | elif(mtype == str): 60 | self.payload = message['payload'] 61 | elif(mtype == dict): 62 | self.payload = message['payload'] 63 | else: 64 | self.payload = message['payload'] 65 | 66 | #格式化显示tele格式的地址内存信息 67 | def show_tele_view(self): 68 | split = self.payload.split(LayoutView.tele_tag) 69 | for i in range(len(split)-1): 70 | data = split[i].split("│") 71 | if(int(data[2],16) == 0): #值为0 显示灰色 72 | update_show_text_view_style(data,LayoutView.color_format_value_grey,LayoutView.tele_tag) 73 | elif(self.stack_base != 0 and hex(int(data[2],16) >>16<<16) == self.stack_base): 74 | update_show_text_view_style(data,LayoutView.color_format_value_pink,LayoutView.tele_tag) 75 | elif(self.code_base != 0 and hex(int(data[2],16) >>16<<16) == self.code_base): 76 | update_show_text_view_style(data,LayoutView.color_format_value_red,LayoutView.tele_tag) 77 | else: 78 | update_show_text_view_style(data,LayoutView.color_format_value_bule,LayoutView.tele_tag) 79 | 80 | #格式化显示registers内存信息 81 | def show_registers_view(self): 82 | split = self.payload.split(LayoutView.register_tag) 83 | for i in range(len(split)-1): 84 | data = split[i].split("│") 85 | if(int(data[1],16) == 0): 86 | update_show_text_view_style(data,LayoutView.color_format_value_grey,LayoutView.register_tag) 87 | elif(self.stack_base != 0 and hex(int(data[1],16) >>16<<16) == self.stack_base): 88 | update_show_text_view_style(data,LayoutView.color_format_value_pink,LayoutView.register_tag) 89 | elif(self.code_base != 0 and hex(int(data[1],16) >>16<<16) == self.code_base): 90 | update_show_text_view_style(data,LayoutView.color_format_value_red,LayoutView.register_tag) 91 | else: 92 | update_show_text_view_style(data,LayoutView.color_format_value_bule,LayoutView.register_tag) 93 | 94 | def show_trace_view(self): 95 | split = self.payload.split(LayoutView.trace_tag) 96 | print(split) 97 | 98 | #格式化代码段视图 99 | def show_code_view(self): 100 | split = self.payload.split(LayoutView.code_tag) 101 | _json = json.loads(split[0]) 102 | offset = str(hex((_json["offset"]))).replace("0x","") 103 | result = dump_target_binary(_json["path"],_json['name'],LayoutView.code_show_row_number,offset) 104 | for i in range(len(result)): 105 | data = result[i].replace("\n","") 106 | if(i < int(LayoutView.code_show_row_number,10)): 107 | print(" 0x{0}".format(data)) 108 | elif(i == int(LayoutView.code_show_row_number,10)): 109 | print(" → \033[32m0x{0}\033[0m".format(data)) 110 | else: 111 | print(" \033[37m0x{0}\033[0m".format(data)) 112 | 113 | #检查是只是初始化值 114 | def check_is_init_segment_address(self): 115 | if LayoutView.init_segment_address_tag in self.payload: 116 | stack = self.payload.split(LayoutView.init_segment_address_tag)[0] 117 | code = self.payload.split(LayoutView.init_segment_address_tag)[1] 118 | LayoutView.view_code = self.payload.split(LayoutView.init_segment_address_tag)[2] 119 | self.step = self.payload.split(LayoutView.init_segment_address_tag)[3] 120 | self.stack_base = hex(int(stack,16) >> 16 << 16) 121 | self.code_base = hex(int(code,16) >> 16 << 16) 122 | return True 123 | else: 124 | return False 125 | 126 | 127 | 128 | #--------------------获取配置信息-------------------- 129 | def get_config_info(): 130 | with open('./style/config.json', 'r') as file: 131 | mjson = json.load(file) 132 | LayoutView.mjson= mjson 133 | LayoutView.end_line_len = mjson['end_line_len'] 134 | LayoutView.code_show_row_number= mjson['code_show_row_number'] 135 | LayoutView.view_stack = mjson['view_stack'] 136 | LayoutView.view_code = mjson['view_code'] 137 | LayoutView.view_trace = mjson['view_trace'] 138 | LayoutView.view_registers = mjson['view_registers'] 139 | 140 | LayoutView.clear_tag = mjson['clear_tag'] 141 | LayoutView.message_tag = mjson['message_tag'] 142 | LayoutView.tele_tag = mjson['tele_tag'] 143 | LayoutView.register_tag = mjson['register_tag'] 144 | LayoutView.code_tag = mjson['code_tag'] 145 | LayoutView.trace_tag = mjson['trace_tag'] 146 | LayoutView.init_segment_address_tag = mjson['init_segment_address_tag'] 147 | 148 | LayoutView.color_format_value_grey = mjson['color_format_value_grey'] 149 | LayoutView.color_format_value_red = mjson['color_format_value_red'] 150 | LayoutView.color_format_value_green = mjson['color_format_value_green'] 151 | LayoutView.color_format_value_yellow = mjson['color_format_value_yellow'] 152 | LayoutView.color_format_value_bule = mjson['color_format_value_bule'] 153 | LayoutView.color_format_value_pink = mjson['color_format_value_pink'] 154 | LayoutView.color_format_value_cyan = mjson['color_format_value_cyan'] 155 | 156 | LayoutView.wecome = """ 157 | _ _______________ _ ____ _______ __ __ __ 158 | | | /| / / __/ ___/ __ \/ |/ / |/ / __/ \ \/ /_ / / 159 | | |/ |/ / _// /__/ /_/ / / /|_/ / _/ \ / // / 160 | |__/|__/___/\___/\____/_/|_/_/ /_/___/ /_/\___/ 161 | """ 162 | LayoutView.banner = """ 163 | ¦ ¦ ¦ ¦ ¦ ¦ ¦__..--.._ 164 | ¦ ..... .--~ ..... `. 165 | .": "`-.. . .' ..-'" :". ` 166 | ` `._ ` _.'`"( `-"'`._ ' _.' ' 167 | ¦ ¦~~~ `. ~~~ 168 | ¦ ¦ ¦ ¦ .' 169 | ¦ ¦ ¦ ¦/ 170 | ¦ ¦ ¦ ( 171 | ¦ ¦ ¦ ¦^---' 172 | """ 173 | print("\033[31m{0}\033[0m".format(LayoutView.banner)) 174 | 175 | #获取目标源文件,进行反汇编代码获取 176 | def dump_target_binary(path,lib_name,row,offset): 177 | result = os.popen("./commond/get_target_binary.sh "+path+" "+lib_name + " "+row + " " + offset) 178 | return result.readlines() 179 | 180 | 181 | #显示头部颜色代表数据说明信息 182 | def show_head_view_tips_info_color(): 183 | print("[ Legend: \033[31m{0}\033[0m | \033[31m{1}\033[0m | \033[32m{2}\033[0m | \033[35m{3}\033[0m | \033[33m{4}\033[0m ]".format("Modified register","Code","Heap","Stack","String")) 184 | 185 | #改变文字的颜色 186 | def update_show_text_view_style(data,color,types): 187 | if(types == LayoutView.tele_tag): 188 | if(color == LayoutView.color_format_value_pink or color == LayoutView.color_format_value_red): 189 | print("\033[36m{0}\033[0m│+{1}: \033[{3}m{2}\033[0m → {4}".format(data[0],"0x%04x" % int(data[1],10),"0x%08x" % int(data[2],16),color,"0x%08x" % int(data[3],16))) 190 | else: 191 | print("\033[36m{0}\033[0m│+{1}: \033[{3}m{2}\033[0m".format(data[0],"0x%04x" % int(data[1],10),"0x%08x" % int(data[2],16),color)) 192 | elif(types == LayoutView.register_tag): 193 | if(color == LayoutView.color_format_value_pink or color == LayoutView.color_format_value_red): 194 | print("\033[31m${0}\033[0m : \033[{2}m{1}\033[0m → {3}".format("{:<3s}".format(data[0]),"0x%08x" % int(data[1],16),color,"0x%08x" % int(data[2],16))) 195 | else: 196 | print("\033[31m${0}\033[0m : \033[{2}m{1}\033[0m".format("{:<3s}".format(data[0]),"0x%08x" % int(data[1],16),color)) 197 | else: 198 | return 199 | --------------------------------------------------------------------------------