└── frida-trace.js /frida-trace.js: -------------------------------------------------------------------------------- 1 | // traceAddr(addr) 2 | // --------------------------------------------------------------------------------------- 3 | let moduleBase; 4 | let pre_regs = []; 5 | let infoMap = new Map(); 6 | let detailInsMap = new Map(); 7 | let regs_map = new Map(); 8 | 9 | function formatArm64Regs(context) { 10 | let regs = [] 11 | regs.push(context.x0); 12 | regs.push(context.x1); 13 | regs.push(context.x2); 14 | regs.push(context.x3); 15 | regs.push(context.x4); 16 | regs.push(context.x5); 17 | regs.push(context.x6); 18 | regs.push(context.x7); 19 | regs.push(context.x8); 20 | regs.push(context.x9); 21 | regs.push(context.x10); 22 | regs.push(context.x11); 23 | regs.push(context.x12); 24 | regs.push(context.x13); 25 | regs.push(context.x14); 26 | regs.push(context.x15); 27 | regs.push(context.x16); 28 | regs.push(context.x17); 29 | regs.push(context.x18); 30 | regs.push(context.x19); 31 | regs.push(context.x20); 32 | regs.push(context.x21); 33 | regs.push(context.x22); 34 | regs.push(context.x23); 35 | regs.push(context.x24); 36 | regs.push(context.x25); 37 | regs.push(context.x26); 38 | regs.push(context.x27); 39 | regs.push(context.x28); 40 | regs.push(context.fp); 41 | regs.push(context.lr); 42 | regs.push(context.sp); 43 | regs.push(context.pc); 44 | regs_map.set('x0', context.x0); 45 | regs_map.set('x1', context.x1); 46 | regs_map.set('x2', context.x2); 47 | regs_map.set('x3', context.x3); 48 | regs_map.set('x4', context.x4); 49 | regs_map.set('x5', context.x5); 50 | regs_map.set('x6', context.x6); 51 | regs_map.set('x7', context.x7); 52 | regs_map.set('x8', context.x8); 53 | regs_map.set('x9', context.x9); 54 | regs_map.set('x10', context.x10); 55 | regs_map.set('x11', context.x11); 56 | regs_map.set('x12', context.x12); 57 | regs_map.set('x13', context.x13); 58 | regs_map.set('x14', context.x14); 59 | regs_map.set('x15', context.x15); 60 | regs_map.set('x16', context.x16); 61 | regs_map.set('x17', context.x17); 62 | regs_map.set('x18', context.x18); 63 | regs_map.set('x19', context.x19); 64 | regs_map.set('x20', context.x20); 65 | regs_map.set('x21', context.x21); 66 | regs_map.set('x22', context.x22); 67 | regs_map.set('x23', context.x23); 68 | regs_map.set('x24', context.x24); 69 | regs_map.set('x25', context.x25); 70 | regs_map.set('x26', context.x26); 71 | regs_map.set('x27', context.x27); 72 | regs_map.set('x28', context.x28); 73 | regs_map.set('fp', context.fp); 74 | regs_map.set('lr', context.lr); 75 | regs_map.set('sp', context.sp); 76 | regs_map.set('pc', context.pc); 77 | return regs; 78 | } 79 | 80 | function getRegsString(index) { 81 | let reg; 82 | if (index === 31) { 83 | reg = "sp" 84 | } else { 85 | reg = "x" + index; 86 | } 87 | return reg; 88 | } 89 | 90 | function isRegsChange(context, ins) { 91 | let currentRegs = formatArm64Regs(context); 92 | let entity = {}; 93 | let logInfo = ""; 94 | // 打印寄存器信息 95 | for (let i = 0; i < 32; i++) { 96 | if (i === 30) { 97 | continue 98 | } 99 | let preReg = pre_regs[i] ? pre_regs[i] : 0x0; 100 | let currentReg = currentRegs[i]; 101 | if (Number(preReg) !== Number(currentReg)) { 102 | if (logInfo === "") { 103 | //尝试读取string 104 | let changeString = ""; 105 | try { 106 | let nativePointer = new NativePointer(currentReg); 107 | changeString = nativePointer.readCString(); 108 | } catch (e) { 109 | changeString = ""; 110 | } 111 | if (changeString !== "") { 112 | currentReg = currentReg + " (" + changeString + ")"; 113 | } 114 | logInfo = " " + getRegsString(i) + ": " + preReg + " --> " + currentReg + ", "; 115 | } else { 116 | logInfo = logInfo + " " + getRegsString(i) + ": " + preReg + " --> " + currentReg + ", "; 117 | } 118 | } 119 | } 120 | 121 | entity.info = logInfo; 122 | pre_regs = currentRegs; 123 | return entity; 124 | } 125 | 126 | function stalkerTraceRange(tid, base, size, offsetAddr) { 127 | Stalker.follow(tid, { 128 | transform: (iterator) => { 129 | const instruction = iterator.next(); 130 | const startAddress = instruction.address; 131 | const isModuleCode = startAddress.compare(base) >= 0 && 132 | startAddress.compare(base.add(size)) < 0; 133 | do { 134 | iterator.keep(); 135 | if (isModuleCode) { 136 | let lastInfo = '[' + ptr(instruction["address"] - base) + ']' + '\t' + ptr(instruction["address"]) + '\t' + (instruction+';').padEnd(30,' '); 137 | let address = instruction.address - base; 138 | detailInsMap.set(String(address), JSON.stringify(instruction)); 139 | infoMap.set(String(address), lastInfo); 140 | 141 | iterator.putCallout((context) => { 142 | let offset = Number(context.pc) - base; 143 | let detailIns = detailInsMap.get(String(offset)); 144 | 145 | let insinfo = infoMap.get(String(offset)); 146 | let entity = isRegsChange(context, detailIns); 147 | let info = insinfo + '\t#' + entity.info; 148 | 149 | let next_pc = context.pc.add(4); 150 | let insn_next = Instruction.parse(next_pc); 151 | insinfo = '[' + ptr(insn_next["address"] - base) + ']' + '\t' + ptr(insn_next["address"]) + '\t' + (insn_next + ';').padEnd(30,' '); 152 | let mnemonic = insn_next.mnemonic; 153 | if (mnemonic.startsWith("b.") || mnemonic === "b" || mnemonic === "bl" || mnemonic === "br" || mnemonic === "bx" || mnemonic.startsWith("bl") || mnemonic.startsWith("bx")) { 154 | info = info + '\n' + insinfo + '\t#'; 155 | } 156 | console.log(info); 157 | }); 158 | } 159 | } while (iterator.next() !== null); 160 | } 161 | }) 162 | } 163 | 164 | function traceAddr(addr,base_addr) { 165 | let moduleMap = new ModuleMap(); 166 | let targetModule = moduleMap.find(addr); 167 | 168 | console.log('-----start trace:', addr, '------'); 169 | moduleBase = base_addr; 170 | Interceptor.attach(addr, { 171 | onEnter: function(args) { 172 | this.tid = Process.getCurrentThreadId() 173 | stalkerTraceRange(this.tid,targetModule.base,targetModule.size,addr); 174 | }, 175 | onLeave: function(ret) { 176 | Stalker.unfollow(this.tid); 177 | Stalker.garbageCollect(); 178 | console.log('ret: ' + ret); 179 | console.log('-----end trace------'); 180 | } 181 | }); 182 | } 183 | // --------------------------------------------------------------------------------------- 184 | 185 | // traceNativeFunction 186 | // --------------------------------------------------------------------------------------- 187 | // 打印调用堆栈 188 | function traceFunction(addr, base_addr){ 189 | 190 | let moduleMap = new ModuleMap(); 191 | let base_size = moduleMap.find(addr).size; 192 | 193 | Interceptor.attach(addr, { 194 | onEnter: function(args) { 195 | this.tid = Process.getCurrentThreadId(); 196 | Stalker.follow(this.tid, { 197 | events: { 198 | call: true 199 | }, 200 | onReceive: function(events) { 201 | let allEvents = Stalker.parse(events); 202 | let first_depth = 0; 203 | let is_first = true; 204 | for (let i = 0; i < allEvents.length; i++) { 205 | // 调用的流程, location是哪里发生的调用, target是调用到了哪里 206 | if (allEvents[i][0] === "call") { 207 | let location = allEvents[i][1]; // 调用地址 208 | let target = allEvents[i][2]; // 目标地址 209 | let depth = allEvents[i][3]; // depth 210 | let description = ''; 211 | let space_num = ''; 212 | if (target.compare(base_addr) >= 0 && target.compare(base_addr.add(base_size)) < 0) { 213 | if (is_first) { 214 | is_first = false; 215 | first_depth = depth; 216 | } 217 | let location_description = ' [' + ptr(location).sub(base_addr) + '] '; 218 | let target_description = ' [' + ptr(target).sub(base_addr) + ']'; 219 | let length = (depth - first_depth); 220 | for (let j = 0; j < length; j++) { 221 | space_num = space_num + ' '; 222 | } 223 | description = space_num + target_description + '(' + location_description + ')' + ' -- ' + length; 224 | console.log(description); 225 | } 226 | } 227 | } 228 | } 229 | }) 230 | }, onLeave: function(retval) { 231 | Stalker.unfollow(this.tid); 232 | } 233 | }) 234 | } --------------------------------------------------------------------------------