Short introduction to EPO
By DoxtorL. /[T.I]
Here is a short introduction to E.P.O. To learn something you have to know basics of Portable Executable Layout. EPO stands for Entry Point Obscured . What does it mean? ------------------ A normal program contains a lots of Api calls for example: push 0 Source: call ExitProcess if we replace this "Api call" by a virus call we have got an example of what is E.P.O But the Api call has to be executed look at the next diagram: Call (Api call before infection) Source -----------------------------> Aim (go to Api address) | ^ | | | | | Call (after infection) |Jump | | | | | | V | BeginningOfVirus EndOfVirus The call is performed from Source address. in the host the called address is Aim We change the called address.Now, it's BeginningOfVirus address. When the virus has terminated its job, it performs a jump to the "Aim" address in the host program. Now, the programs looks like: push 0 Source: call BeginningOfVirus [...] BeginningOfVirus: pusha ;save registers < Virus Code > popa ;restore registers jmp Aim ;go to the inital place We need to know a little bit more about the opcodes of some instructions, performing a jump or a call Especially those ones: I) ***** Source: jmp Aim [...] Aim: %% coded as : db 0e9h dd offset Aim - offset Source - 5 (there exist others direct jmp, but no needed for our purposes) It doesn't matter if Source address is greater than Aim one, the code works too. II) ***** source: jmp [Aim] ;jmp to the address contained in dword Aim [...] Aim: dd X %% coded as: db 0ffh,25h dd offset Aim III) ***** source: call Aim %% coded as: db 0e8h dd offset Aim - offset Source - 5 In fact, only the last two instructions are used in the apis call process per- formed by Windows. But the direct (far) jump opcode is needed in what is following. How does a simple EPO technic works? ------------------------------------ First we search for byte e8h, its surely the beginning of "Call Aim" instruction. (that is, db 0e8h following by a dword X) We need to do that, to find a file pointer ,pointing to the entry point of program. In the different headers of a Portable Executable (PE for short) we can find the virtual address (VA for short) of entry point of program and VA of code section (we need the first VA to find this one, because code section isn't necessary the first section) We can get the PointerToRawData of code section. (it is located in section code header). It's a file pointer. VA isn't a file pointer, a VA + ImageBase value gives you a memory address. A file pointer to entry point is got from the formula: %%% Entry Point Pointer= PointerToRawdata of Code Section + (VA of Entry Point - VA of Code Section) Using this pointer ( a dword), we can scan the section code to find e8h byte. Are we sure the byte e8h (we just find) the first byte of a call? No we aren't! Here is the correct layout of an Api call: Instructions: opcodes: call Aim db 0e8 dd x [...] Aim: jmp [YYYY] dw 0ff25h dd "YYYY" "Aim" isn't an Api address at all! However, we have a method to check if a call is an api call or not. We have just to check if the word ff25h is at the address "Aim"! First, we need to compute the VA of "Aim" VA Aim - VA of "0e8h" byte -5=X then we've got : VA Aim= X+ VA of "0e8h"+5 The VA of Aim is knew. We need to get a file pointer for the VA of Aim. There is no information in the different headers of the PE file to know dir- ctly where is "jmp [YYYY]" :( The VA of Aim is used to know in wich section we can find it. (Sometime, this VA isn't in the mapped PE file. The reason is quite simple, the e8 byte wasn't an opcode for a Call at all!) However, most of the time it's in code section itself. Let's assume it. We 've got the formula: Pointer to Aim = PointerToRawdata of Code Section +(VA of Aim - VA of Code Section) Let's assume this value (a dword) is in EAX register and we have mapped the PE target in memory: add eax,BaseAddressOfMapping cmp dword ptr [eax],25ffh jnz NoJmpHere do the test we need. (before to perform this test, we have to be sure the address in eax is in the file itself, else fault protection page will surely occure!) Now ,we build the new "call" to replace the previous one. We want: Instructions: opcodes: Source: call Beginning of virus db 0e8h dd Y Since , VA of beginning of virus- VA of Source =Y - 5 Then : Y=VA of Beginning of Virus - VA of Source + 5 Let's assume VA of the end of virus code is EndOfVirus We want to jump to real aim of the Api call We Want : Instructions: Opcodes: EndOfVirus: jmp Aim db 0e9h dd Z We compute the needed dword appearing in jump instruction: db 09eh,dd Z (Z is the unknown dword we are searching for). Once more we have: VA Aim- VA of EndOfVirus=Z-5 then: Z=VA Aim -VA EndOfVirus+5 Example of code obtained: before infection: Source: db 0e8h ; dd offset Aim ;Call Aim [...] Aim: After infection: db 0e8h ; dd offset BeginningOfVirus -offset Source+5 ;call BeginningOfVirus [...] Aim: [...] BeginningOfVirus: [...] EndOfVirus: db 0e9h dd offset Aim-Offset EndOfVirus+5 I hope this tutorial will help you to understand a basic EPO technic. Up to now, antiviruses scanners seems to have a bad trip to detect infected files by a virus using EPO. However this article can be used for AV use too! So this basic technic will be outdated soon , i suppose. But there is two things you can do, to make the job of AV more harder. Think by yourself...answers are included in this article ;)