Red de conocimiento informático - Material del sitio web - Cómo implementar la inyección de procesos en .net

Cómo implementar la inyección de procesos en .net

La inyección de procesos es relativamente común, como el uso de depuradores IDE y algunos programas espía. Si solo desea comunicarse con el depurador, puede usar la interfaz del depurador .net (en el espacio de nombres EnvDTE de EnvDTE.dll). Pero independientemente del propósito, la inyección de procesos es algo interesante, así que pruébalo. Parece haber muchos métodos de inyección de procesos (como el método de recopilación que se disfraza de caballo de Troya y hace que el proceso de destino cargue por error su programa en el proceso de destino. Los que se mencionan aquí son solo uno o una combinación de algunos). de ellos.

Así es como funciona:

El proceso fuente (es decir, el proceso donde se encuentra su código) obtiene el ID o el objeto de proceso del proceso objetivo (es decir, el proceso en el que desea inyectar el código)

p>

El proceso fuente proporciona una función de devolución de llamada llamada métodoA (es decir, el código que desea inyectar en el proceso de destino)

Luego cargue el proceso fuente y el método Una función de devolución de llamada en el proceso de destino, que es el código que desea inyectar en el proceso de destino. Código inyectado en el proceso de destino.

Luego cargue el proceso de origen en el proceso de destino.

Envíe la ruta completa del proceso de destino y la función de devolución de llamada métodoA (su ensamblaje, clásico y nombre del método) al inyector (es decir, la clase que escribimos responsable de la inyección) y luego deje que el inyector se complete. la inyección y dejar que el proceso objetivo ejecute la función de devolución de llamada

El inyector obtiene el objeto del proceso objetivo en función del ID del proceso objetivo proporcionado, y luego el inyector obtiene el objeto del proceso objetivo en función del proceso objetivo proporcionado ID y obtiene un hilo del proceso de destino (lo llamamos hilo de destino)

Asigna un bloque de memoria en el hilo de destino y almacena la ruta completa de la función de devolución de llamada métodoA como una cadena en esa memoria

El inyector está instalado en el proceso de destino. Un enlace para monitorear los mensajes de Windows (mensajeA) en el proceso de destino. Escriba la función de devolución de llamada del enlace métodoB (el contenido de este método se explicará más adelante)

Envíe el mensaje A al proceso de destino y simplemente asignará. La dirección base de la memoria se pasa como parámetro del mensaje.

Desde que instalamos el enlace para el mensajeA, el proceso de destino llamará a nuestra función de enlace métodoB e incluirá la dirección base de la memoria asignada en el parámetro de función

métodoB, de acuerdo con la función parámetro La dirección base de la memoria, analizará la memoria para encontrar su objeto real, que es una cadena que representa la ruta completa de nuestro método A. De acuerdo con la cadena representada por Ensamblaje, nombre de clase, nombre de método, use la reflexión .net para reflejar su objeto MethodInfo (tenga en cuenta el punto clave, el método B ya está en el hilo del proceso de destino cuando se vuelve a llamar)

Llame al objeto MethodInfo reflejado, nuestro método A obtendrá la dirección base del parámetro de función en la memoria, el objeto real, es decir, la cadena que representa la ruta completa de nuestro método A. Nuestro método A será ejecutado.

Si aún no lo entiendes, echa un vistazo al código (esto requiere un poco de conocimiento de C++/CLI, pero agregué comentarios en cada oración para que sea fácil de entender, puedes léelo aquí Más información sobre C++/CLI).

#include "stdafx.h"

#include "Injector.h"

#include

Usar Namespace ManagedInjector;

// define un nuevo mensaje de ventana, que se garantiza que será único en todo el sistema.

// El valor del mensaje se puede utilizar al enviar o publicar

static unsigned int WM_GOBABYGO = ::RegisterWindowMessage(L "Injector_GOBABYGO!");

static HHOOK _messageHookHandle;

//---------------------------------- ------------------------------------------------

/ / La función del proceso de monitoreo es la siguiente

//

//------------------ -------- ------------------------------------------ --------

void Injector::Launch(System::IntPtr windowHandle, System::Reflection::Assembly^ ensamblador, System::String^ className, System::String^ MethodName ) {

Sistema::String^ ensamblajeClassAndMethod = ensamblaje->Ubicación + "$" + nombre de clase + "$" + nombre de método;

//convierte cadena a wchar_t* o char local *

pin_ ptr acmLocal = PtrToStringChars(assemblyClassAndMethod);

/Asigna el módulo ejecutable especificado al espacio de direcciones del proceso de llamada.

HINSTANCE hinstDLL = ::LoadLibrary((LPCTSTR) _T("ManagedInjector.dll"));

if (hinstDLL)

{

DWORD ProcessID = 0;

//Obtener ID de proceso e ID de subproceso

DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);

if (ID de proceso)

{

//obtener objeto de proceso de destino (identificador)

HANDLE hProcess = ::.OpenProcess(PROCESS_ALL_ACCESS , FALSO, ID de proceso);

if (hProcess)

{

int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);

//Asigna almacenamiento físico en la memoria o en el archivo de paginación en el disco para las páginas de memoria reservadas especificadas.

//La función inicializa la memoria a cero.

/El valor de retorno es la dirección base del área de página asignada.

void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);

if (acmRemote)

{

//Copiar datos (cadena ensambladoraClassAndMethod) del búfer especificado del proceso actual

//Al rango de direcciones del proceso de destino

::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);

/Recupera la dirección del método MessageHookProc de hindsDLL<

HOOKPROC procAddress = (HOOKPROC)GetProcAddress(hinstDLL, "MessageHookProc");

// Instale el proceso de enlace en el hilo de destino (antes de que el sistema envíe el mensaje al proceso de ventana de destino)

_messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, procAddress, hinstDLL, threadID);

if (_messageHookHandle)

{

/enviar nuestro mensaje personalizado a la ventana de destino del proceso de destino

::SendMessage(( HWND)windowHandle

::SendMessage((HWND)windowHandle.ToPointer(),WM_GOBABYGO,(WPARAM)acmRemote,0);

//Eliminar ganchos instalados en la cadena de ganchos. a través de la función SetWindowsHookEx Proceso

::UnhookWindowsHookEx(_messageHookHandle);

}

// Elimina el proceso de enlace instalado en la cadena de enlaces a través de la función SetWindowsHookEx. .

::VirtualFreeEx(hProcess, acmRemote, buffLen, MEM_RELEASE);

}

::CloseHandle(hProcess);

}

}

}

/Decreducción del recuento de referencias de la DLL cargada

::FreeLibrary(hinstDLL);

.

}

}

__declspec( dllexport )

// Proceso de enlace, este proceso se volverá a llamar después gancho

int __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam) {

// HC_ACTION: Indica que hay parámetros en wparam y lparam

if ( nCode == HC_ACTION)

{

CWPSTRUCT* msg = (CWPSTRUCT*)lparam;

// Cuando la ventana de destino recibe nuestro mensaje personalizado

if (msg msg = NULL && msg-> message == WM_GOBABYGO)

{

//Obtener los parámetros de paso de mensajes

/ De hecho, el parámetro es la dirección base (puntero) de la cadena ensambladorClassAndMethod en la memoria del proceso de destino

/La dirección base de la cadena ensambladorClassAndMethod en la memoria del proceso de destino

wchar_t* acmRemote = (wchar_t* )msg->wParam;

Wchar_t* acmRemote = (wchar_t*)msg->.wParam;

//gcnew: crear un tipo administrado (referencia) en el montón de recolección de basura o tipo de valor)

System::String^ acmLocal = gcnew System::String(acmRemote);

/Use $ para dividir una cadena en una serie de subcadenas. En este contexto:

//acmSplit[0]:La ubicación del ensamblaje

//acmSplit[1]:className;

//acmSplit[ 2]: nombre del método

// Usamos esta información para reflejar el hecho de que la ubicación del ensamblaje es la ubicación del ensamblaje.

Usamos esta información para reflejar el método en el ensamblado de origen y llamarlo en el proceso de destino

cli::array^ acmSplit = acmLocal->Split('$');

//Método Reflection y llámalo

System::Reflection::Assembly^ ensamblador = System:.Reflection::Assembly::LoadFile(acmSplit[0]);< / p>

if (ensamblado! = nullptr)

{

System::Type^ tipo = ensamblaje->GetType(acmSplit[1]);

if (tipo != nullptr)

{

Sistema::Reflexión::MethodInfo^ métodoInfo =

tipo->GetMethod(acmSplit[2 ] , System::Reflection:.BindingFlags::Static | System::Reflection::BindingFlags::Public);

if (methodInfo != nullptr)

{

methodInfo->Invoke(nullptr, nullptr);

}

}

}

}

}

devuelve CallNextHookEx (_messageHookHandle, nCode, wparam, lparam);

}