sábado, 10 de mayo de 2008

Articulo de Programacion #3 (Parte 1)

Recabando información del sistema 1

Bueno este es el inicio de un nuevo articulo. Ahora veremos como listar los procesos del sistema operativo y obtener sus características para fines diversos, por ejemplo, acceder la memoria virtual del proceso, alojar memoria remotamente como vimos en el ejemplo de la inyección de procesos y hasta modificarlos. Existe la forma difícil y la forma fácil. La forma difícil es la que usa el sistema operativo por naturaleza, mediante el uso de las Apis nativas. La api nativa usada por el sistema operativo ZwQuerySystemInformation, esta api recorre una variable del sistema llamada PsActiveProcessHead que es un puntero a una estructura LIST_ENTRY:

typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY;

Esta estructura viene siendo la cabeza de una lista enlazada que contiene a todos los objetos ejecutivos de los procesos (EPROCESS). De esta forma esta api guarda en un buffer la información mas elemental de los procesos en esa lista según el parámetro especificado (esta api se analizara con detenimiento en otro articulo). Existe sin embargo otras Apis que pueden recabarnos una lista de procesos sin tener que usar la api nativa ZwQuerySystemInformation, esta serie de funciones es lo que a partir de los Windows NT se encuentra disponible, PSAPI (Process API). Estas serie de funciones hacen uso de Apis nativas como ZwQueryInformationProcess o ZwQuerySystemInformation en una capa de abstracción que le da al proceso que la usa la información de forma directa ya desglosada.

Veremos una de las funciones mas importantes, EnumProcesses:

BOOL WINAPI EnumProcesses(
  __out  DWORD* pProcessIds,
  __in   DWORD cb,
  __out  DWORD* pBytesReturned
);

Esta función en su primer parámetro es un puntero a un arreglo donde se almacenaran todos los identificadores de procesos que estén ejecutándose o estén pausados (objetos EPROCESS existentes). El segundo parámetro es el tamaño de todo el arreglo pasado en el primer parámetro en bytes y finalmente el tercer parámetro es un puntero a una variable donde se recibirá el numero de bytes que se escribieron en el arreglo del primer parámetro.

Una vez teniendo el arreglo de process ids lleno necesitamos saber información de cada uno de ellos, en este caso el nombre del proceso, por lo cual, se usara la ya vista api OpenProcess para obtener una referencia a los objetos de los procesos el cual usaremos en una llamada a la api GetProcessImageFileName:

DWORD WINAPI GetProcessImageFileName(
  __in   HANDLE hProcess,
  __out  LPTSTR lpImageFileName,
  __in   DWORD nSize
);

El primer parámetro es una referencia obtenida con OpenProcess, el siguiente parámetro es un puntero a un arreglo de chars donde se almacenara el nombre del proceso y finalmente el tercer parámetro es el tamaño de este buffer.

Si tenemos dos procesos con el mismo nombre podemos distinguirlos todavía mas por su ruta completa lo cual lo lograremos con la api GetModuleFileNameEx:

DWORD WINAPI GetModuleFileNameEx(

__in HANDLE hProcess,

__in_opt HMODULE hModule,

__out LPTSTR lpFilename,

__in DWORD nSize

);

El primer parámetro es una referencia al proceso del cual vamos a obtener la ruta completa, el segundo parámetro se refiere al modulo ejecutable del proceso, en este caso pasaremos NULL haciendo referencia al modulo .exe. El siguiente parámetro es un buffer donde se almacenara la ruta completa al proceso y el parámetro final es el tamaño de este buffer.

Todavia podemos obtener mas información del proceso, por ejemplo, las dlls que tenga cargadas el proceso (modulos), para lo cual usamos la api EnumProcessModules:

BOOL WINAPI EnumProcessModules(
  __in   HANDLE hProcess,
  __out  HMODULE* lphModule,
  __in   DWORD cb,
  __out  LPDWORD lpcbNeeded
);

El primer parámetro es una referencia al proceso del cual vamos a obtener las direcciones base de las dlls, el siguiente es un puntero a un arreglo de variables de 4 bytes donde se almacenaran estas direcciones (mismo funcionamiento que la api EnumProcesses), las ultimas dos nos dicen el tamaño del arreglo y el numero de bytes almacenados.

Con esta api obtuvimos las direcciones base de las dlls, pero ahora requerimos saber mas información acerca de estas, para lo cual usamos otra api para saber por ejemplo, el nombre de la dll, esta api es GetModuleBaseName:

DWORD WINAPI GetModuleBaseName(
  __in      HANDLE hProcess,
  __in_opt  HMODULE hModule,
  __out     LPTSTR lpBaseName,
  __in      DWORD nSize
);

El primer parámetro es la referencia al proceso, la siguiente es la dirección base de la dll cuyo nombre queremos saber, el siguiente parámetro es un buffer donde se almacenara el nombre del modulo y el ultimo parámetro es el tamaño de este buffer. Si queremos saber el path completo a la dll usamos la ya explicada api GetModuleFileNameEx pasando como parámetro hModule la dirección base de la dll en vez de pasar NULL.

Con esto terminamos este breve articulo, en el siguiente se explicara como hacer una aplicación similar al taskmanager que nos permita terminar procesos, hasta la próxima!!!

No hay comentarios: