I have encountered a quite obscure 32-bit ELF file (that is a crackme) and I still cannot figure out how can it execute. First, beside some "understandable" property that it has not any section:
# readelf --sections SimpleVM
There are no sections in this file.
Considering the segments:
# readelf --segments SimpleVM
Elf file type is EXEC (Executable file)
Entry point 0xc023dc
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x00c01000 0x00c01000 0x013c7 0x013c7 RWE 0x1000
LOAD 0x00019c 0x0804b19c 0x0804b19c 0x00000 0x00000 RW 0x1000
I observe that the first segments LOAD
has size 0x13c7
bytes, and mapped into memory at 0xc01000
; the second one is not important because its size is zero. But, the entry point of the ELF file is at 0xc023dc
, that means outside any segment LOAD
!!!
I use also IDA 6.8 (evaluation ver.) to load this file, and IDA says that the entry point is illegal.
Since the program has no INTERP
segment, the first executed instruction must be at 0xc023dc
. But this address is outside any "reliably" mapped data, we cannot sure which instruction will be executed. I think that this ELF should have some random behaviors (e.g. it should be crashed usually), but it is not, it executes normally, without any crash.
So my question is: how can this happen?
NB1. In case of someone wants to look at this file, I give the link here, but please do not give directly the solution. I want to handle it myself.
NB2. Using a Pintool to trace out what happens, I find the OEP
of the program is at 0xc01dfa
since its trace is:
0xc023dc mov dword ptr [0xc01bf0], 0x252e8 <=== modify address 0xc01bf0
0xc023e6 jmp 0xc01bf0
0xc01bf0 call 0xc01e47 <=== modified instruction
0xc01e47 pop ebp <=== OEP
0xc01e48 call 0xc01dfa
0xc01dfa pop esi
0xc01dfb lea eax, ptr [ebp-0x9]
0xc01dfe mov edi, dword ptr [eax]
0xc01e00 sub eax, edi
0xc01e02 mov edx, eax
0xc01e04 add eax, dword ptr [eax+0x48]
0xc01e07 add eax, 0xfff
0xc01e0c and eax, 0xfffff000
0xc01e11 push 0x1
0xc01e13 push eax
....
But I still cannot understand why the instruction at 0xc023dc
is always mov dword ptr [0xc01bf0], 0x252e8
(so the binary is somehow "self-modified")