Tu pregunta es muy amplia. Puedo contarte cómo yo hice en un caso, por diversión, en un pequeño juego de arcade hace varios años. Esto debería hacer que adquieras cierta perspectiva educativa, pero no te ayudará mucho, de lo contrario, me temo.
Simplemente tuve otro programa ejecutándose en segundo plano, explorando la memoria del juego de arcade.
Empecé a jugar, y luego perdí una vida. Presione ambas teclas de mayúsculas y se guardó una instantánea de la memoria en el disco sin que lo supiera la arcada en ejecución. Luego otro. BAM otra instantánea. Un tercero, y un cuarto. Y luego el juego terminó y salí del juego de arcade.
Luego comparé las instantáneas, buscando una ubicación de memoria que cambiara de una instantánea a la siguiente, ya sea aumentando o disminuyendo exactamente una. Recuerdo haber encontrado unos veinte de ellos. Podría haberlos comprobado todos, pero descubrí inmediatamente que uno de ellos, y solo uno, tenía un valor de "cinco" al comienzo del juego y se convirtió en "cuatro" en mi primera muerte. Y yo había comenzado con cinco barcos. Ahora eso es interesante ...
Así que escribí un pequeño programa que buscaría esa dirección de memoria, reconociéndolo por su distancia de otras piezas de código y cadenas que no cambió, verificando su valor cada pocos segundos, y solo retrocediendo "5" en él tan pronto como se convirtió en algo menos:
: install
look for string 'COPYRIGHT ACME GAMES'
add 1138
is it a five?
no, abort, something went wrong
yes. lie in wait.
: wait
is it still a five?
no. Set it to five.
sleep for a couple of seconds
goto wait
Efectivamente, en el próximo juego, morí, y un instante después, mis cuatro naves espaciales restantes se convirtieron en cinco de nuevo. Por el gusto de hacerlo, descubrí que podía obtener hasta siete 'vidas' con este método (ocho bloquearon el juego).
Al utilizar un "depurador", también habría sido posible detener el programa tan pronto como se modificó la ubicación, para ver qué instrucción había realizado la escritura. Entonces simplemente borrarías esa instrucción del código del ensamblador. O puede seguir el flujo del programa a la inversa y descubrir dónde, por ejemplo, se realizó el control de colisión entre el sprite de su jugador y los misiles enemigos. Deshazte de ese control, y los misiles enemigos ya no te afectarán (posiblemente, el tuyo ya no los afectará; es un asunto delicado).
Espero que las técnicas hayan madurado y progresado mucho en estos años, pero confío en que, básicamente, la idea sigue siendo la misma: detecte el cambio que no le gusta, luego defang el código que lo está causando, o parche el código para deshacer el daño tan pronto como ocurra.
Para hacer las cosas más difíciles, se podrían idear estrategias para hacer que los cambios se destaquen menos o que parezcan aleatorios. Agregue variables "chaff" o "dummy" que cambian como si fueran útiles. Utilícelos como indicadores: si todas las variables no coinciden, significa que alguien está intentando piratear.
Al final, sin embargo, no puedes vencer a un hacker determinado y experimentado. Todo lo que puedes hacer es intentar que el hecho no valga la pena. Hay ofuscadores de código, protectores de código, encriptadores de código, detectores de depuración, técnicas de anti-virtualización ...