diff --git a/build.gradle b/build.gradle index 292e44867..48299476c 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ allprojects { } jacoco { - toolVersion = "0.8.1" + toolVersion = "0.8.2" } jacocoTestReport { reports { diff --git a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java index ab27165fb..4c6741d8d 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java +++ b/jadx-core/src/main/java/jadx/core/deobf/DeobfPresets.java @@ -116,14 +116,16 @@ class DeobfPresets { } } for (FieldInfo fld : deobfuscator.getFldMap().keySet()) { - list.add(String.format("f %s = %s", fld.getFullId(), fld.getAlias())); + list.add(String.format("f %s = %s", fld.getRawFullId(), fld.getAlias())); } for (MethodInfo mth : deobfuscator.getMthMap().keySet()) { - list.add(String.format("m %s = %s", mth.getFullId(), mth.getAlias())); + list.add(String.format("m %s = %s", mth.getRawFullId(), mth.getAlias())); } Collections.sort(list); FileUtils.writeLines(deobfMapFile, MAP_FILE_CHARSET, list); - list.clear(); + if (LOG.isDebugEnabled()) { + LOG.debug("Deobfuscation map file saved as: {}", deobfMapFile); + } } private static void dfsPackageName(List list, String prefix, PackageNode node) { @@ -140,11 +142,11 @@ class DeobfPresets { } public String getForFld(FieldInfo fld) { - return fldPresetMap.get(fld.getFullId()); + return fldPresetMap.get(fld.getRawFullId()); } public String getForMth(MethodInfo mth) { - return mthPresetMap.get(mth.getFullId()); + return mthPresetMap.get(mth.getRawFullId()); } public void clear() { diff --git a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java index ed0d45f91..7e18b1930 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java +++ b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java @@ -409,6 +409,9 @@ public class Deobfuscator { @Nullable private String getMethodAlias(MethodNode mth) { MethodInfo methodInfo = mth.getMethodInfo(); + if (methodInfo.isClassInit() || methodInfo.isConstructor()) { + return null; + } String alias = mthMap.get(methodInfo); if (alias != null) { return alias; diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java index 6d4844f70..fd35db1de 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java @@ -57,6 +57,10 @@ public final class FieldInfo { return declClass.getFullName() + "." + name + ":" + TypeGen.signature(type); } + public String getRawFullId() { + return declClass.makeRawFullName() + "." + name + ":" + TypeGen.signature(type); + } + public boolean isRenamed() { return !name.equals(alias); } diff --git a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java index 1f49480f7..8aab5fca1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java @@ -68,6 +68,10 @@ public final class MethodInfo { return declClass.getFullName() + "." + shortId; } + public String getRawFullId() { + return declClass.makeRawFullName() + "." + shortId; + } + /** * Method name and signature */ diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java index f7b952e04..561091c64 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/SplitterBlockAttr.java @@ -23,6 +23,6 @@ public class SplitterBlockAttr implements IAttribute { @Override public String toString() { - return "Splitter: " + block; + return "Splitter:" + block; } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java index 96db02e95..dd7d47bf6 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockFinish.java @@ -26,7 +26,7 @@ public class BlockFinish extends AbstractVisitor { for (BlockNode block : mth.getBasicBlocks()) { block.updateCleanSuccessors(); - fixSplitterBlock(block); + fixSplitterBlock(mth, block); } mth.finishBasicBlocks(); @@ -36,7 +36,7 @@ public class BlockFinish extends AbstractVisitor { * For evey exception handler must be only one splitter block, * select correct one and remove others if necessary. */ - private static void fixSplitterBlock(BlockNode block) { + private static void fixSplitterBlock(MethodNode mth, BlockNode block) { ExcHandlerAttr excHandlerAttr = block.get(AType.EXC_HANDLER); if (excHandlerAttr == null) { return; @@ -58,7 +58,7 @@ public class BlockFinish extends AbstractVisitor { } BlockNode topSplitter = BlockUtils.getTopBlock(splitters.keySet()); if (topSplitter == null) { - LOG.warn("Unknown top splitter block from list: {}", splitters); + mth.addWarn("Unknown top exception splitter block from list: " + splitters); return; } for (Map.Entry entry : splitters.entrySet()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java index 4a7750c72..572a2610a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/blocksmaker/BlockSplitter.java @@ -226,12 +226,13 @@ public class BlockSplitter extends AbstractVisitor { BlockNode thisBlock = getBlock(jump.getDest(), blocksMap); connect(srcBlock, thisBlock); } - connectExceptionHandlers(block, insn); + connectExceptionHandlers(block, insn, blocksMap); } } } - private static void connectExceptionHandlers(BlockNode block, InsnNode insn) { + private static void connectExceptionHandlers(BlockNode block, InsnNode insn, + Map blocksMap) { CatchAttr catches = insn.get(AType.CATCH_BLOCK); SplitterBlockAttr spl = block.get(AType.SPLITTER_BLOCK); if (catches == null || spl == null) { @@ -240,7 +241,7 @@ public class BlockSplitter extends AbstractVisitor { BlockNode splitterBlock = spl.getBlock(); boolean tryEnd = insn.contains(AFlag.TRY_LEAVE); for (ExceptionHandler h : catches.getTryBlock().getHandlers()) { - BlockNode handlerBlock = h.getHandlerBlock(); + BlockNode handlerBlock = initHandlerBlock(h, blocksMap); // skip self loop in handler if (splitterBlock != handlerBlock) { if (!handlerBlock.contains(AType.SPLITTER_BLOCK)) { @@ -254,6 +255,16 @@ public class BlockSplitter extends AbstractVisitor { } } + private static BlockNode initHandlerBlock(ExceptionHandler excHandler, Map blocksMap) { + BlockNode handlerBlock = excHandler.getHandlerBlock(); + if (handlerBlock != null) { + return handlerBlock; + } + BlockNode blockByOffset = getBlock(excHandler.getHandleOffset(), blocksMap); + excHandler.setHandlerBlock(blockByOffset); + return blockByOffset; + } + private static boolean isSplitByJump(InsnNode prevInsn, InsnNode currentInsn) { List pJumps = prevInsn.getAll(AType.JUMP); for (JumpInfo jump : pJumps) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java index 106eeee7a..49389ea7b 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java @@ -60,7 +60,7 @@ public class CheckRegions extends AbstractVisitor { && !block.getInstructions().isEmpty() && !block.contains(AFlag.SKIP)) { String blockCode = getBlockInsnStr(mth, block); - mth.addWarn("Missing block: " + block + ", code:" + CodeWriter.NL + blockCode); + mth.addWarn("Missing block: " + block + ", code skipped:" + CodeWriter.NL + blockCode); } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java index 33d544cc3..bb2d543e8 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java @@ -27,7 +27,6 @@ import jadx.core.dex.trycatch.TryCatchBlock; import jadx.core.utils.BlockUtils; import jadx.core.utils.ErrorsCounter; import jadx.core.utils.RegionUtils; -import jadx.core.utils.exceptions.JadxRuntimeException; /** * Extract blocks to separate try/catch region @@ -67,34 +66,39 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { // for each try block search nearest dominator block for (TryCatchBlock tb : tryBlocks) { if (tb.getHandlersCount() == 0) { - LOG.warn("No exception handlers in catch block, method: {}", mth); + mth.addWarn("No exception handlers in catch block: " + tb); continue; } - BitSet bs = new BitSet(mth.getBasicBlocks().size()); - for (ExceptionHandler excHandler : tb.getHandlers()) { - BlockNode handlerBlock = excHandler.getHandlerBlock(); - if (handlerBlock != null) { - SplitterBlockAttr splitter = handlerBlock.get(AType.SPLITTER_BLOCK); - if (splitter != null) { - BlockNode block = splitter.getBlock(); - bs.set(block.getId()); - } + processTryCatchBlock(mth, tb, tryBlocksMap); + } + } + + private static void processTryCatchBlock(MethodNode mth, TryCatchBlock tb, Map tryBlocksMap) { + BitSet bs = new BitSet(mth.getBasicBlocks().size()); + for (ExceptionHandler excHandler : tb.getHandlers()) { + BlockNode handlerBlock = excHandler.getHandlerBlock(); + if (handlerBlock != null) { + SplitterBlockAttr splitter = handlerBlock.get(AType.SPLITTER_BLOCK); + if (splitter != null) { + BlockNode block = splitter.getBlock(); + bs.set(block.getId()); } } - List domBlocks = BlockUtils.bitSetToBlocks(mth, bs); - BlockNode domBlock; - if (domBlocks.size() != 1) { - domBlock = BlockUtils.getTopBlock(domBlocks); - if (domBlock == null) { - throw new JadxRuntimeException("Exception block dominator not found, method:" + mth + ", dom blocks: " + domBlocks); - } - } else { - domBlock = domBlocks.get(0); - } - TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb); - if (prevTB != null) { - ErrorsCounter.methodWarn(mth, "Failed to process nested try/catch"); + } + List domBlocks = BlockUtils.bitSetToBlocks(mth, bs); + BlockNode domBlock; + if (domBlocks.size() != 1) { + domBlock = BlockUtils.getTopBlock(domBlocks); + if (domBlock == null) { + mth.addWarn("Exception block dominator not found, dom blocks: " + domBlocks); + return; } + } else { + domBlock = domBlocks.get(0); + } + TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb); + if (prevTB != null) { + mth.addWarn("Failed to process nested try/catch"); } } @@ -105,7 +109,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { if (region.getSubBlocks().contains(dominator)) { TryCatchBlock tb = tryBlocksMap.get(dominator); if (!wrapBlocks(region, tb, dominator)) { - ErrorsCounter.methodWarn(mth, "Can't wrap try/catch for " + region); + ErrorsCounter.methodWarn(mth, "Can't wrap try/catch for region: " + region); } tryBlocksMap.remove(dominator); return true; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java index 603bfc5c7..7a6d95c5d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/RegionMaker.java @@ -932,7 +932,7 @@ public class RegionMaker { } } for (ExceptionHandler handler : tc.getHandlers()) { - processExcHandler(handler, exits); + processExcHandler(mth, handler, exits); } } return processHandlersOutBlocks(mth, tcs); @@ -971,12 +971,12 @@ public class RegionMaker { return excOutRegion; } - private void processExcHandler(ExceptionHandler handler, Set exits) { + private void processExcHandler(MethodNode mth, ExceptionHandler handler, Set exits) { BlockNode start = handler.getHandlerBlock(); if (start == null) { return; } - RegionStack stack = new RegionStack(mth); + RegionStack stack = new RegionStack(this.mth); BlockNode dom; if (handler.isFinally()) { SplitterBlockAttr splitterAttr = start.get(AType.SPLITTER_BLOCK); @@ -989,11 +989,11 @@ public class RegionMaker { stack.addExits(exits); } BitSet domFrontier = dom.getDomFrontier(); - List handlerExits = BlockUtils.bitSetToBlocks(mth, domFrontier); - boolean inLoop = mth.getLoopForBlock(start) != null; + List handlerExits = BlockUtils.bitSetToBlocks(this.mth, domFrontier); + boolean inLoop = this.mth.getLoopForBlock(start) != null; for (BlockNode exit : handlerExits) { if ((!inLoop || BlockUtils.isPathExists(start, exit)) - && RegionUtils.isRegionContainsBlock(mth.getRegion(), exit)) { + && RegionUtils.isRegionContainsBlock(this.mth.getRegion(), exit)) { stack.addExit(exit); } } @@ -1001,7 +1001,7 @@ public class RegionMaker { ExcHandlerAttr excHandlerAttr = start.get(AType.EXC_HANDLER); if (excHandlerAttr == null) { - LOG.warn("Missing exception handler attribute for start block"); + mth.addWarn("Missing exception handler attribute for start block: " + start); } else { handler.getHandlerRegion().addAttr(excHandlerAttr); } diff --git a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java index a0754fbf5..24fa38ffc 100644 --- a/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java +++ b/jadx-core/src/test/java/jadx/tests/external/BaseExternalTest.java @@ -135,23 +135,36 @@ public abstract class BaseExternalTest extends IntegrationTest { String[] lines = code.split(CodeWriter.NL); for (MethodNode mth : classNode.getMethods()) { if (isMthMatch(mth, mthPattern)) { - int decompiledLine = mth.getDecompiledLine(); + int decompiledLine = mth.getDecompiledLine() - 1; StringBuilder mthCode = new StringBuilder(); + int startLine = getCommentLinesCount(lines, decompiledLine); int brackets = 0; - for (int i = decompiledLine - 1; i > 0 && i < lines.length; i++) { + for (int i = startLine; i > 0 && i < lines.length; i++) { String line = lines[i]; mthCode.append(line).append(CodeWriter.NL); - brackets += StringUtils.countMatches(line, '{'); - brackets -= StringUtils.countMatches(line, '}'); - if (brackets <= 0) { - break; + if (i >= decompiledLine) { + brackets += StringUtils.countMatches(line, '{'); + brackets -= StringUtils.countMatches(line, '}'); + if (brackets <= 0) { + break; + } } } - LOG.info("{}\n{}", mth.getMethodInfo().getShortId(), mthCode); + LOG.info("Print method: {}\n{}", mth.getMethodInfo().getShortId(), mthCode); } } } + protected int getCommentLinesCount(String[] lines, int line) { + for (int i = line - 1; i > 0 && i < lines.length; i--) { + String str = lines[i]; + if (str.isEmpty() || str.equals(CodeWriter.NL)) { + return i + 1; + } + } + return 0; + } + private void printErrorReport(JadxDecompiler jadx) { jadx.printErrorsReport(); assertThat(jadx.getErrorsCount(), is(0)); diff --git a/jadx-gui/build.gradle b/jadx-gui/build.gradle index aa38bae99..956922536 100644 --- a/jadx-gui/build.gradle +++ b/jadx-gui/build.gradle @@ -1,6 +1,6 @@ plugins { id 'edu.sc.seis.launch4j' version '2.4.4' - id 'com.github.johnrengelman.shadow' version '2.0.4' + id 'com.github.johnrengelman.shadow' version '4.0.3' } apply plugin: 'application'