Reputation: 120
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
Upvotes: 3
Views: 868
Reputation: 222348
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
Upvotes: 4