Autor
|
Tema: Llamar a una funcion de una DLL cargada dinamicamente (Leído 7,582 veces)
|
PHREDA
Desconectado
Mensajes: 4
|
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 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
Mensajes: 5.966
Israel nunca torturó niños, ni lo volverá a hacer.
|
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: 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: ((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
Mensajes: 4
|
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: 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 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 //////////////////////////////////////////////////////////////////////////// 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 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
Mensajes: 5.966
Israel nunca torturó niños, ni lo volverá a hacer.
|
hFunc=(int64_t)GetProcAddress((HMODULE)hLib,"WriteConsoleA");
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/writeconsoleMe 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
Mensajes: 4
|
habia entendido mal ! trataba de llamar a GetProcAddressA !!!!
|
|
|
En línea
|
|
|
|
Eternal Idol
Kernel coder
Moderador
Desconectado
Mensajes: 5.966
Israel nunca torturó niños, ni lo volverá a hacer.
|
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
Mensajes: 243
|
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
Mensajes: 5.966
Israel nunca torturó niños, ni lo volverá a hacer.
|
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): ; 45 : ((BOOL (__stdcall *)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION))CreateProcessA_fn) ; 46 : (NULL, argv[1], NULL, NULL, TRUE, 0x1230, NULL, NULL, &si, &pi); mov eax, 8 imul rax, rax, 1 lea rcx, QWORD PTR pi$3[rsp] mov QWORD PTR [rsp+72], rcx lea rcx, QWORD PTR si$5[rsp] mov QWORD PTR [rsp+64], rcx mov QWORD PTR [rsp+56], 0 mov QWORD PTR [rsp+48], 0 mov DWORD PTR [rsp+40], 4656 ; 00001230H mov DWORD PTR [rsp+32], 1 xor r9d, r9d xor r8d, r8d mov rcx, QWORD PTR argv$[rsp] mov rdx, QWORD PTR [rcx+rax] xor ecx, ecx call QWORD PTR CreateProcessA_fn$2[rsp]
; 48 : ((BOOL (__stdcall *)(PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID))CreateProcessA_fn) ; 49 : (NULL, argv[1], NULL, NULL, (PVOID)TRUE, (PVOID)0x1230, NULL, NULL, &si, &pi); mov eax, 8 imul rax, rax, 1 lea rcx, QWORD PTR pi$3[rsp] mov QWORD PTR [rsp+72], rcx lea rcx, QWORD PTR si$5[rsp] mov QWORD PTR [rsp+64], rcx mov QWORD PTR [rsp+56], 0 mov QWORD PTR [rsp+48], 0 mov QWORD PTR [rsp+40], 4656 ; 00001230H mov QWORD PTR [rsp+32], 1 xor r9d, r9d xor r8d, r8d mov rcx, QWORD PTR argv$[rsp] mov rdx, QWORD PTR [rcx+rax] xor ecx, ecx 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
Mensajes: 4
|
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/r3evmBien 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
Mensajes: 243
|
Cierto, me olvidaba de que para x86-64 los parámetros en la pila se alinean a 64 bits.
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
[javascript] llamar a funcion que se recibe por parametro de la funcion
Desarrollo Web
|
Graphixx
|
0
|
6,014
|
24 Abril 2012, 19:36 pm
por Graphixx
|
|
|
Como llamar a una funcion dentro de otra funcion. Una ayuda urgentemente porfavo
Programación C/C++
|
LobateZZZ
|
1
|
10,844
|
14 Abril 2013, 03:07 am
por rir3760
|
|
|
Depurar DLL cargada dinámicamente
Programación C/C++
|
javiherro
|
7
|
3,183
|
11 Diciembre 2013, 11:14 am
por javiherro
|
|
|
[Resuelto] no funciona funcion jquery en nueva fila insertada dinamicamente
Desarrollo Web
|
cv_olehc
|
0
|
1,935
|
25 Julio 2014, 13:42 pm
por cv_olehc
|
|
|
Consulta - Llamar función dentro de su misma función
Programación C/C++
|
DeMoNcRaZy
|
4
|
5,801
|
8 Marzo 2015, 17:29 pm
por DeMoNcRaZy
|
|