Skip to content

Commit

Permalink
fix: improve checking of access modifiers for methods
Browse files Browse the repository at this point in the history
  • Loading branch information
pubiqq committed Aug 15, 2024
1 parent 9a8ec76 commit 5bdd059
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 48 deletions.
43 changes: 2 additions & 41 deletions jadx-core/src/main/java/jadx/core/dex/nodes/utils/ClassUtils.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package jadx.core.dex.nodes.utils;

import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxRuntimeException;

public class ClassUtils {

Expand All @@ -14,44 +12,7 @@ public ClassUtils(RootNode rootNode) {
}

public boolean isAccessible(ClassNode cls, ClassNode callerCls) {
if (cls.equals(callerCls)) {
return true;
}

final AccessInfo accessFlags = cls.getAccessFlags();
if (accessFlags.isPublic()) {
return true;
}

if (accessFlags.isProtected()) {
return isProtectedAccessible(cls, callerCls);
}

if (accessFlags.isPackagePrivate()) {
return isPackagePrivateAccessible(cls, callerCls);
}

if (accessFlags.isPrivate()) {
return isPrivateAccessible(cls, callerCls);
}

throw new JadxRuntimeException(accessFlags + " is not supported");
}

private boolean isProtectedAccessible(ClassNode cls, ClassNode callerCls) {
return isPackagePrivateAccessible(cls, callerCls) || isSuperType(cls, callerCls);
}

private boolean isPackagePrivateAccessible(ClassNode cls, ClassNode callerCls) {
return cls.getPackageNode().equals(callerCls.getPackageNode());
}

private boolean isPrivateAccessible(ClassNode cls, ClassNode callerCls) {
return cls.getTopParentClass().equals(callerCls.getTopParentClass());
}

private boolean isSuperType(ClassNode cls, ClassNode superCls) {
return root.getClsp().getSuperTypes(cls.getRawName()).stream()
.anyMatch(x -> x.equals(superCls.getRawName()));
CodeNodeUtils codeNodeUtils = new CodeNodeUtils(root);
return codeNodeUtils.isAccessible(cls, callerCls);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package jadx.core.dex.nodes.utils;

import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.ICodeNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxRuntimeException;

class CodeNodeUtils {

private final RootNode root;

CodeNodeUtils(RootNode rootNode) {
this.root = rootNode;
}

boolean isAccessible(ICodeNode targetNode, ICodeNode callerNode) {
ClassNode targetCls = getDeclaringClass(targetNode);
ClassNode callerCls = getDeclaringClass(callerNode);

if (targetCls.equals(callerCls)) {
return true;
}

AccessInfo targetVisibility;
if (targetNode == targetCls) {
targetVisibility = targetNode.getAccessFlags().getVisibility();
} else {
AccessInfo targetClsVisibility = targetCls.getAccessFlags().getVisibility();
AccessInfo targetNodeVisibility = targetNode.getAccessFlags().getVisibility();
targetVisibility = targetClsVisibility.isVisibilityWeakerThan(targetNodeVisibility)
? targetClsVisibility
: targetNodeVisibility;
}

if (targetVisibility.isPublic()) {
return true;
}

if (targetVisibility.isProtected()) {
return isProtectedAccessible(targetCls, callerCls);
}

if (targetVisibility.isPackagePrivate()) {
return isPackagePrivateAccessible(targetCls, callerCls);
}

if (targetVisibility.isPrivate()) {
return isPrivateAccessible(targetCls, callerCls);
}

throw new JadxRuntimeException(targetVisibility + " is not supported");
}

private ClassNode getDeclaringClass(ICodeNode node) {
if (node instanceof ClassNode) {
return (ClassNode) node;
} else if (node instanceof MethodNode) {
return ((MethodNode) node).getParentClass();
} else if (node instanceof FieldNode) {
return ((FieldNode) node).getParentClass();
} else {
throw new JadxRuntimeException(node + " is not supported");
}
}

private boolean isProtectedAccessible(ClassNode cls, ClassNode callerCls) {
return isPackagePrivateAccessible(cls, callerCls) || isSuperType(cls, callerCls);
}

private boolean isPackagePrivateAccessible(ClassNode cls, ClassNode callerCls) {
return cls.getPackageNode().equals(callerCls.getPackageNode());
}

private boolean isPrivateAccessible(ClassNode cls, ClassNode callerCls) {
return cls.getTopParentClass().equals(callerCls.getTopParentClass());
}

private boolean isSuperType(ClassNode cls, ClassNode superCls) {
return root.getClsp().getSuperTypes(cls.getRawName()).stream()
.anyMatch(x -> x.equals(superCls.getRawName()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,9 @@ public ClassInfo getMethodOriginDeclClass(MethodNode mth) {
}
return mth.getMethodInfo().getDeclClass();
}

public boolean isAccessible(MethodNode mth, MethodNode callerMth) {
CodeNodeUtils codeNodeUtils = new CodeNodeUtils(root);
return codeNodeUtils.isAccessible(mth, callerMth);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.nodes.utils.ClassUtils;
import jadx.core.dex.nodes.utils.MethodUtils;
import jadx.core.utils.exceptions.JadxException;

@JadxVisitor(
Expand All @@ -25,12 +26,14 @@
public class FixAccessModifiers extends AbstractVisitor {

private ClassUtils classUtils;
private MethodUtils methodUtils;

private boolean respectAccessModifiers;

@Override
public void init(RootNode root) {
this.classUtils = root.getClassUtils();
this.methodUtils = root.getMethodUtils();
this.respectAccessModifiers = root.getArgs().isRespectBytecodeAccModifiers();
}

Expand Down Expand Up @@ -103,11 +106,12 @@ private int fixClassVisibility(ClassNode cls) {
return -1;
}

private static int fixMethodVisibility(MethodNode mth) {
private int fixMethodVisibility(MethodNode mth) {
AccessInfo accessFlags = mth.getAccessFlags();
if (accessFlags.isPublic()) {
return -1;
}

MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE);
if (overrideAttr != null && !overrideAttr.getOverrideList().isEmpty()) {
// visibility can't be weaker
Expand All @@ -117,17 +121,13 @@ private static int fixMethodVisibility(MethodNode mth) {
return parentAccInfo.getVisibility().rawValue();
}
}
if (mth.getUseIn().isEmpty()) {
return -1;
}

ClassNode thisTopParentCls = mth.getParentClass().getTopParentClass();
for (MethodNode useMth : mth.getUseIn()) {
ClassNode useInTPCls = useMth.getParentClass().getTopParentClass();
if (!useInTPCls.equals(thisTopParentCls)) {
if (!methodUtils.isAccessible(mth, useMth)) {
return AccessFlags.PUBLIC;
}
}

return -1;
}
}

0 comments on commit 5bdd059

Please sign in to comment.