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

 

 


Tema destacado: Trabajando con las ramas de git (tercera parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Llamar a una funcion de una DLL cargada dinamicamente
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Llamar a una funcion de una DLL cargada dinamicamente  (Leído 7,068 veces)
PHREDA

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Llamar a una funcion de una DLL cargada dinamicamente
« en: 12 Julio 2021, 03:08 am »

Hola:

Estoy haciendo un interprete y necesito llamar a una funcion tomada de una dll cargada dinamicamente, esto es asi ya que quiero que el programa interpretado cargue la dll y no el interprete. Ademas necesito que los parametros se encuentren en un pila de enteros.

aqui tengo un fragmento del codigo que estoy probando

Código:
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
HMODULE hLib=LoadLibraryA("KERNEL32.DLL");
if (!hLib) {
     printf("Load Error");
     return 0;
   }else{
     printf("Load OK");
     hFunc=(int64_t)GetProcAddress(hLib,"WriteConsole");
     printf("Address=%x ",hFunc);
 
// WriteConsole(hStdout, "coso", 5, 0, 0);  // Esto funciona correctamente
 
// **** quiero que funcione de esta manera ***
      hFunc=(int64_t)(* (int64_t(*)(int64_t,int64_t,int64_t,int64_t,int64_t))hFunc)((int64_t)hStdout,(int64_t)"coso",5,0,0) ;
 
printf("ok?");
   }

la llamada comentada funciona ok ya que no lo esta haciendo por la direccion de la funcion (hFunc)

pero quiero llamarla por esta direccion y le hago un cast para poder llamarla, aqui quiero aclara que necesito que todos los valores sean pasados int64, me imagina que la funcion a la que llame interpretara el valor segun le corresponda (esto no se como funciona)

Alguien sabe como puedo hacer esto?, desde ya gracias.


En línea

Eternal Idol
Kernel coder
Moderador
***
Desconectado Desconectado

Mensajes: 5.935


Israel nunca torturó niños, ni lo volverá a hacer.


Ver Perfil WWW
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #1 en: 12 Julio 2021, 12:51 pm »

Las funciones que reciben cadenas como parametros en realidad terminan en A si son ANSI o en W si son widechar, asi que hasta ahora tu GetProcAddress devuelve 0 siempre. Con eso te deberia funcionar relativamente bien en x64 aunque no estas especificando la convencion de llamada que en este caso deberia ser stdcall.

No entiendo muy bien la razon de usar un entero de 64 bits con signo en lugar de un void * para hFunc (idem para los parametros, al menos que el entero sea sin signo y que sea de 4 bytes para codigo de 32 bits) y %x deberia ser %p para corresponderse con un puntero al usar printf.

¿hFunc es un puntero a funcion y despues se le asigna el valor de retorno de WriteConsoleA?

En principio yo lo hubiera hecho asi:
Código
  1. BOOL b = ((BOOL (__stdcall *)(HANDLE, const VOID *, DWORD, LPDWORD, LPVOID))hFunc)(hStdout, "coso", 5, 0, 0);

O para generalizarlo y que funcione siempre con el tamaño de un puntero como parametro:
Código
  1. ((BOOL (__stdcall *)(PVOID, PVOID, PVOID, PVOID, PVOID))hFunc)((PVOID)hStdout, (PVOID)"coso", (PVOID)5, 0, 0);

Como la funcion maneja los parametros depende de la convencion de llamada que especificara los registros y/o la pila para acceder a ellos.


« Última modificación: 12 Julio 2021, 13:14 pm por Eternal Idol » En línea

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón
PHREDA

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #2 en: 12 Julio 2021, 15:04 pm »

Ante todo, gracias por la respuesta.

efectivamente me da 0 el getprocaddress, pero parece que no existe la version A, en todo caso mas raro aun es que dentro del interprete parace estar funcionando ya que obtengo valores

el codigo del interprete que ejecuta estas funciones:

Código:

        case LOADLIB: // "" -- hmo
TOS=(int64_t)LoadLibraryA((char*)TOS);goto next;
case GETPROCA: // hmo "" -- ad
TOS=(int64_t)GetProcAddress((HMODULE)*NOS,(char*)TOS);NOS--;goto next;
case SYSCALL0: // adr -- rs
TOS=sys0(TOS);goto next;

y el codigo de sys0 que es la llamada con tus indicaciones

Código:
int64_t sys0(int64_t fn) { return ((int64_t (__stdcall *)())fn)(); }

estoy compilando esto en gcc-4.9.2 64 bits en dev-ccp

el main de prueba es este
Código:
////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{

int64_t hFunc;
HMODULE hLib=LoadLibraryA((LPCSTR)"Kernel32.dll");
if (!hLib) {
     printf("Load Error\n");
     return 0;
}else{
     //printf("Load OK\n");
     hFunc=(int64_t)GetProcAddress((HMODULE)hLib,"WriteConsole");
     printf("Address=%p ",hFunc);
    
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    
// hFunc=(int64_t)(* (int64_t(*)(int64_t,int64_t,int64_t,int64_t,int64_t))hFunc)((int64_t)hStdout,(int64_t)"coso",5,0,0) ;
//sys5((int64_t)hFunc,(int64_t)hStdout,(int64_t)"coso",5,0,0);
WriteConsole(hStdout, "coso", 5, 0, 0);

printf("ok?");
   }      

char filename[1024];
if (argc>1)
strcpy(filename,argv[1]);
else
strcpy(filename,"main.r3");
if (!r3compile(filename)) return -1;
runr3(boot);
return 0;
}

la salida del codigo en
Código:
Address=0000000000000000 coso ok?
r3vm - PHREDA
compile:main.r3... ok.
inc:0 - words:24 - code:0Kb - data:0Kb - free:1023Kb

hola fe400000 fe425290 fe41e0a0 fe41d490 fe424ee0 fe424fd0 fe4252f0 fe4253a0 0 allocfe425290
--------------------------------
Process exited after 2.451 seconds with return value 3221225477
Press any key to continue . . .

efectivamente sigue obteniedo 0 pero los numeros que aparecen despues de hola son los  valores que obtiene dentro del interprete

Seguire intentando alternativas.

La razon por el que los parametros son todos interos es que en forth todos los parametros son pasados por una pila de numeros.




recien me di cuenta, WriteConsole, da 0 el resto no..

seguire probando..
gracias compañero !



Lo encontre!, no estaba guardando los 64bits en la memoria que almacena las direcciones de las funciones...
« Última modificación: 12 Julio 2021, 15:47 pm por Eternal Idol » En línea

Eternal Idol
Kernel coder
Moderador
***
Desconectado Desconectado

Mensajes: 5.935


Israel nunca torturó niños, ni lo volverá a hacer.


Ver Perfil WWW
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #3 en: 12 Julio 2021, 15:52 pm »

Código
  1. hFunc=(int64_t)GetProcAddress((HMODULE)hLib,"WriteConsoleA");

Cita de: msdn
A pointer to a buffer that contains characters to be written to the console screen buffer. This is expected to be an array of either char for WriteConsoleA or wchar_t for WriteConsoleW.

https://docs.microsoft.com/en-us/windows/console/writeconsole

Me alegro si conseguiste hacerlo funcionar :)
En línea

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón
PHREDA

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #4 en: 12 Julio 2021, 15:57 pm »

habia entendido mal !
trataba de llamar a GetProcAddressA !!!!

En línea

Eternal Idol
Kernel coder
Moderador
***
Desconectado Desconectado

Mensajes: 5.935


Israel nunca torturó niños, ni lo volverá a hacer.


Ver Perfil WWW
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #5 en: 12 Julio 2021, 18:35 pm »

Ahh, claro, tiene su logica pero como solo se exportan las funciones en ANSI en un PE no hizo falta la pareja de GetProcAddressA/W  ::)
En línea

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón
RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #6 en: 13 Julio 2021, 04:00 am »

En general, no le deberías pasar a una función argumentos de tipos distintos a los que espera de la manera en que lo estás haciendo (o sea, mediante puntero a función con cast en los parámetros). Independientemente de cómo los interprete, el verdadero problema es que los tamaños podrían ser diferentes. Por ejemplo, el tercer parámetro de WriteConsole es de tipo DWORD, que ocupa 32 bits, pero al hacer el cast a int64_t le estarías pasando 64. En este caso imagino que funciona, pero es casi por casualidad. Estás compilando para 64 bits, por lo que los primeros 4 argumentos se van a pasar en registros. Como son independientes, no tienes problemas, pero si se pasaran en la pila, podría fallar. Esto pasaría si intentaras hacerlo en programas de 32 bits, o llamar funciones que reciban más parámetros. Por darte un ejemplo, no podrías llamar de manera confiable a CreateProcess, ni siquiera en 64 bits.

Imagino que lo estás haciendo para practicar, y está bien, pero obviamente, no sería buena idea hacer algo así en algo más "formal".
« Última modificación: 13 Julio 2021, 04:10 am por RayR » En línea

Eternal Idol
Kernel coder
Moderador
***
Desconectado Desconectado

Mensajes: 5.935


Israel nunca torturó niños, ni lo volverá a hacer.


Ver Perfil WWW
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #7 en: 13 Julio 2021, 11:32 am »

Efectivamente eso es lo que pasa con su ejemplo compilado en 32 bits, los parametros que la funcion necesita son de 4 y no 8 bytes pero asi como en Windows en modo protegido en 32 bits los parametros son todos de 4 bytes en Windows en modo largo en x64 los parametros son todos de 8 bytes. Por eso le dije que en principio usara los tipos de parametros de la funcion y de ultima usara PVOID que al menos es el tamaño de un puntero y este se debe poder pasar en un registro y pila "nativamente".

En realidad si podes llamar a CreateProcessA sin problemas, cada parametro en pila ocupa 64 bits de por si, aunque despues la funcion llamada solo lea los primeros 8, 16 o 32 bits. Si bien hay una sutil diferencia en el codigo generado en ambos casos cada parametro ocupa 8 bytes (notese como el  quinto - 1 - y sexto parametros - 0x1230 - se mueven como DWORD o QWORD pero el siguiente parametro siempre esta a la misma distancia, 8 bytes):

Código
  1. ; 45   : ((BOOL (__stdcall *)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION))CreateProcessA_fn)
  2. ; 46   : (NULL, argv[1], NULL, NULL, TRUE, 0x1230, NULL, NULL, &si, &pi);
  3. mov eax, 8
  4. imul rax, rax, 1
  5. lea rcx, QWORD PTR pi$3[rsp]
  6. mov QWORD PTR [rsp+72], rcx
  7. lea rcx, QWORD PTR si$5[rsp]
  8. mov QWORD PTR [rsp+64], rcx
  9. mov QWORD PTR [rsp+56], 0
  10. mov QWORD PTR [rsp+48], 0
  11. mov DWORD PTR [rsp+40], 4656 ; 00001230H
  12. mov DWORD PTR [rsp+32], 1
  13. xor r9d, r9d
  14. xor r8d, r8d
  15. mov rcx, QWORD PTR argv$[rsp]
  16. mov rdx, QWORD PTR [rcx+rax]
  17. xor ecx, ecx
  18. call QWORD PTR CreateProcessA_fn$2[rsp]

Código
  1. ; 48   : ((BOOL (__stdcall *)(PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID))CreateProcessA_fn)
  2. ; 49   : (NULL, argv[1], NULL, NULL, (PVOID)TRUE, (PVOID)0x1230, NULL, NULL, &si, &pi);
  3. mov eax, 8
  4. imul rax, rax, 1
  5. lea rcx, QWORD PTR pi$3[rsp]
  6. mov QWORD PTR [rsp+72], rcx
  7. lea rcx, QWORD PTR si$5[rsp]
  8. mov QWORD PTR [rsp+64], rcx
  9. mov QWORD PTR [rsp+56], 0
  10. mov QWORD PTR [rsp+48], 0
  11. mov QWORD PTR [rsp+40], 4656 ; 00001230H
  12. mov QWORD PTR [rsp+32], 1
  13. xor r9d, r9d
  14. xor r8d, r8d
  15. mov rcx, QWORD PTR argv$[rsp]
  16. mov rdx, QWORD PTR [rcx+rax]
  17. xor ecx, ecx
  18. call QWORD PTR CreateProcessA_fn$2[rsp]

Si podria tener problemas con tipos de coma flotante que se pasan en otros registros pero no recuerdo ninguna API de Windows que los use.



Y de cualquier manera si coincido en que es algo a evitar de ser posible.
« Última modificación: 13 Julio 2021, 11:39 am por Eternal Idol » En línea

La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón
PHREDA

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #8 en: 13 Julio 2021, 13:11 pm »

Gracias RayR por tus comentarios.
Se trata de un interprete, o sea, en tiempo de ejecucion va a cargar un dll y llamar a funciones, no es ningun ejemplo para practicar.
Es cierto que no se que pasara cuando el parametro en punto flotante, veremos cuando use una dll para graficos 3d y como podria solucionar lo
aca subi el proyecto porque ya funciona !
https://github.com/phreda4/r3evm

Bien por el codigo generadp por Eternal Idol, cuando construya el compilador voy a necesitar realizar esto automaticamente, aunque quizas tome el mismo camino que el interprete al inicio, una funcion por cada cantidad de parametros.
El compilador de las versiones anteriores no usaba este mecanismo.

En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: Llamar a una funcion de una DLL cargada dinamicamente
« Respuesta #9 en: 13 Julio 2021, 16:16 pm »

Cierto, me olvidaba de que para x86-64 los parámetros en la pila se alinean a 64 bits.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines