ERROR_INVALID_ADDRESS al usar VirtualAllocEx con una dirección fija

Iniciado por [Zero], 31 Agosto 2010, 17:37 PM

0 Miembros y 1 Visitante están viendo este tema.

[Zero]

Bueno, pues la duda es lo que dice el título, estoy intentando usar VirtualAlloc o VirtualAllocEx, me da igual, para reservar memoria en una dirección de memoria fija, en concreto en 0x0040000 (teniendo el base address de mi ejecutable en 00300000). Levo días buscando la razón del error pero no encuentro nada que me sirva, ejecutando lo siguiente:


#pragma comment(linker,"/NODEFAULTLIB")
#pragma comment(linker,"/ENTRY:main")

#include <Windows.h>

int main()
{
//CHAR MSG[1024];
//SYSTEM_INFO SystemInfo;
//GetSystemInfo(&SystemInfo);

//wsprintfA(MSG,"%s%X%s%X","MinimumApplicationAddress: ",SystemInfo.lpMinimumApplicationAddress,"\nMaximumApplicationAddress: ",SystemInfo.lpMaximumApplicationAddress);
//MessageBoxA(0,MSG,"Info",MB_ICONINFORMATION);

if(!VirtualAllocEx(GetCurrentProcess(),(LPVOID)0x00400000,0x1000,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE))
{
MessageBoxA(0,"Error al reservar memoria en 0x00400000",0,MB_ICONERROR);
return 0;
}

MessageBoxA(0,"Memoria Reservada correctamente en 0x00400000","Éxito",MB_ICONINFORMATION);

return 0;
}


Ojo, linkear el ejecutable con una dirección base diferente de 0x00400000 o en su defecto cambiar la dirección fija a reservar.

Éste código, en mi PC Win7 32bits reserva memoria bien sólo a veces, otras veces falla devolviendo last_error ERROR_INVALID_ADDRESS. Viendo con olly me dice que la dirección no está en uso incluso cuando falla, pero el error es como sí la dirección estuviera ya reservada  :-\.

Gracias por adelandato  :P

"El Hombre, en su orgullo, creó a Dios a su imagen y semejanza.”
Nietzsche

>FedeX<

Con cheat engenie se ve como a veces en 0x00400000 hay memoria en uso...

Littlehorse

Es necesario utilizar una dirección fija que posiblemente pueda no estar libre, o solo es por probar?

Utiliza VirtualQuery para chequear el estado de la región, o en su defecto VADUMP.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

[Zero]

Necesito usarlo con una dirección fija, me da igual cual pero es necesario que sea fija. En la documentación de la MSDN dice que es perfectamente posible, y ese parámetro no tendría sentido si no fuera así, pero buscando no encuentro más que gente con el mismo problema e hilos a los que no se llega a una solución. Si esa memoria está reservada, el proceso no la está utilizando aparentemente para nada, intente hacer VirtualFree pero sigue sin funcionar  :-\.

Al ejecutar VirtualQuery VirtualAlloc falla siempre, incluso cuando ésta me devuelve MEM_FREE  :-\.

Saludos




Edito:

Hice ésto para ver si me quedaba algo más claro que pasaba, pero sólo logró confundirme más  :xD:

#pragma comment(linker,"/NODEFAULTLIB")
#pragma comment(linker,"/ENTRY:main")

#include <Windows.h>

int main()
{
MEMORY_BASIC_INFORMATION Buffer;
VirtualQuery((LPVOID)0x00400000,&Buffer,sizeof(MEMORY_BASIC_INFORMATION));

switch(Buffer.State)
{
case MEM_COMMIT:

MessageBoxA(0,"MEM_COMMIT","Info",MB_ICONINFORMATION);

if(!VirtualFree((LPVOID)0x00400000,0x1000,MEM_DECOMMIT))
{
MessageBoxA(0,"Error al desencomendar memoria",0,MB_ICONERROR);
}
else
{
MessageBoxA(0,"Memoria Desencomendada","Info",MB_ICONINFORMATION);

if(!VirtualFree((LPVOID)0x00400000,0,MEM_RELEASE))
{
MessageBoxA(0,"Error liberar memoria",0,MB_ICONERROR);
}
else
{
MessageBoxA(0,"Memoria Reservada Liberada","Info",MB_ICONINFORMATION);
}
}
break;

case MEM_RESERVE:

MessageBoxA(0,"MEM_RESERVE","Info",MB_ICONINFORMATION);

if(!VirtualFree((LPVOID)0x00400000,0,MEM_RELEASE))
{
MessageBoxA(0,"Error liberar memoria",0,MB_ICONERROR);
}
else
{
MessageBoxA(0,"Memoria Reservada Liberada","Info",MB_ICONINFORMATION);
}
break;

case MEM_FREE:
MessageBoxA(0,"Memoria Libre","Info",MB_ICONINFORMATION);
break;
}


if(!VirtualAlloc((LPVOID)0x00400000,0x1000,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE))
{
MessageBoxA(0,"Error al reservar memoria en 0x00400000",0,MB_ICONERROR);
return 0;
}

MessageBoxA(0,"Memoria Reservada correctamente en 0x00400000","Éxito",MB_ICONINFORMATION);

return 0;
}


"El Hombre, en su orgullo, creó a Dios a su imagen y semejanza.”
Nietzsche

Littlehorse

#4
VirtualAlloc mas direcciones hardcodeadas, no es la mejor combinación. ;D

Cuidado con los 0 de mas y de menos en las direcciones, que a simple vista ya se ven errores:

Código (cpp) [Seleccionar]

if(Buffer.State==MEM_COMMIT)
{
if(!VirtualFree((LPVOID)0x0040000,0x1000,MEM_DECOMMIT))


0x0040000!=0x00400000

Código (cpp) [Seleccionar]
case MEM_RESERVE|MEM_COMMIT:

Ese case esta de mas.

Código (cpp) [Seleccionar]
VirtualFreeEx(GetCurrentProcess(),(LPVOID)0x00400000,0,MEM_DECOMMIT);

Si utilizas decommit en una región de memoria sin utilizar release, esta cambia su estado a reservado , o sea, lista para asignar (Suponiendo que sea posible).
Por ende, la llamada a VirtualAllocEx va a fallar del modo que estas usando, porque estas intentando reservar una dirección que ya esta reservada. Asignarla es lo que debería seguir.

Código (cpp) [Seleccionar]
VirtualAllocEx(GetCurrentProcess(),ADR,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);




Antes de seguir, busca los artículos de Mark Russinovich acerca de todo esto ya que explican todo con lujo de detalle. Y sobre todo atención a los "remarks" de la documentación de cada API, porque es eso lo que te esta trayendo dramas. ;D.

Cabe destacar también, que el proceso real que debería realizarse es mucho mas largo, porque esto vale como ejemplo pero en una aplicacion no podes dejar pasar cosas como las posibles medidas de protección de cada región.

Tengo por acá un código que quizas te pueda servir ya que realiza lo que necesitas, es bastante largo y pesado pero de seguro sacas en limpio lo necesario. En un rato lo busco y si lo encuentro te lo mando por pm.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

[Zero]

Muchas gracias Littlehorse, seguiré trabajando y leyendo esta tarde siguiendo tus indicaciones  ;D.

Saludos




Edito: Arreglé el código de antes, sigue fallando pero al menos ahora los resultados que devuelve son coherentes. Por cierto, ¿que programa usaste arriba para ver el estado de las páginas de memoria?

"El Hombre, en su orgullo, creó a Dios a su imagen y semejanza.”
Nietzsche

Littlehorse

De nada ;D. El programa del screen es Cheat Engine que para este caso vale perfectamente, pero para el resto lo ideal es WinDBG.

Con Cheat Engine: Memory view + (ctrl +R)

Con WinDBG: !address -summary
                     !address Addr
 
Saludos!                    
An expert is a man who has made all the mistakes which can be made, in a very narrow field.