diff --git a/lib/types.js b/lib/types.js index 6a0f977..d3d34a7 100644 --- a/lib/types.js +++ b/lib/types.js @@ -233,6 +233,17 @@ const primitiveTypes = { } }; +const primitiveTypesNames = Object.keys(primitiveTypes).reduce( + (result, key) => { + result[primitiveTypes[key].name] = true; + return result; + }, {}); + +function isPrimitiveType (name) { + const result = primitiveTypesNames[name]; + return (result !== undefined) ? result : false; +} + function getPrimitiveType (name) { const result = primitiveTypes[name]; return (result !== undefined) ? result : null; @@ -436,10 +447,26 @@ function getArrayType (typeName, unbox, factory) { let elementTypeName = typeName.substring(1); const elementType = getType(elementTypeName, unbox, factory); + let nbInternalArrays = 0; + while (nbInternalArrays < elementTypeName.length && elementTypeName[nbInternalArrays] === '[') { + nbInternalArrays++; + } + elementTypeName = elementTypeName.substring(nbInternalArrays, elementTypeName.length); + if (elementTypeName[0] === 'L' && elementTypeName[elementTypeName.length - 1] === ';') { elementTypeName = elementTypeName.substring(1, elementTypeName.length - 1); } + // The type name we get is not always the correct representation of the type so we make it so here. + let internalElementTypeName = elementTypeName.replace(/\./g, '/'); + if (isPrimitiveType(internalElementTypeName)) { + internalElementTypeName = ('['.repeat(nbInternalArrays)) + internalElementTypeName; + } else { + internalElementTypeName = ('['.repeat(nbInternalArrays)) + 'L' + internalElementTypeName + ';'; + } + const internalTypeName = '[' + internalElementTypeName; + elementTypeName = ('['.repeat(nbInternalArrays)) + elementTypeName; + return { name: typeName.replace(/\./g, '/'), type: 'pointer', @@ -476,8 +503,6 @@ function getArrayType (typeName, unbox, factory) { } } - // The type name we get is not always the correct representation of the type so we make it so here. - const internalTypeName = '[L' + elementTypeName.replace(/\./g, '/') + ';'; try { result.$w = factory.cast(arr, factory.use(internalTypeName), owned); } catch (e) { diff --git a/test/re/frida/MethodTest.java b/test/re/frida/MethodTest.java index 86bf7bb..d1d7068 100644 --- a/test/re/frida/MethodTest.java +++ b/test/re/frida/MethodTest.java @@ -66,6 +66,7 @@ public void primitiveArrayCanBePassed() { assertEquals("12", script.getNextMessage()); } + @Test public void primitive2DArrayCanBePassed() { loadScript("var Buffinator = Java.use('re.frida.Buffinator');" + @@ -74,6 +75,20 @@ public void primitive2DArrayCanBePassed() { assertEquals("45", script.getNextMessage()); } + @Test + public void methodWith2DArrayCanBeHooked() { + loadScript("var Buffinator = Java.use('re.frida.Buffinator');" + + "var sum2d = Buffinator.sum2d;" + + "sum2d.implementation = function (arrs) {" + + "send(JSON.stringify(arrs));" + + "return sum2d.call(this, arrs);" + + "};"); + Buffinator buffinator = new Buffinator(); + byte[][] arrs = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + assertEquals(45, buffinator.sum2d(arrs)); + assertEquals("[[1,2,3],[4,5,6],[7,8,9]]", script.getNextMessage()); + } + @Test public void primitiveArrayCanBeModified() { loadScript("var Buffinator = Java.use('re.frida.Buffinator');" +