No se si seas programador o no, pero... escáneres de memoria como el CE simplemente hacen el llamado a APIs nativas del sistema para leer datos en un proceso externo.
En el caso del CE, en modo usuario sí se puede lograr, y no solo desde el CE, sino de cualquier aplicación hecha en un lenguaje de programación que tenga acceso a la API de Windows, desde C++ hasta VB6, etc... algunos lenguajes son más eficientes que otros para este tema, aquí gana la batalla C/C++.
Y... por otro lado, el Cheat Engine sí es open source, Dark Byte (Creador del CE) acostumbra a publicar el código del CE cada cierto tiempo, se ha tardado un poco con el código fuente del CE 6.1 (Que raro...
) pero códigos fuente de versiones anteriores están publicados en su página web oficial.
Ahora, para ser un poco más específicos, lo que el CE hace para poder "acceder" a la memoria de otros procesos, es simplemente un llamado a la API de Windows llamada: ReadProcessMemory (Muy intuitivo su nombre), la cual según definición:
BOOL WINAPI ReadProcessMemory(
__in HANDLE hProcess,
__in LPCVOID lpBaseAddress,
__out LPVOID lpBuffer,
__in SIZE_T nSize,
__out SIZE_T *lpNumberOfBytesRead
);
Dónde sus parámetros serían:
hProcess [Entrante]: Un handle (manejador) del proceso al cual será leída su memoria, éste debe poseer el acceso "PROCESS_VM_READ" para poder ser leído, tal acceso se otorga con otra API de la que luego hablaremos.
lpBaseAddress [Entrante]: Un puntero o dirección dirección en memoria del proceso a ser leído. Antes de la transferencia de datos, el sistema verifica que todos los datos en la dirección de memoria o puntero con el tamaño indicado, sean accesibles para su lectura, en caso contrario, la función fallaría.
lpBuffer [Saliente]: Un puntero a una variable temporal de datos (buffer) que recibirá el contenido del tamaño de memoria leído en la dirección especificada del proceso.
nSize [Entrante]: El número de bytes a ser leídos en el proceso especificado.
lpNumberOfBytesRead [Saliente]: Un puntero a una variable que recibe el número de bytes transferidos dentro del buffer especificado. Si su valor es NULL, éste parámetro es ignorado.
Si la función tiene éxito, el valor de retorno es TRUE, o no-cero.
Si la función falla, el valor de retorno es FALSE, o cero. (Para obtener una información extendida del error, haz una llamada a
GetLastError.)
La función falla si la operación solicitada de lectura cruza a un área de memoria del proceso que es inaccesible.
ReadProcessMemory API: Copia los datos leídos de un rango especificado de direcciones desde el espacio de direcciones del proceso especificado a la variable temporal (buffer) del proceso actual. Cualquier proceso que posea el manejador (handle) con el tipo de acceso PROCESS_VM_READ puede llamar la función con éxito.
Toda el área a ser leída debe ser accesible, en caso contrario la función falla.
Partiendo de ésto, podemos suponer (y comprobar revisando su código fuente) que el CE simplemente da acceso al handle (manejador) del proceso a leer datos en memoria y procede a iniciar un bucle desde la dirección 0x00000000 hasta 0xFFFFFFFF (o en el rango que el usuario establezca) leyendo cada una de estas direcciones en el tamaño especificado según el tipo de dato elegido por el usuario, en el caso de un entero el bucle tendría que leer 4 bytes de cada dirección, hacer una conversión y comprobar si el resultado concuerda con el valor introducido por el usuario, en caso contrario, ignorar esa dirección y seguir a la próxima.
Lógicamente, éste bucle debe hacer comprobaciones para cada área de memoria, si es inaccesible, entonces saltarse a la próxima, etc. Son simples trucos para agilizar el tiempo de escaneo, que la mente de cada programador brille aquí.
Cabe destacar que la API usada para establecer el tipo de acceso a un handle (manejador) es: OpenProcess, la cual puedes buscar su definición en google junto a sus parámetros y valor de retorno.
Saliéndonos un poco del tema, actualmente estoy desarrollando una aplicación similar al CE (No tan poderosa, pero indetectable), es un escáner de memoria pero aún no lo he terminado, es demasiado grande para terminarse en tan poco tiempo
...
Volviéndo al tema: Esto que he dicho, no es más que una introducción a lo que hace el CE en sí, en ello se basa, pero... se debe tener mucho más cuidado, ya que existen hooks a modo usuario y modo kernel que te pueden o no prohibir el acceso a la memoria de un proceso específico. Por supuesto, el CE 6.1 a parte de tener su propio controlador, el cual se encarga de brindarle al CE acceso a la mayoría de procesos protegidos y no protegidos está compilado actualmente en Lazarus, las versiones 5.X y anteriores fueron compiladas en Delphi donde luego, a partir de la versión 6 mudaron a Lazarus. Por tal, si quieres revisar el código fuente del CE 5.1 (Creo que es el último publicado) para aprender como funciona, deberás usar Delphi para analizarle a fondo.
Como notas, es un tema con mucha tela para cortar, demasiados temas abundan en el manejo de memoria de Windows, es para tomárselo con calma
... si tienes alguna duda, publicala aquí mismo, si en mi corto conocimiento está, te daré una mano, que si no... otros usuarios pueden ayudar.
Salud.
P.D.: Disculpas por revivir un tema de hace un mes de inactividad, pero... no había visto esta pregunta, y como el tema me gusta y me desenvuelvo un tanto bien en él, decidí aportar algo.