From c7d6f51220f4c49056aaed2eadeab2f191abb3a6 Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Tue, 23 Jun 2020 19:05:37 -0300 Subject: [PATCH 1/3] dex2jar: Produce MethodParameters and LocalVariableTable --- .../java/com/googlecode/d2j/dex/Dex2Asm.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java index 9f62f59c1..89b591ea2 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java @@ -13,6 +13,8 @@ import com.googlecode.dex2jar.ir.ts.*; import com.googlecode.dex2jar.ir.ts.array.FillArrayTransformer; +import sun.reflect.generics.tree.Tree; + public class Dex2Asm { protected static class Clz { @@ -590,6 +592,59 @@ public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, Clas } } + if (methodNode.codeNode != null && methodNode.codeNode.debugNode != null) { + DexDebugNode debugNode = methodNode.codeNode.debugNode; + boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; + String[] paramTypes = methodNode.method.getParameterTypes(); + + Map localVars = new TreeMap<>(); + if (!isStatic) { + LocalVar local = new LocalVar(0, "this", methodNode.method.getOwner(), null); + localVars.put(local.reg, local); + } + + // Handle debugNode.parameterNames + if (debugNode.parameterNames != null) { + for (int i = 0; i < debugNode.parameterNames.size(); i++) { + String paramName = debugNode.parameterNames.get(i); + + // Put parameter name in MethodParameters attribute + mv.visitParameter(paramName, 0); + + // Also put it into the LocalVariableTable + if (paramName != null) { + LocalVar local = new LocalVar(isStatic ? i : i + 1, paramName, paramTypes[i], null); + localVars.put(local.reg, local); + } + } + } + + // Handle debugNodes to create a LocalVariableTable + int localsOffset = paramTypes.length + (isStatic ? 0 : 1); + if (debugNode.debugNodes != null) { + for (DexDebugNode.DexDebugOpNode opDebugNode : debugNode.debugNodes) { + if (opDebugNode instanceof DexDebugNode.DexDebugOpNode.StartLocalNode) { + DexDebugNode.DexDebugOpNode.StartLocalNode startLocalNode = (DexDebugNode.DexDebugOpNode.StartLocalNode) opDebugNode; + LocalVar localVar = new LocalVar(localsOffset + startLocalNode.reg, startLocalNode.name, startLocalNode.type, startLocalNode.signature); + localVar.start = startLocalNode.label; + localVars.put(localVar.reg, localVar); + } else if (opDebugNode instanceof DexDebugNode.DexDebugOpNode.EndLocal) { + DexDebugNode.DexDebugOpNode.EndLocal endLocalNode = (DexDebugNode.DexDebugOpNode.EndLocal) opDebugNode; + LocalVar localVar = localVars.get(localsOffset + endLocalNode.reg); + if (localVar != null) { + localVar.end = endLocalNode.label; + } + } + } + } + + for (LocalVar localVar : localVars.values()) { + Label startLabel = new Label(); //FIXME: map from localVar.start + Label endLabel = new Label(); //FIXME: map from localVar.start + mv.visitLocalVariable(localVar.name, localVar.type, localVar.signature, startLabel, endLabel, localVar.reg); + } + } + if ((NO_CODE_MASK & methodNode.access) == 0) { // has code if (methodNode.codeNode != null) { mv.visitCode(); @@ -601,6 +656,22 @@ public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, Clas } + class LocalVar { + int reg; + String name; + String type; + String signature; + DexLabel start; + DexLabel end; + + public LocalVar(int reg, String name, String type, String signature) { + this.reg = reg; + this.name = name; + this.type = type; + this.signature = signature; + } + } + public IrMethod dex2ir(DexMethodNode methodNode) { return new Dex2IRConverter() .convert(0 != (methodNode.access & DexConstants.ACC_STATIC), methodNode.method, methodNode.codeNode); From ecf9ce3baeef4bbf0d86b5a34a389038d25e1f1e Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Wed, 24 Jun 2020 00:51:13 -0300 Subject: [PATCH 2/3] Properly handle offsets for Long and Double --- .../java/com/googlecode/d2j/dex/Dex2Asm.java | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java index 89b591ea2..a8b3ef9a3 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java @@ -1,19 +1,60 @@ package com.googlecode.d2j.dex; -import java.util.*; - +import com.googlecode.d2j.DexConstants; +import com.googlecode.d2j.DexLabel; +import com.googlecode.d2j.DexType; +import com.googlecode.d2j.Field; +import com.googlecode.d2j.Method; +import com.googlecode.d2j.MethodHandle; +import com.googlecode.d2j.Proto; +import com.googlecode.d2j.Visibility; import com.googlecode.d2j.converter.Dex2IRConverter; -import org.objectweb.asm.*; -import org.objectweb.asm.tree.InnerClassNode; - -import com.googlecode.d2j.*; import com.googlecode.d2j.converter.IR2JConverter; -import com.googlecode.d2j.node.*; +import com.googlecode.d2j.node.DexAnnotationNode; +import com.googlecode.d2j.node.DexClassNode; +import com.googlecode.d2j.node.DexDebugNode; +import com.googlecode.d2j.node.DexFieldNode; +import com.googlecode.d2j.node.DexFileNode; +import com.googlecode.d2j.node.DexMethodNode; import com.googlecode.dex2jar.ir.IrMethod; -import com.googlecode.dex2jar.ir.ts.*; +import com.googlecode.dex2jar.ir.ts.AggTransformer; +import com.googlecode.dex2jar.ir.ts.CleanLabel; +import com.googlecode.dex2jar.ir.ts.DeadCodeTransformer; +import com.googlecode.dex2jar.ir.ts.EndRemover; +import com.googlecode.dex2jar.ir.ts.ExceptionHandlerTrim; +import com.googlecode.dex2jar.ir.ts.Ir2JRegAssignTransformer; +import com.googlecode.dex2jar.ir.ts.MultiArrayTransformer; +import com.googlecode.dex2jar.ir.ts.NewTransformer; +import com.googlecode.dex2jar.ir.ts.NpeTransformer; +import com.googlecode.dex2jar.ir.ts.RemoveConstantFromSSA; +import com.googlecode.dex2jar.ir.ts.RemoveLocalFromSSA; +import com.googlecode.dex2jar.ir.ts.TypeTransformer; +import com.googlecode.dex2jar.ir.ts.UnSSATransformer; +import com.googlecode.dex2jar.ir.ts.VoidInvokeTransformer; +import com.googlecode.dex2jar.ir.ts.ZeroTransformer; import com.googlecode.dex2jar.ir.ts.array.FillArrayTransformer; -import sun.reflect.generics.tree.Tree; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.InnerClassNode; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; public class Dex2Asm { @@ -597,30 +638,39 @@ public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, Clas boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; String[] paramTypes = methodNode.method.getParameterTypes(); + int localsOffset = 0; Map localVars = new TreeMap<>(); if (!isStatic) { - LocalVar local = new LocalVar(0, "this", methodNode.method.getOwner(), null); + LocalVar local = new LocalVar(localsOffset, "this", methodNode.method.getOwner(), null); localVars.put(local.reg, local); + localsOffset++; } // Handle debugNode.parameterNames if (debugNode.parameterNames != null) { - for (int i = 0; i < debugNode.parameterNames.size(); i++) { - String paramName = debugNode.parameterNames.get(i); + for (int i = 0; i < paramTypes.length; i++) { + String paramName = i < debugNode.parameterNames.size() ? debugNode.parameterNames.get(i) : null; + String paramType = paramTypes[i]; // Put parameter name in MethodParameters attribute mv.visitParameter(paramName, 0); // Also put it into the LocalVariableTable if (paramName != null) { - LocalVar local = new LocalVar(isStatic ? i : i + 1, paramName, paramTypes[i], null); + LocalVar local = new LocalVar(localsOffset, paramName, paramType, null); localVars.put(local.reg, local); } + + // If the local variable at index is of type double or long, it occupies both index and index + 1. + if ("J".equals(paramType) || "D".equals(paramType)) { + localsOffset += 2; + } else { + localsOffset++; + } } } // Handle debugNodes to create a LocalVariableTable - int localsOffset = paramTypes.length + (isStatic ? 0 : 1); if (debugNode.debugNodes != null) { for (DexDebugNode.DexDebugOpNode opDebugNode : debugNode.debugNodes) { if (opDebugNode instanceof DexDebugNode.DexDebugOpNode.StartLocalNode) { From 08c2278d3bd9a2d5b5383866551cd102165e769d Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Wed, 24 Jun 2020 14:58:08 -0300 Subject: [PATCH 3/3] Don't populate localVars I would love to have this information, but variable names are not being assigned to the wrong variables in disassembled code, so I'm probably assigning the wrong registers. Missing info is better than wrong info, so I'm removing it for now. --- .../src/main/java/com/googlecode/d2j/dex/Dex2Asm.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java index a8b3ef9a3..9e9c7f33d 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/dex/Dex2Asm.java @@ -671,6 +671,7 @@ public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, Clas } // Handle debugNodes to create a LocalVariableTable + /* if (debugNode.debugNodes != null) { for (DexDebugNode.DexDebugOpNode opDebugNode : debugNode.debugNodes) { if (opDebugNode instanceof DexDebugNode.DexDebugOpNode.StartLocalNode) { @@ -683,10 +684,11 @@ public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, Clas LocalVar localVar = localVars.get(localsOffset + endLocalNode.reg); if (localVar != null) { localVar.end = endLocalNode.label; + localVars.remove(endLocalNode.reg); } } } - } + }*/ for (LocalVar localVar : localVars.values()) { Label startLabel = new Label(); //FIXME: map from localVar.start