From b64458dee30321b7118c7da6ab0a73734acab709 Mon Sep 17 00:00:00 2001 From: ewt45 <79033456+ewt45@users.noreply.github.com> Date: Mon, 30 Dec 2024 13:53:55 +0800 Subject: [PATCH 1/2] IfRegionMaker find wrong out block --- .../visitors/regions/maker/IfRegionMaker.java | 8 +- .../main/java/jadx/core/utils/BlockUtils.java | 10 +- .../integration/conditions/TestOutBlock.java | 22 +++ .../test/smali/conditions/TestOutBlock.smali | 149 ++++++++++++++++++ 4 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestOutBlock.java create mode 100644 jadx-core/src/test/smali/conditions/TestOutBlock.smali diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/IfRegionMaker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/IfRegionMaker.java index 7711d870f11..ce94e72ec11 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/IfRegionMaker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/maker/IfRegionMaker.java @@ -178,6 +178,8 @@ static IfInfo restructureIf(MethodNode mth, BlockNode block, IfInfo info) { info.setOutBlock(null); return info; } + // init outblock, which will be used in isBadBranchBlock to compare with branch block + info.setOutBlock(BlockUtils.getPathCross(mth, thenBlock, elseBlock)); boolean badThen = isBadBranchBlock(info, thenBlock); boolean badElse = isBadBranchBlock(info, elseBlock); if (badThen && badElse) { @@ -193,8 +195,6 @@ static IfInfo restructureIf(MethodNode mth, BlockNode block, IfInfo info) { info = IfInfo.invert(info); info = new IfInfo(info, elseBlock, null); info.setOutBlock(thenBlock); - } else { - info.setOutBlock(BlockUtils.getPathCross(mth, thenBlock, elseBlock)); } if (BlockUtils.isBackEdge(block, info.getOutBlock())) { info.setOutBlock(null); @@ -219,6 +219,10 @@ private static boolean isBadBranchBlock(IfInfo info, BlockNode block) { } } } + // if branch block itself is outblock + if (info.getOutBlock() != null) { + return block == info.getOutBlock(); + } return !allPathsFromIf(block, info); } diff --git a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java index b9cbc3648af..5a2d233e978 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -761,18 +761,22 @@ public static BlockNode getCommonDominator(MethodNode mth, List block /** * Return common cross block for input set. * - * @return null if cross is a method exit block. + * @return could be one of the giving blocks. null if cross is a method exit block. */ @Nullable public static BlockNode getPathCross(MethodNode mth, Collection blocks) { BitSet domFrontBS = newBlocksBitSet(mth); + BitSet tmpBS = newBlocksBitSet(mth); // store block itself and its domFrontier boolean first = true; for (BlockNode b : blocks) { + tmpBS.clear(); + tmpBS.set(b.getId()); + tmpBS.or(b.getDomFrontier()); if (first) { - domFrontBS.or(b.getDomFrontier()); + domFrontBS.or(tmpBS); first = false; } else { - domFrontBS.and(b.getDomFrontier()); + domFrontBS.and(tmpBS); } } domFrontBS.clear(mth.getExitBlock().getId()); diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestOutBlock.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestOutBlock.java new file mode 100644 index 00000000000..19c3a0af7aa --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestOutBlock.java @@ -0,0 +1,22 @@ +package jadx.tests.integration.conditions; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +/** + * Issue #2384 + */ +public class TestOutBlock extends SmaliTest { + + @Test + public void test() { + allowWarnInCode(); + disableCompilation(); + assertThat(getClassNodeFromSmali()) + .code() + .containsOne("setContentView"); + } +} diff --git a/jadx-core/src/test/smali/conditions/TestOutBlock.smali b/jadx-core/src/test/smali/conditions/TestOutBlock.smali new file mode 100644 index 00000000000..9302d29ae48 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestOutBlock.smali @@ -0,0 +1,149 @@ +.class public Lconditions/TestOutBlock; +.super Lcom/eltechs/axs/activities/FrameworkActivity; + + +.method protected onCreate(Landroid/os/Bundle;)V + .registers 9 + + .line 98 + invoke-super {p0, p1}, Lcom/eltechs/axs/activities/FrameworkActivity;->onCreate(Landroid/os/Bundle;)V + + .line 101 + invoke-virtual {p0}, Lconditions/TestOutBlock;->getApplicationState()Lcom/eltechs/axs/applicationState/ApplicationStateBase; + + move-result-object p1 + + .line 102 + invoke-interface {p1}, Lcom/eltechs/axs/applicationState/ApplicationStateBase;->getEnvironment()Lcom/eltechs/axs/environmentService/AXSEnvironment; + + move-result-object v0 + + const-class v1, Lcom/eltechs/axs/environmentService/components/XServerComponent; + + invoke-virtual {v0, v1}, Lcom/eltechs/axs/environmentService/AXSEnvironment;->getComponent(Ljava/lang/Class;)Lcom/eltechs/axs/environmentService/EnvironmentComponent; + + move-result-object v0 + + check-cast v0, Lcom/eltechs/axs/environmentService/components/XServerComponent; + + .line 103 + invoke-virtual {p0}, Lconditions/TestOutBlock;->getIntent()Landroid/content/Intent; + + move-result-object v1 + + const-string v2, "facadeclass" + + invoke-virtual {v1, v2}, Landroid/content/Intent;->getSerializableExtra(Ljava/lang/String;)Ljava/io/Serializable; + + move-result-object v1 + + check-cast v1, Ljava/lang/Class; + + if-eqz v1, :cond_46 + + const/4 v2, 0x2 + + const/4 v3, 0x0 + + .line 108 + :try_start_23 + new-array v4, v2, [Ljava/lang/Class; + + const-class v5, Lcom/eltechs/axs/xserver/XServer; + + aput-object v5, v4, v3 + + const-class v5, Lcom/eltechs/axs/applicationState/ApplicationStateBase; + + const/4 v6, 0x1 + + aput-object v5, v4, v6 + + invoke-virtual {v1, v4}, Ljava/lang/Class;->getDeclaredConstructor([Ljava/lang/Class;)Ljava/lang/reflect/Constructor; + + move-result-object v1 + + .line 109 + new-array v2, v2, [Ljava/lang/Object; + + invoke-virtual {v0}, Lcom/eltechs/axs/environmentService/components/XServerComponent;->getXServer()Lcom/eltechs/axs/xserver/XServer; + + move-result-object v4 + + aput-object v4, v2, v3 + + aput-object p1, v2, v6 + + invoke-virtual {v1, v2}, Ljava/lang/reflect/Constructor;->newInstance([Ljava/lang/Object;)Ljava/lang/Object; + + move-result-object v1 + + check-cast v1, Lcom/eltechs/axs/xserver/ViewFacade; + :try_end_42 + .catch Ljava/lang/Exception; {:try_start_23 .. :try_end_42} :catch_43 + + goto :goto_47 + + .line 112 + :catch_43 + invoke-static {v3}, Lcom/eltechs/axs/helpers/Assert;->state(Z)V + + :cond_46 + const/4 v1, 0x0 + + .line 118 + :goto_47 + invoke-virtual {p0}, Lconditions/TestOutBlock;->getWindow()Landroid/view/Window; + + move-result-object v2 + + const/16 v3, 0x80 + + invoke-virtual {v2, v3}, Landroid/view/Window;->addFlags(I)V + + .line 120 + invoke-virtual {p0}, Lconditions/TestOutBlock;->getWindow()Landroid/view/Window; + + move-result-object v2 + + const/high16 v3, 0x400000 + + invoke-virtual {v2, v3}, Landroid/view/Window;->addFlags(I)V + + .line 125 + sget v2, Lcom/eltechs/axs/R$layout;->main:I + + invoke-virtual {p0, v2}, Lconditions/TestOutBlock;->setContentView(I)V + + .line 127 + invoke-direct {p0}, Lconditions/TestOutBlock;->checkForSuddenDeath()Z + + move-result v2 + + if-eqz v2, :cond_65 + + return-void + + .line 135 + :cond_65 + new-instance v2, Lcom/eltechs/axs/widgets/viewOfXServer/ViewOfXServer; + + invoke-virtual {v0}, Lcom/eltechs/axs/environmentService/components/XServerComponent;->getXServer()Lcom/eltechs/axs/xserver/XServer; + + move-result-object v0 + + invoke-interface {p1}, Lcom/eltechs/axs/applicationState/ApplicationStateBase;->getXServerViewConfiguration()Lcom/eltechs/axs/configuration/XServerViewConfiguration; + + move-result-object p1 + + invoke-direct {v2, p0, v0, v1, p1}, Lcom/eltechs/axs/widgets/viewOfXServer/ViewOfXServer;->(Landroid/content/Context;Lcom/eltechs/axs/xserver/XServer;Lcom/eltechs/axs/xserver/ViewFacade;Lcom/eltechs/axs/configuration/XServerViewConfiguration;)V + + iput-object v2, p0, Lconditions/TestOutBlock;->viewOfXServer:Lcom/eltechs/axs/widgets/viewOfXServer/ViewOfXServer; + + .line 137 + iget-object p1, p0, Lconditions/TestOutBlock;->periodicIabCheckTimer:Landroid/os/CountDownTimer; + + invoke-virtual {p1}, Landroid/os/CountDownTimer;->start()Landroid/os/CountDownTimer; + + return-void +.end method From 99a247dfda0a1a5496bfc6766033aa8113ffe308 Mon Sep 17 00:00:00 2001 From: ewt45 <79033456+ewt45@users.noreply.github.com> Date: Mon, 30 Dec 2024 15:09:42 +0800 Subject: [PATCH 2/2] fix: test codes fail because of the previous commit --- .../src/main/java/jadx/core/utils/BlockUtils.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java index 5a2d233e978..0d040b8e264 100644 --- a/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/BlockUtils.java @@ -794,7 +794,7 @@ public static BlockNode getPathCross(MethodNode mth, Collection block mth.getLoops().forEach(l -> excluded.set(l.getStart().getId())); if (!mth.isNoExceptionHandlers()) { // exclude exception handlers paths - mth.getExceptionHandlers().forEach(h -> mergeExcHandlerDomFrontier(mth, h, excluded)); + mth.getExceptionHandlers().forEach(h -> addExcHandler(mth, h, excluded)); } domFrontBS.andNot(excluded); oneBlock = bitSetToOneBlock(mth, domFrontBS); @@ -809,7 +809,6 @@ public static BlockNode getPathCross(MethodNode mth, Collection block BitSet domFrontier = block.getDomFrontier(); if (!domFrontier.isEmpty()) { combinedDF.or(domFrontier); - combinedDF.clear(block.getId()); } }); combinedDF.andNot(excluded); @@ -831,18 +830,13 @@ public static BlockNode getPathCross(MethodNode mth, Collection block } } - private static void mergeExcHandlerDomFrontier(MethodNode mth, ExceptionHandler handler, BitSet set) { + private static void addExcHandler(MethodNode mth, ExceptionHandler handler, BitSet set) { BlockNode handlerBlock = handler.getHandlerBlock(); if (handlerBlock == null) { mth.addDebugComment("Null handler block in: " + handler); return; } - BitSet domFrontier = handlerBlock.getDomFrontier(); - if (domFrontier == null) { - mth.addDebugComment("Null dom frontier in handler: " + handler); - return; - } - set.or(domFrontier); + set.set(handlerBlock.getId()); } public static BlockNode getPathCross(MethodNode mth, BlockNode b1, BlockNode b2) {