3

by mistake I deleted the source code of an Elixir escript that I wrote; as a last resort I'm trying to get the source (if possible at all) by decompiling the executable that I deployed on a server.

In case it matters, it was compiled on Ubuntu 16.04 running mix escript.build without additional arguments.

I would appreciate if somebody could give me any pointer how to do this or where to start!

Thanks

asked Apr 20, 2017 at 9:15

1 Answer 1

4

Here's how you can get the compiled Erlang source of your files back. I don't think it's possible to get the original Elixir source back since it is not present in the escript at all; only the compiled Erlang bytecode is. The decompiled Erlang code should be fairly readable if you know some Erlang (if not, check out this quick Erlang <-> Elixir crash course).

The escript executable starts with #! /usr/bin/env escript followed by some lines and then the embedded compiled files are present as a binary zip file. Open the escript file in an editor and delete everything until the line starting with PK (the start of the zip).

$ mix escript.build
$ head -c 59 m
#! /usr/bin/env escript
%%
%%! -escript main m_escript
PK
$ vim m # remove everything until `PK`
$ head -c2 m
PK

Now you can extract the contents of the file with unzip and get all the compiled .beam files:

$ unzip m -d extracted
Archive: m
 inflating: extracted/m_escript.beam
 inflating: extracted/Elixir.Version.Parser.DSL.beam
 inflating: extracted/Elixir.Kernel.LexicalTracker.beam
 inflating: extracted/Elixir.IO.ANSI.beam
 inflating: extracted/Elixir.Inspect.NaiveDateTime.beam
 inflating: extracted/Elixir.Protocol.beam
 inflating: extracted/Elixir.Inspect.Any.beam
 ...

Finally you can decompile the modules you want using decompile-beam:

$ decompile-beam extracted/Elixir.M.beam
-compile(no_auto_import).
-file("lib/m.ex", 1).
-module('Elixir.M').
-export(['__info__'/1, main/0, main/1]).
-spec '__info__'(attributes | compile | exports |
 functions | macros | md5 | module |
 native_addresses) -> atom() |
 [{atom(), any()} |
 {atom(), byte(), integer()}].
'__info__'(functions) -> [{main, 0}, {main, 1}];
'__info__'(macros) -> [];
'__info__'(info) ->
 erlang:get_module_info('Elixir.M', info).
main() -> main([]).
main(args@1) -> 'Elixir.IO':inspect({args@1, args@1}).

This was the original Elixir source:

$ cat lib/m.ex
defmodule M do
 def main(args \\ []) do
 IO.inspect {args, args}
 end
end
answered Apr 20, 2017 at 9:30

1 Comment

Thank you very much, there is still some work to do but it's a great base, much appreciated!!!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.