mirror of
				https://github.com/stulle123/kakaotalk_analysis.git
				synced 2025-10-31 05:11:27 +00:00 
			
		
		
		
	Fix Frida scripts
This commit is contained in:
		
							parent
							
								
									a770a0b587
								
							
						
					
					
						commit
						c50e2eb113
					
				|  | @ -13,7 +13,7 @@ This is how one can run the PoC: | |||
| - Assumption: You've already set up your test environment (see setup description [here](./SETUP.md)) | ||||
| - Wipe all entries in the `public_key_info` and `secret_key_info` tables from the `KakaoTalk.db` database | ||||
| - Start `mitmproxy`: `$ mitmdump -m wireguard -s mitm_secret_chat.py` | ||||
| - Start `Frida`: `$ frida -U -l trace_loco.js -f com.kakao.talk` | ||||
| - Start `Frida`: `$ frida -U -l debug_secret_chat.js -f com.kakao.talk` | ||||
| - Create a new *Secret Chat* room in the KakaoTalk app and send a message | ||||
| - View message in `mitmproxy` terminal window | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,52 +2,88 @@ | |||
| Hook various Secret Chat methods of KakaoTalk 10.4.3. | ||||
| */ | ||||
| 
 | ||||
| import { printStacktrace, dumpByteArray } from "./utils.js"; | ||||
| const locoKey = Java.array( | ||||
|   "byte", | ||||
|   [ | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, | ||||
|   ] | ||||
| ); | ||||
| const patchLocoKey = true; | ||||
| const locoFileNames = [ | ||||
|   "V2SLSink.kt", | ||||
|   "V2SLSource.kt", | ||||
|   "V2SLHandshake.kt", | ||||
|   "LocoV2SLSocket.kt", | ||||
| ]; | ||||
| const enableStacktracePrinting = false; | ||||
| var StringCls = null; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   hookLocoCipherHelper(); | ||||
|   hookLocoCipherHelper_2(); | ||||
|   StringCls = Java.use("java.lang.String"); | ||||
|   hookKeyGeneratorGenerateKey(); | ||||
|   hookSharedSecretStore(); | ||||
|   hookLocoCipherHelper_GenerateRSAPrivateKey(); | ||||
|   hookLocoCipherHelper_GenerateRSAPublicKey(); | ||||
|   hookAESCTRHelper_GenerateIV(); | ||||
|   hookSecretChatHelper(); | ||||
|   hookLocoPubKeyInfo(); | ||||
|   hookTalkLocoPKStore(); | ||||
|   hookTalkLocoPKStore_2(); | ||||
|   hookAESCTRHelper_GenerateIV(); | ||||
|   printAESCTRKeySet(); | ||||
| }); | ||||
| 
 | ||||
| const printStacktrace = false; | ||||
| function hookKeyGeneratorGenerateKey() { | ||||
|   var generateKey = Java.use("javax.crypto.KeyGenerator")[ | ||||
|     "generateKey" | ||||
|   ].overload(); | ||||
| 
 | ||||
| function hookLocoCipherHelper() { | ||||
|   var locoCipherHelper = Java.use("com.kakao.talk.secret.LocoCipherHelper")[ | ||||
|     "s" | ||||
|   ].overload("com.kakao.talk.secret.LocoCipherHelper$c", "[B", "[B"); | ||||
|   locoCipherHelper.implementation = function (arg0, arg1, arg2) { | ||||
|     console.log("hookLocoCipherHelper2 called!"); | ||||
|   generateKey.implementation = function () { | ||||
|     var tmp = this.generateKey(); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     var ret = locoCipherHelper.call(this, arg0, arg1, arg2); | ||||
|     console.log(ret); | ||||
|     return locoCipherHelper.call(this, arg0, arg1, arg2); | ||||
|     const secretKeySpec = Java.cast( | ||||
|       tmp, | ||||
|       Java.use("javax.crypto.spec.SecretKeySpec") | ||||
|     ); | ||||
|     const encodedKey = secretKeySpec.getEncoded(); | ||||
| 
 | ||||
|     if (locoFileNames.includes(caller.getFileName())) { | ||||
|       // console.log("[KeyGenerator.generateKey()]: Object: " + tmp);
 | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       // dumpByteArray("[KeyGenerator.generateKey()]: Key", encodedKey);
 | ||||
|       var base64_key = Java.use("android.util.Base64").encodeToString( | ||||
|         encodedKey, | ||||
|         0 | ||||
|       ); | ||||
|       console.log("Generated key: " + base64_key); | ||||
| 
 | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (patchLocoKey) { | ||||
|       dumpByteArray("Patching LOCO AES key with key", locoKey); | ||||
|       const SecretKeySpec = Java.use("javax.crypto.spec.SecretKeySpec"); | ||||
|       var fakeKey = SecretKeySpec.$new(locoKey, "AES"); | ||||
|       tmp = fakeKey; | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
| 
 | ||||
|     return tmp; | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function hookLocoCipherHelper_2() { | ||||
|   var locoCipherHelper = Java.use("com.kakao.talk.secret.LocoCipherHelper$b")[ | ||||
| function hookSharedSecretStore() { | ||||
|   var locoCipherHelper = Java.use("com.kakao.talk.secret.LocoCipherHelper$e")[ | ||||
|     "$init" | ||||
|   ].overload( | ||||
|     "com.kakao.talk.secret.LocoCipherHelper$d", | ||||
|     "com.kakao.talk.secret.LocoCipherHelper$c" | ||||
|   ); | ||||
|   ].overload("java.lang.String", "long"); | ||||
|   locoCipherHelper.implementation = function (arg0, arg1) { | ||||
|     var tmp = this.$init(arg0, arg1); | ||||
|     console.log("hookLocoCipherHelper5 called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     console.log(arg0); | ||||
|     console.log(arg1); | ||||
|     console.log("Secret Chat shared secret: " + arg0); | ||||
|     console.log("Secret Chat seed for nonce: " + arg1); | ||||
|     console.log(this.toString()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     console.log("##############################################"); | ||||
|   }; | ||||
| } | ||||
|  | @ -59,10 +95,10 @@ function hookLocoCipherHelper_GenerateRSAPrivateKey() { | |||
|   locoCipherHelper.implementation = function (arg0) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     // var private_key = locoCipherHelper.call(this, arg0);
 | ||||
|     // var encoded_key = Java.use("android.util.Base64").encodeToString(private_key.getEncoded(), 0);
 | ||||
|     console.log("Generate RSA private key from string: " + arg0); | ||||
|     // console.log(encoded_key)
 | ||||
|     console.log("Generated RSA private key: " + arg0); | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
|     return locoCipherHelper.call(this, arg0); | ||||
|   }; | ||||
|  | @ -74,13 +110,9 @@ function hookLocoCipherHelper_GenerateRSAPublicKey() { | |||
|   ].overload("java.lang.String"); | ||||
|   locoCipherHelper.implementation = function (arg0) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     var ret = locoCipherHelper.call(this, arg0); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     console.log("Generate RSA public key from string: " + arg0); | ||||
|     var public_key = locoCipherHelper.call(this, arg0); | ||||
|     // var encoded_key = Java.use("android.util.Base64").encodeToString(public_key.getEncoded(), 0);
 | ||||
|     // console.log(encoded_key);
 | ||||
|     if (printStacktrace) { | ||||
|     console.log("Generated RSA public key: " + arg0); | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
|  | @ -96,7 +128,7 @@ function hookLocoPubKeyInfo() { | |||
|     var tmp = this.$init(locoBody); | ||||
|     console.log("locoPubKeyInfo called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     console.log(locoBody); | ||||
|     console.log("##############################################"); | ||||
|   }; | ||||
|  | @ -117,24 +149,11 @@ function hookSecretChatHelper() { | |||
| } | ||||
| 
 | ||||
| function hookTalkLocoPKStore() { | ||||
|   var talkLocoPKStore = Java.use("yl1.x3")["toString"].overload(); | ||||
|   talkLocoPKStore.implementation = function () { | ||||
|     console.log("talkLocoPKStore called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     var ret = talkLocoPKStore.call(this); | ||||
|     console.log(ret); | ||||
|     console.log("##############################################"); | ||||
|     return talkLocoPKStore.call(this); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function hookTalkLocoPKStore_2() { | ||||
|   var talkLocoPKStore = Java.use("yl1.x3$a")["toString"].overload(); | ||||
|   talkLocoPKStore.implementation = function () { | ||||
|     console.log("talkLocoPKStore2 called!"); | ||||
|     console.log("TalkLocoPKStore class called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     var ret = talkLocoPKStore.call(this); | ||||
|     console.log(ret); | ||||
|     console.log("##############################################"); | ||||
|  | @ -150,6 +169,9 @@ function hookAESCTRHelper_GenerateIV() { | |||
|     "javax.crypto.spec.PBEKeySpec" | ||||
|   ); | ||||
|   AESCTRHelper.implementation = function (arg0, arg1, arg2, arg3) { | ||||
|     console.log("AESCTRHelper class called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     dumpByteArray("Generated IV", arg1); | ||||
|     console.log("##############################################"); | ||||
|     return AESCTRHelper.call(this, arg0, arg1, arg2, arg3); | ||||
|  | @ -159,6 +181,9 @@ function hookAESCTRHelper_GenerateIV() { | |||
| function printAESCTRKeySet() { | ||||
|   var AESCTRKeySet = Java.use("d20.b")["$init"].overload("[B", "[B", "[B"); | ||||
|   AESCTRKeySet.implementation = function (arg0, arg1, arg2) { | ||||
|     console.log("AESCTRKeySet class called!"); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     dumpByteArray("Secret key", arg0); | ||||
|     dumpByteArray("IV", arg1); | ||||
|     dumpByteArray("arg2", arg2); | ||||
|  | @ -166,3 +191,69 @@ function printAESCTRKeySet() { | |||
|     return AESCTRKeySet.call(this, arg0, arg1, arg2); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
| 
 | ||||
| function dumpByteArray(title, byteArr) { | ||||
|   if (byteArr != null) { | ||||
|     try { | ||||
|       var buff = new ArrayBuffer(byteArr.length); | ||||
|       var dtv = new DataView(buff); | ||||
|       for (var i = 0; i < byteArr.length; i++) { | ||||
|         /* | ||||
|         Frida sucks sometimes and returns different byteArr.length between ArrayBuffer(byteArr.length) and for(..; i < byteArr.length;..). | ||||
|         It occurred even when Array.copyOf was done to work on copy. | ||||
|         */ | ||||
|         dtv.setUint8(i, byteArr[i]); | ||||
|       } | ||||
|       console.log(title + ":\n"); | ||||
|       console.log(_hexdumpJS(dtv.buffer, 0, byteArr.length)); | ||||
|     } catch (error) { | ||||
|       console.log("Exception has occured in hexdump"); | ||||
|     } | ||||
|   } else { | ||||
|     console.log("byteArr is null!"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function _hexdumpJS(arrayBuffer, offset, length) { | ||||
|   var view = new DataView(arrayBuffer); | ||||
|   offset = offset || 0; | ||||
|   length = length || arrayBuffer.byteLength; | ||||
| 
 | ||||
|   var out = | ||||
|     _fillUp("Offset", 8, " ") + | ||||
|     "  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; | ||||
|   var row = ""; | ||||
|   for (var i = 0; i < length; i += 16) { | ||||
|     row += _fillUp(offset.toString(16).toUpperCase(), 8, "0") + "  "; | ||||
|     var n = Math.min(16, length - offset); | ||||
|     var string = ""; | ||||
|     for (var j = 0; j < 16; ++j) { | ||||
|       if (j < n) { | ||||
|         var value = view.getUint8(offset); | ||||
|         string += value >= 32 && value < 128 ? String.fromCharCode(value) : "."; | ||||
|         row += _fillUp(value.toString(16).toUpperCase(), 2, "0") + " "; | ||||
|         offset++; | ||||
|       } else { | ||||
|         row += "   "; | ||||
|         string += " "; | ||||
|       } | ||||
|     } | ||||
|     row += " " + string + "\n"; | ||||
|   } | ||||
|   out += row; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| function _fillUp(value, count, fillWith) { | ||||
|   var l = count - value.length; | ||||
|   var ret = ""; | ||||
|   while (--l > -1) ret += fillWith; | ||||
|   return ret + value; | ||||
| } | ||||
|  |  | |||
|  | @ -2,36 +2,34 @@ | |||
| Debug WebViews. | ||||
| */ | ||||
| 
 | ||||
| import { printStacktrace, printMap } from "./utils.js"; | ||||
| const enableStacktracePrinting = false; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   enableWebviewDebugging(); | ||||
| }); | ||||
| 
 | ||||
| const printStacktrace = false; | ||||
| 
 | ||||
| function enableWebviewDebugging() { | ||||
|   var Webview = Java.use("android.webkit.WebView"); | ||||
| 
 | ||||
|   Webview.loadUrl.overload("java.lang.String").implementation = function (url) { | ||||
|     console.log("\n[+]Loading URL from", url); | ||||
|     console.log("\n[+] Loading URL from", url); | ||||
|     console.log( | ||||
|       "[+]Setting the value of setWebContentsDebuggingEnabled() to TRUE" | ||||
|       "[+] Setting the value of setWebContentsDebuggingEnabled() to TRUE" | ||||
|     ); | ||||
|     if (printStacktrace) { | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     var js = this.getSettings().getJavaScriptEnabled(); | ||||
|     console.log("[+]JS enabled: " + js); | ||||
|     console.log("[+] JS enabled: " + js); | ||||
| 
 | ||||
|     var mw = this.getSettings().supportMultipleWindows(); | ||||
|     console.log("[+]Mutliple windows?: " + mw); | ||||
|     console.log("[+] Multiple windows?: " + mw); | ||||
| 
 | ||||
|     var fa = this.getSettings().getAllowFileAccess(); | ||||
|     console.log("[+]File access: " + fa); | ||||
|     console.log("[+] File access: " + fa); | ||||
| 
 | ||||
|     var uf = this.getSettings().getAllowUniversalAccessFromFileURLs(); | ||||
|     console.log("[+]Universal file access: " + uf); | ||||
|     console.log("[+] Universal file access: " + uf); | ||||
| 
 | ||||
|     this.setWebContentsDebuggingEnabled(true); | ||||
|     this.loadUrl.overload("java.lang.String").call(this, url); | ||||
|  | @ -39,29 +37,29 @@ function enableWebviewDebugging() { | |||
| 
 | ||||
|   Webview.loadUrl.overload("java.lang.String", "java.util.Map").implementation = | ||||
|     function (url, additionalHttpHeaders) { | ||||
|       console.log("\n[+]Loading URL from", url); | ||||
|       console.log("[+]Additional Headers:"); | ||||
|       console.log("\n[+] Loading URL from", url); | ||||
|       console.log("[+] Additional Headers:"); | ||||
|       var headers = Java.cast(additionalHttpHeaders, Java.use("java.util.Map")); | ||||
|       printMap(headers); | ||||
|       console.log( | ||||
|         "[+]Setting the value of setWebContentsDebuggingEnabled() to TRUE" | ||||
|         "[+] Setting the value of setWebContentsDebuggingEnabled() to TRUE" | ||||
|       ); | ||||
| 
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
| 
 | ||||
|       var js = this.getSettings().getJavaScriptEnabled(); | ||||
|       console.log("[+]JS enabled: " + js); | ||||
|       console.log("[+] JS enabled: " + js); | ||||
| 
 | ||||
|       var mw = this.getSettings().supportMultipleWindows(); | ||||
|       console.log("[+]Multiple windows?: " + mw); | ||||
|       console.log("[+] Multiple windows?: " + mw); | ||||
| 
 | ||||
|       var fa = this.getSettings().getAllowFileAccess(); | ||||
|       console.log("[+]File access: " + fa); | ||||
|       console.log("[+] File access: " + fa); | ||||
| 
 | ||||
|       var uf = this.getSettings().getAllowUniversalAccessFromFileURLs(); | ||||
|       console.log("[+]Universal file access: " + uf); | ||||
|       console.log("[+] Universal file access: " + uf); | ||||
| 
 | ||||
|       this.setWebContentsDebuggingEnabled(true); | ||||
|       this.loadUrl | ||||
|  | @ -71,7 +69,7 @@ function enableWebviewDebugging() { | |||
| 
 | ||||
|   Webview.addJavascriptInterface.implementation = function (object, name) { | ||||
|     console.log( | ||||
|       "[+]Javascript interface:" + | ||||
|       "[+] Javascript interface:" + | ||||
|         object.$className + | ||||
|         " instantiated as: " + | ||||
|         name | ||||
|  | @ -86,7 +84,7 @@ function enableWebviewDebugging() { | |||
|     "android.graphics.Bitmap" | ||||
|   ).implementation = function (view, url, favicon) { | ||||
|     console.log("onPageStarted URL: " + url); | ||||
|     if (printStacktrace) { | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     this.onPageStarted | ||||
|  | @ -124,3 +122,17 @@ function enableWebviewDebugging() { | |||
|     return ret; | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
| 
 | ||||
| function printMap(map) { | ||||
|   var mapIter = map.entrySet().iterator(); | ||||
|   while (mapIter.hasNext()) { | ||||
|     console.log(mapIter.next()); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -2,14 +2,31 @@ | |||
| Hook most of Android's Crypto APIs. | ||||
| */ | ||||
| 
 | ||||
| import { | ||||
|   printStacktrace, | ||||
|   dumpByteArray, | ||||
|   decodeMode, | ||||
|   charArrayToString, | ||||
| } from "./utils.js"; | ||||
| /* | ||||
| const doNotHookFileNames = [ | ||||
|   "SimpleCipher.kt", | ||||
|   "AccountUpdater.kt", | ||||
|   "DataBaseResourceCrypto.kt", | ||||
|   "CookieContentEncryptor.java", | ||||
|   "Aes256Cipher.kt", | ||||
|   "TiaraEncrypt.java", | ||||
| ]; | ||||
| */ | ||||
| const doNotHookFileNames = []; | ||||
| const hookAllClasses = false; | ||||
| const dummyKey = Java.array( | ||||
|   "byte", | ||||
|   [ | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, | ||||
|   ] | ||||
| ); | ||||
| const patchKey = true; | ||||
| const enableStacktracePrinting = false; | ||||
| var StringCls = null; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   StringCls = Java.use("java.lang.String"); | ||||
|   hookCipherGetInstance(); | ||||
|   hookCipherGetInstance2(); | ||||
|   hookCipherGetInstance3(); | ||||
|  | @ -48,29 +65,6 @@ Java.perform(function () { | |||
|   hookKeyPairGeneratorGetInstance(); | ||||
| }); | ||||
| 
 | ||||
| /* | ||||
| const doNotHookFileNames = [ | ||||
|   "SimpleCipher.kt", | ||||
|   "AccountUpdater.kt", | ||||
|   "DataBaseResourceCrypto.kt", | ||||
|   "CookieContentEncryptor.java", | ||||
|   "Aes256Cipher.kt", | ||||
|   "TiaraEncrypt.java", | ||||
| ]; | ||||
| */ | ||||
| 
 | ||||
| const doNotHookFileNames = []; | ||||
| const dummyKey = Java.array( | ||||
|   "byte", | ||||
|   [ | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, | ||||
|   ] | ||||
| ); | ||||
| const patchKey = true; | ||||
| const hookAllClasses = false; | ||||
| const printStacktrace = false; | ||||
| 
 | ||||
| /* | ||||
|     .overload("java.lang.String") | ||||
|     .overload("java.lang.String", "java.security.Provider") | ||||
|  | @ -84,10 +78,10 @@ function hookCipherGetInstance() { | |||
|     var tmp = this.getInstance(type); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log("[Cipher.getInstance()]: type: " + type); | ||||
|       console.log("[Cipher.getInstance()]:  cipherObj: " + tmp); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -181,7 +175,7 @@ function hookCipherInit2() { | |||
|     // dumpByteArray("Secret key", key);
 | ||||
|     var key_base64 = Java.use("android.util.Base64").encodeToString(key, 0); | ||||
|     console.log("Base64 encoded key: " + key_base64); | ||||
|     if (printStacktrace) { | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
|  | @ -221,7 +215,7 @@ function hookCipherInit4() { | |||
|     var tmp = this.init(mode, secretKey, spec); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log( | ||||
|         "[Cipher.init4()]: mode: " + | ||||
|           decodeMode(mode) + | ||||
|  | @ -239,7 +233,7 @@ function hookCipherInit4() { | |||
|         Java.use("javax.crypto.spec.IvParameterSpec") | ||||
|       ); | ||||
|       dumpByteArray("IV", ivParameterSpec.getIV()); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -298,7 +292,7 @@ function hookCipherInit6() { | |||
|         0 | ||||
|       ); | ||||
|       console.log("Secret key: " + secret_key_base64); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -397,7 +391,7 @@ function hookDoFinal2() { | |||
|         0 | ||||
|       ); | ||||
|       // console.log("Result in Base64: " + result_base64)
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -542,10 +536,10 @@ function hookPBEKeySpec3() { | |||
|     console.log( | ||||
|       "[PBEKeySpec.PBEKeySpec3()]: iter: " + iter + " key length: " + keyLength | ||||
|     ); | ||||
|     console.log(caller.getFileName()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     dumpByteArray("Password", charArrayToString(pass).getBytes()); | ||||
|     dumpByteArray("Salt", salt); | ||||
|     if (printStacktrace) { | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
|  | @ -564,9 +558,9 @@ function hookIVParameterSpecDefInit1() { | |||
|   ivParameterSpecDef.implementation = function (arr) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       dumpByteArray("IV", arr); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -582,9 +576,9 @@ function hookIVParameterSpecDefInit2() { | |||
|   ivParameterSpecDef.implementation = function (arr, off, len) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       dumpByteArray("IV", arr); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -604,9 +598,9 @@ function hookSecretKeySpecDefInit1() { | |||
|   secretKeySpecDef.implementation = function (arr, alg) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       dumpByteArray(alg + " Secret Key", arr); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -622,9 +616,9 @@ function hookSecretKeySpecDefInit2() { | |||
|   secretKeySpecDef.implementation = function (arr, off, len, alg) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       dumpByteArray(alg + " Secret Key", arr); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -738,10 +732,10 @@ function hookKeyGeneratorGetInstance() { | |||
|     var tmp = this.getInstance(type); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log("[KeyGenerator.getInstance()]: type: " + type); | ||||
|       console.log("[KeyGenerator.getInstance()]: cipherObj: " + tmp); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -758,10 +752,10 @@ function hookKeyGeneratorGetInstance2() { | |||
|     var tmp = this.getInstance(alg, provider); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log("[KeyGenerator.getInstance2()]: Algorithm: " + alg); | ||||
|       console.log("[KeyGenerator.getInstance2()]: Provider: " + provider); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -778,10 +772,10 @@ function hookKeyGeneratorGetInstance3() { | |||
|     var tmp = this.getInstance(alg, provider); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log("[KeyGenerator.getInstance2()]: Algorithm: " + alg); | ||||
|       console.log("[KeyGenerator.getInstance2()]: Provider: " + provider); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -802,14 +796,14 @@ function hookKeyGeneratorInit() { | |||
|     var tmp = this.init(length, secureRandom); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     if (!doNotHookFileNames.includes(caller.getFileName()) || hookAllClasses) { | ||||
|       console.log(caller.getFileName()); | ||||
|       console.log("Caller: " + caller.getFileName()); | ||||
|       console.log( | ||||
|         "[KeyGenerator.init()]: secureRandom:" + | ||||
|           secureRandom + | ||||
|           " , cipherObj: " + | ||||
|           this | ||||
|       ); | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("##############################################"); | ||||
|  | @ -841,7 +835,7 @@ function hookKeyGeneratorGenerateKey() { | |||
|       ); | ||||
|       console.log("Generated key: " + base64_key); | ||||
| 
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|     } | ||||
|  | @ -867,12 +861,90 @@ function hookKeyPairGeneratorGetInstance() { | |||
|   ].overload("java.lang.String"); | ||||
|   keyPairGetInstance.implementation = function (alg) { | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log(caller.getFileName()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     console.log("[KeyPairGenerator.getInstance()]: Algorithm:" + alg); | ||||
|     if (printStacktrace) { | ||||
|     if (enableStacktracePrinting) { | ||||
|       printStacktrace(); | ||||
|     } | ||||
|     console.log("##############################################"); | ||||
|     return this.getInstance(alg); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
| 
 | ||||
| function dumpByteArray(title, byteArr) { | ||||
|   if (byteArr != null) { | ||||
|     try { | ||||
|       var buff = new ArrayBuffer(byteArr.length); | ||||
|       var dtv = new DataView(buff); | ||||
|       for (var i = 0; i < byteArr.length; i++) { | ||||
|         /* | ||||
|           Frida sucks sometimes and returns different byteArr.length between ArrayBuffer(byteArr.length) and for(..; i < byteArr.length;..). | ||||
|           It occurred even when Array.copyOf was done to work on copy. | ||||
|           */ | ||||
|         dtv.setUint8(i, byteArr[i]); | ||||
|       } | ||||
|       console.log(title + ":\n"); | ||||
|       console.log(_hexdumpJS(dtv.buffer, 0, byteArr.length)); | ||||
|     } catch (error) { | ||||
|       console.log("Exception has occured in hexdump"); | ||||
|     } | ||||
|   } else { | ||||
|     console.log("byteArr is null!"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function _hexdumpJS(arrayBuffer, offset, length) { | ||||
|   var view = new DataView(arrayBuffer); | ||||
|   offset = offset || 0; | ||||
|   length = length || arrayBuffer.byteLength; | ||||
| 
 | ||||
|   var out = | ||||
|     _fillUp("Offset", 8, " ") + | ||||
|     "  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; | ||||
|   var row = ""; | ||||
|   for (var i = 0; i < length; i += 16) { | ||||
|     row += _fillUp(offset.toString(16).toUpperCase(), 8, "0") + "  "; | ||||
|     var n = Math.min(16, length - offset); | ||||
|     var string = ""; | ||||
|     for (var j = 0; j < 16; ++j) { | ||||
|       if (j < n) { | ||||
|         var value = view.getUint8(offset); | ||||
|         string += value >= 32 && value < 128 ? String.fromCharCode(value) : "."; | ||||
|         row += _fillUp(value.toString(16).toUpperCase(), 2, "0") + " "; | ||||
|         offset++; | ||||
|       } else { | ||||
|         row += "   "; | ||||
|         string += " "; | ||||
|       } | ||||
|     } | ||||
|     row += " " + string + "\n"; | ||||
|   } | ||||
|   out += row; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| function _fillUp(value, count, fillWith) { | ||||
|   var l = count - value.length; | ||||
|   var ret = ""; | ||||
|   while (--l > -1) ret += fillWith; | ||||
|   return ret + value; | ||||
| } | ||||
| 
 | ||||
| function decodeMode(mode) { | ||||
|   if (mode == 1) return "Encrypt mode"; | ||||
|   else if (mode == 2) return "Decrypt mode"; | ||||
|   else if (mode == 3) return "Wrap mode"; | ||||
|   else if (mode == 4) return "Unwrap mode"; | ||||
| } | ||||
| 
 | ||||
| function charArrayToString(charArray) { | ||||
|   if (charArray == null) return "(null)"; | ||||
|   else return StringCls.$new(charArray); | ||||
| } | ||||
|  |  | |||
|  | @ -1,47 +0,0 @@ | |||
| /* | ||||
| Print all Strings. | ||||
| */ | ||||
| 
 | ||||
| import { printStacktrace } from "./utils.js"; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   hookStrings(); | ||||
| }); | ||||
| 
 | ||||
| const printStacktrace = false; | ||||
| var StringCls = null; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   StringCls = Java.use("java.lang.String"); | ||||
| }); | ||||
| 
 | ||||
| function hookStrings() { | ||||
|   let StringBuilder = Java.use("java.lang.StringBuilder"); | ||||
|   StringBuilder.toString.overload().implementation = function () { | ||||
|     let StringBuilderResult = this.toString.call(this); | ||||
| 
 | ||||
|     if ( | ||||
|       StringBuilderResult !== null && | ||||
|       StringBuilderResult.indexOf("file:") != -1 | ||||
|     ) { | ||||
|       if (printStacktrace) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|       console.log("[+] StringBuilder:\t", StringBuilderResult); | ||||
|     } | ||||
|     return StringBuilderResult; | ||||
|   }; | ||||
| 
 | ||||
|   let StringBuffer = Java.use("java.lang.StringBuffer"); | ||||
|   StringBuffer.toString.overload().implementation = function () { | ||||
|     let StringBufferResult = this.toString.call(this); | ||||
| 
 | ||||
|     if ( | ||||
|       StringBufferResult !== null && | ||||
|       StringBufferResult.indexOf("http") != -1 | ||||
|     ) { | ||||
|       console.log("[+] StringBuffer:\t", StringBufferResult); | ||||
|     } | ||||
|     return StringBufferResult; | ||||
|   }; | ||||
| } | ||||
|  | @ -2,14 +2,12 @@ | |||
| Debug Deep Links. | ||||
| */ | ||||
| 
 | ||||
| import { printStacktrace } from "./utils.js"; | ||||
| const enableStacktracePrinting = false; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   deepLinkSniffer(); | ||||
| }); | ||||
| 
 | ||||
| const printStacktrace = false; | ||||
| 
 | ||||
| function deepLinkSniffer() { | ||||
|   var Intent = Java.use("android.content.Intent"); | ||||
|   Intent.getData.implementation = function () { | ||||
|  | @ -17,11 +15,13 @@ function deepLinkSniffer() { | |||
|       this.getAction() !== null ? this.getAction().toString() : false; | ||||
|     if (action) { | ||||
|       console.log("[*] Intent.getData() was called"); | ||||
|       console.log("[*] Activity: " + this.getComponent().getClassName()); | ||||
|       if (this.getComponent()) { | ||||
|         console.log("[*] Activity: " + this.getComponent().getClassName()); | ||||
|       } | ||||
|       console.log("[*] Action: " + action); | ||||
|       var uri = this.getData(); | ||||
| 
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
| 
 | ||||
|  | @ -45,3 +45,10 @@ function deepLinkSniffer() { | |||
|     return this.getData(); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
|  |  | |||
|  | @ -2,15 +2,6 @@ | |||
| Decrypt and print LOCO traffic of KakaoTalk 10.4.3. | ||||
| */ | ||||
| 
 | ||||
| import { dumpByteArray, printStacktrace } from "./utils.js"; | ||||
| 
 | ||||
| Java.perform(function () { | ||||
|   hookDoFinal2(); | ||||
|   hookKeyGeneratorGenerateKey(); | ||||
|   hookSharedSecretStore(); | ||||
|   printLocoBody(); | ||||
| }); | ||||
| 
 | ||||
| const locoKey = Java.array( | ||||
|   "byte", | ||||
|   [ | ||||
|  | @ -18,16 +9,20 @@ const locoKey = Java.array( | |||
|     0x00, 0x00, 0x00, 0x00, | ||||
|   ] | ||||
| ); | ||||
| 
 | ||||
| const patchLocoKey = true; | ||||
| const locoFileNames = [ | ||||
|   "V2SLSink.kt", | ||||
|   "V2SLSource.kt", | ||||
|   "V2SLHandshake.kt", | ||||
|   "LocoV2SLSocket.kt", | ||||
| ]; | ||||
| const enableStacktracePrinting = false; | ||||
| 
 | ||||
| const patchLocoKey = true; | ||||
| const printStacktrace = false; | ||||
| Java.perform(function () { | ||||
|   hookDoFinal2(); | ||||
|   hookKeyGeneratorGenerateKey(); | ||||
|   printLocoBody(); | ||||
| }); | ||||
| 
 | ||||
| function hookDoFinal2() { | ||||
|   var cipherInit = Java.use("javax.crypto.Cipher")["doFinal"].overload("[B"); | ||||
|  | @ -44,7 +39,7 @@ function hookDoFinal2() { | |||
|       // var result_base64 = Java.use("android.util.Base64").encodeToString(tmp, 0);
 | ||||
|       // console.log("Result in Base64: " + result_base64)
 | ||||
| 
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
| 
 | ||||
|  | @ -79,7 +74,7 @@ function hookKeyGeneratorGenerateKey() { | |||
|       ); | ||||
|       console.log("Generated key: " + base64_key); | ||||
| 
 | ||||
|       if (printStacktrace) { | ||||
|       if (enableStacktracePrinting) { | ||||
|         printStacktrace(); | ||||
|       } | ||||
|     } | ||||
|  | @ -96,21 +91,6 @@ function hookKeyGeneratorGenerateKey() { | |||
|   }; | ||||
| } | ||||
| 
 | ||||
| function hookSharedSecretStore() { | ||||
|   var locoCipherHelper = Java.use("com.kakao.talk.secret.LocoCipherHelper$e")[ | ||||
|     "$init" | ||||
|   ].overload("java.lang.String", "long"); | ||||
|   locoCipherHelper.implementation = function (arg0, arg1) { | ||||
|     var tmp = this.$init(arg0, arg1); | ||||
|     var caller = Java.use("java.lang.Exception").$new().getStackTrace()[1]; | ||||
|     console.log("Secret Chat shared secret: " + arg0); | ||||
|     console.log("Secret Chat seed for nonce: " + arg1); | ||||
|     console.log(this.toString()); | ||||
|     console.log("Caller: " + caller.getFileName()); | ||||
|     console.log("##############################################"); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function printLocoBody() { | ||||
|   Java.choose("com.kakao.talk.loco.protocol.LocoBody", { | ||||
|     onMatch: function (instance) { | ||||
|  | @ -121,3 +101,69 @@ function printLocoBody() { | |||
|     onComplete: function () {}, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
| 
 | ||||
| function dumpByteArray(title, byteArr) { | ||||
|   if (byteArr != null) { | ||||
|     try { | ||||
|       var buff = new ArrayBuffer(byteArr.length); | ||||
|       var dtv = new DataView(buff); | ||||
|       for (var i = 0; i < byteArr.length; i++) { | ||||
|         /* | ||||
|           Frida sucks sometimes and returns different byteArr.length between ArrayBuffer(byteArr.length) and for(..; i < byteArr.length;..). | ||||
|           It occurred even when Array.copyOf was done to work on copy. | ||||
|           */ | ||||
|         dtv.setUint8(i, byteArr[i]); | ||||
|       } | ||||
|       console.log(title + ":\n"); | ||||
|       console.log(_hexdumpJS(dtv.buffer, 0, byteArr.length)); | ||||
|     } catch (error) { | ||||
|       console.log("Exception has occured in hexdump"); | ||||
|     } | ||||
|   } else { | ||||
|     console.log("byteArr is null!"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function _hexdumpJS(arrayBuffer, offset, length) { | ||||
|   var view = new DataView(arrayBuffer); | ||||
|   offset = offset || 0; | ||||
|   length = length || arrayBuffer.byteLength; | ||||
| 
 | ||||
|   var out = | ||||
|     _fillUp("Offset", 8, " ") + | ||||
|     "  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; | ||||
|   var row = ""; | ||||
|   for (var i = 0; i < length; i += 16) { | ||||
|     row += _fillUp(offset.toString(16).toUpperCase(), 8, "0") + "  "; | ||||
|     var n = Math.min(16, length - offset); | ||||
|     var string = ""; | ||||
|     for (var j = 0; j < 16; ++j) { | ||||
|       if (j < n) { | ||||
|         var value = view.getUint8(offset); | ||||
|         string += value >= 32 && value < 128 ? String.fromCharCode(value) : "."; | ||||
|         row += _fillUp(value.toString(16).toUpperCase(), 2, "0") + " "; | ||||
|         offset++; | ||||
|       } else { | ||||
|         row += "   "; | ||||
|         string += " "; | ||||
|       } | ||||
|     } | ||||
|     row += " " + string + "\n"; | ||||
|   } | ||||
|   out += row; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| function _fillUp(value, count, fillWith) { | ||||
|   var l = count - value.length; | ||||
|   var ret = ""; | ||||
|   while (--l > -1) ret += fillWith; | ||||
|   return ret + value; | ||||
| } | ||||
|  |  | |||
|  | @ -1,84 +0,0 @@ | |||
| export function printStacktrace() { | ||||
|   var stacktrace = Java.use("android.util.Log") | ||||
|     .getStackTraceString(Java.use("java.lang.Exception").$new()) | ||||
|     .replace("java.lang.Exception", ""); | ||||
|   console.log(stacktrace); | ||||
| } | ||||
| 
 | ||||
| export function printMap(map) { | ||||
|   var mapIter = map.entrySet().iterator(); | ||||
|   while (mapIter.hasNext()) { | ||||
|     console.log(mapIter.next()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function decodeMode(mode) { | ||||
|   if (mode == 1) return "Encrypt mode"; | ||||
|   else if (mode == 2) return "Decrypt mode"; | ||||
|   else if (mode == 3) return "Wrap mode"; | ||||
|   else if (mode == 4) return "Unwrap mode"; | ||||
| } | ||||
| 
 | ||||
| export function charArrayToString(charArray) { | ||||
|   if (charArray == null) return "(null)"; | ||||
|   else return StringCls.$new(charArray); | ||||
| } | ||||
| 
 | ||||
| export function dumpByteArray(title, byteArr) { | ||||
|   if (byteArr != null) { | ||||
|     try { | ||||
|       var buff = new ArrayBuffer(byteArr.length); | ||||
|       var dtv = new DataView(buff); | ||||
|       for (var i = 0; i < byteArr.length; i++) { | ||||
|         /* | ||||
|         Frida sucks sometimes and returns different byteArr.length between ArrayBuffer(byteArr.length) and for(..; i < byteArr.length;..). | ||||
|         It occurred even when Array.copyOf was done to work on copy. | ||||
|         */ | ||||
|         dtv.setUint8(i, byteArr[i]); | ||||
|       } | ||||
|       console.log(title + ":\n"); | ||||
|       console.log(_hexdumpJS(dtv.buffer, 0, byteArr.length)); | ||||
|     } catch (error) { | ||||
|       console.log("Exception has occured in hexdump"); | ||||
|     } | ||||
|   } else { | ||||
|     console.log("byteArr is null!"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function _fillUp(value, count, fillWith) { | ||||
|   var l = count - value.length; | ||||
|   var ret = ""; | ||||
|   while (--l > -1) ret += fillWith; | ||||
|   return ret + value; | ||||
| } | ||||
| 
 | ||||
| function _hexdumpJS(arrayBuffer, offset, length) { | ||||
|   var view = new DataView(arrayBuffer); | ||||
|   offset = offset || 0; | ||||
|   length = length || arrayBuffer.byteLength; | ||||
| 
 | ||||
|   var out = | ||||
|     _fillUp("Offset", 8, " ") + | ||||
|     "  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; | ||||
|   var row = ""; | ||||
|   for (var i = 0; i < length; i += 16) { | ||||
|     row += _fillUp(offset.toString(16).toUpperCase(), 8, "0") + "  "; | ||||
|     var n = Math.min(16, length - offset); | ||||
|     var string = ""; | ||||
|     for (var j = 0; j < 16; ++j) { | ||||
|       if (j < n) { | ||||
|         var value = view.getUint8(offset); | ||||
|         string += value >= 32 && value < 128 ? String.fromCharCode(value) : "."; | ||||
|         row += _fillUp(value.toString(16).toUpperCase(), 2, "0") + " "; | ||||
|         offset++; | ||||
|       } else { | ||||
|         row += "   "; | ||||
|         string += " "; | ||||
|       } | ||||
|     } | ||||
|     row += " " + string + "\n"; | ||||
|   } | ||||
|   out += row; | ||||
|   return out; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 stulle123
						stulle123