Problema interceptando ReadFile

Iniciado por sonnyk88, 29 Julio 2010, 13:56 PM

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

sonnyk88

Este es mi primer post. Les cuento mi problema de principiante.

Hice una DLL que decifra un archivo en memoria, intercepta el parametro lpBuffer de ReadFile() y lo reemplaza por los datos descifrados.

Funciona perfectamente con aplicaciones que llaman a la funcion UNA sola vez (es decir: que con un solo llamado logran cargar completamente el lpBuffer con el contenido total del archivo).

El problema es que hay algunas aplicaciones que (no entiendo la razon) llaman ReadFile muchas veces y ahi mi DLL desborda la memoria (crashea).

¿alguien sabe cuales son los parametros de ReadFile que contienen el offset y la cantidad de bytes leidos?
¿o alguien conoce algun ejemplo en c++ donde la funcion ReadFile se llame varias veces?

Segun MSDN, el parametro seria lpNumberOfBytesRead. Lo intercepté tambien pero no tuve exito alguno. lpNumberOfBytesRead no me da valores exactos (conclui esto creando una variable tipo contador y su resultado final siempre era mas grande que el tamaño real del archivo).

nNumberOfBytesToRead es un parametro que tampoco me sirve porque (segun lei en otros lugares) es el Maximo que ReadFile va a leer y este Maximo NO SIEMPRE se logra. Por lo cual es algo virtualmente impredecible de lo que no me puedo valer.

Lo ultimo que me queda probar (aun no se como) es la Overlapped Structure pero antes de meterme en ese embrollo, decidi consultar a los expertos.

Gracias por su atencion.


Eternal Idol

#1
¿Y si el archivo ocupara 2GB? Lo normal es leer en pedazos (chunks).

En lpOverlapped podes encontrar el offset pero no es muy usada esa estructura, en ese caso podes obtener el offset con SetFilePointer/Ex (el sistema lleva el puntero del archivo).

El tamaño leido solo sera valido DESPUES de llamar a la funcion original y sera guardado en lpNumberOfBytesRead.

lpNumberOfBytesRead
[out] A pointer to the variable that receives the number of bytes read.
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

sonnyk88

#2
Eternal Idol: Che! muchísimas Gracias por tu respuesta. Tendré que ver como interceptar los valores especificos de esa estructura entonces.... mucho de estructuras en C++ no se ni mucho menos como interceptar valores de una estructura en el tiempo de ejecución de una aplicación mediante hooks (o interceptores).

Te sigo explicando mas lo de mi problema el cual me causo bastante dolores de cabeza ya!

Aquí podés ver una imagen de una de las tantas aplicaciones que usan ReadFile() para leer archivos en partes(o chunks). Para ello hice uso de ProcMon de sysinternals.



(Disculpá lo berreta que es el servidor de imágenes que usé.)

Aquí podes ver como intercepto la función. Funciona perfectamente con las aplicaciones que te conté...

extern "C" void __stdcall __E__675__(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)

{
int TamanoArchivo = GetFileSize(hFile,Null)
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped);
[b]
memcpy(lpBuffer, BufferDescifrado, TamanoArchivo) // aqui ocurre el crash con las aplicaciones que usan ReadFile para leer en partes(o chunks)...[/b]
}


En las aplicaciones que les gusta leer archivos en partes el crash se debe a que memcpy() sobreescribe lpBuffer con mas información de la que esta última puede contener (seguramente nNumberOfBytesToRead o lpNumberOfBytesRead ajustan el tamaño de lpBuffer... para algo deben estar no?)

Mi primera intuición fue poner en el ultimo parámetro de memcpy nNumberOfBytesToRead.. la aplicacion ya no crashea pero el archivo se lee re mal... lo comprobé con el Readme.txt de este juego (curiosamente, ocupa menos de 70 kb y aun asi se lee por partes).

De todas formas cree otro Readme.txt de unos pocos bytes y lo cifré...


El archivo en el disco se ve algo así:
Citar
·"%"·$%·$&/%&/(&/()()/()=$"··$"·$"·$$%&(()
El archivo descifrado por la DLL en BufferDescifrado se ve así:
Citar
Hola, este es un archivo cifrado que no se puede leer
Ahora cuando ajusto el memcpy a valores de lpNumberOfBytesRead o nNumberOfBytesToRead la aplicacion me muestra esto...
Citar
Hola, este esHola, este esHola, este esHola, este esHola, este esHola, este esHola, este esHola, este esHola, este es

Con este "experimento" no solo me queda claro que no me puedo valer de lpNumberOfBytesRead o nNumberOfBytesToRead sino que también tengo que usar una función que corte BufferDescifrado correctamente (en largo exacto y desde la ubicación u offset exacta) la cual ya he encontrado, es una función que imita la función mid() en VisualBasic y funcionaría de maravillas si tan solo supiera como interceptar los valores requeridos.


Eternal Idol

Código (cpp) [Seleccionar]
extern "C" void __stdcall __E__675__(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
...
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped); //aca lpNumberOfBytesRead no tiene sentido

//AHORA, despues de llamar a ReadFile, lpNumberOfBytesRead contiene exactamente el numero de bytes leidos
...
}
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

sonnyk88

Tambien pense eso (en base a lo que lei en MSDN) veamos, me dijiste esto...


extern "C" void __stdcall __E__675__(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
...
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped); //aca lpNumberOfBytesRead no tiene sentido

//AHORA, despues de llamar a ReadFile, lpNumberOfBytesRead contiene exactamente el numero de bytes leidos
...
}


.... supongamos que agrego una variable tipo contador y el codigo quedaria asi:


extern "C" void __stdcall __E__675__(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
...
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped); //aca lpNumberOfBytesRead no tiene sentido

ContadorBytes = ContadorBytes + (int)lpNumberOfBytesRead;
...
}


Haciendo esto, es logico concluir que ContadorBytes tendria el tamaño exacto que el archivo en el disco pero cuando hice eso, ContadorBytes siempre tenia un tamaño mas grande que el tamaño total del archivo.  :huh: (como tres veces mayor) y obviamente esto era inexplicable para mi. La verdad que no se que estoy haciendo mal. Me queda probar con la Overlapped structure.... espero poder solucionar el problema igual te agradezco a vos y a todos por compartir mi dolor de cabeza jeje! :D

Eternal Idol

#5
¿Y estas seguro de que el hFile es siempre el mismo?

Edito:
El contador asi como lo pusiste estaria mal, lpNumberOfBytesRead es un puntero:

ContadorBytes = ContadorBytes + *lpNumberOfBytesRead;

PD. En este caso el OVERLAPPED no esta siendo usado por la imagen que mostraste, se usa cuando las operaciones son ASINCRONAS.
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

sonnyk88

#6
Uhhh buenisimo si no hace uso de la estructura esa...

y gracias por aclararle lo del puntero... pense que haciendo un typecast (agregando (int)) lo convertiria en un entero que pueda manejar jeje....

Citar
¿Y estas seguro de que el hFile es siempre el mismo?

Mi DLL tambien intercepta CreateFile y cuando detecta que "readme.txt" es llamado, guarda el Handle en una variable, llamémosle: elHandle. (sino el juego que he parcheado crashearia mucho antes de llegar a la pantalla donde muestra el Readme.txt pues cientos de archivos se cargan antes de esto)

ahora cuando intercepto ReadFile() simplemente hago esto:


extern "C" void __stdcall __E__675__(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
if (hFile == elHandle) {
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped);
...
Contador = Contador + *lpNumberOfBytesRead;
}
else {
// se llama readfile normalmente y todos vivieron felices para siempre :P digo porque los demas archivos se cargan de maravilla.
ReadFile(hFile,lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,lpOverlapped);
}


Mi funcion modificada de CreateFile() tambien llama la funcion de descifrar los datos del archivo y guardarlos en la variable llamada BufferDescifrado la cual ReadFile se encarga de transferir a su lpBuffer pero no la he incluido aqui para mantener topic.

Talvez con esto nuevo del puntero que me dijiste funcione, voy a probar mas tarde ahora tengo que ir al laburo MUCHISIMAS GRACIAS por aclararme lo de la estructura.  Es un pequeño avance pues me ahorra bastante dolor de cabeza. Aun soy principiante en C++...

Eternal Idol

De nadas, suerte con eso y para todo este tipo de cosas DEPURAR es lo mejor que hay por lejos.
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