En el primer artículo de esta seríe describí las funciones RegOpenKeyEx y RegCloseKey, así como la forma de interpretarlas, básicamente, desde la herramienta de Process Monitor. En esta nueva entrega me concentraré exclusivamente a la función RegCreateKeyEx, puesto que es un poco más completa de comprender cuando estamos haciendo diagnóstico.
RegCreateKeyEx
La operación principal de esta función, perteneciente a la API de Windows, consiste en crear una subclave de registro; en caso de que la subclave ya exista, la función la abre para utilizarla posteriormente. Ahora, tomando de ejemplo la subclave HKEY_CURRENT_USER\WinSide, la siguiente gráfica explica la definición que acabo de dar:
HKEY_CURRENT_USER o su abreviación, HKCU, como lo dije en el primer artículo de esta serie, es una clave raíz; aunque WinSide es la verdadera subclave, se le puede llamar también subclave a todo el conjunto, es decir, HKEY_CURRENT_USER\WinSide.
Teniendo en cuenta la misma subclave de ejemplo, HKCU\WinSide, analicemos un poco el código que podríamos escribir en C/C++ con la API. Estas son las variables que requiere la función:
//RegCreateKeyEx
HKEY hKey = HKEY_CURRENT_USER;
LPCWSTR subKey = L»WinSide»;
DWORD reserved = 0;
LPWSTR classType = NULL;
DWORD options = REG_OPTION_NON_VOLATILE;
REGSAM samDesired = KEY_WRITE;
LPSECURITY_ATTRIBUTES securityAttributes = NULL;
HKEY createdKey;
DWORD disposition;
La variable hKey contiene la clave raíz que pudo ser abierta por alguna función como RegOpenKeyEx o, como en este caso, una de las claves raíces que tiene el registro de Windows; la variable de subKey es un apuntador al nombre de la subclave que deseamos abrir o crear, en este caso WinSide; reserved es una variable reservada por el sistema y siempre debe ser cero; classType es el tipo de clase definida para la clave, pero puede ser NULL; la variable options me permite indicar diferentes comportamientos que puede tener la subclave, en el caso de REG_OPTION_NON_VOLATILE, le indica a Windows que la información almacenada se conserva después del reinicio; samDesired indica los derechos de acceso para la subclave, es decir, qué quiero hacer; la variable de securityAttributes almacena los atributos de seguridad, pero al darle NULL la subclave obtiene los predeterminados; createdKey va a tener el handle de la subclave abierta o creada; y disposition me indicará si la sublcave existía y se abrio o no existía y se creó.
Para poder ilustrar lo que Process Monitor captura, invocaré a la función RegCreateKeyEx para que abra o cree la subclave:
/* Función para crear o abrir la subclave
HKEY_CURRENT_USER\WinSide */
LONG createKey = RegCreateKeyEx(hKey, subKey, reserved,
classType, options, samDesired,
securityAttributes, &createdKey, &disposition);
La variable createKey recibirá el código de error devuelto por el manejador de errores de Windows; yo puedo utilizar una función adicional para traducir eso a texto, pero obtaré por lo más sencillo que es validar si es satisfactorio o si es necesario mostrar el código de error, así:
if (createKey != ERROR_SUCCESS)
{
wprintf(L»Error opening the key. Code: %li\n», createKey);
}
else
{
wprintf(L»Subkey was opened or created!\n»);
}
Por supuesto, yo podría darle un poco más de estilo y aprovechar el valor retornado por disposition: es REG_CREATED_NEW_KEY si Windows creó la clave desde cero o REG_OPENED_EXISTING_KEY si la clave ya existía y solo se abrió. Nada más útil que llamar al condicional switch.
switch (disposition)
{
case REG_CREATED_NEW_KEY:
wprintf(L»Key did not existed and was created\n»);
break;
case REG_OPENED_EXISTING_KEY:
wprintf(L»Key existed and was just opened\n»);
break;
default:
wprintf(L»Unkown value\n»);
break;
}
El código de toda la validación se vería así:
if (createKey != ERROR_SUCCESS)
{
wprintf(L»Error opening the key. Code: %li\n», createKey);
}
else
{
switch (disposition)
{
case REG_CREATED_NEW_KEY: //Key was created
wprintf(L»Key did not existed and was created\n»);
break;
case REG_OPENED_EXISTING_KEY: //Key was opened
wprintf(L»Key existed and was just opened\n»);
break;
default:
wprintf(L»Unkown value\n»);
break;
}
//Do not forget to close the handle!
RegCloseKey(createdKey);
}
De esta forma la consola mostrará el mensaje adecuado según se haya creado o abierto la subclave.
Aquí pueden ver la documentación oficial de RegCreateKeyEx:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724844(v=vs.85).aspx
Process Monitor en acción
Empecemos por ver cómo nos muestra Process Monitor las operaciones que se hagan sobre la subclave HKCU\WinSide, para eso basta con filtrar por ruta y proceso de la aplicación, así:
Al ejecutar la aplicación, sin que esté la subclave creada, la validación se va por el REG_CREATED_NEW_KEY y me muestra el mensaje correspondiente:
¿Qué pasa en Process Monitor? Esto es lo que me muestra después de mostrado el mensaje:
La primera operación que hay listada es RegCreateKey, que corresponde a la que en código tengo como RegCreateKeyEx, está trabajando sobre el Path de HKCU\WinSide, handle que abrió o creó, según sea la disposición. El resultado, como también pueden ver fue SUCCESS, lo que indica que la operación se completó sin problemas y, finalmente, la columna de Detail me da datos importantes como el Desired Access (derechos de acceso solicitados) y Disposition (que me indica si la clave se creó o se abrió).
Después de estas operaciones, vemos que RegCloseKey se encarga de hacer la operación sobre la misma subclave, HKCU\WinSide, para cerrar el handle, es decir, terminar lo que se está haciendo sobre la subclave.
Noten que aunque yo conozco el código, los datos extraídos son todos desde Process Monitor, así que no necesitaría el código para saber qué pretende hacer la aplicación efectuando esa operación. Como datos adicionales, puedo entrar a las propiedades de la operación haciendo doble clic, pestaña de Process y ver detalles más completos:
Integrity me indica el nivel de integridad en el que se está ejecutando el proceso, que en este caso es Medium, como cada proceso de usuario estándar; Architecture me indica, como su nombre en inglés lo dice, la arquitectura de la aplicación, que en este caso es 32-bit, por lo que en algún punto está actuando también la capa de emulación de WOW64.
Si vamos a la pestaña de Stack, podremos ver detalles de toda la transición entre User Mode y Kernel Mode, información bastante completa para alguien que entienda de Windows Internals. Una de las cosas que se puede identificar, por ejemplo, es que puedo ver que a la función exacta que se llama es RegCreateKeyExW (el W al final indica que se compiló como Unicode).
Nota: para ver claramente esto, es necesario que Process Monitor tenga configurado los símbolos.
Aunque desde la vista general de Process Monitor puedo ver los detalles, también está disponible la pestaña de Event en donde tengo todo el resumen:
Es importante anotar que así en el código de la aplicación el valor de disposition sea NULL, Process Monitor podrá mostrarlo y así sabremos, a ciencia cierta, si la clave se abrió o se creó. Por ejempo, si yo ejecuto otra vez la misma aplicación de muestra, pero esta vez sin indicarle el disposition, puedo el resultado será el mismo:
Debido a que la subclave ya existía, puedo concluir, gracias al detalle de Process Monitor (Disposition: REG_OPENED_EXISTING_KEY), que Windows abrió la clave sin necesidad de crearla otra vez.
Una característica particular que tiene las llamadas a la API es que puedo crear más de una subclave de una vez. Por ejemplo, si en el código que mostré en este artículo quisiera abrir o crear la subclave HKCU\WinSide\Learning\Internals, bastaría con indicarle a la variable subKey todo el árbol, así:
LPCWSTR subKey = L»WinSide\\Learning\\Internals»;
Nota: el doble signo de ‘\’ es para indicarle que deseamos poner una barra inversa y no una secuencia de escape.
Después de esto, solo es necesario ejecutarlo y esperar el resultado. El mensaje que nos devolverá será para toda la subclave y no para cada una individualmente.
En Process Monitor, sin embargo, podremos ver todo el proceso:
Lo primero que intenta hacer la aplicación es abrir la subclave HKCU\WinSide\Learning\Internals; como la clave no existe, empieza a hacer todo el procedimiento de abrir o crear desde la primera subclave, WinSide, hasta la última subclave, Internals. Noten que cada subclave se va cerrando después de pasar el handle a la otra. Cuando termina toda la operación hasta Internals, todos los handles se cierran y el resultado es nuestra subclave creada:
Desde Process Monitor, entonces, podemos identificar cuál es la subclave final desde antes de que la aplicación la cree y hacer un seguimiento detallado de cada subclave.
Espero que esto les pueda servir tanto como a mi me está sirviendo para aprender. Intentaré mejorar cada vez más las entradas, conforme vaya aprendiendo yo; además, es posible que toque otras funciones, sea de registro o de sistema de archivos.
P.D.: cualquier comentario o corrección es bienvenido.
Saludos,
—Checho