No puedes implementar esto de manera efectiva.
Se está encontrando en lo que generalmente se conoce como el "problema DRM": el código que se ejecuta en una plataforma informática de propósito general siempre puede ser subvertido o modificado por el propietario de ese sistema. Su código ya no es su código cuando se ejecuta en un sistema de usuario.
Diseñar este tipo de sistemas anti-dumping, anti-inyección, anti-modificación, anti-depuración, anti-cracking, anti-reversible, anti-emulación, anti-lo que sea que más te sientas, es un proceso continuo. Campo de investigación y esfuerzo comercial. Hasta ahora nadie ha sido capaz de producir una protección incomparable. Ha habido casos en los que la protección de ruptura fue particularmente difícil, pero todos los esquemas se rompieron de alguna manera, incluso en el caso de que se usó hardware especializado (ver: HDCP , PS3 LV0 keys )
La discusión de lo que se puede hacer para dificultar las cosas para alguien que intente subvertir su programa podría abarcar todo un libro, pero aquí hay un resumen de los trucos en una plataforma Windows:
- trucos anti-análisis tales como:
- Compresión o cifrado de código (embalaje)
- Máquinas virtuales (implementar un emulador de procesador personalizado, escribir código para eso)
- ofuscación de flujo de control
- Cadena y ofuscación de datos
- código falso
- Modificación del código de tiempo de ejecución
- trucos anti-depuración como:
- Ejecución temprana de código (pre-EntryPoint) mediante devoluciones de llamada TLS.
- Comparaciones de tiempo de ejecución utilizando
rdtsc
o GetTickCount
.
- Verificaciones directas del depurador (indicadores PEB,
IsDebuggerPresent
, etc.)
- Explotación de vulnerabilidades en depuradores comunes (por ejemplo, OllyDbg
OutputDebugString
bug)
- Detección de depuradores y herramientas comunes mediante nombres de procesos, nombres de ventanas, clases de ventanas, exclusión mutua y otros objetos, controladores, presencia de archivos
- Al inyectar el depurador se comprueba en otros procesos (por ejemplo, el explorador) para evitar que se identifiquen.
- Un sinfín de otros ...
- trucos anti-modificación tales como:
- Sumas de comprobación en tiempo de ejecución de códigos y datos críticos
- Instantáneas de datos críticos para su posterior verificación
- Cifrado de memoria utilizando
CryptProtectMemory
API.
- Mover operaciones críticas al kernel (usando un controlador) para dificultar que un usuario manipule el código.
- Detección de VM (de nuevo se pueden escribir libros enteros sobre esto)
- Conectar las API comunes en todos los procesos (ya sea en modo de usuario mediante inyección DLL, o en el kernel) para rechazar o manipular las llamadas que intentan acceder a su proceso.
- Trucos anti-rastreo que utilizan puntos de interrupción de software y controladores de excepciones.
- Fortalecimiento general de la seguridad, como habilitar NX + ASLR + ForceIntegrity, más políticas de mitigación lo que puede dificultar que el software acceda al proceso o inyecte DLL.
Incluso si implementó todas las funciones de esta lista, todo se puede omitir con algún trabajo.
Es importante tener en cuenta que .NET en sí no tiene necesariamente una debilidad real para ser editado en memoria que los ejecutables nativos (por ejemplo, C, C ++) no. Lo que hace que .NET sea más fácil de atacar en general es que las instrucciones y metadatos del lenguaje intermedio (IL) que contiene pueden ser más fácilmente revertidos y convertidos en algo comprensible para el ser humano, mientras que los ejecutables nativos tienen más opciones para la ofuscación y los trucos antiinversión. t contienen tales metadatos. El artículo que vinculó simplemente muestra una forma de utilizar la reflexión para obtener acceso a la variable en lugar de un enfoque más nativo que funcionaría igual de bien.