All Projects → clojure-goes-fast → Clj Java Decompiler

clojure-goes-fast / Clj Java Decompiler

Licence: epl-1.0
REPL-integrated Clojure-to-Java decompiler

Programming Languages

java
68154 projects - #9 most used programming language
clojure
4091 projects
bytecode
52 projects

Projects that are alternatives of or similar to Clj Java Decompiler

Reko
Reko is a binary decompiler.
Stars: ✭ 942 (+432.2%)
Mutual labels:  decompiler
Jsc Decompile Mozjs 34
A javascript bytecode decoder for mozilla spider-monkey version 34. May decompile jsc file compile by cocos-2dx
Stars: ✭ 101 (-42.94%)
Mutual labels:  decompiler
Bytecode Viewer
A Java 8+ Jar & Android APK Reverse Engineering Suite (Decompiler, Editor, Debugger & More)
Stars: ✭ 12,606 (+7022.03%)
Mutual labels:  decompiler
Ex4 to mq4 cli
Unofficial CLI support for ex4_to_mq4 decompiler. Note: This is the wrapper, not decompiler!
Stars: ✭ 42 (-76.27%)
Mutual labels:  decompiler
Mrspicky
MrsPicky - An IDAPython decompiler script that helps auditing calls to the memcpy() and memmove() functions.
Stars: ✭ 86 (-51.41%)
Mutual labels:  decompiler
Unreal Library
A decompiler library for Unreal packages such as .upk and .u files, supporting Unreal Engine 1, 2, and 3.
Stars: ✭ 123 (-30.51%)
Mutual labels:  decompiler
Protobuf Decompiler
Stars: ✭ 9 (-94.92%)
Mutual labels:  decompiler
Ilspy
.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
Stars: ✭ 14,011 (+7815.82%)
Mutual labels:  decompiler
Jremapper
Remapping tool for compiled java programs.
Stars: ✭ 97 (-45.2%)
Mutual labels:  decompiler
Elisp Bytecode
Let's document Emacs Lisp Bytecode (Lisp Assembly Program) instructions
Stars: ✭ 151 (-14.69%)
Mutual labels:  decompiler
Termux Apktool
Decompile and Recompile android aplication use termux without openjdk installed
Stars: ✭ 53 (-70.06%)
Mutual labels:  decompiler
Simplesmali
通过精简Smali语法细节来增强反编译代码阅读性,自定义了一种简单语法
Stars: ✭ 61 (-65.54%)
Mutual labels:  decompiler
Despector
Java / Kotlin Decompiler and AST Library
Stars: ✭ 126 (-28.81%)
Mutual labels:  decompiler
Protodec
Protobuf decompiler
Stars: ✭ 37 (-79.1%)
Mutual labels:  decompiler
Abyss
abyss - IDAPython Plugin for Postprocessing of Hexrays Decompiler Output
Stars: ✭ 161 (-9.04%)
Mutual labels:  decompiler
Befa Library
High-level library for executable binary file analysis
Stars: ✭ 12 (-93.22%)
Mutual labels:  decompiler
Gda Android Reversing Tool
GDA is a new fast and powerful decompiler in C++(working without Java VM) for the APK, DEX, ODEX, OAT, JAR, AAR, and CLASS file. which supports malicious behavior detection, privacy leaking detection, vulnerability detection, path solving, packer identification, variable tracking, deobfuscation, python&java scripts, device memory extraction, dat…
Stars: ✭ 2,332 (+1217.51%)
Mutual labels:  decompiler
Ghidrasnippets
Python snippets for Ghidra's Program and Decompiler APIs
Stars: ✭ 172 (-2.82%)
Mutual labels:  decompiler
Radeco
radare2-based decompiler and symbol executor
Stars: ✭ 313 (+76.84%)
Mutual labels:  decompiler
Mips to c
A MIPS decompiler.
Stars: ✭ 140 (-20.9%)
Mutual labels:  decompiler

clj-java-decompiler

You can read the motivation behind clj-java-decompiler and the usage example in the blog post.

This library is an integrated Clojure-to-Java decompiler usable from the REPL. It is a wrapper around Procyon which is a suite of Java metaprogramming tools focused on code generation and analysis.

Quick demo:

user> (clj-java-decompiler.core/decompile
        (loop [i 100, sum 0]
          (if (< i 0)
            sum
            (recur (unchecked-dec i) (unchecked-add sum i)))))

// Decompiling class: user$fn__13332
import clojure.lang.*;

public final class user$fn__13332 extends AFunction
{
    public static Object invokeStatic() {
        long i = 100L;
        long sum = 0L;
        while (i >= 0L) {
            final long n = i - 1L;
            sum += i;
            i = n;
        }
        return Numbers.num(sum);
    }

    public Object invoke() {
        return invokeStatic();
    }
}

Why?

There are several usecases when you may want to use a Java decompiler:

  • To get a general understanding how Clojure compiler works: how functions are compiled into classes, how functions are invoked, etc.
  • To optimize performance bottlenecks when using low-level constructs like loops, primitive math, and type hints.
  • To investigate how Java interop facilities are implemented (reify, proxy, gen-class).

Usage

Add com.clojure-goes-fast/clj-java-decompiler to your dependencies:

Then, at the REPL:

user> (require '[clj-java-decompiler.core :refer [decompile]])
nil
user> (decompile (fn [] (println "Hello, decompiler!")))
// Decompiling class: clj_java_decompiler/core$fn__13257
import clojure.lang.*;

public final class core$fn__13257 extends AFunction
{
    public static final Var const__0;

    public static Object invokeStatic() {
        return ((IFn)const__0.getRawRoot()).invoke((Object)"Hello, decompiler!");
    }

    public Object invoke() {
        return invokeStatic();
    }

    static {
        const__0 = RT.var("clojure.core", "println");
    }
}

You can also disassemble to bytecode, with the output being similar to the one of javap.

user> (disassemble (fn [] (println "Hello, decompiler!")))

;;; Redacted

    public static java.lang.Object invokeStatic();
        Flags: PUBLIC, STATIC
        Code:
                  linenumber      1
               0: getstatic       clj_java_decompiler/core$fn__17004.const__0:Lclojure/lang/Var;
               3: invokevirtual   clojure/lang/Var.getRawRoot:()Ljava/lang/Object;
                  linenumber      1
               6: checkcast       Lclojure/lang/IFn;
               9: getstatic       clj_java_decompiler/core$fn__17004.const__1:
Lclojure/lang/Var;
              12: invokevirtual   clojure/lang/Var.getRawRoot:()Ljava/lang/Object;
                  linenumber      1
              15: checkcast       Lclojure/lang/IFn;
              18: ldc             "Hello, decompiler!"
                  linenumber      1
              20: invokeinterface clojure/lang/IFn.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
                  linenumber      1
              25: invokeinterface clojure/lang/IFn.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
              30: areturn

To make the output clearer, clj-java-decompiler by default disables locals clearing for the code it compiles. You can re-enable it by setting this compiler option to false explicitly, like this:

(binding [*compiler-options* {:disable-locals-clearing false}]
  (decompile ...))

You can also change other compiler options (static linking, metadata elision) in the same way.

Usage from Emacs

You can use clj-decompiler.el package (installable from MELPA) to fluidly invoke clj-java-decompiler right from your Clojure code buffer. Like with cider-macroexpand, you place your cursor at the end of the form you want to decompile and invoke M-x clj-decompiler-decompile. This will compile the form before the cursor, then decompile it with clj-java-decompiler, and present you the Java output in a separate syntax-highlighted buffer.

clj-decompiler.el can also automatically inject clj-java-decompiler dependency at cider-jack-in time. Check its repository for more details.

Comparison with no.disassemble

no.disassemble (ND) is another tool that lets you inspect what the Clojure code compiles to. However, it substantially differs from clj-java-decompiler (CJD).

  • ND can only disassemble the compiled code to bytecode representation. CJD decompiles the code into Java which is much easier to comprehend.
  • ND requires the program to be loaded with its Java agent present. You either have to add the agent to JVM options manually or start the REPL with its Leiningen plugin. CJD can be loaded into any REPL dynamically.
  • ND tracks every class that was loaded since the beginning of the program, so it has memory overhead. CJD bears no overhead.
  • ND can disassemble any already defined Clojure function. CJD needs the Clojure form to be passed directly to it.

The last limitation comes from the fact that Java and Clojure don't keep the bytecode for classes it loaded anywhere. When the Clojure compiler compiles a piece of Clojure code, it transforms it into bytecode in memory, then loads with a classloader, and discards the bytecode.

no.disassemble works around this by being a Java agent which instruments the classloader to save all classes it ever loaded into an accessible hashmap, so that they can be retrieved later. This however means you must start the Clojure program with ND's agent on the classpath.

So, you can't decompile an existing function definition with CJD. But if you are using CIDER, you can jump to the definition of the function you want to decompile, disable read-only mode (C-x C-q), wrap the defn form with clj-java-decompiler.core/decompile and recompile the form (C-c C-c).

License

clj-java-decompiler is distributed under the Eclipse Public License. See LICENSE.

Copyright 2018-2020 Alexander Yakushev

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].