Developer's Diary

11 noviembre, 2014

Inyeccion DLL. Mostrando un ejemplo

Filed under: .net, API, ASP.Net, Curso C#, Programación, Seguridad — Etiquetas: , , , — jnavero @ 11:43 PM

Hace mucho quiero escribir este post en él quiero mostrar como hacer inyección DLL a través de aplicaciones creadas en .NET.

Esto sirvió como respuesta a una pregunta curiosa y es la respuesta a como modificar el comportamiento de una aplicación existente.

Crearé dos post para poder explicar todo esto de la mejor forma posible. En este post voy a mostrar varias funciones que consisten en:

1º. La aplicacion “Victima” que se trata de una aplicación sencilla creada en .NET con un statusLabel.

2º. Una aplicación creada en .NET que será la aplicación que inyecta la DLL.

3º. Una DLL Creada en .NET que será la librería que vamos a inyectar y que “manipulará” la aplicación “Victima”.

4º. Una ayudita en C++ ya que la inyeccion DLL de .NET tiene un problemilla que veremos en estos post.

Antes de comenzar, veamos ¿Qué es la Inyección dll?

Para explicarlo un poco con mis palabras, diremos que es una técnica que busca ejecutar un código concreto (nuestro código) en una aplicación externa. De esta forma, podemos modificar su comportamiento de la forma que deseemos.

Todo el código aquí visto lo subiré a la cuenta de git.

Primero, veremos la aplicación “Victima” que es la más sencilla.

victima

Como se puede ver la aplicación no tiene nada mas que un formulario vacío con un toolStripStatusLabel.

Una vez visto el primer proyecto veamos el segundo. Este contiene mucha “Chicha” ya que es el encargado de realizar la “magia” de la inyección. Es decir inyecta una DLL externa en la victima

inject

Esta contiene tres botones.

El botón Busca Proc:

private string findForm()
{
var p = Process.GetProcesses().FirstOrDefault(x => x.ProcessName.Trim().ToUpper() == "VICTIMA");
if (p != null){
MessageBox.Show("No encontrado...");
return string.Empty;
}
pApplication = Process.GetProcessById(p.Id);
if (pApplication != null)
return pApplication.ProcessName;
return string.Empty;
}

He de reconocer que este código tiene mucho tiempo y aunque estoy arreglándolo un poco, se puede mejorar muchísimo.

Esta función busca el proceso llamado VICTIMA que es nuestra primera aplicación y guarda el proceso en la variable pAplication para usarlo posteriormente.

El Botón BuscaDLL no hace nada mas que buscar la DLL

OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Dynamic Link Library|*.dll";
ofd.FileOk += new CancelEventHandler(dll_FileOk);
ofd.ShowDialog();

Por último el botón Inyecta que es donde está todo lo importante en este formulario. Este botón llama a una clase que es donde se encuentra todo el motor de inyección que expongo a continuación.

He de decir, que a lo largo del tiempo he ido poniendo apis del sistema por el blog, con el fin de poder entender este post.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Inject
{

public static class Inyeccion
{

private static class WINAPI
{

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
Int32 bInheritHandle,
UInt32 dwProcessId);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 CloseHandle(
IntPtr hObject);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string lpProcName);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(
string lpModuleName);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
IntPtr dwSize,
uint flAllocationType,
uint flProtect);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern Int32 WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] buffer,
uint size,
out IntPtr lpNumberOfBytesWritten);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttribute,
IntPtr dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
IntPtr lpThreadId);

public static class VAE_Enums
{

public enum AllocationType
{
MEM_COMMIT = 0x1000,
MEM_RESERVE = 0x2000,
MEM_RESET = 0x80000,
}

public enum ProtectionConstants
{
PAGE_EXECUTE = 0X10,
PAGE_EXECUTE_READ = 0X20,
PAGE_EXECUTE_READWRITE = 0X40,
PAGE_EXECUTE_WRITECOPY = 0X80,
PAGE_NOACCESS = 0X01
}
}

}

public static bool DoInject(Process pToBeInjected, string sDllPath, out string sError)
{
IntPtr hwnd = IntPtr.Zero;
if (!CRT(pToBeInjected, sDllPath, out sError, out hwnd)) //CreateRemoteThread
{
if (hwnd != (IntPtr)0)
WINAPI.CloseHandle(hwnd);
return false;
}
int wee = Marshal.GetLastWin32Error();
return true;
}

private static bool CRT(Process pToBeInjected, string sDllPath, out string sError, out IntPtr hwnd)
{
sError = String.Empty; //in case we encounter no errors
IntPtr hndProc = WINAPI.OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), //create thread, query info, operation
//write, and read
1,
(uint)pToBeInjected.Id);
hwnd = hndProc;
if (hndProc == (IntPtr)0)
{
sError = "Unable to attatch to process.n";
sError += "Error code: " + Marshal.GetLastWin32Error();
return false;
}

IntPtr lpLLAddress = WINAPI.GetProcAddress(
WINAPI.GetModuleHandle("kernel32.dll"),
"LoadLibraryA");

if (lpLLAddress == (IntPtr)0)
{
//sError = "Unable to find address of " + LoadLibraryA + "n";
sError += "Error code: " + Marshal.GetLastWin32Error();
return false;
}

IntPtr lpAddress = WINAPI.VirtualAllocEx(
hndProc,
(IntPtr)null,
(IntPtr)sDllPath.Length, //520 bytes should be enough
(uint)WINAPI.VAE_Enums.AllocationType.MEM_COMMIT |
(uint)WINAPI.VAE_Enums.AllocationType.MEM_RESERVE,
(uint)WINAPI.VAE_Enums.ProtectionConstants.PAGE_EXECUTE_READWRITE);

if (lpAddress == (IntPtr)0)
{
if (lpAddress == (IntPtr)0)
{
sError = "Unable to allocate memory to target process.n";
sError += "Error code: " + Marshal.GetLastWin32Error();
return false;
}
}

byte[] bytes = CalcBytes(sDllPath);
IntPtr ipTmp = IntPtr.Zero;

WINAPI.WriteProcessMemory(
hndProc,
lpAddress,
bytes,
(uint)bytes.Length,
out ipTmp);

if (Marshal.GetLastWin32Error() != 0)
{
sError = "Unable to write memory to process.";
sError += "Error code: " + Marshal.GetLastWin32Error();
return false;
}

IntPtr ipThread = WINAPI.CreateRemoteThread(
hndProc,
(IntPtr)null,
(IntPtr)0,
lpLLAddress,
lpAddress,
0,
(IntPtr)null);

if (ipThread == (IntPtr)0)
{
sError = "Unable to load dll into memory.";
sError += "Error code: " + Marshal.GetLastWin32Error();
return false;
}
return true;
}

private static byte[] CalcBytes(string sToConvert)
{
byte[] bRet = System.Text.Encoding.ASCII.GetBytes(sToConvert);
return bRet;
}

}
}

La función DoInject es la función de entrada a la que se le pasan los parámetros como el PID de la victima, la ruta de la DLL que vamos a inyectar. Esta función a su vez llama a la función CRT que se encarga de toda la chicha.
Dicha función usa OpenProcess para abrir el proceso (Victima).
Posteriormente se usa GetProcAddress que carga LoadLibraryA de forma dinámica esta funcion junto con VirtualAllocEx nos servirán posteriormente para crear un hilo remoto y escribir nuestra DLL en memoria, para esto usamos
WriteProcessMemory y por ultimo con CreateRemoteThread creamos el hilo remoto al proceso victima.

Hasta aquí, dejo la primera parte de los dos post. En el segundo post hablaré de los otros dos puntos indicados.

Anuncios

1 comentario »

  1. […] en el post Inyección DLL. Mostrando un ejemplo hablé de los cuatro proyectos que conforman estos artículos y me faltaron dos por explicar. En […]

    Pingback por Inyeccion DLL. Mostrando un ejemplo II | Devthisblog — 15 noviembre, 2014 @ 7:31 PM


RSS feed for comments on this post. TrackBack URI

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: