miércoles, 21 de mayo de 2008

Articulo de Programacion #3 (Parte 2)

Recabando información del sistema 2

Ya vimos lo necesario para recabar procesos y su información de cada uno, como fue dicho en el articulo anterior, ahora vamos a poner todo en practica, crearemos un sencillo taskmanager dándonos información básica de los procesos y haremos operaciones sobre ellos. En este ejemplo usaremos el compilador Dev C++, y un programa en modo consola (el gui se vera en otro articulo).

Como siempre, en cualquier programa que hagamos donde usemos las Apis Win32. Tenemos que incluir la librería Windows.h asi como es stdio para los programas en modo consola de c. En este fichero de inclusión de encuentran las declaraciones y estructuras de estas Apis, las definiciones de tipos y las importaciones. Tambien requeriremos usar las funciones del psapi mencionado en el articulo anterior, el problema es que estas definiciones no se encuentran en Windows.h y estas Apis tampoco están incluidas en las librerías kernel32.dll o ntdll.dll, aunque las funciones mencionadas hacen uso de las funciones ntdll.dll, estas serian las Apis nativas que veremos mas adelante. Tenemos entonces que hacer un enlace a psapi.dll mediante su lib, psapi.lib, sin embargo, vamos a aplicar lo aprendido sobre dlls, entonces nosotros dinámicamente enlazaremos nuestro programa con estas funciones. Debemos asegurarnos sin embargo que la dll psapi.dll este en nuestro sistema, generalmente esta ya se encuentra instalada en los sistemas operativos desde Windows 2000.

Tenemos entonces las definiciones de las funciones, por ejemplo, la de EnumProcesses:

BOOL WINAPI EnumProcesses(

__out DWORD* pProcessIds,

__in DWORD cb,

__out DWORD* pBytesReturned

);

Lo que hay que hacer entonces es declararlo como un puntero a función, quedaría de la siguiente forma:


typedef BOOL (WINAPI* TEnumProcesses)(PDWORD, DWORD, PDWORD);


Es importante especificar la opcion de declaracion WINAPI, que es un typedef a la convencion stdcall, lo cual es importante declarar explicitamente ya que de lo contrario se usara otra convencion de llamado de funcion que ocasionara que los parámetros sean empujados a la pila de forma inversa y por lo tanto ocurrirá una excepción. De la misma forma haremos lo mismo para las demás funciones:


typedef DWORD (WINAPI* TGetProcessImageFileName)(HANDLE, LPSTR, DWORD);

typedef DWORD (WINAPI* TGetModuleFileNameEx)(HANDLE, HMODULE, LPSTR, DWORD);

typedef BOOL (WINAPI* TEnumProcessModules)(HANDLE, HMODULE*, PDWORD);

typedef DWORD (WINAPI* TGetModuleBaseName)(HANDLE, HMODULE, LPSTR, DWORD);

typedef BOOL (WINAPI* TEnumProcesses)(PDWORD, DWORD, PDWORD);


Ahora usaremos la api LoadLibrary como vimos en el primer articulo para cargar la dll en el proceso, en caso de que ya este cargada, esta api solo incrementara la referencia de cargado una unidad mas. Esta funcion nos retornara la dirección base de la dll cargada, que en este caso será la psapi.dll.

Usaremos entonces la técnica de punteros a funciones que ofrece C, esto es de las declaraciones que hicimos vamos a declarar estas variables:


TGetProcessImageFileName GetProcessImageFileName;

TGetModuleFileNameEx GetModuleFileNameEx;

TEnumProcessModules EnumProcessModules;

TGetModuleBaseName GetModuleBaseName;

TEnumProcesses EnumProcesses;


Ahora bien, tenemos que depositar en ellos una dirección de memoria, para saber a donde deben empujar los parámetros y hacer el call respectivo, en este usamos la api GetProcAddress y casteamos el tipo que retorna al tipo de puntero de nuestro contenedor, por ejemplo:


GetProcessImageFileName=(TGetProcessImageFileName)GetProcAddress(PspAddress, "GetProcessImageFileNameA");


Codigo:


bool Inicializa(){

HMODULE PspAddress;

PspAddress=LoadLibrary("psapi.dll");

if(!PspAddress){

printf("No se pudo cargar psapi.dll");

return false;

}

GetProcessImageFileName=(TGetProcessImageFileName)GetProcAddress(

PspAddress, "GetProcessImageFileNameA");

if(!GetProcessImageFileName){

printf("No se encontro funcion GetProcessImageFileName");

return false;

}

GetModuleFileNameEx=(TGetModuleFileNameEx)GetProcAddress(

PspAddress, "GetModuleFileNameExA");

if(!GetModuleFileNameEx){

printf("No se encontro funcion GetModuleFileNameEx");

return false;

}

EnumProcessModules=(TEnumProcessModules)GetProcAddress(

PspAddress, "EnumProcessModules");

if(!EnumProcessModules){

printf("No se encontro funcion EnumProcessModules");

return false;

}

GetModuleBaseName=(TGetModuleBaseName)GetProcAddress(

PspAddress, "GetModuleBaseNameA");

if(!GetModuleBaseName){

printf("No se encontro funcion EnumProcessModules");

return false;

}

}


Ahora si ya podremos usar estas funciones, comenzaremos primero listando los procesos en el sistema mediante la ya explicada técnica del EnumProcesses.


void MostrarInformacion(HANDLE hProcess, DWORD ProcessId){

LPSTR buffer;

buffer=(char*)malloc(MAX_PATH);

memset(buffer, 0, MAX_PATH);

printf("ProcessId: %d\n", ProcessId);

if(!GetModuleBaseName(hProcess, NULL, buffer, MAX_PATH)){

printf("Proceso: ?????\n");

}

else{

printf("Proceso: %s\n", buffer);

}

if(!GetModuleFileNameEx(hProcess, NULL, buffer, MAX_PATH)){

printf("Ruta: ??????\n");

}

else{

printf("Ruta: %s\n\n", buffer);

}

free(buffer);

}


bool ListaProcesos(){

HANDLE hProcess;

DWORD Returned, i;

PDWORD Lista;

Lista=(PDWORD)malloc(100*sizeof(DWORD));

memset(Lista, 0, 100*sizeof(DWORD));

if(!EnumProcesses(Lista, 100*sizeof(DWORD), &Returned)){

printf("Ocurrio un error al listar los procesos");

free(Lista);

return false;

}

for(i=0; i<(Returned/sizeof(DWORD)); i++){

hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, Lista[i]);

if(hProcess){

MostrarInformacion(hProcess, Lista[i]);

CloseHandle(hProcess);

}

}

free(Lista);

return true;

}


Como podemos ver en la funcion ListaProcesos, primero alojamos un buffer los suficientemente largo para poder obtener los Process Ids de todos los procesos del sistema, no sabemos cuantos pudiesen ser, incluso pueden llegar a ser mas de 100 (lo máximo que nuestro buffer alojado en esa funcion pudiese soportar), para poder determinar el numero de procesos en el sistema antes de guardarlos en el buffer hay que llamar una vez a la funcion y lo que nos retorne el parámetro de bytes returned usarlo en otra llamada a EnumProcesses, de esta forma ahora ya sabemos que tamaño debe tener el buffer para alojar los PIDs. Si la funcion falla retorna 0 y si no retorna un valor distinto a este lo cual lo checamos en nuestro if. Una vez que nuestro buffer ha sido llenado, el parámetro bytes returned nos da el numero de bytes escritos a este, para saber cuantos elementos son en nuestro arreglo tenemos que dividir el numero de bytes entre 4, asi sabemos cuantas casillas de nuestro arreglo tenemos. Despues solo queda usar cada Process Id recabado y abrirlo con OpenProcess y si podemos obtener referencia a el (existe), lo pasamos a nuestra subrutina MostrarInformacion. En esta subrutina aplicamos la teoría del articulo anterior para obtener el nombre y la ruta completa del proceso.

El ejemplo posee tres funciones sobre los procesos, terminarlos, congelarlos y descongelarlos. Para terminar un proceso, usamos la api de la dll kernel32, TerminateProcess. A esta api recibe dos parámetros, el primero es el handle del proceso a terminar y el segundo el código de la razón de terminación. Las otras dos funciones no se encuentran dentro de las Apis de la categoría win32, son nativas en la dll ntdll.dll. Para poder usarlas, usamos la misma técnica que usamos con las funciones del psapi.dll, las declaramos, obtenemos los punteros de las funciones y las usamos finalmente:


typedef DWORD (WINAPI *TNtSuspendProcess)(HANDLE);

typedef DWORD (WINAPI *TNtResumeProcess)(HANDLE);

ntdllAddress=GetModuleHandle("ntdll.dll");

NtSuspendProcess=(TNtSuspendProcess)GetProcAddress(ntdllAddress, "ZwSuspendProcess");

NtResumeProcess=(TNtResumeProcess)GetProcAddress(ntdllAddress, "NtResumeProcess");


Estas apis nativas reciben en su primer parametro una referencia del proceso a suspender o continuar, mas adelante se analizaran mas a fondo estas apis nativas.

Y con esto termina este articulo de programación, jaja espero que haya sido de tu agrado, hasta la próxima XD.


Descarga el código fuente completo:


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!!!

Articulo de Programacion #2 (Parte 3)

Dll Injection (Parte 2)


En la pasada parte de este articulo de programacion #2 vimos algunas de las apis necesarias para realizar el cometido de una inyeccion de una dll en el contexto de un proceso remoto, ahora veremos ya la aplicacion de las mismas.

Una de las funciones vistas crucial para lograr ejecutar esta tecnica es la funcion CreateRemoteThread, esta funcion no es mas que la funcion final en la cadena de funciones para crear un hilo. CreateRemoteThread termina invocando la funcion NtCreateThread en la libreria ntdll.dll, que asu vez invoca el servicio Nt NtCreateThread en el kernel (ntoskrnl.exe) este ultimo se encarga de crear el objeto tipo Thread necesario para el manejo y funcionamiento del mismo, el objeto que es el cuerpo del hilo creado. Es asi como esta funcion recaba un manejador o handle al proceso destino, el cual obtenemos mediante OpenProcess, la cadena es algo como:


Modo usuario:CreateThread->CreateRemoteThread->NtCreateThread|Modo Kernel:KiServiceTable->NtCreateThread->PspCreateThread

Ahora bien, cuando un thread se crea en nuestro propio proceso, tenemos la certeza que el codigo ejecutado va a ejecutarse de la manera como lo programamos, ya que las variables y direcciones las tenemos localizadas en el contexto de memoria de nuestro proceso de la memoria virtual. Como con un thread o hilo remoto estaremos en un contexto diferente, las direcciones que querramos acceder no contendran la misma informacion que la del contexto de nuestro proceso, incluso podrian ser invalidas, recordemos el manejo de la memoria virtual, que permite que las direcciones apunten a diferentes paginas de la memoria fisica para cada proceso, diferentes mundos distintos de memoria, apuntando a una misma memoria ram.

La tecnica de inyeccion de una dll consiste en obligar a un proceso a cargar una dll, como bien aprendimos, para cargar una dll necesitamos usar la funcion LoadLibrary, pero en este caso haremos que el proceso remoto lo use sin que lo tenga en sus planes de hacerlo =), para cumplir esto, necesitamos crear un thread alterno en su contexto, ya con esto concluimos que necesitamos de crear un thread en el proceso donde queremos que cargue la dll usando CreateRemoteThread y hacer que ejecute la funcion LoadLibraryA.


HMODULE WINAPI LoadLibrary(

LPCTSTR lpFileName

);


Esta funcion requiere un parametro el cual es la ruta al archivo de la dll que va a ser cargada, esa ruta debe estar escrita en alguna direccion de memoria del proceso remoto, no es lo mismo tener la cadena de caracteres en nuestro proceso, y usar esa direccion en el proceso remoto, la direccion virtual no apunta a la misma pagina de memoria fisica, por lo cual necesitamos acceder al otro proceso escribir los datos que vamos a usar.

Programando en lenguaje c o cualquier otro lenguaje, hemos visto la necesidad de alojar memoria dinamicamente, segun las necesidades de nuestro programa y no tener que estar haciendo uso de muchas variables declaradas o arreglos, asi bien, se haria con un malloc usando la libreria estandar, o hasta usando la funcion new en c++; estados dos funciones al final hacen uso de la apis de windows, la cual invoca a VirtualAlloc una api para reserver o alojar nueva memoria virtual con respecto a una nueva pagina de memoria fisica tomada del directorio de paginas de la misma. En este caso necesitamos tener un espacio de memoria en el proceso remoto, para ello no podriamos usar malloc, new o VirtualAlloc, para ello windows nos ofrece otra api llamada VirtualAllocEx, esta nos permite alojar memoria en el contexto de un proceso que no sea el nuestro, es la funcion que es invocada por VirtualAlloc usando como handle NtCurrentProcess ((HANDLE)0xFFFFFFFF). Veamos la definicion de VirtualAllocEx:


LPVOID VirtualAllocEx(

HANDLE hProcess,

LPVOID lpAddress,

SIZE_T dwSize,

DWORD flAllocationType,

DWORD flProtect

);


Veamos los parametros de esta funcion, como ya pudimos ver en la entrada anterior, esta funcion requiere un handle o manejador al proceso donde se va alojar el espacio, este se obtiene usando OpenProcess con el ProcessId del proceso remoto, lpAddress: este parametro se indica la direccion donde queremos que se aloje la memoria, si especificamos un valor y ese espacio ya esta reservado o alojado la funcion VirtualAllocEx fallara, por lo cual, en este parametro debemos pasar 0 o NULL, de esta manera el sistema operativo usara la direccion de memoria que mas convenga y donde encuentre espacio, el siguiente parametro, dwSize especifica la cantidad de bytes que se necesitan alojar, estos se redondean al tamaño de pagina mas proximo (generalmente 4096 bytes o 4 kb), el siguiente parametro se especifica el tipo de alojamiento ya sea para reservar o para alojar, cuando es una reservacion, la memoria virtual no es accesible pero tampoco puede ser reservado otra vez (MEM_RESERVE), cuando es alojado (MEM_COMMIT) la memoria virtual es referenciada con una pagina de la memoria fisica y a partir de entonces se vuelve valida, cabe decir que una direccion de memoria no puede ser alojado sin que haya sido reservada primero, es por ello que en esta funcion por lo general se usan los dos flags combinados (MEM_RESERVE|MEM_COMMIT), el ultimo parametro es el tipo de proteccion que va a tener la pagina alojada, existen diferentes tipos de protecciones, entre las mas importantes se encuentran PAGE_READ, PAGE_WRITE, PAGE_READWRITE, PAGE_NOACCESS, PAGE_EXECUTE, PAGE_EXECUTE_READWRITE, despues se explicaran cada uno de ellos.


Ahora ya explicada esa funcion necesitaremos de poder escribir en la memoria del proceso remoto, esto lo haremos con una funcion para depuradores de la api Win32 llamado WriteProcessMemory, veamos su definicion:


BOOL WriteProcessMemory(

HANDLE hProcess,

LPVOID lpBaseAddress,

LPCVOID lpBuffer,

SIZE_T nSize,

SIZE_T* lpNumberOfBytesWritten

);


El primer parametro es un manejador al proceso remoto, el segundo nos indica la direccion virtual en el CONTEXTO del proceso remoto donde vamos a escribir los datos contenidos en el tercer parametro (lpBuffer), este tercer parametro es un puntero dentro del contexto de nuestro PROPIO proceso, es decir, puede ser una variable o buffer alojado dinamicamente con malloc o VirtualAlloc dentro de nuestro proceso, este buffer sera copiado exactamente igual en la direccion especificada en el parametro anterior, y el numero de bytes a copiar seran los que sean especificados en el cuarto parametro (nSize), el ultimo parametro es opcional y podemos pasar NULL o 0, aunque si queremos saber cuantos bytes se copiaron, podemos pasar la direccion de memoria de una variable la cual sera llenada por esta funcion con el numero de bytes copiados.

Ahora si, con todo esta teoria ya podemos empezar aplicar la tecnica =), lo que haremos es inyectar una dll llamada hack.dll en la unidad C:\ de nuestro disco en el proceso del buscaminas:


char DllPath[MAX_PATH]="C:\\hack.dll";
HWND Buscaminas;
DWORD BuscaminasPID;
HANDLE BuscaminasHandle;
HMODULE hKernel;
PVOID LoadLibraryAddress, RemoteVirtualAddress;
BOOL bSuccess;
HANDLE hRemoteThread;

/*Obtenemos la direccion base de la libreria kernel32 donde reside LoadLibraryA*/
hKernel=GetModuleHandle("kernel32.dll");

/*Buscamos en la libreria la funcion exportada*/
LoadLibraryAddress=(PVOID)GetProcAddress(hKernel, "LoadLibraryA");


/*Nota: Aqui no nos preocupamos por la memoria virtual del contexto del otro proceso con respecto a las funciones que acabos de recabar, ya que todas son proyectadas en la misma direccion de memoria en todos los procesos =)*/

/*Intentamos encontrar el handle a la ventana del buscaminas*/

Buscaminas=FindWindow(NULL, "Buscaminas");


if(!Buscaminas)
return; //error

/*Recabamos el processId del proceso que posee la ventana*/
GetWindowThreadProcessId(Buscaminas, &BuscaminasPID);

/*Abrimos una referencia al proceso con el process id obtenido*/
BuscaminasHandle=OpenProcess(PROCESS_ALL_ACCESS, FALSE, BuscaminasPID);

/*Alojamos memoria en el proceso remoto =)*/
RemoteVirtualAddress=VirtualAllocEx(BuscaminasHandle, NULL, strlen(DllPath), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);


if(!RemoteVirtualAddress)
return; //error

/*Escribimos en el espacio remoto que acabamos de alojar el string al camino de la dll*/
bSuccess=WriteProcessMemory(BuscaminasHandle, RemoteVirtualAddress, DllPath, strlen(DllPath), NULL);


if(!bSuccess)
return; //error

/*Creamos el hilo remoto y pasamos de parametro la direccion de memoria donde se encuentra nuestra cadena de caracteres que tiene la ruta de nuestro ejecutable =D*/
hRemoteThread=CreateRemoteThread(BuscaminasHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddress, (LPVOID)RemoteVirtualAddress, 0);


if(!hRemoteTHread)
return; //error

/*Esperamos a que el thread remoto termine de ejecutarse, este paso es opcional*/

WaitForSingleObject(hRemoteThread, INFINITE);


Y con esto terminamos este segundo articulo de programacion =D, espero que te haya gustado, jajaja, proximamente hare el tercero donde explicare una tecnica fundamental en la administracion del sistema operativo, recabar los procesos en el sistema, hasta la proxima xD.

Articulo de Programacion #2 (Parte 2)

Dll Injection (Parte 1)


Ya vimos lo que es un proceso y un hilo o thread en la parte anterior, sabiendo como son los procesos, la unica manera de poder ejecutar una funcion en su contexto seria creando un hilo dentro de el, la pregunta seria como hacerlo, ya que normalmente un proceso solo puede crear hilos dentro de si mismo, Microsoft nos dio un regalo para superar esa adversidad bajo usermode, y nos brinda la funcion llamada CreateRemoteThread:


HANDLE WINAPI CreateRemoteThread(

HANDLE hProcess,

LPSECURITY_ATTRIBUTES lpThreadAttributes,

SIZE_T dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId

);


Analicemos la funcion, el primer parametro es un handle representando el proceso en el que queremos crear el thread, lpThreadAttributes son los atributos de seguridad del thread a crear, generalmente este parametro no lo usamos, dWStackSize es el tamaño que tendra la pila del thread creado, lpStartAddress seria el parametro mas importante, especifica la direccion donde empieza el thread creado, lpParameter es un puntero a una variable que le podemos pasar la funcion del thread, ojo, como estamos en contexto de otro proceso, ese parametro lo tenemos que alojar en el proceso remoto (mas adelante se explicara), dwCreationFlags significa la manera de como se crea el nuevo Thread, se puede dejar en tres estados, los mas importantes, son en estado Pausado o Resumido, el ultimo parametro es un puntero que recibira el ThreadId del nuevo thread creado.

Primeramente para poder usar la funcion, necesitamos sacar el handle del proceso en el que queremos crear el thread, como se explico, un proceso es un objeto ejecutivo en el kernel de windows, un handle es una representacion abstracta de ese objeto que hace referencia al mismo. Para poder obtener el handle, primero necesitamos obtener el ProcessId del proceso, el processid es una manera de simplificar el significado del proceso, y es que realmente es un handle que hace referencia a su localizacion en la PspCidTable, una tabla de handles que mantiene un registro de todos los procesos creados. Una de las tantas maneras de obtener la pid es localizando el nombre de la ventana del proceso, por ejemplo digamos que el buscamina muestre un cuadro de dialogo que pregunte si deseas cerrar la aplicacion o no, esto de manera inmediata y sin permiso previo del programa, primero necesitamos localizarlo, esto se haria usando la funcion FindWindow:


HWND FindWindow(
LPCTSTR lpClassName,

LPCTSTR lpWindowName

);


El primer parametro de esta funcion lo pasamos para especificar el nombre de la clase de la ventana a encontrar, el segundo para especificar solamente el nombre de la ventana (es la que usariamos mas habitualmente), se pueden pasar ambos parametros tambien de ser necesario. Si la funcion es un exito, regresa el HWND de la ventana encontrada, un HWND es tambien un handle que hace referencia a la ventana requerida. Ahora una vez que la ventana ha sido encontrada, necesitamos obtener el process Id de quien la ventana pertenece, eso lo hacemos con la funcion GetWindowThreadProcessId:


DWORD GetWindowThreadProcessId(
HWND hWnd,

LPDWORD lpdwProcessId

);


El primer parametro de esta funcion es el HWND de la ventana de la que queremos saber el process id del proceso a quien pertenece, el segundo parametro es un puntero que recibe el processid de la ventana requerida, la funcion retorna el ThreadId del HWND de la ventana pasada a esta funcion. Ahora que ya tenemos el processid, ya podemos obtener el handle a este, el cual obtendremos con la funcion OpenProcess:


HANDLE WINAPI OpenProcess(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId

);


El primer parametro de esta funcion es el acceso que tendra el handle referenciado, por lo general siempre se usa la constante PROCESS_ALL_ACCESS. El segundo parametro es para indicar si el handle es heredado de un proceso padre, por lo general este parametro es puesto en falso, por ultimo el parametro mas importante, dwProcessId, aqui se pasa el processid del proceso a referenciar. Como resultado la funcion retorna la referencia al objeto del proceso, es decir el handle.

Y ahora si, tenemos lo mas importante para crear un Thread en el proceso, ahora es cuestion de poner todo esto en orden y ponerlo a la practica, pero eso lo veremos en la tercera parte de este articulo xD.

Articulo de Programacion #2 (Parte 1)

Hilos y Procesos


Esta es la segunda parte de los articulos de programacion, la ultima vez nos quedamos viendo que era una dll y el efecto que tiene al ser cargada en un proceso, ahora veremos una comun tecnica usada en el hacking, llamada Dll Injection. Pero antes veamos que es un thread o hilo. Todos los procesos que se ejecutan tienen una determinada cantidad de hilos que se ejecutan al mismo tiempo, windows es un sistema multi-hilos, es decir, tiene la capacidad de ejecutar multiples hilos a la vez, tal vez nos preguntemos, como sera posible eso si la computadora a lo mucho tiene 1 o 2 procesadores?, bueno, realmente en un cpu, no se pueden ejecutar dos instrucciones al mismo tiempo, solamente una a la vez, asi que lo que hace el sistema operativo, es dividir el tiempo de ejecucion, y esta ejecucion es dividido en unidades de ejecucion, cada uno con su respectivo stack y registros (contexto), llamados hilos, windows reparte el tiempo para cada hilo segun su prioridad en el sistema, de esta manera se crea el efecto de que varios hilos se ejecutan al mismo tiempo debido a que hoy en dia, la velocidad de los procesadores es bastante rapido. Bueno ahora que vimos que el hilo es la unidad minima de ejecucion, podemos concluir que un proceso no es mas que un conjunto de hilos en un hyperespacio virtual propio. Cuando un proceso es creado, este crea un hilo principal en el cual el codigo de inicio del ejecutable es ejecutado. A su vez, ese mismo hilo puede ejecutar mas hilos, dentro del mismo proceso, para poder satisfacer diferentes tareas de una manera mas eficiente a que si lo hiciera un solo hilo. Ahora bien, la vez pasada creamos una dll con un punto de inicio opcional, que ejecutaba un cuadro de texto, cuando una dll es cargada de esa manera la libreria Ntdll.dll en su funcion LdrLoadModule, es crear un thread en sus funciones internas para ejecutar el punto de entrada opcional DllMain, de esta manera se crea un hilo de ejecucion alterno al que estaba corriendo el mismo programa. El objetivo ahora es cargar la misma dll, pero en el contexto de otro proceso, pero antes de empezar, tenemos que entender bien lo que son los procesos. Como bien se definio antes, un proceso es un objeto de windows que mantiene un espacio virtual propio e hilos que se ejecutan en el mismo. Anteriormente en muchos sistemas operativos, se usaba un manejo de memoria linear, es decir, la memoria que se accedia era directamente la memoria ram o memoria fisica, eso ocasionaba muchos problemas en entornos donde se ejecutaban varios procesos a la vez, ya que un proceso podia acceder a la memoria de otro, alterando sus datos e inclusive colga el sistema. Actualmente en los sistemas operativos, como windows NT, maneja la memoria de manera diferente, la llamada Memoria Virtual La memoria virtual es la representacion abstracta de la memoria fisica, las cuales se dividen en paginas, las cuales se almacenan en directorios en un espacio de la memoria fisica destinada para ello. La memoria virtual permite que cada proceso tenga un espacio de memoria de 4 GB, te preguntaras, como es eso posible!!!, pues bueno, realmente no se tienen completos los 4GB, si no fisicamente se tienen 1 MB y a lo mucho 1 GB, esto es debido a que para que una direccion de memoria virtual pueda ser utilizada, necesita primero ser paginada en el direcotrio de paginas del proceso que esta en ejecucion, de esta manera al acceder a la direccion 0x00400000 de un proceso, al ser convertido a la direccion linear (memoria fisica), esta apunta a la direccion 0x1CEFFF20 de la memoria fisica donde actualmente reside contenido de la direccion, mientras que en otro proceso al tener un directorio de pagina distinto, la misma direccion virtual apuntaria a 0x00CEFF14, de esta manera se evita que otros proceso interfieran en la memora de otros, aunque esto puede ser tambien un problema, ya que los procesos se aislan, imposibilitando la comunicacion entre ellos, aunque no es imposible, existen tecnicas para comunicarlos, aunque eso ya se vera en proximos aritulos.

Ya que vimos un poco de informacion que son los hilos y comprendimos el concepto de los procesos, procederemos a explicar en la practica como cargar una dll en otro proceso. eso se vera en la parte dos de este segundo articulo :)


Articulo de Programacion #1

Dll (Dynamic Load Library)

Bueno, en este space quize empezar con algunos tutoriales de programación, no c porque, quiero compartir un poco del conocimiento que he adquirido xD, bueno, el primero de estos tutoriales sera hablar sobre las famosas Dlls. Para empezar tenemos que saber que es una dll, Dll significa Dynamic Load Library (Librería de enlace dinamica) que es esto? es simplemente una variante de archivo ejecutable, tiene su punto de entrada y codigo, tabla de importaciones y exportaciones, la diferencia radica, en que no puede ejecutarse asi mismo como un exe convencional, son una especie de pedazos de ejecutables. Entonces cual es la utilidad de las dlls? Bueno pues una dll al incluir codigo y funciones, se puede ensamblar a un exe previamentejecutarlas, =O ahora tiene sentido el uso de una dll, seri creado, sin que haya sido programado en el mismo lenguaje, un ejecutable puede importar sus funciones contenidas y ea como un ensamblaje de un automóvil, se crean sus partes y al final se unen. Ahora bien, la dll puede ser usada por un proceso de diversas maneras, pero la mas comun es mediante la api LoadLibraryA contenida en la dll Kernel32.dll, ahora bien que es una api? Bueno, una api significa Application Programming Inteface (Interface de programación de Aplicaciones), una api es una funcion que interactua con el sistema operativo, exportada en una dll. El sistema operativo Windows tiene todas sus funciones en distintas dlls, pero las mas importantes estan en las librerias: kernel32.dll, advapi.dll, user32.dll, ntdll.dll, asi pues estas dlls contienen funciones que el sistema operativo llama para invocar a otras funciones de mas bajo nivel en el sistema, esas funciones nos “facilitan” el trabajo en pocas palabras, y esas son las que usaremos para interactuar con el sistema operativo. Como mencionamos anteriormente, se usa la api LoadLibraryA para cargar una dll, al invocarla, “ensamblara” la dll en nuestro proceso y lo posicionara de tal manera que ya esten todas sus funciones listas para usarse. Asi pues una vez que usemos LoadLibraryA, ya podremos usar las funciones contenidas en la dll y ser usadas por nuestro proceso. Ahora nos preguntaremos, como usar esas funciones?, pues facil, tendremos que hacer uso de punteros a funciones, y la api GetProcAddress:

/*Declaramos el prototipo funcion*/

typedef void (*TFuncion1)(void);

/*Definimos la funcion*/

TFuncion1 Funcion1;

/*Cargamos la dll y almacenamos su direccion base*/

HMODULE DllHandle=LoadLibrary(“Nombredeladll.dll”);

/*Una vez obtenido la base procedermos al uso de GetProcAddress*/

PVOID Direccion=(void*)GetProcAddress(DllHandle, “Funcion1”);

/*Una vez obtenida la direccion de la funcion, la almacenamos en el puntero*/

Funcion1=(TFuncion)Direccion;

/*Una vez que la funcion tenga su direccion almacenada ya la podemos invocar =D*/

Funcion1();

Recordemos que esto unicamente lo podremos hacer cuando la funcion este exportada, de otro modo tendremos que buscar el punto de entrada de la funcion nosotros mismos.

Pero se preguntaran tambien, que pasaria si en vez de que tenga funciones exportadas, la dll ejecute codigo al ser cargada? Pues eso tambien se puede, pero tenemos que indicarle a la dll un punto de entrada opcional llamado DllMain:

BOOL __stdcall DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved)

{

switch(reason)

{

case DLL_PROCESS_ATTACH:

break;

case DLL_THREAD_ATTACH:

break;

case DLL_THREAD_DETACH:

break;

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

Analizemos este codigo, primero, la primera linea indica el punto de inicio de la dll, hModule recibe la direccion base donde esta cargada nuestra dll, Reason contiene el codigo que indica la razon de la dll al ser cargada, pueden ser cuatro rezones:
ProcessAttach: Esta ocurre cuando la dl les cargada totalmente en el proceso.

ThreadAttach: Esta ocurre cuando un nuevo thread es creado en el proceso al momento que la dll haya cargado en el proceso

ThreadDetach: Es lo contrario de la razon anterior, y es usada con fines de limpieza de memoria.

ProcessDetach: es lo contrario de processattach y ocurre cuando la dl les descargada del proceso, asi podremos ejecutar las acciones necesarias para limpiar completamente el proceso de la dll.

Ahora bien, si queremos que al cargar nuestra dll se ejecute ciertas funciones unicamente lo que tenemos que hacer es poner nuestro codigo dentro del case DLL_PROCESS_ATTACH:

BOOL __stdcall DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved)

{

switch(reason)

{

case DLL_PROCESS_ATTACH:

MessageBox(NULL, “Hola xD”, “O_O”, NULL);

break;

case DLL_THREAD_ATTACH:

break;

case DLL_THREAD_DETACH:

break;

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

En el codigo anterior, la dll al ser cargada ejecutara un cuadro de mensaje que diga hola xD. Asi en esa razon se pueden invocar otras funciones internas de la dll u otras acciones.

Pero que tal si queremos ejecutar esas funciones en otro proceso que no sea el nuestro? Parace interesante, pero eso lo veremos en el proximo articulo = )