├── EmuDumpedMem ├── EmuDumpedMem.java ├── README.md └── dump_memory.py ├── README.md ├── bypassVPNdetect.js ├── certAuthentication.js ├── dump_so.js ├── find_native_java_func_addr.js ├── frida_exception_break.js ├── hookEvent.js ├── hook_RegistNatives.js ├── hook_androlua_pro_string.js ├── hook_art.js ├── hook_dlopen.js ├── ida_suspend_other_thread.py ├── killapp.js ├── libmsaoaidsec_frida_bypass.js ├── listen_mem.js ├── lldb_find_module.py ├── look_db.py ├── myTrace.js ├── patch_exclusive_operate.py └── search_address_from_memory.js /EmuDumpedMem/EmuDumpedMem.java: -------------------------------------------------------------------------------- 1 | package xxxxxx; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.github.unidbg.AndroidEmulator; 6 | import com.github.unidbg.Module; 7 | import com.github.unidbg.arm.backend.*; 8 | import com.github.unidbg.linux.android.AndroidEmulatorBuilder; 9 | import com.github.unidbg.linux.android.AndroidResolver; 10 | import com.github.unidbg.linux.android.dvm.*; 11 | import com.github.unidbg.memory.Memory; 12 | import com.github.unidbg.memory.MemoryBlock; 13 | import com.github.unidbg.pointer.UnidbgPointer; 14 | import com.github.unidbg.utils.Inspector; 15 | import org.apache.commons.io.IOUtils; 16 | import org.apache.log4j.Level; 17 | import org.apache.log4j.Logger; 18 | import unicorn.Arm64Const; 19 | import unicorn.ArmConst; 20 | import unicorn.UnicornConst; 21 | 22 | import java.io.*; 23 | import java.nio.ByteBuffer; 24 | import java.nio.ByteOrder; 25 | import java.util.Arrays; 26 | import java.util.List; 27 | import java.util.concurrent.ConcurrentHashMap; 28 | import java.util.zip.DataFormatException; 29 | import java.util.zip.Inflater; 30 | 31 | public class EmuDumpedMem extends AbstractJni { 32 | private final AndroidEmulator emulator; 33 | private final VM vm; 34 | final Memory memory; 35 | final Backend backend; 36 | int UNICORN_PAGE_SIZE = 0x1000; 37 | // 创建一个全局的ConcurrentHashMap来存储内存块的指针和大小 38 | ConcurrentHashMap memoryMap = new ConcurrentHashMap<>(); 39 | 40 | EmuDumpedMem() { 41 | emulator = AndroidEmulatorBuilder.for64Bit() 42 | .setProcessName("com.ss.android.ugc.aweme") 43 | .addBackendFactory(new Unicorn2Factory(true)) 44 | .build(); 45 | memory = emulator.getMemory(); 46 | memory.setLibraryResolver(new AndroidResolver(23)); 47 | 48 | vm = emulator.createDalvikVM(); 49 | backend = emulator.getBackend(); 50 | vm.setJni(this); 51 | vm.setVerbose(true); 52 | Logger.getRootLogger().setLevel(Level.ALL); 53 | } 54 | 55 | private long align_page_down(long x){ 56 | return x & ~(UNICORN_PAGE_SIZE - 1); 57 | } 58 | private long align_page_up(long x){ 59 | return (x + UNICORN_PAGE_SIZE - 1) & ~(UNICORN_PAGE_SIZE - 1); 60 | } 61 | private void map_segment(long address, long size, int perms){ 62 | 63 | long mem_start = address; 64 | long mem_end = address + size; 65 | long mem_start_aligned = align_page_down(mem_start); 66 | long mem_end_aligned = align_page_up(mem_end); 67 | 68 | if (mem_start_aligned < mem_end_aligned){ 69 | emulator.getBackend().mem_map(mem_start_aligned, mem_end_aligned - mem_start_aligned, perms); 70 | } 71 | } 72 | 73 | private void load_context(String dump_dir) throws IOException, DataFormatException, IOException { 74 | backend.reg_write(Arm64Const.UC_ARM64_REG_CPACR_EL1, 0x300000L); 75 | backend.reg_write(Arm64Const.UC_ARM64_REG_TPIDR_EL0, 0x6ed66cf000L); // MRS 指令执行后第一个寄存器的值 76 | 77 | String context_file = dump_dir + "/" + "memory_dump.json"; 78 | InputStream is = new FileInputStream(context_file); 79 | String jsonTxt = IOUtils.toString(is, "UTF-8"); 80 | JSONObject context = JSONObject.parseObject(jsonTxt); 81 | JSONObject regs = context.getJSONObject("registers"); 82 | 83 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, Long.parseUnsignedLong(regs.getString("x0").substring(2), 16)); 84 | backend.reg_write(Arm64Const.UC_ARM64_REG_X1, Long.parseUnsignedLong(regs.getString("x1").substring(2), 16)); 85 | backend.reg_write(Arm64Const.UC_ARM64_REG_X2, Long.parseUnsignedLong(regs.getString("x2").substring(2), 16)); 86 | backend.reg_write(Arm64Const.UC_ARM64_REG_X3, Long.parseUnsignedLong(regs.getString("x3").substring(2), 16)); 87 | backend.reg_write(Arm64Const.UC_ARM64_REG_X4, Long.parseUnsignedLong(regs.getString("x4").substring(2), 16)); 88 | backend.reg_write(Arm64Const.UC_ARM64_REG_X5, Long.parseUnsignedLong(regs.getString("x5").substring(2), 16)); 89 | backend.reg_write(Arm64Const.UC_ARM64_REG_X6, Long.parseUnsignedLong(regs.getString("x6").substring(2), 16)); 90 | backend.reg_write(Arm64Const.UC_ARM64_REG_X7, Long.parseUnsignedLong(regs.getString("x7").substring(2), 16)); 91 | backend.reg_write(Arm64Const.UC_ARM64_REG_X8, Long.parseUnsignedLong(regs.getString("x8").substring(2), 16)); 92 | backend.reg_write(Arm64Const.UC_ARM64_REG_X9, Long.parseUnsignedLong(regs.getString("x9").substring(2), 16)); 93 | backend.reg_write(Arm64Const.UC_ARM64_REG_X10, Long.parseUnsignedLong(regs.getString("x10").substring(2), 16)); 94 | backend.reg_write(Arm64Const.UC_ARM64_REG_X11, Long.parseUnsignedLong(regs.getString("x11").substring(2), 16)); 95 | backend.reg_write(Arm64Const.UC_ARM64_REG_X12, Long.parseUnsignedLong(regs.getString("x12").substring(2), 16)); 96 | backend.reg_write(Arm64Const.UC_ARM64_REG_X13, Long.parseUnsignedLong(regs.getString("x13").substring(2), 16)); 97 | backend.reg_write(Arm64Const.UC_ARM64_REG_X14, Long.parseUnsignedLong(regs.getString("x14").substring(2), 16)); 98 | backend.reg_write(Arm64Const.UC_ARM64_REG_X15, Long.parseUnsignedLong(regs.getString("x15").substring(2), 16)); 99 | backend.reg_write(Arm64Const.UC_ARM64_REG_X16, Long.parseUnsignedLong(regs.getString("x16").substring(2), 16)); 100 | backend.reg_write(Arm64Const.UC_ARM64_REG_X17, Long.parseUnsignedLong(regs.getString("x17").substring(2), 16)); 101 | backend.reg_write(Arm64Const.UC_ARM64_REG_X18, Long.parseUnsignedLong(regs.getString("x18").substring(2), 16)); 102 | backend.reg_write(Arm64Const.UC_ARM64_REG_X19, Long.parseUnsignedLong(regs.getString("x19").substring(2), 16)); 103 | backend.reg_write(Arm64Const.UC_ARM64_REG_X20, Long.parseUnsignedLong(regs.getString("x20").substring(2), 16)); 104 | backend.reg_write(Arm64Const.UC_ARM64_REG_X21, Long.parseUnsignedLong(regs.getString("x21").substring(2), 16)); 105 | backend.reg_write(Arm64Const.UC_ARM64_REG_X22, Long.parseUnsignedLong(regs.getString("x22").substring(2), 16)); 106 | backend.reg_write(Arm64Const.UC_ARM64_REG_X23, Long.parseUnsignedLong(regs.getString("x23").substring(2), 16)); 107 | backend.reg_write(Arm64Const.UC_ARM64_REG_X24, Long.parseUnsignedLong(regs.getString("x24").substring(2), 16)); 108 | backend.reg_write(Arm64Const.UC_ARM64_REG_X25, Long.parseUnsignedLong(regs.getString("x25").substring(2), 16)); 109 | backend.reg_write(Arm64Const.UC_ARM64_REG_X26, Long.parseUnsignedLong(regs.getString("x26").substring(2), 16)); 110 | backend.reg_write(Arm64Const.UC_ARM64_REG_X27, Long.parseUnsignedLong(regs.getString("x27").substring(2), 16)); 111 | backend.reg_write(Arm64Const.UC_ARM64_REG_X28, Long.parseUnsignedLong(regs.getString("x28").substring(2), 16)); 112 | 113 | backend.reg_write(Arm64Const.UC_ARM64_REG_FP, Long.parseUnsignedLong(regs.getString("fp").substring(2), 16)); 114 | backend.reg_write(Arm64Const.UC_ARM64_REG_LR, Long.parseUnsignedLong(regs.getString("lr").substring(2), 16)); 115 | backend.reg_write(Arm64Const.UC_ARM64_REG_SP, Long.parseUnsignedLong(regs.getString("sp").substring(2), 16)); 116 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, Long.parseUnsignedLong(regs.getString("pc").substring(2), 16)); 117 | backend.reg_write(ArmConst.UC_ARM_REG_CPSR, Long.parseUnsignedLong(regs.getString("cpsr").substring(2), 16)); 118 | 119 | 120 | JSONArray segments = context.getJSONArray("segments"); 121 | for (int i = 0; i < segments.size(); i++) { 122 | JSONObject segment = segments.getJSONObject(i); 123 | String path = segment.getString("name"); 124 | long start = segment.getLong("start"); 125 | long end = segment.getLong("end"); 126 | String content_file = segment.getString("content_file"); 127 | JSONObject permissions = segment.getJSONObject("permissions"); 128 | int perms = 0; 129 | if (permissions.getBoolean("r")){ 130 | perms |= UnicornConst.UC_PROT_READ; 131 | } 132 | if (permissions.getBoolean("w")){ 133 | perms |= UnicornConst.UC_PROT_WRITE; 134 | } 135 | if (permissions.getBoolean("x")){ 136 | perms |= UnicornConst.UC_PROT_EXEC; 137 | } 138 | 139 | String[] paths = path.split("/"); 140 | String module_name = paths[paths.length - 1]; 141 | 142 | List white_list = Arrays.asList(new String[]{"libxxxxx.so", "libc.so", "[anon:stack_and_tls:19943]", "[anon:scudo:primary]", "[anon:.bss]"}); 143 | if (white_list.contains(module_name)){ 144 | int size = (int)(end - start); 145 | 146 | map_segment(start, size, perms); 147 | String content_file_path = dump_dir + "/" + content_file; 148 | 149 | File content_file_f = new File(content_file_path); 150 | if (content_file_f.exists()){ 151 | InputStream content_file_is = new FileInputStream(content_file_path); 152 | byte[] content_file_buf = IOUtils.toByteArray(content_file_is); 153 | 154 | // zlib解压 155 | Inflater decompresser = new Inflater(); 156 | decompresser.setInput(content_file_buf, 0, content_file_buf.length); 157 | byte[] result = new byte[size]; 158 | int resultLength = decompresser.inflate(result); 159 | decompresser.end(); 160 | 161 | backend.mem_write(start, result); 162 | } 163 | else { 164 | System.out.println("not exists path=" + path); 165 | byte[] fill_mem = new byte[size]; 166 | Arrays.fill( fill_mem, (byte) 0 ); 167 | backend.mem_write(start, fill_mem); 168 | } 169 | 170 | } 171 | } 172 | } 173 | 174 | private void impl_func() { 175 | backend.hook_add_new(new CodeHook() { 176 | @Override 177 | public void hook(Backend backend, long address, int size, Object user) { 178 | long module_base = 0x6ed94e4458L - 0x66458L; 179 | // 解决三方 so 调用错误 180 | // call libc.so free 181 | if (address == module_base + 0x2FAE0) { 182 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 183 | // 从map中去掉 184 | int ptr = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).intValue(); 185 | memoryMap.remove(ptr); 186 | } 187 | // call libc.so malloc 188 | if (address == module_base + 0x2FB80) { 189 | int msize = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).intValue(); 190 | MemoryBlock block = emulator.getMemory().malloc(msize, true); 191 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, block.getPointer().toIntPeer()); 192 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 193 | // 将分配的内存块的指针和大小存入map中 194 | memoryMap.put(block.getPointer().toIntPeer(), msize); 195 | } 196 | // call libc.so realloc 197 | if (address == module_base + 0x2FD80) { 198 | // 获取realloc的参数:ptr和new_size 199 | long ptrAddress = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).longValue(); 200 | int newSize = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).intValue(); 201 | 202 | // 获取原始内存块的大小(这里假设你知道如何获取原始大小,或者你有其他方式来管理内存) 203 | int originalSize = memoryMap.getOrDefault((int)ptrAddress, 1024); 204 | 205 | // 如果新大小大于原始大小,扩展内存块 206 | if (newSize > originalSize) { 207 | // 分配新的内存块 208 | MemoryBlock newBlock = emulator.getMemory().malloc(newSize, true); 209 | // 复制原始数据到新块 210 | byte[] buffer = new byte[originalSize]; 211 | UnidbgPointer.pointer(emulator, ptrAddress).read(0, buffer, 0, originalSize); 212 | newBlock.getPointer().write(0, buffer, 0, originalSize); 213 | // 释放原始内存块 214 | memoryMap.remove((int)ptrAddress); 215 | // 将分配的内存块的指针和大小存入map中 216 | memoryMap.put(newBlock.getPointer().toIntPeer(), newSize); 217 | // 更新指针 218 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, newBlock.getPointer().toUIntPeer()); 219 | } else { 220 | // 如果新大小小于或等于原始大小,我们只是返回原始指针 221 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, ptrAddress); 222 | } 223 | 224 | // 使程序跳转到lr寄存器,继续执行 225 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 226 | } 227 | // call libc.so strndup 228 | if (address == module_base + 0x30170) { 229 | // 获取strndup的参数:src字符串和最大长度n 230 | UnidbgPointer srcPointer = emulator.getContext().getPointerArg(0); 231 | int n = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).intValue(); 232 | 233 | // 读取src字符串的前n个字节 234 | byte[] bytes = new byte[n]; 235 | srcPointer.read(0, bytes, 0, n); 236 | 237 | // 找到字符串的实际结尾,因为C字符串以null字节结尾 238 | int actualLength = 0; 239 | for (; actualLength < n; actualLength++) { 240 | if (bytes[actualLength] == 0) { 241 | break; 242 | } 243 | } 244 | 245 | // 分配新的内存块来存储复制的字符串,并把字符串复制进去 246 | MemoryBlock block = emulator.getMemory().malloc(actualLength + 1, true); 247 | block.getPointer().write(0, bytes, 0, actualLength); 248 | // 确保字符串以null字节结尾 249 | backend.mem_write(block.getPointer().toIntPeer() + actualLength, new byte[]{0}); 250 | 251 | // 返回新分配的内存块的地址 252 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, block.getPointer().toUIntPeer()); 253 | 254 | // 将分配的内存块的指针和大小存入map中 255 | memoryMap.put(block.getPointer().toIntPeer(), actualLength + 1); 256 | 257 | Inspector.inspect("[strndup]addr:0x" + Integer.toHexString(block.getPointer().toIntPeer()), bytes, actualLength + 1); 258 | 259 | // 使程序跳转到lr寄存器,继续执行 260 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 261 | } 262 | // call libc.so gettimeofday 263 | if (address == module_base + 0x2F8B0) { 264 | UnidbgPointer tv_ptr = emulator.getContext().getPointerArg(0); 265 | ByteBuffer tv = ByteBuffer.allocate(8); 266 | tv.order(ByteOrder.LITTLE_ENDIAN); 267 | long timestamp = System.currentTimeMillis(); 268 | tv.putLong(timestamp); 269 | byte[] data = tv.array(); 270 | tv_ptr.write(0,data,0,8); 271 | System.out.println("[gettimeofday] time:" + timestamp); 272 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 273 | } 274 | // call libc.so _cxa_atexit 275 | if (address == module_base + 0x301C0) { 276 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 277 | } 278 | 279 | // call libc.so pthread_once 280 | if (address == module_base + 0x2FC60) { 281 | int ONCE_INITIALIZATION_NOT_YET_STARTED = 0; 282 | int ONCE_INITIALIZATION_UNDERWAY = 1; 283 | int ONCE_INITIALIZATION_COMPLETE = 2; 284 | long once_control_ptr = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).longValue(); 285 | UnidbgPointer uni_once_control_ptr = UnidbgPointer.pointer(emulator, once_control_ptr); 286 | int old_value = uni_once_control_ptr.getInt(0); 287 | if (old_value == ONCE_INITIALIZATION_COMPLETE) { 288 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 289 | } else { 290 | System.out.println("请实现 pthread_once 没有初始化的情况。"); 291 | } 292 | } 293 | 294 | // call libc.so calloc 295 | if (address == module_base + 0x2FB50) { 296 | // 获取calloc的参数:元素数量和每个元素的大小 297 | int num = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).intValue(); 298 | int msize = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).intValue(); 299 | 300 | // 计算总的分配大小 301 | int totalSize = num * msize; 302 | 303 | // 分配内存块,并初始化为零 304 | MemoryBlock block = emulator.getMemory().malloc(totalSize, true); 305 | block.getPointer().write(0, new byte[totalSize], 0, totalSize); 306 | 307 | // 将分配的内存块地址放入x0寄存器 308 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, block.getPointer().toUIntPeer()); 309 | 310 | // 将分配的内存块的指针和大小存入map中 311 | memoryMap.put(block.getPointer().toIntPeer(), totalSize); 312 | 313 | // 跳转到返回地址,继续执行程序 314 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_LR).longValue()); 315 | } 316 | } 317 | 318 | @Override 319 | public void onAttach(UnHook unHook) { 320 | 321 | } 322 | 323 | @Override 324 | public void detach() { 325 | 326 | } 327 | }, 1, 0, emulator); 328 | } 329 | 330 | // 有些地址是 0xb4开头,没有完整的内存管理,会报unmap的错误 331 | private void fix_ptr_addr() { 332 | backend.hook_add_new(new CodeHook() { 333 | @Override 334 | public void hook(Backend backend, long address, int size, Object user) { 335 | if (address == 0x6ed94d4760L) { 336 | long addr = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).longValue(); 337 | addr &= 0xffffffffffL; 338 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, addr); 339 | } 340 | } 341 | 342 | @Override 343 | public void onAttach(UnHook unHook) { 344 | 345 | } 346 | 347 | @Override 348 | public void detach() { 349 | 350 | } 351 | }, 1, 0, emulator); 352 | } 353 | 354 | // 由于是dump的内存,所以 jobject 的引用 unidbg 是没有管理的。 355 | private void fix_jni_ctx() { 356 | backend.hook_add_new(new CodeHook() { 357 | @Override 358 | public void hook(Backend backend, long address, int size, Object user) { 359 | if (address == 0x6ed95a61e4L) { 360 | int jobj_index = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).intValue(); 361 | if (jobj_index == 0x38c6) { 362 | DvmClass AwemeHostApplication = vm.resolveClass("xxxxxxxx", new DvmClass[0]); 363 | int index = vm.addGlobalObject(AwemeHostApplication); 364 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, index); 365 | System.out.println("[GetObjectClass] xxxxxxxx@0x" + Integer.toHexString(index)); 366 | // 同时替换掉原先的 jobj 367 | DvmObject AwemeHostApplication_obj = AwemeHostApplication.newObject(null); 368 | int index2 = vm.addGlobalObject(AwemeHostApplication_obj); 369 | backend.reg_write(Arm64Const.UC_ARM64_REG_X22, index2); 370 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_PC).longValue() + 4); 371 | } 372 | } 373 | } 374 | 375 | @Override 376 | public void onAttach(UnHook unHook) { 377 | 378 | } 379 | 380 | @Override 381 | public void detach() { 382 | 383 | } 384 | }, 1, 0, emulator); 385 | } 386 | 387 | private void call_func() throws FileNotFoundException { 388 | // 有一个全局变量是 JavaVM * 389 | UnidbgPointer jvm = (UnidbgPointer) vm.getJavaVM(); 390 | long module_base = 0x6ed94e4458L - 0x66458L; 391 | 392 | ByteBuffer buffer = ByteBuffer.allocate(8); // 分配8字节的缓冲区 393 | buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置为小端字节序 394 | buffer.putLong(jvm.peer); // 将long值写入缓冲区 395 | byte[] byteArray = buffer.array(); // 获取字节数组 396 | 397 | backend.mem_write(module_base + 0x2877C0, byteArray); 398 | 399 | // 需要将 maxLengthLibraryName = memory.getMaxLengthLibraryName().length(); 改为 maxLengthLibraryName = 32; 400 | // emulator.traceCode(); 401 | // 需要将 int maxLength = emulator.getMemory().getMaxLengthLibraryName().length(); 改为 maxLength = 16; 402 | // emulator.attach().addBreakPoint(0x6ed94e460cL); 403 | long ctx_addr = backend.reg_read(Arm64Const.UC_ARM64_REG_PC).longValue(); 404 | Number result = Module.emulateFunction(emulator, ctx_addr); 405 | } 406 | 407 | public static void main(String[] args) throws Exception { 408 | EmuDumpedMem emuDumpedMem = new EmuDumpedMem(); 409 | emuDumpedMem.impl_func(); 410 | emuDumpedMem.fix_ptr_addr(); 411 | emuDumpedMem.fix_jni_ctx(); 412 | emuDumpedMem.load_context("your/dumped/path"); 413 | emuDumpedMem.call_func(); 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /EmuDumpedMem/README.md: -------------------------------------------------------------------------------- 1 | ## EmuDumpedMem 2 | 3 | 该项目结合了内存 dump 和 unidbg 的功能特点,可以在程序运行的某个节点保存内存上下文,然后在 unidbg 中恢复程序执行的上下文,可以解决参数是复杂结构体难以构造的问题。 4 | 5 | ## 使用 6 | 7 | ### 1. 内存 dump 8 | 9 | 可以使用 stackplz 的 uprobe hook + SIGSTOP,让程序在指定的位置中断。 10 | 11 | ``` 12 | ./stackplz -n com.ss.android.ugc.aweme -w 0x66454 --lib libmetasec_ml.so --kill SIGSTOP 13 | ``` 14 | 15 | 在命令行中使用 kill -SIGCONT {{pid}} 命令恢复程序运行。 16 | 17 | 使用 lldb 连接手机的 lldb-server,运行 dump 内存的脚本。 18 | 19 | ``` 20 | 安卓手机客户端 21 | ./lldb-server platform --listen "*:1234" --server 22 | 23 | pc客户端 24 | export ANDROID_PLATFORM_LOCAL_PORT=1234 25 | export ANDROID_PLATFORM_LOCAL_GDB_PORT=1234 26 | lldb 27 | (lldb) platform select remote-android 28 | (lldb) platform connect connect://:1234 29 | (lldb) attach {{pid}} 30 | (lldb) t {{tid}} 31 | (lldb) command script import xxxxxx/dump_memory.py 32 | (lldb) dump_memory 33 | (lldb) process detach 34 | ``` 35 | 36 | ### 2. Unidbg 加载内存 37 | 38 | 调用装载内存函数 39 | 40 | ``` 41 | emuDumpedMem.load_context("your/dumped/path"); 42 | ``` 43 | 44 | 替换 UC_ARM64_REG_TPIDR_EL0 的值,这个需要等 MRS 指令执行后,获取第一个寄存器的值 45 | 46 | ``` 47 | backend.reg_write(Arm64Const.UC_ARM64_REG_TPIDR_EL0, 0x6ed66cf000L); // MRS 指令执行后第一个寄存器的值 48 | ``` 49 | 50 | 填写需要加载的内存段,这里最开始先写目标 so 和 libc.so,其他的内存段需要程序运行后报错进行确认。一般在目标 so 的指令执行时,会出现 UNMAP 的错误,如果不是目标 so 的指令出现的错误,一般是因为调用的第三方函数,这时就要手动实现了。 51 | 52 | ``` 53 | List white_list = Arrays.asList(new String[]{"libxxx.so", "libc.so", "[anon:stack_and_tls:19943]", "[anon:scudo:primary]", "[anon:.bss]"}); 54 | ``` 55 | 56 | 修改 impl_func 函数中的 module_base,计算方法是内存中的第一条指令的地址减去对应的偏移地址。 57 | 58 | ``` 59 | long module_base = 0x6ed94e4458L - 0x66458L; 60 | ``` 61 | 62 | 修改 impl_func 函数中的方法偏移,偏移寻找方法是根据方法名称在ida 的 import 中找到对应的函数,然后分局交叉引用找到对应的跳板函数的第一条指令的地址。 63 | 64 | ``` 65 | // call libc.so free 66 | if (address == module_base + 0x2FAE0) { 67 | ``` 68 | 69 | 修改或禁用 fix_ptr_addr 函数,因为有些内存的地址类似于0xb400006e875a9c7e,这种 unidbg 执行时会报错,如果没有那么紧用掉 fix_ptr_addr 函数的调用。 70 | 71 | ``` 72 | if (address == 0x6ed94d4760L) { 73 | long addr = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).longValue(); 74 | addr &= 0xffffffffffL; 75 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, addr); 76 | } 77 | ``` 78 | 79 | 修改或禁用 fix_jni_ctx 函数,因为 dump 的内存中 jobject 存放的是一个引用,在 unidbg 模拟执行时是不知道 jobject 引用的具体实例的,所以需要手动修复。 80 | 81 | ``` 82 | if (address == 0x6ed95a61e4L) { 83 | int jobj_index = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).intValue(); 84 | if (jobj_index == 0x38c6) { 85 | DvmClass AwemeHostApplication = vm.resolveClass("com.ss.android.ugc.aweme.app.host.AwemeHostApplication", new DvmClass[0]); 86 | int index = vm.addGlobalObject(AwemeHostApplication); 87 | backend.reg_write(Arm64Const.UC_ARM64_REG_X0, index); 88 | System.out.println("[GetObjectClass] com.xxx.xxx@0x" + Integer.toHexString(index)); 89 | // 同时替换掉原先的 jobj 90 | DvmObject AwemeHostApplication_obj = AwemeHostApplication.newObject(null); 91 | int index2 = vm.addGlobalObject(AwemeHostApplication_obj); 92 | backend.reg_write(Arm64Const.UC_ARM64_REG_X22, index2); 93 | backend.reg_write(Arm64Const.UC_ARM64_REG_PC, backend.reg_read(Arm64Const.UC_ARM64_REG_PC).longValue() + 4); 94 | } 95 | } 96 | ``` 97 | 98 | 最后自己实现 call_func 函数进行模拟执行。 99 | 100 | # Ref 101 | 102 | 本项目参考了以下项目和文章: 103 | 104 | 1. [dump内存与模拟执行(二)——编写dump脚本](https://blog.seeflower.dev/archives/166/) 105 | 2. [dump内存与模拟执行(三)——实践dump上下文](https://blog.seeflower.dev/archives/169/) 106 | 3. [dump内存与模拟执行(四)——接入unidbg](https://blog.seeflower.dev/archives/170/) 107 | 4. [dump内存与模拟执行(五)——实战复杂样本](https://blog.seeflower.dev/archives/171/) 108 | 109 | -------------------------------------------------------------------------------- /EmuDumpedMem/dump_memory.py: -------------------------------------------------------------------------------- 1 | import lldb 2 | import json 3 | import hashlib 4 | import zlib 5 | import os 6 | from datetime import datetime 7 | from pathlib import Path 8 | import sys 9 | 10 | 11 | def dump_arch_info(target): 12 | triple = target.GetTriple() 13 | print(f'[dump_arch_info] triple => {triple}') 14 | arch, vendor, sys, abi = triple.split('-') 15 | if arch == 'aarch64' or arch == 'arm64': 16 | return 'arm64le' 17 | elif arch == 'aarch64_be': 18 | return 'arm64be' 19 | elif arch == 'armeb': 20 | return 'armbe' 21 | elif arch == 'arm': 22 | return 'armle' 23 | else: 24 | return '' 25 | 26 | def dump_regs(frame): 27 | regs = {} 28 | registers = None 29 | for registers in frame.GetRegisters(): 30 | for register in registers: 31 | register_name = register.GetName() 32 | register.SetFormat(lldb.eFormatHex) 33 | register_value = register.GetValue() 34 | if register_value is None: 35 | register_value = "N/A" # 或者其他表示无法读取的值 36 | print(f"Can't read {register_name}") 37 | regs[register_name] = register_value 38 | print(f'regs => {json.dumps(regs, ensure_ascii=False, indent=4)}') 39 | return regs 40 | 41 | def dump_memory_info(target): 42 | print('start dump_memory_info') 43 | sections = [] 44 | for module in target.module_iter(): 45 | for section in module.section_iter(): 46 | module_name = module.file.GetFilename() 47 | start, end, size, name = get_section_info(target, section) 48 | section_info = { 49 | 'module': module_name, 50 | 'start': start, 51 | 'end': end, 52 | 'size': size, 53 | 'name': name, 54 | } 55 | print(f'Appending: {name}') 56 | sections.append(section_info) 57 | return sections 58 | 59 | def get_section_info(target, section): 60 | start_addr = section.GetLoadAddress(target) 61 | file_addr = section.GetFileAddress() 62 | size = section.GetByteSize() 63 | name = section.GetName() 64 | return start_addr, file_addr + start_addr, size, name 65 | 66 | def _dump_memory(process, dump_path, black_list, max_seg_size): 67 | print('start dump memory') 68 | memory_list = [] 69 | mem_info = lldb.SBMemoryRegionInfo() 70 | start_addr = -1 71 | next_region_addr = 0 72 | while next_region_addr > start_addr: 73 | err = process.GetMemoryRegionInfo(next_region_addr, mem_info) 74 | if not err.Success(): 75 | print(f'GetMemoryRegionInfo failed, {err}, break') 76 | break 77 | next_region_addr = mem_info.GetRegionEnd() 78 | if next_region_addr >= sys.maxsize: 79 | print(f'next_region_addr:0x{next_region_addr:x} >= sys.maxsize, break') 80 | break 81 | start = mem_info.GetRegionBase() 82 | end = mem_info.GetRegionEnd() 83 | region_name = 'UNKNOWN' 84 | if mem_info.IsMapped(): 85 | name = mem_info.GetName() if mem_info.GetName() else '' 86 | mem_info_obj = { 87 | 'start': start, 88 | 'end': end, 89 | 'name': name, 90 | 'permissions': { 91 | 'r': mem_info.IsReadable(), 92 | 'w': mem_info.IsWritable(), 93 | 'x': mem_info.IsExecutable(), 94 | }, 95 | 'content_file': '', 96 | } 97 | memory_list.append(mem_info_obj) 98 | for seg_info in memory_list: 99 | try: 100 | start_addr = seg_info['start'] 101 | end_addr = seg_info['end'] 102 | region_name = seg_info['name'] 103 | permissions = seg_info['permissions'] 104 | if not permissions['r']: 105 | print(f'Skip dump {region_name} permissions => {permissions}') 106 | continue 107 | predicted_size = end_addr - start_addr 108 | if predicted_size > max_seg_size: 109 | print(f'Skip dump {region_name} size:0x{predicted_size:x}') 110 | continue 111 | skip_dump = False 112 | for rule in black_list['startswith']: 113 | if region_name.startswith(rule): 114 | skip_dump = True 115 | print(f'Skip dump {region_name} hit startswith rule:{rule}') 116 | if skip_dump: continue 117 | for rule in black_list['endswith']: 118 | if region_name.endswith(rule): 119 | skip_dump = True 120 | print(f'Skip dump {region_name} hit endswith rule:{rule}') 121 | if skip_dump: continue 122 | for rule in black_list['includes']: 123 | if rule in region_name: 124 | skip_dump = True 125 | print(f'Skip dump {region_name} hit includes rule:{rule}') 126 | if skip_dump: continue 127 | ts = datetime.now() 128 | err = lldb.SBError() 129 | seg_content = process.ReadMemory(start_addr, predicted_size, err) 130 | tm = (datetime.now() - ts).total_seconds() 131 | if seg_content is None: 132 | print(f'Segment empty: @0x{start_addr:016x} {region_name} => {err}') 133 | else: 134 | print(f'Dumping @0x{start_addr:016x} {tm:.2f}s size:0x{len(seg_content):x}: {region_name} {permissions}') 135 | compressed_seg_content = zlib.compress(seg_content) 136 | md5_sum = hashlib.md5(compressed_seg_content).hexdigest() + '.bin' 137 | seg_info['content_file'] = md5_sum 138 | (dump_path / md5_sum).write_bytes(compressed_seg_content) 139 | except Exception as e: 140 | print(f'Exception reading segment {region_name}', exc_info=e) 141 | return memory_list 142 | 143 | def __lldb_init_module(debugger, internal_dict): 144 | debugger.HandleCommand('command script add -o -f dump_memory.dump_memory dump_memory') 145 | print("Memory dump command added successfully.") 146 | 147 | def dump_memory(debugger, command, exe_ctx, result, internal_dict): 148 | print("Starting memory dump process...") 149 | target = exe_ctx.GetTarget() 150 | process = exe_ctx.GetProcess() 151 | 152 | arch_long = dump_arch_info(target) 153 | print(f"Architecture: {arch_long}") 154 | 155 | frame = process.GetSelectedThread().GetSelectedFrame() 156 | regs = dump_regs(frame) 157 | 158 | sections = dump_memory_info(target) 159 | 160 | dump_path = Path('your/dump/path') # Set your dump path here 161 | black_list = { 162 | 'startswith': ['/dev', '/system/fonts', '/dmabuf'], 163 | 'endswith': ['(deleted)', '.apk', '.odex', '.vdex', '.dex', '.jar', '.art', '.oat', '.art]'], 164 | 'includes': [], 165 | } 166 | max_seg_size = 64 * 1024 * 1024 # 64MB 167 | segments = _dump_memory(process, dump_path, black_list, max_seg_size) 168 | 169 | dump_info = { 170 | 'architecture': arch_long, 171 | 'registers': regs, 172 | 'sections': sections, 173 | 'segments': segments, 174 | } 175 | 176 | print("Saving memory dump to file...") 177 | try: 178 | with open(dump_path / 'memory_dump.json', 'w') as f: 179 | json.dump(dump_info, f, indent=4) 180 | print("Memory dump saved successfully.") 181 | except Exception as e: 182 | print(f"Failed to save memory dump: {e}") 183 | 184 | result.SetStatus(lldb.eReturnStatusSuccessFinishNoResult) 185 | print("Memory dump process completed.") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyHooker 2 | 搜集平时学习工作中常用的 frida/ida/lldb 脚本 3 | -------------------------------------------------------------------------------- /bypassVPNdetect.js: -------------------------------------------------------------------------------- 1 | function bypassVPNDetect(){ 2 | Java.perform(function(){ 3 | var NetworkInterface = Java.use("java.net.NetworkInterface") 4 | NetworkInterface.getAll.implementation = function(){ 5 | var nis = this.getAll() 6 | console.log("call getAll function !!!") 7 | nis.forEach(function(ni){ 8 | if (ni.name.value.indexOf("tun0")>=0 || ni.name.value.indexOf("ppp0")>=0 || 9 | ni.displayName.value.indexOf("tun0")>=0 || ni.displayName.value.indexOf("ppp0")>=0){ 10 | ni.name.value = "xxxx" 11 | ni.displayName.value = "xxxx" 12 | } 13 | }) 14 | return nis 15 | } 16 | 17 | var can_hook = false 18 | var ConnectivityManager = Java.use("android.net.ConnectivityManager"); 19 | ConnectivityManager.getNetworkInfo.overload('int').implementation = function(){ 20 | if(arguments[0] == 17){ 21 | can_hook = true 22 | } 23 | var ret = this.getNetworkInfo(arguments[0]) 24 | return ret 25 | } 26 | 27 | var NetworkInfo = Java.use("android.net.NetworkInfo") 28 | NetworkInfo.isConnected.implementation = function(){ 29 | let ret = this.isConnected() 30 | if(can_hook){ 31 | ret = false 32 | can_hook = false 33 | console.log("call isConnected function !!!") 34 | } 35 | return ret 36 | } 37 | 38 | var NetworkCapabilities = Java.use("android.net.NetworkCapabilities") 39 | NetworkCapabilities.hasTransport.implementation = function(){ 40 | var ret = this.hasTransport(arguments[0]) 41 | if(arguments[0] == 4){ 42 | console.log("call hasTransport function !!!") 43 | ret = false 44 | } 45 | return ret 46 | } 47 | 48 | NetworkCapabilities.transportNameOf.overload('int').implementation = function(){ 49 | var ret = this.transportNameOf(arguments[0]) 50 | if(ret.indexOf("VPN") >= 0){ 51 | ret = "WIFI" 52 | } 53 | return ret; 54 | } 55 | }) 56 | } 57 | 58 | setImmediate(bypassVPNDetect) -------------------------------------------------------------------------------- /certAuthentication.js: -------------------------------------------------------------------------------- 1 | function hook_hasOnlyVpnAndAppsTrustAnchors() { 2 | Java.perform(function () { 3 | var cls = Java.use("com.android.certinstaller.CredentialHelper") 4 | cls.hasOnlyVpnAndAppsTrustAnchors.implementation = function () { 5 | var ret = this.hasOnlyVpnAndAppsTrustAnchors.apply(this, arguments) 6 | console.log("The result is " + ret) 7 | ret = false 8 | return ret 9 | } 10 | }) 11 | } 12 | 13 | function main() { 14 | hook_hasOnlyVpnAndAppsTrustAnchors() 15 | } 16 | setImmediate(main) -------------------------------------------------------------------------------- /dump_so.js: -------------------------------------------------------------------------------- 1 | function dump_so(so_name) { 2 | var libso = Process.findModuleByName(so_name); 3 | if (libso == null) { 4 | return -1; 5 | } 6 | Memory.protect(ptr(libso.base), libso.size, 'rwx'); 7 | var libso_buffer = ptr(libso.base).readByteArray(libso.size); 8 | var f = new File("/data/data/com.mdcg.a360/libjiagu_64.so", "wb") // 更改保存路径 9 | f.write(libso_buffer) 10 | f.flush() 11 | f.close() 12 | console.log("success dump so, base:" + libso.base) 13 | } 14 | -------------------------------------------------------------------------------- /find_native_java_func_addr.js: -------------------------------------------------------------------------------- 1 | var offset = -1 2 | //这个函数是用来做偏移矫正的 3 | function get_android_api_jnioffset() { 4 | 5 | if(offset != -1){ 6 | return offset 7 | } 8 | var native_addr = Module.findExportByName("libandroid_runtime.so", "_Z32android_os_Process_getUidForNameP7_JNIEnvP8_jobjectP8_jstring") 9 | // console.log("native_addr:",native_addr) 10 | var className = "android.os.Process"; 11 | var classResult = Java.use(className).class; 12 | var methodArr = classResult.getDeclaredMethods(); 13 | for (var i = 0; i < methodArr.length; i++) { 14 | 15 | var methodName = methodArr[i].toString(); 16 | var flags = methodArr[i].getModifiers() 17 | if (flags & 256) { 18 | if(methodName.indexOf("getUidForName")!= -1){ 19 | var artmethod = methodArr[i].getArtMethod(); 20 | for (var i = 0; i < 30; i=i+1) { 21 | var jni_native_addr = Memory.readPointer(ptr(artmethod + i)) 22 | if(native_addr.equals(jni_native_addr)){ 23 | offset = i 24 | return i 25 | } 26 | } 27 | } 28 | } 29 | } 30 | 31 | return -1 32 | } 33 | // 遍历一个类的所有native 方法并打印地址 34 | function get_jni_native_method_addr(classResult) { 35 | 36 | var jnioffset = get_android_api_jnioffset() 37 | var methodArr = classResult.getDeclaredMethods(); 38 | 39 | for (var i = 0; i < methodArr.length; i++) { 40 | 41 | var methodName = methodArr[i].toString(); 42 | 43 | var flags = methodArr[i].getModifiers() 44 | if (flags & 256) { 45 | var artmethod = methodArr[i].getArtMethod(); 46 | var native_addr = Memory.readPointer(ptr(artmethod + jnioffset)) 47 | //找到本手机系统中artmethod的偏移地址,然后用20+偏移 48 | var module 49 | var offset 50 | console.log("methodName->", methodName); 51 | try { 52 | module = Process.getModuleByAddress(native_addr) 53 | offset = native_addr - module.base 54 | console.log("Func.offset==", module.name, offset); 55 | } catch (err) { 56 | } 57 | console.log("Func.getArtMethod->native_addr:", native_addr); //打印出java方法jni函数调用的native函数地址 58 | console.log("Func.flags->", flags); 59 | } 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /frida_exception_break.js: -------------------------------------------------------------------------------- 1 | function set_exceprion_break(addr, size, pattern) { 2 | Process.setExceptionHandler(function(details) { 3 | console.log(`type:${details.type} addr:${details.address} memory:${details.memory.address.toString()}:${details.memory.operation}`) 4 | Memory.protect(addr, size, 'rwx') 5 | return true; 6 | }) 7 | Memory.protect(addr, size, pattern) 8 | } 9 | 10 | // 监听写入操作 11 | // set_exceprion_break(ptr(this.context.x0), 8, "rx") 12 | -------------------------------------------------------------------------------- /hookEvent.js: -------------------------------------------------------------------------------- 1 | var jclazz = null; 2 | var jobj = null; 3 | function getObjClassName(obj) { 4 | if (!jclazz) { 5 | var jclazz = Java.use("java.lang.Class"); 6 | } 7 | if (!jobj) { 8 | var jobj = Java.use("java.lang.Object"); 9 | } 10 | return jclazz.getName.call(jobj.getClass.call(obj)); 11 | } 12 | 13 | function watch(obj, mtdName) { 14 | var listener_name = getObjClassName(obj); 15 | var target = Java.use(listener_name); 16 | if (!target || !mtdName in target) { 17 | return; 18 | } 19 | target[mtdName].overloads.forEach(function (overload) { 20 | overload.implementation = function () { 21 | console.log("[WatchEvent] " + mtdName + ": " + getObjClassName(this)) 22 | return this[mtdName].apply(this, arguments); 23 | }; 24 | }) 25 | } 26 | 27 | function OnClickListener() { 28 | Java.perform(function () { 29 | Java.use("android.view.View").setOnClickListener.implementation = function (listener) { 30 | if (listener != null) { 31 | watch(listener, 'onClick'); 32 | } 33 | return this.setOnClickListener(listener); 34 | }; 35 | 36 | Java.choose("android.view.View$ListenerInfo", { 37 | onMatch: function (instance) { 38 | instance = instance.mOnClickListener.value; 39 | if (instance) { 40 | console.log("mOnClickListener name is :" + getObjClassName(instance)); 41 | watch(instance, 'onClick'); 42 | } 43 | }, 44 | onComplete: function () { 45 | } 46 | }) 47 | }) 48 | } 49 | setImmediate(OnClickListener); -------------------------------------------------------------------------------- /hook_RegistNatives.js: -------------------------------------------------------------------------------- 1 | function find_RegisterNatives(params) { 2 | var symbols = Module.enumerateSymbolsSync("libart.so"); 3 | var addrRegisterNatives = null; 4 | for (var i = 0; i < symbols.length; i++) { 5 | var symbol = symbols[i]; 6 | 7 | //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi 8 | if (symbol.name.indexOf("art") >= 0 && 9 | symbol.name.indexOf("JNI") >= 0 && 10 | symbol.name.indexOf("RegisterNatives") >= 0 && 11 | symbol.name.indexOf("CheckJNI") < 0) { 12 | addrRegisterNatives = symbol.address; 13 | console.log("RegisterNatives is at ", symbol.address, symbol.name); 14 | hook_RegisterNatives(addrRegisterNatives) 15 | } 16 | } 17 | 18 | } 19 | 20 | function hook_RegisterNatives(addrRegisterNatives) { 21 | 22 | if (addrRegisterNatives != null) { 23 | Interceptor.attach(addrRegisterNatives, { 24 | onEnter: function (args) { 25 | console.log("[RegisterNatives] method_count:", args[3]); 26 | // console.warn("class_name指的是注册的是java层中哪个类的的方法,name指的是java层的方法名,sig对应的是签名信息,fnPtr对应的是native中动态注册方法的实际地址,fnOffset指的是动态注册方法的偏移地址,callee输出该函数的被调用信息"); 27 | var env = args[0]; 28 | var java_class = args[1]; 29 | var class_name = Java.vm.tryGetEnv().getClassName(java_class); 30 | //console.log(class_name); 31 | 32 | var methods_ptr = ptr(args[2]); 33 | 34 | var method_count = parseInt(args[3]); 35 | for (var i = 0; i < method_count; i++) { 36 | var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3)); 37 | var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize)); 38 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2)); 39 | 40 | var name = Memory.readCString(name_ptr); 41 | var sig = Memory.readCString(sig_ptr); 42 | var find_module = Process.findModuleByAddress(fnPtr_ptr); 43 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, " fnOffset:", ptr(fnPtr_ptr).sub(find_module.base), " callee:", DebugSymbol.fromAddress(this.returnAddress)); 44 | } 45 | } 46 | }); 47 | } 48 | } 49 | 50 | setImmediate(find_RegisterNatives); -------------------------------------------------------------------------------- /hook_androlua_pro_string.js: -------------------------------------------------------------------------------- 1 | function hook_dlopen(soName = '') { 2 | Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), 3 | { 4 | onEnter: function (args) { 5 | var pathptr = args[0]; 6 | if (pathptr !== undefined && pathptr != null) { 7 | var path = ptr(pathptr).readCString(); 8 | if (path.indexOf(soName) >= 0) { 9 | this.is_can_hook = true; 10 | } 11 | } 12 | }, 13 | onLeave: function (retval) { 14 | if (this.is_can_hook) { 15 | // do something 16 | crack() 17 | hook_libc() 18 | } 19 | } 20 | } 21 | ); 22 | } 23 | 24 | function crack() { 25 | let module = Process.findModuleByName("libluajava.so") 26 | Interceptor.attach(module.findExportByName("luaL_checklstring"), { 27 | onEnter(args) { 28 | this.len = this.context.r2 29 | }, 30 | onLeave(retval) { 31 | let src = ptr(retval).readCString() 32 | let md52 = null 33 | // console.log(src) 34 | if (src.indexOf("卡密不存在") >= 0) { 35 | // src = JSON.parse(src) 36 | // console.log(src["wb569a04a9d5a36d0d01"]) 37 | let time = Math.floor(Date.now() / 1000) 38 | let str = String.raw`{"wb569a04a9d5a36d0d01":42900409,"w893c8f0e02a09b1d456":{"w4f7c661779204e7a5bb698af870a702b":"5519a2cdbae6ec53e0fe6a932d6ebb2c","wc67ecedeb18e0870203":2105380,"wb20f98c65058d838c15":"code","w150c99a51e259947af9":1717046228},"wb6bf85eefb5573bd940":${time},"wc2e86b326e09409e0fd":"dd9199d043971e5c4d7e4cf184efdc25","w295f80348b106b9c15c":"f50a7dadcc9830250affcddb09e75d03"}` 39 | ptr(this.len).writeInt(374) 40 | ptr(this.context.r0).writeUtf8String(str) 41 | console.log(ptr(retval).readCString()) 42 | } 43 | } 44 | }) 45 | } 46 | 47 | function hook_libc() { 48 | // lua字符串比较 49 | Interceptor.attach(Module.getExportByName(null, "memcmp"), { 50 | onEnter(args) { 51 | let str1 = ptr(this.context.r0).readCString() 52 | let str2 = ptr(this.context.r0).readCString() 53 | if (str1.indexOf("dd9199d043971e5c4d7e4cf184efdc25") >= 0 || str2.indexOf("dd9199d043971e5c4d7e4cf184efdc25") >= 0) { 54 | console.log(str1 + "---" + str2) 55 | } 56 | } 57 | }) 58 | } 59 | 60 | function main() { 61 | hook_dlopen("libluajava.so") 62 | } 63 | 64 | setImmediate(main) 65 | -------------------------------------------------------------------------------- /hook_art.js: -------------------------------------------------------------------------------- 1 | 2 | (function(){ 3 | function klog(data,...args){ 4 | for (let item of args){ 5 | data+="\t"+item; 6 | } 7 | var message={}; 8 | message["jsname"]="hook_art"; 9 | message["data"]=data; 10 | send(message); 11 | } 12 | 13 | //替换了console.log 14 | console.log = (function (oriLogFunc) { 15 | return function () { 16 | //判断配置文件是否开启日志调试 17 | let arr = [] 18 | arr.push(...arguments) 19 | klog(JSON.stringify(arr)) 20 | } 21 | })(console.log); 22 | 23 | 24 | const STD_STRING_SIZE = 3 * Process.pointerSize; 25 | class StdString { 26 | constructor() { 27 | this.handle = Memory.alloc(STD_STRING_SIZE); 28 | } 29 | 30 | dispose() { 31 | const [data, isTiny] = this._getData(); 32 | if (!isTiny) { 33 | Java.api.$delete(data); 34 | } 35 | } 36 | 37 | disposeToString() { 38 | const result = this.toString(); 39 | this.dispose(); 40 | return result; 41 | } 42 | 43 | toString() { 44 | const [data] = this._getData(); 45 | return data.readUtf8String(); 46 | } 47 | 48 | _getData() { 49 | const str = this.handle; 50 | const isTiny = (str.readU8() & 1) === 0; 51 | const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer(); 52 | return [data, isTiny]; 53 | } 54 | } 55 | 56 | function prettyMethod(method_id, withSignature) { 57 | const result = new StdString(); 58 | Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); 59 | return result.disposeToString(); 60 | } 61 | 62 | /* 63 | GetFieldID is at 0xe39b87c5 _ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_ 64 | GetMethodID is at 0xe39a1a19 _ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_ 65 | NewStringUTF is at 0xe39cff25 _ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc 66 | RegisterNatives is at 0xe39e08fd _ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi 67 | GetStaticFieldID is at 0xe39c9635 _ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_ 68 | GetStaticMethodID is at 0xe39be0ed _ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_ 69 | GetStringUTFChars is at 0xe39d06e5 _ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh 70 | FindClass is at 0xe399ae5d _ZN3art3JNI9FindClassEP7_JNIEnvPKc 71 | */ 72 | 73 | function hook_libart() { 74 | klog("init","hook_art.js init hook success") 75 | 76 | var symbols = Module.enumerateSymbolsSync("libart.so"); 77 | var addrGetStringUTFChars = null; 78 | var addrNewStringUTF = null; 79 | var addrFindClass = null; 80 | var addrGetMethodID = null; 81 | var addrGetStaticMethodID = null; 82 | var addrGetFieldID = null; 83 | var addrGetStaticFieldID = null; 84 | var addrRegisterNatives = null; 85 | var so_name = "lib"; //TODO 这里写需要过滤的so 86 | 87 | for (var i = 0; i < symbols.length; i++) { 88 | var symbol = symbols[i]; 89 | if (symbol.name.indexOf("art") >= 0 && 90 | symbol.name.indexOf("JNI") >= 0 && 91 | symbol.name.indexOf("CheckJNI") < 0 && 92 | symbol.name.indexOf("_ZN3art3JNI") >= 0 93 | ) { 94 | if (symbol.name.indexOf("GetStringUTFChars") >= 0) { 95 | addrGetStringUTFChars = symbol.address; 96 | console.log("GetStringUTFChars is at ", symbol.address, symbol.name); 97 | } else if (symbol.name.indexOf("NewStringUTF") >= 0) { 98 | addrNewStringUTF = symbol.address; 99 | console.log("NewStringUTF is at ", symbol.address, symbol.name); 100 | } else if (symbol.name.indexOf("FindClass") >= 0) { 101 | addrFindClass = symbol.address; 102 | console.log("FindClass is at ", symbol.address, symbol.name); 103 | } else if (symbol.name.indexOf("GetMethodID") >= 0) { 104 | addrGetMethodID = symbol.address; 105 | console.log("GetMethodID is at ", symbol.address, symbol.name); 106 | } else if (symbol.name.indexOf("GetStaticMethodID") >= 0) { 107 | addrGetStaticMethodID = symbol.address; 108 | console.log("GetStaticMethodID is at ", symbol.address, symbol.name); 109 | } else if (symbol.name.indexOf("GetFieldID") >= 0) { 110 | addrGetFieldID = symbol.address; 111 | console.log("GetFieldID is at ", symbol.address, symbol.name); 112 | } else if (symbol.name.indexOf("GetStaticFieldID") >= 0) { 113 | addrGetStaticFieldID = symbol.address; 114 | console.log("GetStaticFieldID is at ", symbol.address, symbol.name); 115 | } else if (symbol.name.indexOf("RegisterNatives") >= 0) { 116 | addrRegisterNatives = symbol.address; 117 | console.log("RegisterNatives is at ", symbol.address, symbol.name); 118 | } else if (symbol.name.indexOf("CallStatic") >= 0) { 119 | console.log("CallStatic is at ", symbol.address, symbol.name); 120 | Interceptor.attach(symbol.address, { 121 | onEnter: function (args) { 122 | var module = Process.findModuleByAddress(this.returnAddress); 123 | if (module != null && module.name.indexOf(so_name) == 0) { 124 | var java_class = args[1]; 125 | var mid = args[2]; 126 | var class_name = Java.vm.tryGetEnv().getClassName(java_class); 127 | if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) { 128 | var method_name = prettyMethod(mid, 1); 129 | console.log("<>CallStatic:", DebugSymbol.fromAddress(this.returnAddress), class_name, method_name); 130 | } 131 | } 132 | }, 133 | onLeave: function (retval) { } 134 | }); 135 | } else if (symbol.name.indexOf("CallNonvirtual") >= 0) { 136 | console.log("CallNonvirtual is at ", symbol.address, symbol.name); 137 | Interceptor.attach(symbol.address, { 138 | onEnter: function (args) { 139 | var module = Process.findModuleByAddress(this.returnAddress); 140 | if (module != null && module.name.indexOf(so_name) == 0) { 141 | var jobject = args[1]; 142 | var jclass = args[2]; 143 | var jmethodID = args[3]; 144 | var obj_class_name = Java.vm.tryGetEnv().getObjectClassName(jobject); 145 | var class_name = Java.vm.tryGetEnv().getClassName(jclass); 146 | if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) { 147 | var method_name = prettyMethod(jmethodID, 1); 148 | console.log("<>CallNonvirtual:", DebugSymbol.fromAddress(this.returnAddress), class_name, obj_class_name, method_name); 149 | } 150 | } 151 | }, 152 | onLeave: function (retval) { } 153 | }); 154 | } else if (symbol.name.indexOf("Call") >= 0 && symbol.name.indexOf("Method") >= 0) { 155 | console.log("Call<>Method is at ", symbol.address, symbol.name); 156 | Interceptor.attach(symbol.address, { 157 | onEnter: function (args) { 158 | var module = Process.findModuleByAddress(this.returnAddress); 159 | if (module != null && module.name.indexOf(so_name) == 0) { 160 | var java_class = args[1]; 161 | var mid = args[2]; 162 | var class_name = Java.vm.tryGetEnv().getObjectClassName(java_class); 163 | if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) { 164 | var method_name = prettyMethod(mid, 1); 165 | console.log("<>Call<>Method:", DebugSymbol.fromAddress(this.returnAddress), class_name, method_name); 166 | } 167 | } 168 | }, 169 | onLeave: function (retval) { } 170 | }); 171 | } 172 | } 173 | } 174 | 175 | if (addrGetStringUTFChars != null) { 176 | Interceptor.attach(addrGetStringUTFChars, { 177 | onEnter: function (args) { 178 | }, 179 | onLeave: function (retval) { 180 | if (retval != null) { 181 | var module = Process.findModuleByAddress(this.returnAddress); 182 | if (module != null && module.name.indexOf(so_name) == 0) { 183 | var bytes = Memory.readCString(retval); 184 | console.log("[GetStringUTFChars] result:" + bytes, DebugSymbol.fromAddress(this.returnAddress)); 185 | } 186 | } 187 | } 188 | }); 189 | } 190 | if (addrNewStringUTF != null) { 191 | Interceptor.attach(addrNewStringUTF, { 192 | onEnter: function (args) { 193 | if (args[1] != null) { 194 | var module = Process.findModuleByAddress(this.returnAddress); 195 | if (module != null && module.name.indexOf(so_name) == 0) { 196 | var string = Memory.readCString(args[1]); 197 | console.log("[NewStringUTF] bytes:" + string, DebugSymbol.fromAddress(this.returnAddress)); 198 | } 199 | 200 | } 201 | }, 202 | onLeave: function (retval) { } 203 | }); 204 | } 205 | 206 | if (addrFindClass != null) { 207 | Interceptor.attach(addrFindClass, { 208 | onEnter: function (args) { 209 | if (args[1] != null) { 210 | var module = Process.findModuleByAddress(this.returnAddress); 211 | if (module != null && module.name.indexOf(so_name) == 0) { 212 | var name = Memory.readCString(args[1]); 213 | console.log("[FindClass] name:" + name, DebugSymbol.fromAddress(this.returnAddress)); 214 | } 215 | } 216 | }, 217 | onLeave: function (retval) { } 218 | }); 219 | } 220 | if (addrGetMethodID != null) { 221 | Interceptor.attach(addrGetMethodID, { 222 | onEnter: function (args) { 223 | if (args[2] != null) { 224 | var clazz = args[1]; 225 | var class_name = Java.vm.tryGetEnv().getClassName(clazz); 226 | var module = Process.findModuleByAddress(this.returnAddress); 227 | if (module != null && module.name.indexOf(so_name) == 0) { 228 | var name = Memory.readCString(args[2]); 229 | if (args[3] != null) { 230 | var sig = Memory.readCString(args[3]); 231 | console.log("[GetMethodID] class_name:" + class_name + " name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress)); 232 | } else { 233 | console.log("[GetMethodID] class_name:" + class_name + " name:" + name, DebugSymbol.fromAddress(this.returnAddress)); 234 | } 235 | } 236 | } 237 | }, 238 | onLeave: function (retval) { } 239 | }); 240 | } 241 | if (addrGetStaticMethodID != null) { 242 | Interceptor.attach(addrGetStaticMethodID, { 243 | onEnter: function (args) { 244 | if (args[2] != null) { 245 | var clazz = args[1]; 246 | var class_name = Java.vm.tryGetEnv().getClassName(clazz); 247 | var module = Process.findModuleByAddress(this.returnAddress); 248 | if (module != null && module.name.indexOf(so_name) == 0) { 249 | var name = Memory.readCString(args[2]); 250 | if (args[3] != null) { 251 | var sig = Memory.readCString(args[3]); 252 | console.log("[GetStaticMethodID] class_name:" + class_name + " name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress)); 253 | } else { 254 | console.log("[GetStaticMethodID] class_name:" + class_name + " name:" + name, DebugSymbol.fromAddress(this.returnAddress)); 255 | } 256 | } 257 | } 258 | }, 259 | onLeave: function (retval) { } 260 | }); 261 | } 262 | if (addrGetFieldID != null) { 263 | Interceptor.attach(addrGetFieldID, { 264 | onEnter: function (args) { 265 | if (args[2] != null) { 266 | var module = Process.findModuleByAddress(this.returnAddress); 267 | if (module != null && module.name.indexOf(so_name) == 0) { 268 | var name = Memory.readCString(args[2]); 269 | if (args[3] != null) { 270 | var sig = Memory.readCString(args[3]); 271 | console.log("[GetFieldID] name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress)); 272 | } else { 273 | console.log("[GetFieldID] name:" + name, DebugSymbol.fromAddress(this.returnAddress)); 274 | } 275 | } 276 | } 277 | }, 278 | onLeave: function (retval) { } 279 | }); 280 | } 281 | if (addrGetStaticFieldID != null) { 282 | Interceptor.attach(addrGetStaticFieldID, { 283 | onEnter: function (args) { 284 | if (args[2] != null) { 285 | var module = Process.findModuleByAddress(this.returnAddress); 286 | if (module != null && module.name.indexOf(so_name) == 0) { 287 | var name = Memory.readCString(args[2]); 288 | if (args[3] != null) { 289 | var sig = Memory.readCString(args[3]); 290 | console.log("[GetStaticFieldID] name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress)); 291 | } else { 292 | console.log("[GetStaticFieldID] name:" + name, DebugSymbol.fromAddress(this.returnAddress)); 293 | } 294 | } 295 | } 296 | }, 297 | onLeave: function (retval) { } 298 | }); 299 | } 300 | 301 | if (addrRegisterNatives != null) { 302 | Interceptor.attach(addrRegisterNatives, { 303 | onEnter: function (args) { 304 | console.log("[RegisterNatives] method_count:", args[3], DebugSymbol.fromAddress(this.returnAddress)); 305 | var env = args[0]; 306 | var java_class = args[1]; 307 | var class_name = Java.vm.tryGetEnv().getClassName(java_class); 308 | 309 | var methods_ptr = ptr(args[2]); 310 | 311 | var method_count = parseInt(args[3]); 312 | for (var i = 0; i < method_count; i++) { 313 | var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3)); 314 | var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize)); 315 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2)); 316 | 317 | var name = Memory.readCString(name_ptr); 318 | var sig = Memory.readCString(sig_ptr); 319 | var find_module = Process.findModuleByAddress(fnPtr_ptr); 320 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base)); 321 | 322 | } 323 | }, 324 | onLeave: function (retval) { } 325 | }); 326 | } 327 | } 328 | 329 | setImmediate(hook_libart); 330 | 331 | })(); 332 | -------------------------------------------------------------------------------- /hook_dlopen.js: -------------------------------------------------------------------------------- 1 | function hook_dlopen(soName = '') { 2 | Interceptor.attach(Module.findExportByName(null, "dlopen"), 3 | { 4 | onEnter: function (args) { 5 | var pathptr = args[0]; 6 | if (pathptr !== undefined && pathptr != null) { 7 | var path = ptr(pathptr).readCString(); 8 | // console.log("load " + path); 9 | if (path.indexOf(soName) >= 0) { 10 | this.is_can_hook = true; 11 | } 12 | } 13 | }, 14 | onLeave: function (retval) { 15 | if (this.is_can_hook) { 16 | // do something 17 | } 18 | } 19 | } 20 | ); 21 | 22 | Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), 23 | { 24 | onEnter: function (args) { 25 | var pathptr = args[0]; 26 | if (pathptr !== undefined && pathptr != null) { 27 | var path = ptr(pathptr).readCString(); 28 | // console.log("load " + path); 29 | if (path.indexOf(soName) >= 0) { 30 | this.is_can_hook = true; 31 | } 32 | } 33 | }, 34 | onLeave: function (retval) { 35 | if (this.is_can_hook) { 36 | // do something 37 | } 38 | } 39 | } 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /ida_suspend_other_thread.py: -------------------------------------------------------------------------------- 1 | import ida_dbg 2 | 3 | current_tid = ida_dbg.get_current_thread() 4 | for number in range(ida_dbg.get_thread_qty()): 5 | tid = ida_dbg.getn_thread(number) 6 | if (tid != current_tid): 7 | ida_dbg.suspend_thread(tid) 8 | -------------------------------------------------------------------------------- /killapp.js: -------------------------------------------------------------------------------- 1 | function main(){ 2 | Java.perform(function(){ 3 | //finish(); 4 | var clazz = Java.use("android.app.Activity"); 5 | clazz.finish.overload().implementation = function(){ 6 | console.warn(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 7 | } 8 | 9 | //android.os.Process.killProcess(android.os.Process.myPid()); 10 | var clazz2 = Java.use("android.os.Process"); 11 | clazz2.killProcess.implementation = function(){ 12 | console.warn(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 13 | } 14 | 15 | // System.exit(0);//正常退出 16 | // System.exit(1);//非正常退出 17 | var clazz3 = Java.use("java.lang.System"); 18 | clazz3.exit.implementation = function(){ 19 | console.warn(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); 20 | } 21 | }); 22 | } 23 | setImmediate(main); -------------------------------------------------------------------------------- /libmsaoaidsec_frida_bypass.js: -------------------------------------------------------------------------------- 1 | function hook_dlopen(soName = '') { 2 | Interceptor.attach(Module.findExportByName(null, "dlopen"), 3 | { 4 | onEnter: function (args) { 5 | var pathptr = args[0]; 6 | if (pathptr !== undefined && pathptr != null) { 7 | var path = ptr(pathptr).readCString(); 8 | // console.log("load " + path); 9 | if (path.indexOf(soName) >= 0) { 10 | // Thread.sleep(20) 11 | locate_init() 12 | // hook_libc() 13 | } 14 | } 15 | } 16 | } 17 | ); 18 | 19 | Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), 20 | { 21 | onEnter: function (args) { 22 | var pathptr = args[0]; 23 | if (pathptr !== undefined && pathptr != null) { 24 | var path = ptr(pathptr).readCString(); 25 | // console.log("load " + path); 26 | if (path.indexOf(soName) >= 0) { 27 | // Thread.sleep(20) 28 | locate_init() 29 | // hook_libc() 30 | } 31 | } 32 | } 33 | } 34 | ); 35 | } 36 | 37 | function locate_init() { 38 | let secmodule = null 39 | Interceptor.attach(Module.findExportByName(null, "__system_property_get"), 40 | { 41 | // _system_property_get("ro.build.version.sdk", v1); 42 | onEnter: function (args) { 43 | secmodule = Process.findModuleByName("libmsaoaidsec.so") 44 | var name = args[0]; 45 | if (name !== undefined && name != null) { 46 | name = ptr(name).readCString(); 47 | if (name.indexOf("ro.build.version.sdk") >= 0) { 48 | // 这是.init_proc刚开始执行的地方,是一个比较早的时机点 49 | hook_so() 50 | } 51 | } 52 | } 53 | } 54 | ); 55 | } 56 | 57 | function detect() { 58 | let secmodule = Process.findModuleByName("libmsaoaidsec.so") 59 | Interceptor.attach(secmodule.base.add(0xC63A + 0x1), { 60 | onEnter(args) { 61 | console.log("pc: " + ptr(this.context.pc).sub(secmodule.base)) 62 | } 63 | }) 64 | } 65 | 66 | function hook_so() { 67 | // detect() 68 | console.log("libmsaoaidsec.so --- " + Process.findModuleByName("libmsaoaidsec.so").base) 69 | bypass() 70 | } 71 | 72 | function hook_libc(){ 73 | // Interceptor.attach(Module.findExportByName(null, "openat"), 74 | // { 75 | // onEnter: function (args) { 76 | // var name = args[1]; 77 | // if (name !== undefined && name != null) { 78 | // name = ptr(name).readCString(); 79 | // console.log("openat --> " + name) 80 | // // if (name.indexOf("ro.build.version.sdk") >= 0) { 81 | 82 | // // } 83 | // } 84 | // } 85 | // } 86 | // ); 87 | 88 | // Interceptor.attach(Module.findExportByName(null, "open"), 89 | // { 90 | // onEnter: function (args) { 91 | // var name = args[0]; 92 | // if (name !== undefined && name != null) { 93 | // name = ptr(name).readCString(); 94 | // console.log("open --> " + name) 95 | // // if (name.indexOf("ro.build.version.sdk") >= 0) { 96 | 97 | // // } 98 | // } 99 | // } 100 | // } 101 | // ); 102 | 103 | // Interceptor.attach(Module.findExportByName(null, "readlinkat"), 104 | // { 105 | // onEnter: function (args) { 106 | // var name = args[1]; 107 | // if (name !== undefined && name != null) { 108 | // name = ptr(name).readCString(); 109 | // console.log("readlinkat --> " + name) 110 | // // if (name.indexOf("ro.build.version.sdk") >= 0) { 111 | 112 | // // } 113 | // } 114 | // } 115 | // } 116 | // ); 117 | 118 | // Interceptor.attach(Module.findExportByName(null, "strstr"), 119 | // { 120 | // onEnter: function (args) { 121 | // var arg0 = args[0]; 122 | // var arg1 = args[1] 123 | // if (arg0 !== undefined && arg0 != null) { 124 | // arg0 = ptr(arg0).readCString(); 125 | // arg1 = ptr(arg1).readCString(); 126 | // console.log("strstr --> " + arg0 + " --- " + arg1) 127 | // } 128 | // } 129 | // } 130 | // ); 131 | 132 | // Interceptor.attach(Module.findExportByName(null, "sprintf"), 133 | // { 134 | // onEnter: function (args) { 135 | // this.arg0 = args[0] 136 | // },onLeave(retval){ 137 | // let str = ptr(this.arg0).readCString(); 138 | // console.log("sprintf --> " + str) 139 | // } 140 | // } 141 | // ); 142 | 143 | // Interceptor.attach(Module.findExportByName(null, "snprintf"), 144 | // { 145 | // onEnter: function (args) { 146 | // this.arg0 = args[0] 147 | // },onLeave(retval){ 148 | // let str = ptr(this.arg0).readCString(); 149 | // console.log("snprintf --> " + str) 150 | // } 151 | // } 152 | // ); 153 | 154 | Interceptor.attach(Module.findExportByName("libc.so", "pthread_create"),{ 155 | onEnter(args){ 156 | let func_addr = args[2] 157 | console.log("The thread function address is " + func_addr) 158 | // console.log('pthread_create called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n'); 159 | } 160 | }) 161 | } 162 | 163 | function nop(addr) { 164 | Memory.patchCode(ptr(addr), 4, code => { 165 | const cw = new ThumbWriter(code, { pc: ptr(addr) }); 166 | cw.putNop(); 167 | cw.putNop(); 168 | cw.flush(); 169 | }); 170 | } 171 | 172 | function bypass(){ 173 | let module = Process.findModuleByName("libmsaoaidsec.so") 174 | nop(module.base.add(0x10AE4)) 175 | nop(module.base.add(0x113F8)) 176 | } 177 | 178 | function main() { 179 | hook_dlopen("libmsaoaidsec.so") 180 | } 181 | 182 | setImmediate(main) 183 | -------------------------------------------------------------------------------- /listen_mem.js: -------------------------------------------------------------------------------- 1 | // 使用frida Stalker进行code trace 2 | // 此脚本只对STR、STRB和STRH指令进行trace,用于监听对内存的写入,有需要的话可自行扩展其它指令 3 | let moduleBase; 4 | let isFirstIn = true; 5 | let pre_regs; 6 | let infoMap = new Map(); 7 | let detailInsMap = new Map(); 8 | 9 | function isStrInstuction(logInfo) { 10 | //13c78 strb w11, [x10, x9] 11 | let re = /str.*([wx].*?),.*\[(x\d+),\s([wx]\d+)\]/ 12 | let re_ret = logInfo.match(re) 13 | if (re_ret != null) { 14 | return re_ret 15 | } 16 | //146dc strb w8, [x9, #3] ; 17 | re = /str.*([wx].*?),.*\[(x\d+).*/ 18 | re_ret = logInfo.match(re) 19 | if (re_ret != null) { 20 | return re_ret 21 | } 22 | return null; 23 | } 24 | 25 | let strace = { 26 | start: function (soname, addr, size) { 27 | let module = Process.findModuleByName(soname); 28 | moduleBase = module.base; 29 | console.log(JSON.stringify(module)); 30 | 31 | Interceptor.attach(moduleBase.add(addr), { 32 | onEnter: function (args) { 33 | this.pid = Process.getCurrentThreadId(); 34 | 35 | Stalker.follow(this.pid, { 36 | transform: function (iterator) { 37 | let lastInfo; 38 | const instruction = iterator.next(); 39 | let startAddress = instruction.address; 40 | if (size === 0) { 41 | size = module.size; 42 | addr = 0; 43 | } 44 | const isModuleCode = startAddress.compare(moduleBase.add(addr)) >= 0 && 45 | startAddress.compare(moduleBase.add(addr).add(size)) < 0; 46 | // const isModuleCode = startAddress.compare(moduleBase) >= 0 && 47 | // startAddress.compare(moduleBase.add(module.size)) < 0; 48 | do { 49 | if (isModuleCode) { 50 | let s = parserNextAddr(instruction); 51 | let address = instruction.address; 52 | let offset = address - moduleBase; 53 | let lastInfo = s.toString(16) + "\t\t" + instruction; 54 | detailInsMap.set(offset, JSON.stringify(instruction)); 55 | infoMap.set(offset, lastInfo); 56 | iterator.putCallout(function (context) { 57 | let regs = JSON.stringify(context); 58 | //保存寄存器 59 | pre_regs = formatArm64Regs(context); 60 | let pcReg = getPcReg(pre_regs); 61 | let offset = Number(pcReg) - moduleBase; 62 | let logInfo = infoMap.get(offset); 63 | var isStr_ret = isStrInstuction(logInfo) 64 | if (isStr_ret) { 65 | let value_reg = isStr_ret[1]; 66 | let addr_reg = isStr_ret[2]; 67 | let index_reg = null 68 | if (isStr_ret.length == 4) { 69 | index_reg = isStr_ret[3] 70 | } 71 | isStr_ret = null 72 | let value_value = getReg(pre_regs, value_reg) 73 | let addr_value = getReg(pre_regs, addr_reg) 74 | let index_value = null 75 | if (index_reg != null) { 76 | index_value = getReg(pre_regs, index_reg) 77 | } 78 | let index_str = '' 79 | if (index_value != null) { 80 | index_str = " " + index_reg + '=' + index_value 81 | } 82 | console.log(logInfo + " ; " + addr_reg + "=" + addr_value + index_str + " " + value_reg + '=' + value_value) 83 | 84 | // 保存到文件中 85 | var f = new File("/data/data/com.kanxue.ollvm5/trace4.txt", "a") 86 | f.write(logInfo + " ; " + addr_reg + "=" + addr_value + index_str + " " + value_reg + '=' + value_value + "\n") 87 | f.flush() 88 | f.close() 89 | } 90 | }) 91 | } 92 | iterator.keep() 93 | 94 | } while (iterator.next() != null) 95 | }, 96 | 97 | }) 98 | }, 99 | onLeave: function (ret) { 100 | // libtprt.saveStringMapTofile(); 101 | Stalker.unfollow(this.pid); 102 | console.log("ret:" + ret); 103 | 104 | } 105 | }) 106 | } 107 | } 108 | 109 | function parserNextAddr(ins) { 110 | let s = JSON.stringify(ins); 111 | let address = ins.address; 112 | // console.log("address:"+address) 113 | let offset = address - moduleBase; 114 | let s1 = (offset).toString(16); 115 | let entity = {} 116 | entity.address = offset; 117 | return s1; 118 | } 119 | 120 | const byteToHex = []; 121 | 122 | for (let n = 0; n <= 0xff; ++n) { 123 | const hexOctet = n.toString(16).padStart(2, "0"); 124 | byteToHex.push(hexOctet); 125 | } 126 | 127 | function formatArm64Regs(context) { 128 | let regs = [] 129 | regs.push(context.x0); 130 | regs.push(context.x1); 131 | regs.push(context.x2); 132 | regs.push(context.x3); 133 | regs.push(context.x4); 134 | regs.push(context.x5); 135 | regs.push(context.x6); 136 | regs.push(context.x7); 137 | regs.push(context.x8); 138 | regs.push(context.x9); 139 | regs.push(context.x10); 140 | regs.push(context.x11); 141 | regs.push(context.x12); 142 | regs.push(context.x13); 143 | regs.push(context.x14); 144 | regs.push(context.x15); 145 | regs.push(context.x16); 146 | regs.push(context.x17); 147 | regs.push(context.x18); 148 | regs.push(context.x19); 149 | regs.push(context.x20); 150 | regs.push(context.x21); 151 | regs.push(context.x22); 152 | regs.push(context.x23); 153 | regs.push(context.x24); 154 | regs.push(context.x25); 155 | regs.push(context.x26); 156 | regs.push(context.x27); 157 | regs.push(context.x28); 158 | regs.push(context.fp); 159 | regs.push(context.lr); 160 | regs.push(context.sp); 161 | regs.push(context.pc); 162 | return regs; 163 | } 164 | 165 | function getPcReg(regs) { 166 | return regs[32]; 167 | } 168 | 169 | function getReg(regs, reg) { 170 | let map = { 171 | 'x0': 0, 172 | 'x1': 1, 173 | 'x2': 2, 174 | 'x3': 3, 175 | 'x4': 4, 176 | 'x5': 5, 177 | 'x6': 6, 178 | 'x7': 7, 179 | 'x8': 8, 180 | 'x9': 9, 181 | 'x10': 10, 182 | 'x11': 11, 183 | 'x12': 12, 184 | 'x13': 13, 185 | 'x14': 14, 186 | 'x15': 15, 187 | 'x16': 16, 188 | 'x17': 17, 189 | 'x18': 18, 190 | 'x19': 19, 191 | 'x20': 20, 192 | 'x21': 21, 193 | 'x22': 22, 194 | 'x23': 23, 195 | 'x24': 24, 196 | 'x25': 25, 197 | 'x26': 26, 198 | 'x27': 27, 199 | 'x28': 28 200 | } 201 | if (reg == 'xzr' || reg == 'wzr') { 202 | return '0x0' 203 | } 204 | reg = reg.replace('w', 'x') 205 | let index = map[reg] 206 | return regs[index] 207 | } 208 | 209 | let once = false; 210 | let straceInject = { 211 | start: function (soName, offset, size) { 212 | let module = Process.findModuleByName(soName); 213 | if (module !== undefined) { 214 | trace(soName, offset, size) 215 | return; 216 | } 217 | let open = Module.findExportByName(null, "open"); 218 | if (open != null) { 219 | Interceptor.attach(open, { 220 | onEnter: function (args) { 221 | let path = args[0].readCString(); 222 | if (path.indexOf(soName) !== -1) { 223 | this.hook = true; 224 | } 225 | }, 226 | onLeave: function (ret) { 227 | if (this.hook) { 228 | trace(soName, offset, size); 229 | } 230 | } 231 | }) 232 | } 233 | } 234 | } 235 | 236 | function trace(soName, offset, size) { 237 | 238 | let module = Process.findModuleByName(soName); 239 | console.log("module:" + module) 240 | if (module === undefined 241 | || module === null) { 242 | setTimeout(function () { 243 | trace(soName, offset, size); 244 | }, 100); 245 | } 246 | console.log("module:" + module.base) 247 | if (once) { 248 | return 249 | } 250 | once = true; 251 | strace.start(soName, offset, size); 252 | } 253 | 254 | function main() { 255 | // 模块名 代码偏移 大小 256 | // 大小为0,表示trace整个模块 257 | straceInject.start("libnative-lib.so", 0x19A84, 0x0); 258 | } 259 | 260 | setImmediate(main) 261 | -------------------------------------------------------------------------------- /lldb_find_module.py: -------------------------------------------------------------------------------- 1 | import lldb 2 | 3 | def find_module(debugger:lldb.SBDebugger, command, result, internal_dict): 4 | lib_name = command 5 | target: lldb.SBTarget = debugger.GetSelectedTarget() 6 | for module in target.modules: 7 | stream = lldb.SBStream() 8 | module.GetDescription(stream) 9 | module_name = stream.GetData() 10 | if (lib_name in module_name): 11 | print("find " + module_name) 12 | for sec in module.section_iter(): 13 | print(sec.GetName() + " -- " + hex(sec.GetLoadAddress(target))) 14 | 15 | def __lldb_init_module(debugger, internal_dict): 16 | debugger.HandleCommand('command script add -o -f lldb_find_module.find_module find_module') 17 | -------------------------------------------------------------------------------- /look_db.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import os 3 | 4 | db_dir = "/Users/lihuaqi/MyPlace/codeHouse/frida/files/逆向过程记录/8230/databases/" 5 | for file in os.listdir(db_dir): 6 | if (file.endswith(".db")): 7 | db_file_path = db_dir + file 8 | 9 | try: 10 | conn = sqlite3.connect(db_file_path) 11 | print("connect " + db_file_path) 12 | c = conn.cursor() 13 | 14 | tables = [] 15 | 16 | cursor = c.execute("SELECT name FROM sqlite_master WHERE type='table';") 17 | for row in cursor: 18 | table_name = row[0] 19 | tables.append(table_name) 20 | 21 | for table_name in tables: 22 | print("TABLE_NAME " + table_name) 23 | cursor2 = c.execute("SELECT * FROM " + table_name + ";") 24 | for row in cursor2: 25 | print(row) 26 | 27 | conn.close() 28 | print("close " + db_file_path) 29 | except Exception as e: 30 | pass 31 | -------------------------------------------------------------------------------- /myTrace.js: -------------------------------------------------------------------------------- 1 | // 使用frida Stalker进行code trace 2 | let moduleBase; 3 | let isFirstIn = true; 4 | let pre_regs; 5 | let infoMap = new Map(); 6 | let detailInsMap =new Map(); 7 | 8 | let strace = { 9 | start: function (soname, addr, size) { 10 | let module = Process.findModuleByName(soname); 11 | moduleBase = module.base; 12 | console.log(JSON.stringify(module)); 13 | 14 | Interceptor.attach(moduleBase.add(addr), { 15 | onEnter: function (args) { 16 | this.pid = Process.getCurrentThreadId(); 17 | //看下结构体的值 18 | 19 | Stalker.follow(this.pid, { 20 | transform: function (iterator) { 21 | let lastInfo; 22 | const instruction = iterator.next(); 23 | let startAddress = instruction.address; 24 | // console.log("startAddress:" + startAddress + " base:" + module.base + " offset:" + offset); 25 | if (size === 0) { 26 | size = module.size; 27 | addr=0; 28 | } 29 | const isModuleCode = startAddress.compare(moduleBase.add(addr)) >= 0 && 30 | startAddress.compare(moduleBase.add(addr).add(size)) < 0; 31 | do { 32 | if (isModuleCode) { 33 | let s = parserNextAddr(instruction); 34 | let address = instruction.address; 35 | let offset = address - moduleBase; 36 | let lastInfo = s.toString(16) + "\t\t" + instruction; 37 | detailInsMap.set(offset,JSON.stringify(instruction)); 38 | infoMap.set(offset, lastInfo); 39 | iterator.putCallout(function (context) { 40 | let regs = JSON.stringify(context); 41 | if (isFirstIn) { 42 | isFirstIn = false; 43 | //保存寄存器 44 | pre_regs = formatArm64Regs(context); 45 | } else { 46 | //打印的实际是上一次的 这样延迟一次可以打印出寄存器变化 47 | let pcReg = getPcReg(pre_regs); 48 | let offset = Number(pcReg) - moduleBase; 49 | let logInfo = infoMap.get(offset); 50 | let detailIns = detailInsMap.get(offset); 51 | // console.log("detailIns:"+detailIns) 52 | let entity = isRegsChange(context,detailIns); 53 | console.log(logInfo + " ; " + entity.info); 54 | } 55 | }) 56 | } 57 | iterator.keep() 58 | 59 | } while (iterator.next() != null) 60 | }, 61 | 62 | }) 63 | }, 64 | onLeave: function (ret) { 65 | // libtprt.saveStringMapTofile(); 66 | Stalker.unfollow(this.pid); 67 | console.log("ret:" + ret); 68 | 69 | } 70 | }) 71 | } 72 | } 73 | 74 | function parserNextAddr(ins) { 75 | let s = JSON.stringify(ins); 76 | let address = ins.address; 77 | // console.log("address:"+address) 78 | let offset = address - moduleBase; 79 | let s1 = (offset).toString(16); 80 | let entity = {} 81 | entity.address = offset; 82 | return s1; 83 | } 84 | 85 | const byteToHex = []; 86 | 87 | for (let n = 0; n <= 0xff; ++n) { 88 | const hexOctet = n.toString(16).padStart(2, "0"); 89 | byteToHex.push(hexOctet); 90 | } 91 | 92 | function hex(arrayBuffer) { 93 | const buff = new Uint8Array(arrayBuffer); 94 | const hexOctets = []; 95 | for (let i = 0; i < buff.length; ++i) 96 | hexOctets.push(byteToHex[buff[i]]); 97 | return hexOctets.join(""); 98 | } 99 | 100 | function formatArm64Regs(context) { 101 | let regs = [] 102 | regs.push(context.x0); 103 | regs.push(context.x1); 104 | regs.push(context.x2); 105 | regs.push(context.x3); 106 | regs.push(context.x4); 107 | regs.push(context.x5); 108 | regs.push(context.x6); 109 | regs.push(context.x7); 110 | regs.push(context.x8); 111 | regs.push(context.x9); 112 | regs.push(context.x10); 113 | regs.push(context.x11); 114 | regs.push(context.x12); 115 | regs.push(context.x13); 116 | regs.push(context.x14); 117 | regs.push(context.x15); 118 | regs.push(context.x16); 119 | regs.push(context.x17); 120 | regs.push(context.x18); 121 | regs.push(context.x19); 122 | regs.push(context.x20); 123 | regs.push(context.x21); 124 | regs.push(context.x22); 125 | regs.push(context.x23); 126 | regs.push(context.x24); 127 | regs.push(context.x25); 128 | regs.push(context.x26); 129 | regs.push(context.x27); 130 | regs.push(context.x28); 131 | regs.push(context.fp); 132 | regs.push(context.lr); 133 | regs.push(context.sp); 134 | regs.push(context.pc); 135 | return regs; 136 | } 137 | 138 | function getPcReg(regs) { 139 | return regs[32]; 140 | } 141 | 142 | function isRegsChange(context,ins) { 143 | let currentRegs = formatArm64Regs(context); 144 | let logInfo = ""; 145 | for (let i = 0; i < 32; i++) { 146 | if (i === 30) { 147 | continue 148 | } 149 | let preReg = pre_regs[i]; 150 | let currentReg = currentRegs[i]; 151 | if (Number(preReg) !== Number(currentReg)) { 152 | if (logInfo === "") { 153 | //尝试读取string 154 | let changeString = ""; 155 | 156 | try { 157 | let nativePointer = new NativePointer(currentReg); 158 | changeString = nativePointer.readCString(); 159 | } catch (e) { 160 | changeString = ""; 161 | } 162 | if (changeString !== "") { 163 | currentReg = currentReg + " (" + changeString + ")"; 164 | } 165 | logInfo = "\t " + getRegsString(i) + " = " + preReg + " --> " + currentReg; 166 | } else { 167 | logInfo = logInfo + "\t " + getRegsString(i) + " = " + preReg + " --> " + currentReg; 168 | } 169 | } 170 | } 171 | //打印PC寄存器 172 | let parse = JSON.parse(ins); 173 | let mnemonic = parse.mnemonic;//补充str 174 | if (mnemonic==="str"){ 175 | let strParams = getStrParams(parse,currentRegs); 176 | logInfo=logInfo+strParams; 177 | }else if (mnemonic==="cmp"){ 178 | let cmpParams = getCmpParams(parse,currentRegs); 179 | logInfo=logInfo+cmpParams; 180 | }else if (mnemonic==="b.gt" || mnemonic==="b.le" ||mnemonic==="b.eq" || mnemonic==="b.ne" || mnemonic==="b"){ 181 | // console.log(ins) 182 | let bgtAddr = getbgtAddr(parse,currentRegs); 183 | logInfo=logInfo+bgtAddr; 184 | } 185 | let entity ={}; 186 | entity.info =logInfo; 187 | let address = parse.address; 188 | if (lastAddr===undefined){ 189 | 190 | lastAddr=address; 191 | }else { 192 | let number = address- lastAddr; 193 | if (number===0x4){ 194 | 195 | }else { 196 | currentIndex++; 197 | 198 | } 199 | lastAddr=address; 200 | } 201 | pre_regs = currentRegs; 202 | return entity; 203 | } 204 | let lastAddr=undefined; 205 | let currentIndex=0; 206 | function getRegsString(index) { 207 | let reg; 208 | if (index === 31) { 209 | reg = "sp" 210 | } else { 211 | reg = "x" + index; 212 | } 213 | return reg; 214 | } 215 | function getbgtAddr(parser,currentRegs){ 216 | let bgtAddr=""; 217 | let operands = parser.operands; 218 | for (let i = 0; i < operands.length; i++) { 219 | let operand = operands[i]; 220 | if (operand.type==="imm"){ 221 | let value = operand.value; 222 | let number = value-moduleBase; 223 | bgtAddr="\t block addr:"+number.toString(16); 224 | break 225 | } 226 | } 227 | return bgtAddr; 228 | } 229 | function getStrParams(parser,currentRegs){ 230 | let operands = parser.operands; 231 | for (let i = 0; i < operands.length; i++) { 232 | let operand = operands[i]; 233 | if (operand.type==="reg"){ 234 | //获取value 235 | let value = operand.value; 236 | if (value==="wzr"){ 237 | return "\t "+ "str = 0"; 238 | }else { 239 | let replace = value.replace("w",""); 240 | let index = replace.replace("x",""); 241 | let index_reg= currentRegs[index]; 242 | 243 | let changeString = ""; 244 | 245 | try { 246 | let nativePointer = new NativePointer(index_reg); 247 | changeString = nativePointer.readCString(); 248 | } catch (e) { 249 | changeString = ""; 250 | } 251 | //读取值 252 | if (changeString!==""){ 253 | index_reg = index_reg + " (" + changeString + ")"; 254 | } 255 | return "\t "+ "str = "+index_reg ; 256 | } 257 | 258 | } 259 | } 260 | } 261 | function getCmpParams(parser,currentRegs){ 262 | let operands = parser.operands; 263 | let cmpInfo =""; 264 | for (let i = 0; i < operands.length; i++) { 265 | let operand = operands[i]; 266 | if (operand.type==="reg"){ 267 | let value = operand.value; 268 | let replace = value.replace("w",""); 269 | let index = replace.replace("x",""); 270 | let index_reg= currentRegs[index]; 271 | let changeString = ""; 272 | try { 273 | let nativePointer = new NativePointer(index_reg); 274 | changeString = nativePointer.readCString(); 275 | } catch (e) { 276 | changeString = ""; 277 | } 278 | //读取值 279 | if (changeString!==""){ 280 | index_reg = index_reg + " (" + changeString + ")"; 281 | } 282 | cmpInfo = cmpInfo+ "\t " +value+" = "+index_reg; 283 | } 284 | } 285 | return cmpInfo; 286 | } 287 | 288 | let once=false; 289 | let straceInject={ 290 | start:function (soName,offset,size){ 291 | let module = Process.findModuleByName(soName); 292 | if (module!==undefined){ 293 | trace(soName,offset,size) 294 | return; 295 | } 296 | let open = Module.findExportByName(null, "open"); 297 | if (open!=null){ 298 | Interceptor.attach(open,{ 299 | onEnter:function (args){ 300 | let path = args[0].readCString(); 301 | if (path.indexOf(soName)!==-1){ 302 | this.hook=true; 303 | } 304 | }, 305 | onLeave:function (ret){ 306 | if (this.hook){ 307 | trace(soName,offset,size); 308 | } 309 | } 310 | }) 311 | } 312 | } 313 | } 314 | 315 | function trace(soName,offset,size){ 316 | 317 | let module = Process.findModuleByName(soName); 318 | console.log("module:"+module) 319 | if (module===undefined 320 | || module===null){ 321 | setTimeout(function (){ 322 | trace(soName,offset,size); 323 | },100); 324 | } 325 | console.log("module:"+module.base) 326 | if (once){ 327 | return 328 | } 329 | once=true; 330 | strace.start(soName,offset,size); 331 | } 332 | 333 | function main() { 334 | // 模块名 代码偏移 大小 335 | // 如果大小为0x0,则对整个模块进行trace 336 | straceInject.start("libr0ysue.so",0x77C,0x68); 337 | } 338 | 339 | setImmediate(main) 340 | -------------------------------------------------------------------------------- /patch_exclusive_operate.py: -------------------------------------------------------------------------------- 1 | from capstone import * 2 | import re 3 | from keystone import * 4 | 5 | exclusive_store_instructions = ["STLXP", "STLXR", "STLXRB", "STLXRH", "STXP", "STXR", "STXRB", "STXRH"] 6 | exclusive_load_instructions = ["LDAXP", "LDAXR", "LDAXRB", "LDAXRH", "LDXP", "LDXR", "LDXRB", "LDXRH"] 7 | exclusive_judge_instructions = ["CBNZ", "CBZ"] 8 | 9 | f = open('libxxx.so', '+rb') 10 | code = f.read() 11 | new_code = bytearray(code) 12 | 13 | count = 0 14 | 15 | md = Cs(CS_ARCH_ARM64, CS_MODE_ARM) 16 | ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN) 17 | 18 | start_address = 0x305D0 19 | end_address = 0x1AAE44 20 | 21 | for addr in range(start_address, end_address, 4): 22 | # Extract the 4-byte chunk 23 | chunk = code[addr:addr + 4] 24 | 25 | # Perform disassembly if the chunk is of size 4 26 | if len(chunk) == 4: 27 | for (address, size, mnemonic, op_str) in md.disasm_lite(chunk, addr): 28 | try: 29 | # 检查指令是不是原子存储 30 | if (mnemonic.upper() in exclusive_store_instructions): 31 | print("0x%x:\t%s\t%s" %(address, mnemonic, op_str)) 32 | ld_ins = {"addr":None, "mnem":None, "op":None} 33 | judge_ins = {"addr":None, "mnem":None, "op":None} 34 | # 寻找原子加载指令 35 | for (address1, size1, mnemonic1, op_str1) in md.disasm_lite(code[address-20:address], address-20): 36 | if (mnemonic1.upper() in exclusive_load_instructions): 37 | ld_ins["addr"] = address1 38 | ld_ins["mnem"] = mnemonic1 39 | ld_ins["op"] = op_str1 40 | break 41 | # 寻找条件跳转指令 42 | for (address2, size2, mnemonic2, op_str2) in md.disasm_lite(code[address:address+20], address): 43 | if (mnemonic2.upper() in exclusive_judge_instructions): 44 | judge_ins["addr"] = address2 45 | judge_ins["mnem"] = mnemonic2 46 | judge_ins["op"] = op_str2 47 | break 48 | print("0x%x:\t%s\t%s" %(ld_ins["addr"], ld_ins["mnem"], ld_ins["op"])) 49 | print("0x%x:\t%s\t%s" %(judge_ins["addr"], judge_ins["mnem"], judge_ins["op"])) 50 | 51 | # patch load instruction 52 | if (ld_ins["mnem"].upper() in ["LDAXRB", "LDXRB"]): 53 | new_ins = "ldrb " + ld_ins["op"] 54 | encoding, count = ks.asm(bytes(new_ins, 'utf-8'),addr=ld_ins["addr"]) 55 | new_code[ld_ins["addr"]:ld_ins["addr"]+len(encoding)] = encoding 56 | else: 57 | new_ins = "ldr " + ld_ins["op"] 58 | encoding, count = ks.asm(bytes(new_ins, 'utf-8'),addr=ld_ins["addr"]) 59 | new_code[ld_ins["addr"]:ld_ins["addr"]+len(encoding)] = encoding 60 | 61 | # patch store instruction 62 | if (mnemonic.upper() in ["STLXRB", "STXRB"]): 63 | new_op = re.match(r'[wx]\d+, (.*)', op_str).group(1) 64 | new_ins = "strb " + new_op 65 | encoding, count = ks.asm(bytes(new_ins, 'utf-8'),addr=address) 66 | new_code[address:address+len(encoding)] = encoding 67 | else: 68 | new_op = re.match(r'[wx]\d+, (.*)', op_str).group(1) 69 | new_ins = "str " + new_op 70 | encoding, count = ks.asm(bytes(new_ins, 'utf-8'),addr=address) 71 | new_code[address:address+len(encoding)] = encoding 72 | 73 | # patch judge instruction 74 | if (judge_ins["mnem"].upper() == "CBNZ"): 75 | encoding, count = ks.asm(bytes("nop", 'utf-8')) 76 | new_code[judge_ins["addr"]:judge_ins["addr"]+len(encoding)] = encoding 77 | else: 78 | b_addr = re.match(r'.*?(#0x[a-f0-9]+)', judge_ins["op"]).group(1) 79 | new_ins = "b " + b_addr 80 | encoding, count = ks.asm(bytes(new_ins, 'utf-8'),addr=judge_ins["addr"]) 81 | new_code[judge_ins["addr"]:judge_ins["addr"]+len(encoding)] = encoding 82 | except Exception as e: 83 | print(f"An error occurred: {e}") 84 | continue 85 | new_f = open('libxxx_patch.so', '+wb') 86 | new_f.write(bytes(new_code)) 87 | new_f.flush() 88 | -------------------------------------------------------------------------------- /search_address_from_memory.js: -------------------------------------------------------------------------------- 1 | // pattern example '00 00 00 00 ?? 13 37 ?? 42' 2 | function search_address_from_memory(module_name, pattern) { 3 | let m = Process.findModuleByName(module_name) 4 | const results = Memory.scanSync(m.base, m.size, pattern) 5 | if(results.length == 1){ 6 | return results[0]['address']; 7 | } 8 | else if(results.length > 1){ 9 | console.log("search_address_from_memory results more than one!!!") 10 | return 0; 11 | } 12 | else{ 13 | console.log("don't find the pattern in memory!!!") 14 | return 0; 15 | } 16 | } 17 | --------------------------------------------------------------------------------