Tutorial: Crear un parche 1

Iniciado por 85, 25 Febrero 2013, 09:12 AM

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

85

Estaba mirando un tema acerca de como se pasaba por alto la detección de un anticheat y se me ocurrió la idea de mostrar como se puede hacer un parche básico dentro de un mismo proceso. Es decir tenemos un ejecutable, lo ejecutamos y parcheamos nuestra propia memoria. Esto se puede hacer de varias formas, una de ellas es inyectando una DLL , pero esto es algo más fácil :p

Cómo es una demostración el propio programa se parchea así mismo, por lo que necesitamos saber en que lugar vamos a querer modificar las cosas.
Para eso en el programa puse un bloque condicional que es el que me interesa parchear para poder accederlo aunque no se cumpla la condición.
Por Ejemplo:

if( 0 == 1){ /* no se cumple */ }

Eso no se cumple, pero parcheándolo se logra acceder de todas formas..

Con un desensamblador, abro el ejecutable (el archivo EXE) y procedo a mirar el código ensamblador.


Identifico el OPCODE que me interesa cambiar, en este caso es JZ (0x74), y procedo a obtener la posición en donde se encuentra (dirección de memoria).

Es 0x40106C

En realidad lo que nos interesa es saber el desplazamiento en bytes que hay desde la dirección base del ejecutable hasta el punto en el que queremos parchear.
Se puede tomar en cuenta la sección de código también pero no es la base del ejecutable, recordar al momento de hacer la cuenta..


Bueno el offset (desplazamiento) es 0x6C y 0x1000 de la sección de código.

Bueno sabiendo estas cosas, ya vamos al código..
Con respecto al código, como decía antes, la idea viene de algo que estaba mirando sobre llamadas seguras a funciones para evitar detecciones de un anticheat por ejemplo,,
Por eso fui a crear una función (Check()) que trata de ser en forma figurativa la detección de modificaciones en la memoria.
Aunque en realidad una función de este tipo no tiene mucho sentido en el mismo hilo de ejecución, se debería hacer desde otro..

Y otro concepto que se puede apreciar en todo esto, es la importancia de restaurar la memoria luego de modificarla y lograr lo deseado.
Por eso , en este programa luego de realizar el parche y de llamar a la función de prueba (Target()) , se procede a restaurar la memoria a como estaba antes, para que las detecciones no se disparen.

Véase el bloque condicional donde se desea poder ingresar

...
if(master==MASTERNUM)//Aquí es donde queremos entrar XD
{ ...


Código (cpp) [Seleccionar]


//
// By 85
// Credits: Organner
// elhacker.net
// etalking.com.ar
// 2013
//

///////////////////

#include<windows.h>
#include<stdio.h>

//////////////////////

DWORD dwPatchPlace = 0x00000000;
BYTE Opcode_JZ = 0x74;
BYTE Opcode_JNZ = 0x75;

///////////

inline void Patch(){//Función de parcheadora

if(*(PBYTE)dwPatchPlace!=Opcode_JZ) return;

DWORD dwOldProtect;
   VirtualProtect( (LPVOID)dwPatchPlace,
                   1,
                   PAGE_EXECUTE_WRITECOPY,
                   &dwOldProtect );

WriteProcessMemory( GetCurrentProcess(),
                       (LPVOID)dwPatchPlace,
                       &Opcode_JNZ,
                       1,
                       NULL );

VirtualProtect( (LPVOID)dwPatchPlace,
                   1,
                   dwOldProtect,
                   &dwOldProtect );
}

//
inline void UnPatch(){//Función restauradora

if(*(PBYTE)dwPatchPlace!=Opcode_JNZ) return;

DWORD dwOldProtect;
   VirtualProtect( (LPVOID)dwPatchPlace,
                   1,
                   PAGE_EXECUTE_WRITECOPY,
                   &dwOldProtect );

WriteProcessMemory( GetCurrentProcess(),
                       (LPVOID)dwPatchPlace,
                       &Opcode_JZ,
                       1,
                       NULL );

VirtualProtect( (LPVOID)dwPatchPlace,
                   1,
                   dwOldProtect,
                   &dwOldProtect );
}

////////////////////

void Target(){//Función objetivo para ser alterada

while(1){

#define MASTERNUM 85
int master=0x99999997;
char* ingreso = new char[256];

system("cls");
printf("Ingrese la llave maestra\n");
scanf("%s", ingreso);

if(!strcmpi(ingreso, new char[]= "key85\0")){

master = 85;
}

delete []ingreso;
if(master==MASTERNUM)//Aquí es donde queremos entrar XD
{
printf("FELICITACIONES! USTED HA INGRESADO\n");
printf("\n");
system("pause");
break;
}

// if(GetAsyncKeyState(VK_END)) break;// En otro hilo
if(!strcmpi(ingreso, new char[]= "exit\0")) break;
}
}

//
void Check()//Función que representa un método de seguridad
{
if(*(PBYTE)dwPatchPlace != Opcode_JZ)
{
printf("0x%X\n",*(PBYTE)dwPatchPlace);
printf("Memoria alterada!, se sale del programa..\n");
printf("\n");
system("pause");
ExitProcess(45);
}
}

/////////

int main(){

// We have to replace JZ with JNZ.

dwPatchPlace=(DWORD)GetModuleHandle(NULL);//Retorna la BaseAddress

//Sumamos el offset obtenido del desensamblado
dwPatchPlace+=0x00001000;
dwPatchPlace+=0x6C;

//Logs
printf("0x%X\n",(DWORD)GetModuleHandle(NULL));
printf("0x%X\n",dwPatchPlace);
printf("0x%X\n",*(PBYTE)dwPatchPlace);
printf("\n");
system("pause");

//Parcheamos la memoria antes de llamar a la función
Patch();

//Llamamos a la función objetivo
Target();

//Volvemos a dejar la memoria como estaba antes
// UnPatch();

//Se deja que las comprobaciones de seguridad sigan su curso normalmente
Check();

return 0;
}


Unas imágenes, aunque voy a dejar el proyecto para descargar.


La llamada a UnPatch() está comentada, por eso la detección se dispara..


Un comentario acerca del uso de WriteProcessMemory, no es necesario,,
ya que con simplemente hacer esto:
*(PBYTE)dwPatchPlace= Opcode_JNZ;
es suficiente, ya que es un mismo proceso.
lo que pasa que ambas funciones fueron sacadas de un post de un tal Organner, que algunos deben saber quien es, sólo les cambié una cosa y listo, aunque tampoco son algo especial como para que deban tener un autor XD

Proyecto MSVC6
http://www.mediafire.com/?j7s6a85bp4k5p3t

Este tutorial está orientado a gente principiante en la programación, no sea considerado un tutorial avanzado  ;D

Hasta Luego
Me cerraron el Windows Live Spaces, entonces me creé un WordPress XD
http://etkboyscout.wordpress.com/

x64core

Ten el habito de usar las retornos de las funciones, por algo están.  ::)

85

#2
si gracias, VirtualProtect y WriteProcessMemory deben comprobarse.. usando incluso GetLastError en caso de excepción , para obtener información.

atte

Me cerraron el Windows Live Spaces, entonces me creé un WordPress XD
http://etkboyscout.wordpress.com/