Inyeccion DLL. Mostrando un ejemplo « Devthisblog

Devthisblog Desarrollo .net, Diseño Web, Seguridad… Y todo lo que se me vaya ocurriendo…

noviembre 11, 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:

 C | 
 
 copy code |
?

01
02
private string findForm()
03
{
04
   var p = Process.GetProcesses().FirstOrDefault(x => x.ProcessName.Trim().ToUpper() == "VICTIMA");
05
   if (p != null){
06
      MessageBox.Show("No encontrado...");
07
      return string.Empty;
08
   }
09
   pApplication = Process.GetProcessById(p.Id);
10
   if (pApplication != null)
11
      return pApplication.ProcessName;
12
   return string.Empty;
13
}
14

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

 C | 
 
 copy code |
?

1
2
   OpenFileDialog ofd = new OpenFileDialog();
3
   ofd.Filter = "Dynamic Link Library|*.dll";
4
   ofd.FileOk += new CancelEventHandler(dll_FileOk);
5
   ofd.ShowDialog();
6

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.

 C | 
 
 copy code |
?

001
002
using System;
003
using System.Collections.Generic;
004
using System.Linq;
005
using System.Text;
006
using System.Threading.Tasks;
007
using System.Runtime.InteropServices; 
008
using System.Diagnostics; 
009
 
010
 
011
namespace Inject
012
{       
013
 
014
    public static class Inyeccion
015
    {
016
 
017
        private static class WINAPI 
018
        { 
019
 
020
            [DllImport("kernel32.dll", SetLastError = true)] 
021
            public static extern IntPtr OpenProcess( 
022
                UInt32 dwDesiredAccess, 
023
                Int32 bInheritHandle, 
024
                UInt32 dwProcessId); 
025
 
026
            [DllImport("kernel32.dll", SetLastError = true)] 
027
            public static extern Int32 CloseHandle( 
028
                IntPtr hObject); 
029
 
030
 
031
 
032
            [DllImport("kernel32.dll", SetLastError = true)] 
033
            public static extern IntPtr GetProcAddress( 
034
                IntPtr hModule, 
035
                string lpProcName); 
036
 
037
            [DllImport("kernel32.dll", SetLastError = true)] 
038
            public static extern IntPtr GetModuleHandle( 
039
                string lpModuleName); 
040
 
041
            [DllImport("kernel32.dll", SetLastError = true)] 
042
            public static extern IntPtr VirtualAllocEx( 
043
                IntPtr hProcess, 
044
                IntPtr lpAddress, 
045
                IntPtr dwSize, 
046
                uint flAllocationType, 
047
                uint flProtect); 
048
 
049
            [DllImport("kernel32.dll", SetLastError = true)] 
050
            public static extern Int32 WriteProcessMemory( 
051
                IntPtr hProcess, 
052
                IntPtr lpBaseAddress, 
053
                byte[] buffer, 
054
                uint size, 
055
                out IntPtr lpNumberOfBytesWritten); 
056
 
057
            [DllImport("kernel32.dll", SetLastError = true)] 
058
            public static extern IntPtr CreateRemoteThread( 
059
                IntPtr hProcess, 
060
                IntPtr lpThreadAttribute, 
061
                IntPtr dwStackSize, 
062
                IntPtr lpStartAddress, 
063
                IntPtr lpParameter, 
064
                uint dwCreationFlags, 
065
                IntPtr lpThreadId); 
066
 
067
            public static class VAE_Enums 
068
            { 
069
 
070
                public enum AllocationType 
071
                { 
072
                    MEM_COMMIT = 0x1000, 
073
                    MEM_RESERVE = 0x2000, 
074
                    MEM_RESET = 0x80000, 
075
                } 
076
 
077
                public enum ProtectionConstants 
078
                { 
079
                    PAGE_EXECUTE = 0X10, 
080
                    PAGE_EXECUTE_READ = 0X20, 
081
                    PAGE_EXECUTE_READWRITE = 0X40, 
082
                    PAGE_EXECUTE_WRITECOPY = 0X80, 
083
                    PAGE_NOACCESS = 0X01 
084
                } 
085
            } 
086
 
087
        } 
088
 
089
        public static bool DoInject(Process pToBeInjected, string sDllPath, out string sError) 
090
        { 
091
            IntPtr hwnd = IntPtr.Zero; 
092
            if (!CRT(pToBeInjected, sDllPath, out sError, out hwnd)) //CreateRemoteThread 
093
            { 
094
                if (hwnd != (IntPtr)0) 
095
                    WINAPI.CloseHandle(hwnd); 
096
                return false; 
097
            } 
098
            int wee = Marshal.GetLastWin32Error(); 
099
            return true; 
100
        } 
101
 
102
        private static bool CRT(Process pToBeInjected, string sDllPath, out string sError, out IntPtr hwnd) 
103
        {
104
            sError = String.Empty; //in case we encounter no errors 
105
            IntPtr hndProc = WINAPI.OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), //create thread, query info, operation 
106
                //write, and read 
107
                1, 
108
                (uint)pToBeInjected.Id); 
109
            hwnd = hndProc; 
110
            if (hndProc == (IntPtr)0) 
111
            { 
112
                sError = "Unable to attatch to process.n"; 
113
                sError += "Error code: " + Marshal.GetLastWin32Error(); 
114
                return false; 
115
            } 
116
 
117
            IntPtr lpLLAddress = WINAPI.GetProcAddress( 
118
                WINAPI.GetModuleHandle("kernel32.dll"), 
119
                "LoadLibraryA"); 
120
 
121
            if (lpLLAddress == (IntPtr)0) 
122
            { 
123
                //sError = "Unable to find address of " + LoadLibraryA  + "\n"; 
124
                sError += "Error code: " + Marshal.GetLastWin32Error(); 
125
                return false; 
126
            } 
127
 
128
           IntPtr lpAddress = WINAPI.VirtualAllocEx( 
129
                hndProc, 
130
                (IntPtr)null, 
131
                (IntPtr)sDllPath.Length, //520 bytes should be enough 
132
                (uint)WINAPI.VAE_Enums.AllocationType.MEM_COMMIT | 
133
                (uint)WINAPI.VAE_Enums.AllocationType.MEM_RESERVE, 
134
                (uint)WINAPI.VAE_Enums.ProtectionConstants.PAGE_EXECUTE_READWRITE); 
135
 
136
            if (lpAddress == (IntPtr)0) 
137
            { 
138
                if (lpAddress == (IntPtr)0) 
139
                { 
140
                    sError = "Unable to allocate memory to target process.n"; 
141
                    sError += "Error code: " + Marshal.GetLastWin32Error(); 
142
                    return false; 
143
                } 
144
            } 
145
 
146
            byte[] bytes = CalcBytes(sDllPath); 
147
            IntPtr ipTmp = IntPtr.Zero; 
148
 
149
           WINAPI.WriteProcessMemory( 
150
                hndProc, 
151
               lpAddress, 
152
                bytes, 
153
                (uint)bytes.Length, 
154
                out ipTmp); 
155
 
156
            if (Marshal.GetLastWin32Error() != 0) 
157
            { 
158
                sError = "Unable to write memory to process."; 
159
                sError += "Error code: " + Marshal.GetLastWin32Error(); 
160
                return false; 
161
            } 
162
 
163
            IntPtr ipThread = WINAPI.CreateRemoteThread( 
164
                hndProc, 
165
                (IntPtr)null, 
166
                (IntPtr)0, 
167
                lpLLAddress, 
168
                lpAddress, 
169
                0, 
170
                (IntPtr)null); 
171
 
172
            if (ipThread == (IntPtr)0) 
173
            { 
174
                sError = "Unable to load dll into memory."; 
175
                sError += "Error code: " + Marshal.GetLastWin32Error(); 
176
                return false; 
177
           } 
178
           return true; 
179
        }
180
 
181
        private static byte[] CalcBytes(string sToConvert) 
182
        { 
183
            byte[] bRet = System.Text.Encoding.ASCII.GetBytes(sToConvert); 
184
            return bRet; 
185
        } 
186
 
187
    }
188
}
189

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.

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 by Inyeccion DLL. Mostrando un ejemplo II | Devthisblog — noviembre 15, 2014 @ 7:31 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress