
Hackme: Deconstructing an ELF File - mvanga
http://manoharvanga.com/hackme/
======
buff-a
Don't want to take the wind out of anyone's sails, but this program is hardly
hard-to-hack. Bravo for getting to grips with ELF, assembly and reverse
engineering. But this article represented just the first few steps on a long
an intriguing road.

If it was hard-to-hack then I would expect (at least) the following:

    
    
      * Output messages can't be discovered using "strings"
      * Program is self-encrypted
      * Password isn't even stored, just hash result.
    

The "hard-to-hack" program presented would take about 30 seconds using IDA[1].

[1] <http://www.hex-rays.com/idapro/>

(And I consider myself an _amateur_ at this kind of thing).

~~~
mvanga
That was mostly the point of the article: that it wasn't so hard to hack in
the end and all the information needed to break it was visible in plain sight.

Like you said, if you really wanted to write a hard to hack binary, just use a
strong hash without the plaintext on a hellish password. Heck, just leave the
hash in the strings output :)

------
tehjones
Thats brilliant. It reminds me of the size matters article I read a couple of
years ago, the most difficult title to google too
[http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm...](http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html)

------
angusgr
Any chance someone who knows more assembly than me can explain how the symbol
names for dlsym() are retrieved?

ie I would have expected to see 'ptrace', 'scanf' and 'printf' in the strings
output, but they must be obfuscated in some way (otherwise I guess there's no
point using the dlopen/dlsym trick at all.)

I only see one call to dlsym (at 8048506), so it seems to me the program is
doing something tricky to build each symbol name string and then calling a
routine there to dlsym() it.

That's about where my x86-fu fails me, though, and I remember I should be
working on other things. :/

~~~
sparky
The function names are hidden in the .text section; each character is xored
with 0x55. You can see the xoring here:

    
    
      80484e0: 83 f2 55              xor    $0x55,%edx
    

The encoded strings are:

    
    
      >>> def ascii_to_xored_hex(s, xorval):
      ...   return ''.join(['%02x' % (ord(c) ^ xorval) for c in s])
      ... 
      >>> ascii_to_xored_hex('ptrace', 0x55)
      '252127343630'
      >>> ascii_to_xored_hex('printf', 0x55)
      '25273c3b2133'
    

They're hidden in plain sight!

    
    
      mrj10@mjlap:~/Downloads$ xxd hackme | grep 2521
      0000680: 008d 7600 2521 2734 3630 0090 2636 343b  ..v.%!'460..&64;
      mrj10@mjlap:~/Downloads$ xxd hackme | grep 2527
      0000690: 3300 6690 2527 3c3b 2133 0090 6afb 4c8d  3.f.%'<;!3..j.L.
    
      To the disassembler, these strings look like and-xor sequences.  e.g., for 'ptrace':
    
       8048684: 25 21 27 34 36        and    $0x36342721,%eax
       8048689: 30 00                 xor    %al,(%eax)
    

As you can see from the hexdump, these did show up when he ran strings (e.g.,
_%!'460_ and _%' <;!3_ ), they just weren't recognizable.

~~~
mvanga
Nice catch! I didn't notice this because I restricted my search to between the
printf calls. The strings output makes more sense now!

------
0x0
Interesting, but the objdump output is very primitive compared to more
advanced disassemblers, which should be able to provide string cross-
references etc in-line.

~~~
jdthomas
Any particular disassembler(s) you recommend? How about on other
architectures; MIPS or ARM?

~~~
angusgr
For free (as in beer) you can get IDA Pro 5.0 (an older version than the
latest.)

Not sure what architectures that version supports outside of x86 (the latest
commercial version does ARM and the Advanced variant does MIPS.)

~~~
daeken
IDA Free has traditionally only supported x86 PE binaries, but I don't know if
that's changed with the bump up to 5.0.

