Red de conocimiento informático - Computadora portátil - Cómo lidiar con el secuestro de archivos DLL

Cómo lidiar con el secuestro de archivos DLL

Cuando una DLL ejecuta un archivo ejecutable, el cargador de Windows asigna el módulo ejecutable al espacio de direcciones del proceso.

Debido a que la tabla de entrada contiene solo el nombre de la DLL y no su ruta, el cargador debe buscar el archivo DLL en el disco. Primero intentará cargar la DLL desde el directorio donde se encuentra el programa actual y, si no puede encontrarla, buscará en el directorio del sistema de Windows y, finalmente, en cada directorio enumerado en las variables de entorno. Cuando el programa llama a la DLL del sistema, primero llamará a la DLL falsa en el directorio actual. Después de completar las funciones relevantes, saltará a la función de la DLL del sistema con el mismo nombre para su ejecución, como se muestra en la Figura 18.4.

18

18

18

Esta es la primera vez que una DLL del sistema ha sido secuestrada.

184.gif

Después de utilizar este método para obtener el control, puede parchear el programa principal. Este método solo funciona para archivos DLL fuera de las bibliotecas principales del sistema (como kernel32.dll, ntdll.dll, etc.). Estas DLL pueden ser secuestradas, como ws2_32.dll para aplicaciones web, d3d8.dll para programas de juegos y lpk.dll, al que llaman la mayoría de las aplicaciones.

Utilizando CrackMeNet.exe proporcionado en el Capítulo 5.6.2 para demostrar cómo crear un parche usando técnicas de secuestro, el archivo de destino está protegido por un shell Themida v1.9.2.0.

1. Dirección del parche

Para eliminar este método de verificación de red CrackMe, consulte el Capítulo 5. El código de parche relevante se almacena en la función PatchProcess (). Por ejemplo, cambie 401496h a:

Código: 00401496 EB 29 jmp short 004014C1

La programación del parche se implementa como:

Código:

unsigned char p401496[2] = {0xEB, 0x29};

WriteProcessMemory(hProcess, (LPVOID)0x401496, p401496, 2, NULL);

El formato de datos de este La matriz p401496 se puede obtener a través del complemento OllyDBG o convertirla mediante la herramienta hexadecimal. Por ejemplo, abra el archivo con Hex Workshop y ejecute el menú Editar/Copiar como/Fuente para obtener el formato de código correspondiente.

2. Construya la función de salida

Al observar la tabla de entrada del ejemplo CrackMeNet.exe, encontrará el nombre de la DLL ws2_32.dll, por lo que necesita construir una DLL. con el mismo nombre para completar la tarea de parcheo. El ws2_32.dll falso tiene las mismas funciones de salida que el ws2_32.dll real y el código fuente completo se puede encontrar en el CD. Esto se puede lograr mediante el uso de un reenviador de funciones en un módulo DLL, que redirige una llamada a una función a otra función en otra DLL. Puede utilizar una directiva pragma como esta:

Código: #pragma comment(linker, "/EXPORT: SomeFunc=DllWork.someOtherFunc")

Esta pragma le dice al vinculador que la DLL se está compilando Se debe generar una función llamada SomeFunc. Sin embargo, la implementación de la función SomeFunc en realidad existe en otra función llamada SomeOtherFunc, que está contenida en un módulo llamado DllWork.dll.

Para secuestrar una DLL, la función de salida de la DLL generada debe tener el mismo nombre que la función de salida de la DLL de destino, en cuyo caso la directiva pragma se puede construir así:

Código: # pragma comment(linker, "/EXPORT: WSAStartup=_MemCode_ WSAStartup, @115")

Después de compilar la DLL, habrá una función de salida WSAStartup con el mismo nombre que ws2_32.DLL. En la práctica, debe crear una línea separada de código pragma para cada función que se reenviará. Los lectores pueden escribir herramientas o utilizar otros métodos para convertir las funciones de salida de ws2_32.dll en las instrucciones pragma correspondientes.

Cuando una aplicación llama a una función de salida disfrazada de ws2_32.dll, debe transferirse al sistema ws2_32.dl, que implementa esta parte del código.

Por ejemplo, la función de salida WSAStartup se construye de la siguiente manera:

Código:

ALCDECL MemCode_WSAStartup(void)

{

GetAddress( "WSAStartup" );

__asm ​​​​JMP EAX; // Vaya a la función de salida WSAStartup del sistema ws2_32.dll

}

El código de la función GetAddress() es la siguiente:

Código:

//MemCode namespace

namespace MemCode

{

HMODULE m_hModule = NULL; //Identificador del módulo original

DWORD m_dwReturn[500] = {0}; //Dirección de retorno de la función original

//Cargar módulo original

p>

carga BOOL WINAPI en línea()

{

TCHAR tzPath[MAX_PATH]={0}

TCHAR tzTemp[MAX_PATH]={ 0};

GetSystemDirectory(tzPath, sizeof(tzPath));

strcat( tzPath, "\\ws2_32.dll"); (tzPath); //cargar el directorio del sistema ws2_32.dll

if (m_hModule == NULL)

{

wsprintf (tzTemp, TEXT("Podría no carga s, el programa no se ejecuta correctamente."), tzPath);

MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP);

}

return (m_hModule! = NULL);

}

// Liberar el módulo original

inline VOID WINAPI Free()

{

si (m_hModule)

FreeLibrary(m_hModule);

}

FreeLibrary();

}

// Obtener la dirección de la función original

FARPROC WINAPI GetAddress(PCSTR pszProcName)

{

FARPROC fpAddress;

TCHAR szProcName[16]={ 0};

TCHAR tzTemp[MAX_PATH]={0};

if (m_hModule == NULL)

{

if (Load() == FALSE)

ExitProcess(-1);

}

fpAddress = GetProcAddress( m_hModule, pszProcName);

if (fpAddr

ess == NULL)

{

if (HIWORD(pszProcName) == 0)

{

wsprintf(szProcName, " d", pszProcName);

pszProcName = szProcName;

}

wsprintf(tzTemp, TEXT("No se puede encontrar la función hs y el programa no se puede ejecutar normalmente . "), pszProcName);

MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP);

ExitProcess(-2);

}

return fpAddress;

}

}

Usar espacio de nombres MemCode

Después de la compilación, falso ws2_32; Función de salida .dll, que es exactamente la misma que la ws2_32.dll real, como se muestra en la Figura 18.5.

185.gif

Compruebe si hay funciones de salida en el ws2_32.dll falso, como WSACleanup:

Código:

. texto: 10001CC0; int __stdcall WSACleanup()

.text.

.text: 10001CC0 WSACleanup proc cerca

.text: 10001CC0 push offset aWsacleanup; "

.text: 10001CC5 call sub_10001000; GetAddress(WSACleanup)

.text: 10001CCA jmp eax

.text: 10001CCA WSACleanup endp

Observe que la función de salida WSACleanup() primero llama a GetAddress(WSACleanup) para obtener la dirección real de WSACleanup en ws2_32.dll y luego salta a la ejecución. En otras palabras, cada función de salida de ws2_32.dll está enganchada.

3. Funciones de salida de secuestro

ws2_32.dll tiene muchas funciones de salida. Después del análisis, cuando el programa envía o recibe paquetes de datos, se llamará a la función de salida WSAStartup por adelantado. el código del parche se colocará en esta función de salida. El código es el siguiente:

Código:

ALCDECL MemCode_WSAStartup(void)

{

hijack();

GetAddress("WSAStartup");

__asm ​​​​JMP EAX;

}

La función hijack() determina principalmente si es el objetivo programa, y ​​si es así, llama a PatchProcess() para parchearlo.

void hijack()

{

if (isTarget(GetCurrentProcess()))// Determine si el programa principal es el programa de destino, si es así, open Patch

{

PatchProcess() es el programa de destino.

GetCurrentProcess());

}

}

Después de crear el ws2_32.dll falso, colóquelo en el directorio actual del programa, para que usarse como el original Cuando el programa llama a la función WSAStartup, llama a la función WSAStartup falsa de ws2_32.dll. La función hijack () es responsable de verificar la suma de verificación del programa de destino y parchear los datos relacionados. Después del procesamiento, ingresa ws2_32.dll en el directorio del sistema para su ejecución.

Esta técnica de parcheo es muy eficaz para el software protegido por shell. Es mejor elegir una función de enlace de shell que no haya sido llamada. Cuando se ejecuta la función de enlace, el código relevante se ha descomprimido y se puede parchear directamente. En algunos casos, se debe utilizar un contador para contar el número de veces que se llama a la función de enlace para aproximar el OEP. Este método evita claramente la complejidad de la detección de carcasas y es ideal para parchear empacadores.

Algunos troyanos o virus también utilizan técnicas de secuestro de DLL para causar daños, por lo que cuando encuentre algunos archivos DLL del sistema en el directorio de la aplicación, debe prestar atención a su presencia.