El cracking es el proceso de analizar y modificar software para eliminar o evitar ciertas restricciones, como:
Tipo | Descripción |
---|---|
Keygen | Crear generadores de claves válidas |
Patch | Modificar el ejecutable para saltarse protecciones |
Loader | Cargar el programa en memoria y modificar su comportamiento |
Reverse Engineering | Ingeniería inversa para entender el funcionamiento |
El ensamblador es crucial para entender cómo funciona un programa a bajo nivel.
EAX/RAX: Acumulador (resultados de operaciones) EBX/RBX: Base (puntero a datos) ECX/RCX: Contador (bucles) EDX/RDX: Datos (extensión para operaciones) ESI/RSI: Índice fuente (operaciones con cadenas) EDI/RDI: Índice destino (operaciones con cadenas) ESP/RSP: Puntero de pila EBP/RBP: Puntero de base EIP/RIP: Puntero de instrucción
MOV dest, src ; Mueve datos de src a dest PUSH valor ; Empuja valor en la pila POP dest ; Saca valor de la pila a dest CALL dirección ; Llama a una función/subrutina RET ; Retorna de una función JMP dirección ; Salto incondicional JE/JZ dirección ; Salto si igual/cero JNE/JNZ dirección ; Salto si no igual/no cero CMP op1, op2 ; Compara dos operandos TEST op1, op2 ; Operación AND bit a bit (sin guardar) ADD dest, src ; Suma SUB dest, src ; Resta NOP ; No operation (90 en x86)
; Supongamos que encontramos esta rutina de validación 00401234 MOV EAX, [ESP+4] ; Carga el serial ingresado 00401238 CALL 00401500 ; Llama a la función de validación 0040123D TEST EAX, EAX ; Comprueba el resultado 0040123F JZ 00401250 ; Salta si es cero (serial incorrecto) 00401241 MOV DWORD [ESP], 00403000 ; "Registro exitoso" 00401248 CALL MessageBoxA 0040124D JMP 00401260 00401250 MOV DWORD [ESP], 00403020 ; "Serial incorrecto" 00401257 CALL MessageBoxA 0040125C JMP 00401260 ; Para crackear, podemos: ; 1. Cambiar JZ a JMP (salto incondicional) ; Original: 74 0F (JZ +15) ; Modificado: EB 0F (JMP +15) ; 2. O cambiar TEST EAX,EAX a XOR EAX,EAX (siempre cero) ; Original: 85 C0 ; Modificado: 31 C0
Los ejecutables .NET son más fáciles de analizar ya que contienen metadatos y MSIL (Microsoft Intermediate Language).
// Código original en C# public bool ValidateLicense(string key) { if (key == null) return false; return key == "VALID-KEY-12345"; } // IL original .method public hidebysig instance bool ValidateLicense(string key) cil managed { ldarg.1 brfalse.s IL_0012 ldarg.1 ldstr "VALID-KEY-12345" call bool [mscorlib]System.String::op_Equality(string, string) ret IL_0012: ldc.i4.0 ret } // Para crackear, podemos modificar el IL para que siempre retorne true: .method public hidebysig instance bool ValidateLicense(string key) cil managed { ldc.i4.1 // Carga 1 (true) en la pila ret // Retorna }
Los archivos JAR y WAR son básicamente archivos ZIP que contienen clases Java compiladas.
// Código original decompilado public class LicenseChecker { public boolean isValid(String key) { return "SECRETKEY".equals(key); } } // Para crackear, podemos: // 1. Modificar el método para que siempre retorne true public boolean isValid(String key) { return true; } // 2. O cambiar la clave hardcodeada public boolean isValid(String key) { return "MYCRACKEDKEY".equals(key); }
Las APKs son paquetes Android que contienen código DEX (Dalvik Executable).
# Método original en smali .method public isValidLicense(Ljava/lang/String;)Z .locals 1 const-string v0, "SECRET_KEY" invoke-virtual {v0, p1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 return v0 .end method # Modificado para siempre retornar true .method public isValidLicense(Ljava/lang/String;)Z .locals 1 const/4 v0, 0x1 return v0 .end method
Protección | Técnica de Bypass |
---|---|
Checksum | Parchear la rutina de verificación o modificar los valores esperados |
Debugger Detection | NOPear las llamadas a IsDebuggerPresent o patchear las APIs |
VM Detection | Modificar las comprobaciones de entornos virtuales |
Code Obfuscation | Usar herramientas de deofuscación o análisis dinámico |
Packing | Dumpear el proceso después de que se descomprima en memoria |
Crear un generador de claves válidas requiere entender el algoritmo de validación:
// Algoritmo simple de validación bool ValidateKey(char* key) { if (strlen(key) != 10) return false; int sum = 0; for (int i = 0; i < 10; i++) { sum += key[i] * (i + 1); } return (sum % 0x1A) == 0; } // Keygen correspondiente void GenerateKey() { char key[11] = {0}; int sum = 0; // Generar 9 caracteres aleatorios for (int i = 0; i < 9; i++) { key[i] = 'A' + (rand() % 26); sum += key[i] * (i + 1); } // Calcular el último carácter para que (sum % 26) == 0 int last_char_weight = 10; int required = (26 - (sum % 26)) % 26; key[9] = 'A' + (required / last_char_weight); printf("Key generada: %s\n", key); }
Conociendo cómo se crackea el software, puedes proteger mejor tus aplicaciones:
// Detección simple de debugger en C bool IsDebuggerPresentSimple() { return IsDebuggerPresent(); } // Técnica más avanzada usando el flag BeingDebugged en PEB bool IsDebuggerPresentAdvanced() { #ifdef _WIN64 PPEB pPeb = (PPEB)__readgsqword(0x60); #else PPEB pPeb = (PPEB)__readfsdword(0x30); #endif return pPeb->BeingDebugged; } // Técnica de timing attack bool IsDebuggerPresentTiming() { DWORD start = GetTickCount(); // Operación que debería ser rápida volatile int sum = 0; for (int i = 0; i < 1000000; i++) { sum += i; } DWORD end = GetTickCount(); // Si el tiempo es demasiado largo, probablemente hay un debugger return (end - start) > 100; }
El cracking es un campo complejo que requiere conocimientos de programación, sistemas operativos y arquitectura de computadoras. Este manual cubre los fundamentos, pero la práctica constante es esencial para dominar estas técnicas.