From 5f70fefdc0e930e4b1039cbaff4cfa162deebf38 Mon Sep 17 00:00:00 2001 From: Bob Pan Date: Fri, 1 Sep 2023 19:50:47 +0800 Subject: [PATCH 1/2] bring back asm bridge (#601) * revert AsmBridge * Update dependencies * Apply miscellaneous fixes * Reformat code * Reformat * Reformat code based on CheckStyle * clean up --------- Co-authored-by: Nico Mexis --- .../com/googlecode/d2j/dex/ExDex2Asm.java | 23 ++-- .../java/org/objectweb/asm/AsmBridge.java | 101 ++++++++++++++++++ 2 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java diff --git a/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java b/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java index e003be9bd..bd0da422c 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java @@ -16,6 +16,7 @@ */ package com.googlecode.d2j.dex; +import org.objectweb.asm.AsmBridge; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; @@ -32,7 +33,7 @@ public ExDex2Asm(DexExceptionHandler exceptionHandler) { @Override public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) { -// MethodVisitor mw = AsmBridge.searchMethodWriter(mv); + MethodVisitor mw = AsmBridge.searchMethodWriter(mv); MethodNode mn = new MethodNode(Opcodes.ASM9, methodNode.access, methodNode.method.getName(), methodNode.method.getDesc(), null, null); try { @@ -48,15 +49,15 @@ public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCt } // code convert ok, copy to MethodWriter and check for Size mn.accept(mv); -// if (mw != null) { -// try { -// AsmBridge.sizeOfMethodWriter(mw); -// } catch (Exception ex) { -// mn.instructions.clear(); -// mn.tryCatchBlocks.clear(); -// exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); -// AsmBridge.replaceMethodWriter(mw, mn); -// } -// } + if (mw != null) { + try { + AsmBridge.sizeOfMethodWriter(mw); + } catch (Exception ex) { + mn.instructions.clear(); + mn.tryCatchBlocks.clear(); + exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); + AsmBridge.replaceMethodWriter(mw, mn); + } + } } } diff --git a/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java b/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java new file mode 100644 index 000000000..b2fd06ca7 --- /dev/null +++ b/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java @@ -0,0 +1,101 @@ +/* + * dex2jar - Tools to work with android .dex and java .class files + * Copyright (c) 2009-2014 Panxiaobo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.objectweb.asm; + +import java.lang.reflect.Field; +import org.objectweb.asm.tree.MethodNode; + +public final class AsmBridge { + + public static MethodVisitor searchMethodWriter(MethodVisitor methodVisitor) { + while (methodVisitor != null && !(methodVisitor instanceof MethodWriter)) { + methodVisitor = methodVisitor.mv; + } + return methodVisitor; + } + + public static int sizeOfMethodWriter(MethodVisitor methodVisitor) { + MethodWriter mw = (MethodWriter) methodVisitor; + return mw.computeMethodInfoSize(); + } + + private static void removeMethodWriter(MethodWriter methodWriter) { + MethodWriter firstMethodWriter; + MethodWriter lastMethodWriter; + + try { + ClassWriter classWriter = reflectForClassWriter(methodWriter); + + Field fmField = ClassWriter.class.getDeclaredField("firstMethod"); + fmField.setAccessible(true); + firstMethodWriter = (MethodWriter) fmField.get(classWriter); + + Field lmField = ClassWriter.class.getDeclaredField("lastMethod"); + lmField.setAccessible(true); + lastMethodWriter = (MethodWriter) lmField.get(classWriter); + + // mv must be the last element + if (firstMethodWriter == methodWriter) { + fmField.set(classWriter, null); + if (lastMethodWriter == methodWriter) { + lmField.set(classWriter, null); + } + } else { + while (firstMethodWriter != null) { + if (firstMethodWriter.mv == methodWriter) { + firstMethodWriter.mv = methodWriter.mv; + if (lastMethodWriter == methodWriter) { + lmField.set(classWriter, firstMethodWriter); + } + break; + } else { + firstMethodWriter = (MethodWriter) firstMethodWriter.mv; + } + } + } + } catch (IllegalAccessException | NoSuchFieldException exc) { + exc.printStackTrace(); + } + } + + private static ClassWriter reflectForClassWriter(MethodWriter methodWriter) throws NoSuchFieldException, IllegalAccessException { + // Get the SymbolTable for accessing ClassWriter + Field stField = MethodWriter.class.getDeclaredField("symbolTable"); + stField.setAccessible(true); + SymbolTable symbolTable = (SymbolTable) stField.get(methodWriter); + // Get ClassWriter object from methodWriter's SymbolTable + return symbolTable.classWriter; + } + + public static void replaceMethodWriter(MethodVisitor methodVisitor, MethodNode methodNode) { + MethodWriter methodWriter = (MethodWriter) methodVisitor; + + try { + ClassWriter classWriter = reflectForClassWriter(methodWriter); + + methodNode.accept(classWriter); + removeMethodWriter(methodWriter); + } catch (IllegalAccessException | NoSuchFieldException exc) { + exc.printStackTrace(); + } + } + + private AsmBridge() { + throw new UnsupportedOperationException(); + } + +} From 476e64c6e9d3e4a59f61c890e663558c76b0e626 Mon Sep 17 00:00:00 2001 From: Bob Pan Date: Fri, 1 Sep 2023 20:09:35 +0800 Subject: [PATCH 2/2] remove hidden access flags (#600) * remove hidden access flags cherry-pick f6dc51e578c1304b3a0c5b9d6ff32f13ecf3651f * move removeHiddenAccess to Dex2Asm --- .../java/com/googlecode/d2j/DexConstants.java | 4 +++ .../java/com/googlecode/d2j/dex/Dex2Asm.java | 25 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java b/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java index decf099ff..b71df6b2a 100644 --- a/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java +++ b/dex-reader-api/src/main/java/com/googlecode/d2j/DexConstants.java @@ -44,6 +44,10 @@ public interface DexConstants { int ACC_CONSTRUCTOR = 0x10000;// constructor method (class or instance initializer) int ACC_DECLARED_SYNCHRONIZED = 0x20000; + int ACC_VISIBILITY_FLAGS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; + int ACC_DEX_HIDDEN_BIT = 0x00000020; // field, method (not native) + int ACC_DEX_HIDDEN_BIT_NATIVE = 0x00000200; // method (native) + String ANNOTATION_DEFAULT_TYPE = "Ldalvik/annotation/AnnotationDefault;"; String ANNOTATION_SIGNATURE_TYPE = "Ldalvik/annotation/Signature;"; String ANNOTATION_THROWS_TYPE = "Ldalvik/annotation/Throws;"; 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 2bce6eae8..95d921158 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 @@ -58,6 +58,20 @@ import java.util.Stack; public class Dex2Asm { + private static boolean isPowerOfTwo(int i) { + return (i & (i - 1)) == 0; + } + + private static int removeHiddenAccess(int accessFlags) { + // Refer to art/libdexfile/dex/hidden_api_access_flags.h + if (!isPowerOfTwo(accessFlags & DexConstants.ACC_VISIBILITY_FLAGS)) { + accessFlags ^= DexConstants.ACC_VISIBILITY_FLAGS; + } + accessFlags &= ~((accessFlags & DexConstants.ACC_NATIVE) != 0 ? + DexConstants.ACC_DEX_HIDDEN_BIT_NATIVE : DexConstants.ACC_DEX_HIDDEN_BIT); + return accessFlags; + } + public static class ClzCtx { public String classDescriptor; public String hexDecodeMethodNamePrefix; @@ -319,7 +333,9 @@ private static MethodVisitor collectBasicMethodInfo(DexMethodNode methodNode, Cl + " by changing its signature to null"); signature = null; } - int access = methodNode.access; + + // HiddenApiAccessFlags is valid for .dex but not for .class + int access = removeHiddenAccess(methodNode.access); // clear ACC_DECLARED_SYNCHRONIZED and ACC_CONSTRUCTOR from method flags final int cleanFlag = ~((DexConstants.ACC_DECLARED_SYNCHRONIZED | DexConstants.ACC_CONSTRUCTOR)); access &= cleanFlag; @@ -615,10 +631,11 @@ public void convertField(DexClassNode classNode, DexFieldNode fieldNode, ClassVi signature = null; } - + // HiddenApiAccessFlags is valid for .dex but not for .class + int access = removeHiddenAccess(fieldNode.access); final int fieldCleanFlag = ~((DexConstants.ACC_DECLARED_SYNCHRONIZED | Opcodes.ACC_SYNTHETIC)); - FieldVisitor fv = cv.visitField(fieldNode.access & fieldCleanFlag, fieldNode.field.getName(), - fieldNode.field.getType(), signature, value); + FieldVisitor fv = cv.visitField(access & fieldCleanFlag, fieldNode.field.getName(), + fieldNode.field.getType(), signature, value); if (fv == null) { return;