From f0513a1a5512634b192b0c1f34f4d7cd496ab364 Mon Sep 17 00:00:00 2001 From: Skylot <118523+skylot@users.noreply.github.com> Date: Thu, 7 Nov 2024 20:02:41 +0000 Subject: [PATCH] fix: insert new filled array insn before first usage (#2340) --- .../core/dex/visitors/ReplaceNewArray.java | 22 +++++++++--- .../arrays/TestArrayInitField2.java | 17 +++++++++ .../smali/arrays/TestArrayInitField2.smali | 36 +++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayInitField2.java create mode 100644 jadx-core/src/test/smali/arrays/TestArrayInitField2.smali diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java index 80ebc34ab..6bf592401 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ReplaceNewArray.java @@ -25,7 +25,6 @@ import jadx.core.dex.nodes.IFieldInfoRef; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; -import jadx.core.utils.BlockUtils; import jadx.core.utils.InsnList; import jadx.core.utils.InsnRemover; import jadx.core.utils.InsnUtils; @@ -109,11 +108,15 @@ public class ReplaceNewArray extends AbstractVisitor { } // collect put instructions sorted by array index SortedMap arrPuts = new TreeMap<>(); + InsnNode firstNotAPutUsage = null; for (RegisterArg registerArg : useList) { InsnNode parentInsn = registerArg.getParentInsn(); if (parentInsn == null || parentInsn.getType() != InsnType.APUT || !arrArg.sameRegAndSVar(parentInsn.getArg(0))) { + if (firstNotAPutUsage == null) { + firstNotAPutUsage = parentInsn; + } continue; } Object constVal = InsnUtils.getConstValueByArg(mth.root(), parentInsn.getArg(1)); @@ -158,12 +161,23 @@ public class ReplaceNewArray extends AbstractVisitor { remover.addAndUnbind(put); prevIndex = index; } + // add missing trailing zeros + for (long i = prevIndex + 1; i < len; i++) { + filledArr.addArg(InsnArg.lit(0, elemType)); + } remover.addAndUnbind(newArrayInsn); + // place new insn at last array put or before first usage InsnNode lastPut = arrPuts.get(arrPuts.lastKey()); - int replaceIndex = InsnList.getIndex(instructions, lastPut); - instructions.set(replaceIndex, filledArr); - BlockUtils.replaceInsn(mth, lastPut, filledArr); + int newInsnPos = InsnList.getIndex(instructions, lastPut); + if (firstNotAPutUsage != null) { + int idx = InsnList.getIndex(instructions, firstNotAPutUsage); + if (idx != -1) { + // TODO: check that all args already assigned + newInsnPos = Math.min(idx, newInsnPos); + } + } + instructions.add(newInsnPos, filledArr); return true; } diff --git a/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayInitField2.java b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayInitField2.java new file mode 100644 index 000000000..a0509885c --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/arrays/TestArrayInitField2.java @@ -0,0 +1,17 @@ +package jadx.tests.integration.arrays; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestArrayInitField2 extends SmaliTest { + @Test + public void test() { + forceDecompiledCheck(); + assertThat(getClassNodeFromSmali()) + .code() + .containsOne("static long[] myArr = {1282979400, 0, 0};"); + } +} diff --git a/jadx-core/src/test/smali/arrays/TestArrayInitField2.smali b/jadx-core/src/test/smali/arrays/TestArrayInitField2.smali new file mode 100644 index 000000000..fc077c62a --- /dev/null +++ b/jadx-core/src/test/smali/arrays/TestArrayInitField2.smali @@ -0,0 +1,36 @@ +.class public Larrays/TestArrayInitField2; +.super Ljava/lang/Object; + +.field static myArr:[J + +.method static constructor ()V + .locals 4 + + const v0, 0x3 + new-array v0, v0, [J + sput-object v0, Larrays/TestArrayInitField2;->myArr:[J + const/4 v1, 0x0 + const-wide/32 v2, 0x4c78b648 + aput-wide v2, v0, v1 + return-void + nop + +.end method + +.method public check()V + .registers 5 + sget-object v0, Larrays/TestArrayInitField2;->myArr:[J + invoke-static {v0}, Lorg/assertj/core/api/Assertions;->assertThat([J)Lorg/assertj/core/api/AbstractLongArrayAssert; + move-result-object v0 + const/4 v1, 0x3 + invoke-virtual {v0, v1}, Lorg/assertj/core/api/AbstractLongArrayAssert;->hasSize(I)Lorg/assertj/core/api/AbstractLongArrayAssert; + + sget-object v0, Larrays/TestArrayInitField2;->myArr:[J + const/4 v1, 0x0 + aget-wide v0, v0, v1 + invoke-static {v0, v1}, Lorg/assertj/core/api/Assertions;->assertThat(J)Lorg/assertj/core/api/AbstractLongAssert; + move-result-object v0 + const-wide/32 v2, 0x4c78b648 + invoke-virtual {v0, v2, v3}, Lorg/assertj/core/api/AbstractLongAssert;->isEqualTo(J)Lorg/assertj/core/api/AbstractLongAssert; + return-void +.end method