Brief introduction on reverse engineering Crystal binaries.
Crystal is a “new” Ruby-syntax-based programming language, born in 2014. The main diference is, that this is not a Ruby implementation, this is another compiled programming language, but its syntax is based in ruby, so Crystal != Ruby.
You can learn more about Crystal here: crystal
Any new compiled programming language results interesting from a reverse engineering perspective, malware is becoming more and more based on this kind of compiled programming language, whose syntax is easier than C or C++, but mantaining the ability to run standalone.
A Crystal Hello World example, looks like this:
puts 'Hello world!'
Yes, just like Ruby. To compile this, let’s save it as hello.cr and execute the Crystal compiler: crystal build hello.cr. This should create a hello executable with the following characteristics: hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped
A dinamically linked, non-stripped binary. Cool!
IDA analysis.
Let’s load this newly created binary using IDA Free 7.0 for Linux, (keep calm radare2 fanboys). Something catch my attention when load finished:

Maaaaaaan 2055 functions?!!! Calm down buddy, if you take a look at other compiled languages, like Golang, this is normal. Modern compiled languages, import everything they need to be cross-platform, so lot of functions are included in a single binary to be able to compile binaries for Windows, Linux and OSX using a single compiler.
So where’s the program itself?
By default, IDA show us to the first function basic blocks executed in the program.

Ok cool, so this function just calls another function: main_0, which also calls another function main_user_code

And main_user_code just calls another function __crystal_main

Let’s then analyze this __crystal_main function, opening their basic blocks view, something really ugly happen:

… what the hell man, where the fuck is our application code? Just at the end!

There you can see the loading of our “Hello world!” string, which is at off_9A530, and a call to puts function which seems to be a wrapper for puts_0 function, which really executes the output operation and shows our string in stdout.
Ok, so the workflow seems to be:
main -> main_0 -> main_user_code -> __crystal_main and, at the end, our script code is executed.
Let’s see how conditionals and classes works at Crystal creating a simple script with the following code:
class MyHelloClass
  def initialize(number=0)
    @number = number
  end
  def test_random
    if @number < 4
      puts "A is lower than 4"
    else
      puts "A is GREATER than 4"
    end
  end
end
puts "Now, an if sentence will appear based on rand numeric value"
num = rand(6)
a = MyHelloClass.new(num)
a.test_random
Ok simple, let’s compile it crystal build hello2.cr and open it using IDA, this time going directly to __crystal_main buttom, where our code should be.

There it is, first, rand is called, which is, again a wrapper for Random::PCG32 function identified in IDA as new_98
Then, a call to new_101 is done, when inspecting this is our MyHelloClass::new function, which is the wrapper for the initialize function in our class. In Ruby, the initialize function is the constructor of the class.

As you can see in this basic block, memory is created for our new object using _crystal_malloc_antomic64 function, a wrapper for GC_generic_malloc which, after lot of operations, is a malloc itself.
Then, a call test_random is done, remember, Crystal compiler does not strip binaries by default so function names remain intact.

Here it is our conditional, and our puts calls on each condition. Cool!
Radare2, show us function names processed, so it’s a bit easier to identify the binary work flow with a single s sym.__crystal_main pdf call.

That’s all, thanks for reading, and hope this post can be helpful for someone facing this kind of binaries for the first time.
Please, feel free to contact me if you see any mistake, also my written english is not the best, so sorry for those whose eyes explode while reading this.
See you!