diff --git a/scripts/unity.js b/scripts/unity.js index dcce0d4..1d1ba3d 100644 --- a/scripts/unity.js +++ b/scripts/unity.js @@ -1,3 +1,186 @@ +function binary2hex2ascii(array, readBytesNum) { + var result = []; + // performance wise to read 100 bytes + readBytesNum = readBytesNum || 100; + for (var i = 0; i < readBytesNum; ++i) { + // TODO fix unicode for Hebrew and Math related symbols + // * (double) doesn't work, but + (plus) works + result.push(String.fromCharCode( + parseInt( + ('0' + (array[i] & 0xFF).toString(16) ).slice(-2), // binary2hex part + 16 + ) + )); + } + // TODO extract facebookID from previous_winners packet, #OSINT ? + return result.join(''); +} + +function hookInputStream() { + Java.use('java.io.InputStream').read.overload('[B').implementation = function(b) { + var retval = this.read(b); + var resp = binary2hex2ascii(b); + // conditions to not print garbage packets + if ( + resp.indexOf('isBot') == -1 + && resp.indexOf(' Answer') == -1 + && resp.indexOf('Pinged') == -1 + ) { + console.log( resp ); + } + if (resp.indexOf('Waiting To Show Question') != -1) { + console.log("\n\n\t{{ " + binary2hex2ascii( b , 1200) + " }}\n\n"); + } + // TODO mimic answer packet (hook OutputStream), send to get back the answer + return retval; + }; +} + +function hookOutputStream() { + var bClass = Java.use("java.io.OutputStream"); + bClass.write.overload('int').implementation = function(x) { + console.log("[1] " + x); + return this.write(x); + } + bClass.write.overload('[B').implementation = function(b) { + console.log("[2] " + binary2hex2ascii(b) ); + return this.write(b); + } + bClass.write.overload('[B','int','int').implementation = function(b,y,z) { + console.log("[3] " + binary2hex2ascii(b)); + return this.write(b,y,z); + } +} + +function hookConstructor() { + var Map = Java.use('java.util.Map'); + Java.use('com.unity3d.player.UnityWebRequest').$init + .overload('long', 'java.lang.String', 'java.util.Map', 'java.lang.String', 'int').implementation = function(long1, str2, map3, str4, int5) { + console.log(this, JSON.stringify({ + '#1': long1, + method: str2, + headers: Java.cast(map3, Map).toString(), + url: str4, + '#5': int5 + }, null, 2)); + this.$init(long1, str2, map3, str4, int5); + }; +} + +function hookUploadCallback() { + Java.use('com.unity3d.player.UnityWebRequest').uploadCallback.overload('java.nio.ByteBuffer').implementation = function(buf1) { + console.log('uploadCallback', buf1); + this.uploadCallback(buf1); + }; +} + + +function traceClass(targetClass) { + var hook = Java.use(targetClass); + var methods = hook.class.getDeclaredMethods(); + hook.$dispose; + + var parsedMethods = []; + methods.forEach(function(method) { + parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); + }); + + var targets = uniqBy(parsedMethods, JSON.stringify); + targets.forEach(function(targetMethod) { + traceMethod(targetClass + "." + targetMethod); + }); +} + +function traceMethod(targetClassMethod) { + var delim = targetClassMethod.lastIndexOf("."); + if (delim === -1) return; + + var targetClass = targetClassMethod.slice(0, delim) + var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) + var hook = Java.use(targetClass); + var overloadCount = hook[targetMethod].overloads.length; + console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); + for (var i = 0; i < overloadCount; i++) { + hook[targetMethod].overloads[i].implementation = function() { + console.warn("\n*** entered " + targetClassMethod); + + // print backtrace + // Java.perform(function() { + // var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); + // console.log("\nBacktrace:\n" + bt); + // }); + + // print args + if (arguments.length) console.log(); + for (var j = 0; j < arguments.length; j++) { + console.log("arg[" + j + "]: " + arguments[j]); + } + + // print retval + var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?) + console.log("\nretval: " + retval); + console.warn("\n*** exiting " + targetClassMethod); + return retval; + } + } +} + +function uniqBy(array, key) { // remove duplicates from array + var seen = {}; + return array.filter(function(item) { + var k = key(item); + return seen.hasOwnProperty(k) ? false : (seen[k] = true); + }); +} + +// Main +Java.perform(function() { + try { +// hookInputStream(); +// hookOutputStream(); +// hookConstructor(); +// hookUploadCallback(); +// https://blogs.unity3d.com/2014/06/11/all-about-the-unity-networking-transport-layer/ + traceClass('com.unity3d.player.WWW'); + } catch (e) { + console.error(e); + } +}); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + function binary2hex2ascii(array, readBytesNum) { var result = []; // performance wise to read 100 bytes