elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Introducción a Git (Primera Parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  DLL wrapper 1: Creando nuestra psapi.dll sin .DEF
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: DLL wrapper 1: Creando nuestra psapi.dll sin .DEF  (Leído 1,880 veces)
85

Desconectado Desconectado

Mensajes: 206



Ver Perfil WWW
DLL wrapper 1: Creando nuestra psapi.dll sin .DEF
« en: 2 Abril 2013, 17:24 pm »

NIVEL: Beginner
Test: WinXP SP3 32BITS

Tomando en cuenta el tutorial anterior acerca del creamiento de una versión propia de una DLL conocida,
http://foro.elhacker.net/programacion_cc/dll_wrapper_1_creando_nuestra_psapidll_con_def-t386996.0.html

Algo que se denominaba ‘wrapper’, en este caso vamos a hacer lo mismo pero sin la necesidad de usar un archivo .DEF para los símbolos exportados.
El tema es que para hacer la exportación de símbolos en este caso sin usar .DEF tenemos que utilizar en nuestras funciones de reemplazo, el nombre completo y correcto de las funciones originales.
 
Primero vayamos a las opciones del proyecto, y veamos que la opción de la convención de llamada  esté en __cdecl, porque si bien sabíamos que PSAPI usaba __stdcall, pero lo que vamos a hacer en esta ocasión es especificarlo explícitamente en el código, para cada función.
Por defecto siempre esta opción se encuentra en __cdecl, en otras palabras lo que quiero decir es que lo dejen así..



Empecemos diciendo en lo que es similar al anterior método, por ejemplo los prototipos de las funciones. Veamos una definición de tipo para la función EnumProcesses en main.cpp
 
Código
  1. typedef BOOL (WINAPI* EnumProcesses_t)(DWORD*,DWORD,DWORD*);

Una declaración de puntero a función
Código
  1. BOOL (WINAPI* pEnumProcesses)(DWORD*,DWORD,DWORD*);

Veamos como se expecifica explícitamente la convención de llamada __stdcall (WINAPI).
La definición de nuestra función de reemplazo, que como habíamos visto antes, retorna el puntero a función original. En este caso a la EnumProcesses original en la DLL original que renombramos PSAPI2.DLL
Código
  1. BOOL WINAPI newEnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned)
  2. {
  3.      return pEnumProcesses(pProcessIds, cb, pBytesReturned);
  4. }

El tema es que como no estamos usando un .DEF tenemos que especificar en el código, qué funciones son las que van a ser exportadas. Esto se hace con __declspec (dllexport)
 
Veamos una macro que al mismo tiempo también especifica que se trata de un estilo de función de C con lo cual evitamos el planchado de nombres en los símbolos exportados.
Código
  1. #define DLLEXPORTING extern "C" __declspec (dllexport)

 Más información acerca de esto:
 http://msdn.microsoft.com/es-es/library/a90k134d(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx
http://msdn.microsoft.com/es-AR/library/0603949d(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/aa278942(v=vs.60).aspx

En el compilador vamos a dejar que la convención de llamada por defecto sea __cdecl, y vamos a valernos de especificar __stdcall en los prototipos o definiciones de tipos y en los punteros a función, como ya vimos.
En el anterior tutorial, teníamos 2 instancias de funciones de reemplazo para cada función que íbamos a exportar. Y vimos que la segunda instancia no era necesaria antes, pero ahora si lo va a ser.
 
Veamos exports.cpp
Esta es la segunda instancia, debe ser del tipo __cdecl para ser compatible con la directiva extern “C”, y al mismo tiempo debe ser el símbolo marcado para ser exportado, eso se hace con __declspec (dllexport) como dijimos antes. Y por último, el nombre de esta función debe ser exactamente igual al de la original.

Código
  1. DLLEXPORTING BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned)
  2. {
  3.       //return newEnumProcesses(pProcessIds, cb, pBytesReturned);
  4. }

Por eso si la convención de llamada por defecto es __cdecl entonces esta función tendría esa convención.
Por eso dije antes que la dejen como estaba a la opción esa. De otra forma debería especificar __cdecl
explícitamente en la definición de la función.
 
En teoría debería deberíamos usar el puntero a la función original a modo de una llamada a función por puntero (ya sea como return+puntero o sólo el puntero si se trata de una función de tipo void).
 
Es en este punto donde necesitamos ver este tutorial anterior en el cual se comentaba un caso en el cual el compilador genera código de stack frame dentro de la función lo cual altera la pila y el registro EBP.
Link:
http://foro.elhacker.net/programacion_cc/gltest1_problema_con_la_convencion_de_llamada-t384879.0.html
 
Esta situación no es diferente a la del enlace anterior, por lo que la solución es la misma; nuestra función de reemplazo de tipo __cdecl va a tener que restaurar el registro EBP antes de saltar a la función original.
Vamos a utilizar la instrucción JMP para ir a la original y no la instrucción CALL (aunque vimos que se puede).
 
Código
  1. DLLEXPORTING BOOL EnumProcesses(DWORD* pProcessIds, DWORD cb, DWORD* pBytesReturned)
  2. {
  3.             int a = 85;
  4.             a = 85 - 85 + 85;
  5.             // usa ebp
  6.             // agrega edi al stack
  7.             // add esp, 0x14
  8.  
  9.             __asm mov eax,[esp+0x10]
  10.             __asm mov EnumProcesses_ebp_save,eax
  11.             __asm mov ebp,EnumProcesses_ebp_save
  12.             __asm add esp,0x14//debe borrar hasta ebp, no más que eso (no el retaddress ni los argumentos)
  13.             __asm jmp newEnumProcesses
  14.             //return newEnumProcesses(pProcessIds, cb, pBytesReturned);
  15. }

El fix con ensamblador en línea (inline ASM), guarda el registro EBP y lo restaura antes de saltar a la función original, también se deja la pila equilibrada con ADD ESP, X
Tanto la ubicación del EBP original en la pila como la cantidad de espacios que se deben reducir para equilibrar la misma, se deben obtener de un desensamblador por ejemplo. Sino, pueden utilizar un depurador como el OllyDBG.
 
Veamos igualmente una imagen de como resulta el código de ensamblador:



Citar
10001000 >  55                           PUSH EBP
10001001    8BEC                        MOV EBP,ESP
10001003    51                            PUSH ECX
10001004    53                            PUSH EBX
10001005    56                            PUSH ESI
10001006    57                            PUSH EDI
10001007    C745 FC 5500000>      MOV DWORD PTR SS:[EBP-4],55
1000100E    C745 FC 5500000>      MOV DWORD PTR SS:[EBP-4],55
10001015    8B4424 10                 MOV EAX,DWORD PTR SS:[ESP+10]
10001019    A3 D0320010             MOV DWORD PTR DS:[100032D0],EAX
1000101E    8B2D D0320010          MOV EBP,DWORD PTR DS:[100032D0]
10001024    83C4 14                    ADD ESP,14
10001027    E9 64040000             JMP psapi.10001490
1000102C    5F                           POP EDI
1000102D    5E                           POP ESI
1000102E    5B                           POP EBX
1000102F    8BE5                        MOV ESP,EBP
10001031    5D                           POP EBP
10001032    C3                           RETN

Como ustedes pueden ver se genera al final este código:
Citar
1000102C 5F POP EDI
1000102D 5E POP ESI
1000102E 5B POP EBX
1000102F 8BE5 MOV ESP,EBP
10001031 5D POP EBP
Lo cual es una correcta liberación de pila, pero el problema es que este código no se genera sino usamos el fix.

Como ya dije, es la misma situación que la del tutorial de convención de llamada para un caso con Opengl32.
 
El resultado es una DLL wrapper de PSAPI.DLL que no requiere .DEF para realizar las exportaciones.
Psapi.lib tampoco es requerida, recordemos que hacemos un enlazamiento dinámico con la DLL PSAPI.DLL original (que renombramos a PSAPI2.DLL).

Y los nombres de los EXPORTS no resultan cambiados.



Funciona.



Proyecto VC++6:
http://www.mediafire.com/?8su3luoh0r72ypf

Saludos


« Última modificación: 2 Abril 2013, 17:47 pm por 85 » En línea

Me cerraron el Windows Live Spaces, entonces me creé un WordPress XD
http://etkboyscout.wordpress.com/
Puntoinfinito


Desconectado Desconectado

Mensajes: 919


#! /win/archlinux


Ver Perfil WWW
Re: DLL wrapper 1: Creando nuestra psapi.dll sin .DEF
« Respuesta #1 en: 2 Abril 2013, 18:07 pm »

Gracias!! Parece que esto promete bastante!! Muy útil!


En línea

AHORA EN SOFTONIC || CLICK HERE!!
Base64: QWNhYmFzIGRlIHBlcmRlciAxIG1pbnV0byBkZSB0dSB2aWRhLiBPbOkh



HACK AND 1337 : http://hackandleet.blogspot.com
WEBSITE: http://www.infiniterware.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
[Nuestra Camara] - « 1 2 »
Diseño Gráfico
+ enrique ZP 18 14,638 Último mensaje 10 Julio 2006, 21:54 pm
por Jacker x2
¿Que es y como usar un Wrapper en JAVA?
Java
cyberserver 6 13,321 Último mensaje 7 Diciembre 2009, 16:28 pm
por Leyer
DLL wrapper 1: Creando nuestra psapi.dll con .DEF
Programación C/C++
85 0 1,724 Último mensaje 2 Abril 2013, 17:11 pm
por 85
Wrapper de Opengl32.dll de Crusader (2002)
Programación C/C++
85 2 2,025 Último mensaje 5 Abril 2013, 21:00 pm
por 85
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines