• Github每日精选(第38期):Java 8+ Jar 和 Android APK 逆向工程套件(反编译器、编辑器、调试器等)bytecode-viewer


    bytecode-viewer

    bytecode-viewer 是一个 轻量级用户友好的 Java/Android 字节码查看器、反编译器。

    BCV 由几个开源工具提供支持,旨在帮助逆向过程。

    BCV 带有 6 个反编译器、3 个反汇编器、2 个汇编器、2 个 APK 转换器、高级搜索、调试等。

    它完全用 Java 编写,并且是开源的。它目前由 Konloch 维护和开发。

    github 的地址在这里

    在这里插入图片描述

    主要特征
    • 只需拖放即可反编译和搜索 Java Jars 和 Android APK
    • 文件格式支持:Class、Jar、XAPK、APK、DEX、WAR、JSP、图像资源、文本资源等
    • 6 个内置 Java 反编译器:Krakatau、CFR、Procyon、FernFlower、JADX、JD-GUI
    • 3 个内置字节码反汇编器,包括 2 个汇编器:Krakatau 和 Smali/BakSmali
    • 来自 Dex2Jar 和 Enjarify 的 APK/DEX 支持
    • 内置Java编译器
    • 高级静态搜索功能
    • 可定制的用户界面
    • 插件+脚本引擎设计
    • 恶意代码扫描API
    • 翻译成 30 多种语言,包括:阿拉伯语、德语、日语、普通话、俄语、西班牙语)
    • 将功能导出为 Runnable Jar、Zip、APK、反编译为 Zip 等。
    命令行输入
    	-help                         Displays the help menu
    	-clean                        Deletes the BCV directory
    	-english                      Forces English language translations
    	-list                         Displays the available decompilers
    	-decompiler <decompiler>      Selects the decompiler, procyon by default
    	-i <input file>               Selects the input file (Jar, Class, APK, ZIP, DEX all work automatically)
    	-o <output file>              Selects the output file (Java or Java-Bytecode)
    	-t <target classname>         Must either be the fully qualified classname or "all" to decompile all as zip
    	-nowait                       Doesn't wait for the user to read the CLI messages
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    如何使用
    • 从 Jar、Zip、ClassFile 或 Android 文件(APK、DEX、XAPK 等)开始,将其拖入 BCV。它将自动开始解码过程。
    • 从这里您可以通过选择 View Pane>View 1、View 2、View 3 等来选择您想要使用的反编译器。
    • 视图窗格用于并排显示最多 3 个反编译器,您也可以在此处切换可编辑性。
    • 通过使用资源列表导航选择您要打开的资源,BCV 将尽力显示它(反编译、反汇编等)。
    • 您可以使用插件来帮助您搜索以及使用左下角的搜索窗格。
    代码分析

    这里主要分析MethodNodeDecompiler.java 下的反编译代码,反编译代码也是这个项目的核心,通过反编译代码可以看看这种逆向工具是如何做到对编译的代码进行逆向的。

    public static PrefixedStringBuilder decompile(PrefixedStringBuilder sb,
                                                      MethodNode m, ClassNode cn) {
            String class_;
            if (cn.name.contains("/")) {
                class_ = cn.name.substring(cn.name.lastIndexOf("/") + 1);
            } else {
                class_ = cn.name;
            }
    
            String s = getAccessString(m.access);
            sb.append("     ");
            sb.append(s);
            if (s.length() > 0)
                sb.append(" ");
    
            if (m.name.equals("")) {
                sb.append(class_);
            } else if (!m.name.equals("")) {
                Type returnType = Type.getReturnType(m.desc);
                sb.append(returnType.getClassName());
                sb.append(" ");
                sb.append(m.name);
            }
    
            TypeAndName[] args = new TypeAndName[0];
    
            if (!m.name.equals("")) {
                sb.append("(");
    
                final Type[] argTypes = Type.getArgumentTypes(m.desc);
                args = new TypeAndName[argTypes.length];
    
                for (int i = 0; i < argTypes.length; i++) {
                    final Type type = argTypes[i];
    
                    final TypeAndName tan = new TypeAndName();
                    final String argName = "arg" + i;
    
                    tan.name = argName;
                    tan.type = type;
    
                    args[i] = tan;
    
                    sb.append(type.getClassName() + " " + argName
                            + (i < argTypes.length - 1 ? ", " : ""));
                }
    
                sb.append(")");
            }
    
            int amountOfThrows = m.exceptions.size();
            if (amountOfThrows > 0) {
                sb.append(" throws ");
                sb.append(m.exceptions.get(0));// exceptions is list
                for (int i = 1; i < amountOfThrows; i++) {
                    sb.append(", ");
                    sb.append(m.exceptions.get(i));
                }
            }
    
            if (s.contains("abstract")) {
                sb.append(" {}");
                sb.append(" //");
                sb.append(m.desc);
                sb.append(nl);
            } else {
    
                sb.append(" {");
    
                if (BytecodeViewer.viewer.debugHelpers.isSelected()) {
                    if (m.name.equals(""))
                        sb.append(" // ");
                    else if (m.name.equals(""))
                        sb.append(" // ");
                }
    
                sb.append(" //");
                sb.append(m.desc);
    
                sb.append(nl);
    
                if (m.signature != null) {
                    sb.append("         ).append(m.signature).append(">");
                }
    
                if (m.annotationDefault != null) {
                    sb.append(m.annotationDefault);
                    sb.append("\n");
                }
    
                InstructionPrinter insnPrinter = new InstructionPrinter(m, args);
    
                addAttrList(m.attrs, "attr", sb, insnPrinter);
                addAttrList(m.invisibleAnnotations, "invisAnno", sb, insnPrinter);
                addAttrList(m.invisibleAnnotations, "invisLocalVarAnno", sb,
                        insnPrinter);
                addAttrList(m.invisibleTypeAnnotations, "invisTypeAnno", sb,
                        insnPrinter);
                addAttrList(m.localVariables, "localVar", sb, insnPrinter);
                addAttrList(m.visibleAnnotations, "visAnno", sb, insnPrinter);
                addAttrList(m.visibleLocalVariableAnnotations, "visLocalVarAnno",
                        sb, insnPrinter);
                addAttrList(m.visibleTypeAnnotations, "visTypeAnno", sb,
                        insnPrinter);
    
                List<TryCatchBlockNode> tryCatchBlocks = m.tryCatchBlocks;
                for (int i = 0; i < tryCatchBlocks.size(); i++) {
                    TryCatchBlockNode o = tryCatchBlocks.get(i);
                    sb.append("         ");
                    sb.append("TryCatch").append(i).append(": L");
                    sb.append(insnPrinter.resolveLabel(o.start));
                    sb.append(" to L");
                    sb.append(insnPrinter.resolveLabel(o.end));
                    sb.append(" handled by L");
                    sb.append(insnPrinter.resolveLabel(o.handler));
                    sb.append(": ");
                    if (o.type != null)
                        sb.append(o.type);
                    else
                        sb.append("Type is null.");
                    sb.append(nl);
                }
                for (String insn : insnPrinter.createPrint()) {
                    sb.append("         ");
                    sb.append(insn);
                    sb.append(nl);
                }
                sb.append("     }" + nl);
            }
            return sb;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
  • 相关阅读:
    java计算机毕业设计springboot+vue度假山庄酒店管理系统(源码+系统+mysql数据库+Lw文档)
    基于SpringBoot的单应用项目模板(考虑到后期做微服务,内部已经做了拆分)
    利用python爬虫采集苹果公司各产品销售收入统计报告
    Golang API框架
    一篇文章就足够解决大数据实时面试
    vue 中引入 jquery
    vue学习之列表渲染
    ArmSoM-W3之RK3588 Debian11详解
    MySql性能优化(一)数据类型优化
    STM32F407ZGT6|实现中断操作
  • 原文地址:https://blog.csdn.net/weixin_40425640/article/details/126278782