deflog_pcap(pcap_file, ssl_session_id, function, src_addr, src_port, dst_addr, dst_port, data): """Writes the captured data to a pcap file. Args: pcap_file: The opened pcap file. ssl_session_id: The SSL session ID for the communication. function: The function that was intercepted ("SSL_read" or "SSL_write"). src_addr: The source address of the logged packet. src_port: The source port of the logged packet. dst_addr: The destination address of the logged packet. dst_port: The destination port of the logged packet. data: The decrypted packet data. """ t = time.time() if ssl_session_id notin ssl_sessions: ssl_sessions[ssl_session_id] = (random.randint(0, 0xFFFFFFFF), random.randint(0, 0xFFFFFFFF)) client_sent, server_sent = ssl_sessions[ssl_session_id] if function == "SSL_read": seq, ack = (server_sent, client_sent) else: seq, ack = (client_sent, server_sent) for writes in ( # PCAP record (packet) header ("=I", int(t)), # Timestamp seconds ("=I", int((t * 1000000) % 1000000)), # Timestamp microseconds ("=I", 40 + len(data)), # Number of octets saved ("=i", 40 + len(data)), # Actual length of packet # IPv4 header (">B", 0x45), # Version and Header Length (">B", 0), # Type of Service (">H", 40 + len(data)), # Total Length (">H", 0), # Identification (">H", 0x4000), # Flags and Fragment Offset (">B", 0xFF), # Time to Live (">B", 6), # Protocol (">H", 0), # Header Checksum (">I", src_addr), # Source Address (">I", dst_addr), # Destination Address # TCP header (">H", src_port), # Source Port (">H", dst_port), # Destination Port (">I", seq), # Sequence Number (">I", ack), # Acknowledgment Number (">H", 0x5018), # Header Length and Flags (">H", 0xFFFF), # Window Size (">H", 0), # Checksum (">H", 0)): # Urgent Pointer pcap_file.write(struct.pack(writes[0], writes[1])) pcap_file.write(data) if function == "SSL_read": server_sent += len(data) else: client_sent += len(data) ssl_sessions[ssl_session_id] = (client_sent, server_sent)
//在要hook的模块加载完后,才调用hook代码 Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'),{ onEnter: function(args){ // first arg is the path to the library loaded var library_path = Memory.readCString(args[0]) //判断当前加载的模块是否是目标模块 if( library_path.includes(library_name)){ console.log("[...] Loading library : " + library_path) library_loaded = 1 } }, onLeave: function(args){
// if it's the library we want to hook, hooking it if(library_loaded == 1){ console.log("[+] Loaded") //hook目标函数 hook_jni(library_name, function_name) library_loaded = 0 } } })
/* Calculate the given funcName address from the JNIEnv pointer //计算出jni函数的地址 */ functiongetJNIFunctionAdress(jnienv_addr,func_name){ //最关键的起始就是这里,根据jnienv的地址和函数名,计算出偏移,其实就是拿函数的当前索引。这个了解类对象的结构就很清楚了。 var offset = jni_struct_array.indexOf(func_name) * Process.pointerSize // console.log("offset : 0x" + offset.toString(16)) return Memory.readPointer(jnienv_addr.add(offset)) }
// Hook all function to have an overview of the function called //hook全部jni函数 functionhook_all(jnienv_addr){ jni_struct_array.forEach(function(func_name){ // Calculating the address of the function if(!func_name.includes("reserved")) { var func_addr = getJNIFunctionAdress(jnienv_addr,func_name) Interceptor.attach(func_addr,{ onEnter: function(args){ console.log("[+] Entered : " + func_name) } }) } }) }
//hook_RegisterNative.js的部分,就是这段。找RegisterNative函数的地址。 var symbols = Module.enumerateSymbolsSync("libart.so"); var addrRegisterNatives = null; for (var i = 0; i < symbols.length; i++) { var symbol = symbols[i];
//_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi if (symbol.name.indexOf("art") >= 0 && symbol.name.indexOf("JNI") >= 0 && symbol.name.indexOf("RegisterNatives") >= 0 && symbol.name.indexOf("CheckJNI") < 0) { addrRegisterNatives = symbol.address; log("RegisterNatives is at "+symbol.address+" "+symbol.name); } }
//hook_artmethod.js的部分 //这里是遍历所有符号,匹配出ArtMethod的Invoke var module_libart = Process.findModuleByName("libart.so"); var symbols = module_libart.enumerateSymbols(); var ArtMethod_Invoke = null; for (var i = 0; i < symbols.length; i++) { var symbol = symbols[i]; var address = symbol.address; var name = symbol.name; var indexArtMethod = name.indexOf("ArtMethod"); var indexInvoke = name.indexOf("Invoke"); var indexThread = name.indexOf("Thread"); if (indexArtMethod >= 0 && indexInvoke >= 0 && indexThread >= 0 && indexArtMethod < indexInvoke && indexInvoke < indexThread) { //将后面的hook代码去掉。可以看到这里最终匹配到的结果是_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc //转换下格式之后的结果是art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) console.log(name); ArtMethod_Invoke = address; } } //如果上面匹配到了Invoke函数后。就hook打印。 if (ArtMethod_Invoke) { Interceptor.attach(ArtMethod_Invoke, { onEnter: function (args) { var method_name = prettyMethod(args[0], 0); if (!(method_name.indexOf("java.") == 0 || method_name.indexOf("android.") == 0)) { console.log("ArtMethod Invoke:" + method_name + ' called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n') + '\n'); } } }); } //这里也是个重点。打印当前函数名的方式。 functionprettyMethod(method_id, withSignature) { const result = new StdString(); Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); return result.disposeToString(); }