Extraer el Paquete de Lenguaje desde Windows Update y cambiar el idioma para mostrar en Windows 8 manualmente

1537_Win8Logo_01_008485DD

Desde versiones atrás de Windows, existen los Paquetes de Idioma, que contienen una serie de recursos necesarios para poder localizar la Interfaz de Usuario (UI) en un idioma específico. Esto por supuesto ha brindado flexibilidad a las compañías a la hora de implementar Windows, pues es relativamente sencillo y tiene varios caminos la forma en que se puede implementar un idioma diferente al original del sistema operativo. El problema hasta Windows 7, es que solo en ediciones Enterprise y Ultimate se podía descargar un Paquete de Lenguajes desde Windows Update, y la única forma de tenerlo offline, era a través de algún modelo de licencias por volumen, o Suscripción MSDN / TechNet. Además, ediciones inferiores a Ultimate y Enterprise, no aceptaban cambio dinámico ni con el Paquete de Lenguaje y la única era haciéndolo a través de línea de comandos con DISM.

Uno de los cambios más favorables de Windows 8 respecto a esto, es que ahora cualquier edición, exceptuando la SL puede hacer el cambio de idioma para mostrar por medio de Windows Update, así que solo es necesario tener una conexión a internet, agregar el método de entrada deseado en el teclado y si hay un idioma disponible, Windows lo notificará para hacer descarga:

L4

Para ver el paso a paso, consulten el siguiente artículo que escribí hace varios meses ya en la página de Fermu.com:
http://www.fermu.com/es/articulos/windows/articulos-y-tutoriales/819-cambiar-el-idioma-para-mostrar-en-windows-8

También sigue existiendo los Paquetes de Lenguajes, pero aún sólo a través de Licenciamiento por Volumen o Suscripción. La pregunta que me hice en este punto fue:
¿Qué puedo hacer si en un entorno empresarial no tengo acceso a la descarga, y deseo implementar un paquete de forma offline?

Utilizando Process Monitor y aprovechando un poco de la amabilidad de Windows Update, en lo que resta del artículo mostraré cómo podemos obtener fácilmente el Paquete de Lenguaje deseado por medio de las Actualizaciones y posteriormente usarlo para implementarlo en nuestro sistema con DISM.

Adquiriendo el Paquete de Idioma a por medio de Windows Update

El primer paso consiste en Configurar el teclado y Preferencias de Lenguaje para seleccionar el idioma deseado y llegar hasta el punto donde se le indica descargar el idioma. Antes de eso, hay que poner a monitorear el equipo con Process Monitor y empezar la descarga:

L6

Es necesario esperar a que la descarga se complemente con todo su peso indicando desde el asistente. Al terminar, volvemos a Process Monitor, paramos la ejecución, y buscamos referencias a .cab que es la extensión de los paquetes de lenguaje, o si sabemos parte del nombre, como ESN (Para español) lo hacemos de la misma forma.

Si se puso desde el momento que era, verán que Process Monitor reportará una operación de escritura sobre el directorio de C:WindowsSoftwareDistributionDownload con el nombre del paquete descargado, al principio probablemente con resultado de NAME NOT FOUND, pero posteriormente con SUCCESS:

image

El nombre debe el formato de Windows8-KB2607607-<Arq>-<Lang>.cab donde <Arq> se refiere a la arquitectura del equipo (32 o 64 bits) y <Lang> al idioma que se está descargando. Por ejemplo, en mi caso que era para 64 bits y en Español, sería así:

image

La única parte fija del directorio, es C:WindowsSoftwareDistributionDownload y el resto será un nombre temporal para el directorio en el que reside el paquete.

El otro camino es muchísimo más fácil, y consiste en dejar descargar también el paquete, es decir, hasta que notifique que lo empezará a instalar, cancelar, navegar hasta el directorio: C:WindowsSoftwareDistributionDownload y utilizar el Explorador de Archivos para buscar todo lo que termine en .cab. El siguiente paso es solo reconocer el nombre de nuestro paquete y copiarlo a otro directorio:

L7

El peso del archivo debe ser alrededor de 105 MB.

Para el próximo paso, por facilidad recomiendo renombrar el paquete con algo sencillo como “lp.cab” y copiarlo a un directorio como la unidad C:

Implementando el paquete

Después de tener el paquete y ubicarlo en un directorio adecuado y de fácil acceso, procederemos a inyectar el Paquete oficial de Lenguaje haciendo lo siguiente:

1. Desde la Pantalla de Inicio, buscamos CMD, clic derecho y Ejecutar como Administrador. Esto abrirá el Símbolo del Sistema con privilegios elevados.

2. Digitar:

Dism /Online /Add-Package /PackagePath:<Dir>lp.cab

Donde <Dir> hace referencia a la ubicación del Paquete de Lenguaje extraído de la carpeta Download en los pasos anteriores. Para mi caso, que lo dejé en la unidad de Windows, sería:

Dism /Online /Add-Package /PackagePath:C:lp.cab

image

3. Es necesario verificar que el Paquete de Lenguaje haya quedado instalado, para esto, basta con ejecutar desde la misma consola:

Dism /Online /Get-Intl

image

Notarán que el idioma que se muestra de forma predeterminada en la Interfaz de Usuario, para este caso es en-US, correspondiente a inglés, pero debe aparecer el idioma adicional (para mi caso Español) que se instaló en la parte inferior.

4. Es necesario ahora reiniciar el sistema para que Windows sea notificado de los cambios, y ahora tenga disponible desde las opciones del idioma el enlace para hacerlo el primario:

image

Nota: Se puede establecer un lenguaje predeterminado desde DISM también, pero esto requiere que la imagen no esté online y además se le tendría que hacer el procedimiento de monte y desmonte. Veré si puedo cubrir esto en otro artículo.

Espero les sirva.

PD. No olviden seguirme en Twitter: https://twitter.com/secalderonr

Checho

El archivo “Comdlg32.ocx” no registrado para ejecutar la aplicación, Process Monitor, Regsvr32 y su solución

Tal cual mostraré en el problema de hoy, se ven muchos casos similares dentro de las empresas con aplicaciones que están hechas a la medida, y vitales para el negocio, sobre todo en los procesos normales que hacen las compañías con respecto a la Compatibilidad de Aplicaciones sobre una nueva versión del sistema operativo. Aunque el caso lo expondré sobre una aplicación que no marca trascendencia, decidí exponerlo para mostrar algunos detalles importantes y válidos para cuando alguna vez lo enfrenten.

El problema y su causa

El inconveniente lo traigo – como en muchas ocasiones – de un hilo abierto en los Foros de Windows 8 en Microsoft Community. Básicamente, un usuario estaba intentando ejecutar una aplicación llamada Pokémon Gold Sprite Editor que realiza un tipo de modificación sobre algunos ROMs del famoso juego de Pokemon, pero estaba recibiendo el siguiente mensaje de error:

image

Inglés:Component ‘COMDLG32.OCX’ or one of its dependencies not correctly registered: a file is missing or invalid

Español:El componente ‘COMDLG32.OCX’ o alguna de sus dependencias no está registrada correctamente: archivo perdido o inválido

Como ven, el ejecutable estaba dependiendo de una OCX que normalmente no aparece en Windows 8, y por tanto no se podía seguir, solo aceptar para cerrarse. Este tipo de errores suele verse mucho con aplicaciones que están escritas en Visual Basic 6, y por lo general es durante el proceso de instalación, aunque es normal que algunos dejen incluso terminar la instalación, pero al momento de abrir algún módulo, presente algún tipo de error no controlado.

Tengamos presentes que los archivos con extensión .OCX son Controles ActiveX que la aplicación requiere tener en el Registro de Windows para funcionar adecuadamente.

Ahora, ¿Dónde se supone que esta aplicación estaba buscando el Control ActiveX? Para saber eso, ejecuté Process Monitor de Sysinternals y lo puse a monitorear mientras ejecutaba, y una vez terminado, busqué dentro de la Traza (CTRL + F) por el nombre de Comdlg32.ocx y esto fue lo que encontré:

PK6

Si analizamos un poco el resultado de Procmon, el ejecutable está tratando de abrir el Control ActiveX COMDLG32.OCX desde distintas partes, empezando por la ubicación original del ejecutable, así como en SysWOW64 que es donde normalmente deben residir estos controles y las respectivas DLLs utilizadas, pero también en otros directorios que Windows puede considerar como locación de referencia. Bastante autosuficiente el sistema operativo.

Para aclarar un poco la razón del por qué Process Monitor muestra la operación como CreateFile, es que si nos vamos a la API de Windows, por lo menos en Registro y Archivos, Antes de pasar a crear algo, la función internamente la busca para ver si ya existe.

Como mencioné, si esto fuera un instalador completo, tal cual debería suceder, o si tuviera embebido el Control ya que tanto lo necesita, podría registrarlo buscándolo en algún directorio fuente, así que para este caso, primero había que buscarlo manualmente desde algún servidor de confianza. Aquí por supuesto entro a decir que es algo bastante riesgoso, pues es muy probable que llegue a tener software malintencionado dependiendo de donde se baje. Con fines de prueba, y para poder encontrar la solución, yo recurrí a un blog de un MVP donde se entregaba la descarga del OCX y aún así, Sigcheck de Sysinternals reportaba como no firmado:

image

Para facilitar el trabajo a la aplicación, tenía el OCX en la misma carpeta de donde se lanzaba, pues ahí lo buscaba de primero. Si se ejecutaba entonces con privilegios estándar, seguía apareciendo el mismo error, pero al ejecutarlo con privilegios elevados (Clic derecho, Ejecutar como Administrador), mi sorpresa fue que la aplicación estaba viva:

image

¿Por qué? Claramente estaba haciendo algo más que buscar y abrir el archivo, así que busqué nuevamente en Process Monitor, y antes que nada iba a reportarla como SUCCESS al tratar de buscarla:

image

Lo interesante es que si iba un poco más adelante en todas las operaciones de CreateFile, viendo el Stack dentro de las Propiedades de la operación, me encontraría con la ejecución de la función DllRegisterServer:

image

No tengo los conocimientos necesarios para reproducir esto programáticamente con la API, o explicar en detalle, pero según la documentación oficial de Microsoft, con esto hace el registro Windows internamente, sea llamado por la respectiva aplicación, o utilizando la herramienta de Regsvr32.exe embebida.

Después de esto, ya podía correr el ejecutable incluso sin permisos administrativos, y abría correctamente. Esto sucedía porque ahora cada vez que se ejecutaba, la OCX había quedado registrada, y ya no la buscaría en su directorio, sino que la referenciaría directamente contra el Registro de Windows:

image

Para este caso, lo hacía específicamente en el valor (Default) ubicado en:

HKCRWow6432NodeCLSID{F9043C85-F6F2-101A-A3C9-08002B2F49FB}InprocServer32

*Nota: WOW64Node es porque es un equipo a 64 bits, y la aplicación es de 32 bits. La ruta normal sería: HKEY_CLASSES_ROOTCLSID

Si veía esto desde el Editor de Registro, me iba a encontrar con que el contenido del valor indicaba la ruta exacta de la OCX:

image

Esto quiere decir, que si esa OCX la eliminaba del directorio desde donde la aplicación la registró, el problema seguiría ocurriendo. Con la falta de la sub-clave InprocServer32, también se reproducía el problema, pero en general es necesaria toda la clave para que esté bien registrada.

¿La solución?

Pues bien, la solución consiste en registrar siempre el OCX de una forma correcta, y con esto me refiero a ubicación y procedimiento, dado el caso que la aplicación no lo haga bien y se presenten este tipo de mensajes.

Lo primero que debemos hacer es pegar el Control ActiveX (.OCX) en la carpeta System32 si es que estamos sobre un sistema operativo de 32 bits (x86), o en la carpeta SysWOW64 para una arquitectura de 64 bits (x64 o AMD64). Ambos directorios están ubicados en la carpeta %SystemDrive%Windows, siendo %SystemDrive% por lo general C:

Para este caso, al ser un sistema de 64 bits, la OCX la pegué en C:WindowsSysWOW64

image

El siguiente paso es abrir un Símbolo del Sistema con privilegios elevados, y desde Windows 8 se puede hacer fácilmente haciendo clic derecho en la parte inferior izquierda de la Barra de Tareas y seleccionar Símbolo del Sistema (Administrador):

PK1

El Símbolo del Sistema nos debe abrir en la ubicación C:WindowsSystem32, y el movernos dependerá de si el OCX se va a registrar en un equipo de 32 o 64 bits, pues si es el primero, la ubicación es la perfecta, pero si no es el caso, debemos digitar:

cd C:WindowsSysWOW64

image

Al asegurarnos estar en el directorio correcto y con la OCX copiada, haremos uso de la herramienta de Regsvr32 embebida en Windows para registrar el Control ActiveX digitando:

regsvr32 Comdlg32.ocx

image

Si el proceso se lleva a cabo correctamente, al presionar ENTER nos debe dar un mensaje con la operación completada sin problemas:

image

Después de esto, nuestra aplicación ejecutará normalmente, sin preocuparnos de nada más, mientras se mantenga la OCX en la ubicación correcta:

P3

PD. No olviden seguirme en Twitter: https://twitter.com/secalderonr

Saludos,

Checho

Explorando la API de Windows en C++: La función RegOpenKeyEx para abrir claves de Registro

TechDays-Figure-with-Laptop_7A06897A

Volviendo a lo que espero sea una larga serie de artículos sobre la API de Windows, hemos visto al detalle ya cómo utilizar las funciones de RegCreateKeyEx para crear una sub-clave de registro y RegSetValueEx para establecer un tipo de valor e indicarle su contenido. Por supuesto, en todas he tocado RegCloseKey para cerrar la operación en la clave o sub-clave de Registro.

Si fuéramos a resumir, ya sabemos crear una sub-clave de registro, utilizar un apuntador para establecer un valor y cerrarla pero falta algo muy importante en el orden natural que debería tener, y es básicamente abrir la clave para funcionar con ella. Aunque Windows ya lo hace de forma nativa sobre las principales claves (HKCU, HKLM, e.t.c), abrir una clave de producto nos facilitará el acceso para escribir directamente un valor, en vez de tener que crear la sub-clave nosotros mismos. A continuación entonces, pasaré a describir de la misma forma cómo debemos declarar las variables de RegOpenKeyEx y para que haya algo de valor, unir esta función con RegCreateKeyEx y RegSetValueEx.

La función RegOpenKeyEx

Para poder utilizar correctamente esta función, es necesario realizar las siguientes declaraciones:

HKEY hKey: Como siempre, aquí se debe declarar un apuntador a una clave que esté abierta. Puede ser retornada por RegCreateKeyEx, o bien utilizar algunas de las que están predefinidas:

HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

LPCTSTR lpSubKey: Aquí en este caso va el nombre de la sub-clave que se va a abrir. En caso de que deseemos utilizar algunas de las claves predefinidas como HKCU, es necesario declararlo como NULL para que no tome la sub-clave.

DWORD ulOptions: Tal cual funciona la variable de Reserved en las anteriores funciones, esta es la equivalente para RegOpenKeyEx, por lo tanto debe ser cero (0).

REGSAM samDesired: Como en todas las otras declaraciones, aquí debemos especificar el acceso que deseamos tener sobre la clave que se va a abrir. Hay que tener presente que como lo indica la documentación, el acceso puede fallar si los descriptores de seguridad que tiene la clave no lo permite.

PHKEY phkResult: Es el apuntador a la variable que va a recibir el apuntador de la clave que se abrió.

Como siempre, en caso de que la operación sea exitosa, se retornará un ERROR_SUCCESS. Es necesario utilizar una variable de tipo long para recibir y funcionar con el resultado.

Ahora, digamos que deseo abrir una sub-clave llamada DemoKey, ubicada en la clave HKCU, es decir: HKEY_CURRENT_USERDemoKey.

La declaración primero que todo sería entonces:

//Declarando variables para RegOpenKeyEx
        HKEY hKey = HKEY_CURRENT_USER;
        LPCTSTR lpSubKey = L"DemoKey";
        DWORD ulOptions = 0;
        REGSAM samDesired = KEY_READ | KEY_WRITE;
        HKEY phkResult;

Cuando se llame a la función, bastará con especificar todas variables que necesita:

//Llamando a la función
        long Result = RegOpenKeyEx(hKey, lpSubKey, ulOptions,
                                   samDesired, &phkResult);

Por último, para mostrar algún resultado sobre la operación, comprobaríamos lo que devuelva la variable de Result, así:

if (Result == ERROR_SUCCESS)
    MessageBox(NULL, L"La clave se abrió correctamente.",
                  L"Abriendo clave", MB_ICONINFORMATION);
else
    MessageBox(NULL, L"Error al abrir la clave",
               L"Abriendo clave", MB_ICONERROR);

Si recordamos bien, la función de RegCreateKeyEx también abre o crea la sub-clave dependiendo de su existencia. Esta actúa igual, pero sólo abre o no abre. Por supuesto, en el mini ejemplo anterior solo estamos contemplando la posibilidad de que haya abierto, de lo contrario, sin importarnos la razón, mostraremos el mensaje. En un ambiente más controlado, tendríamos que saber que manejar varios errores, como el que la Clave o Sub-Clave no se encuentre, tal como en este caso lo indica Process Monitor:

image

De la teoría a la práctica: RegOpenKeyEx, RegCreateKeyEx y RegSetValueEx

Muy bien, para que esta serie de artículos tengan un poco más de sentido, y podamos aprender de Windows Internals, plantearé un escenario más elaborado donde se pueda combinar las funciones de RegOpenKeyEx, RegCreateKeyEx y RegSetValueEx ya vistas.

Tomaremos como base la clave de HKEY_CURRENT_USER, y lo que haremos será básicamente abrir la sub-clave DemoKey, si se puede abrir, crearemos el valor DemoValue pero si la sub-clave no se puede abrir, crearemos la clave con RegCreateKeyEx y posteriormente estableceremos el mismo valor de DemoValue.

Empecemos con lo primordial, y es el mismo método principal, con su respectiva cabecera:

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow){
}

En conjunto con la declaración anterior para RegOpenKeyEx, es necesario agregar las correspondientes a RegCreateKeyEx y RegSetValueEx:

//Declarando variables para RegCreateKeyEx
        DWORD Reserved = 0;
        LPTSTR lpClass = NULL;
        DWORD dwOptions = REG_OPTION_NON_VOLATILE;
        LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
        DWORD lpdwDisposition;
//Declarando variables para RegSetValueEx
        LPCTSTR lpValueName = L"DemoValue";
        DWORD dwType = REG_DWORD;
        DWORD lpData = 1;
        DWORD cbData = sizeof(lpData);

*Nota: Cabe recordar que estas declaraciones están explicadas al detalle en los dos artículos anteriores.

Tal cual lo hicimos antes, lo primero es buscar que la clave esté o no abierta utilizando la función RegOpenKeyEx:

//Llamando a la función
        long Result = RegOpenKeyEx(hKey, lpSubKey, ulOptions,
                                   samDesired, &phkResult);

Después haremos uso de un switch para controlar diferentes retornos en el resultado de la operación como Encontrado, No encontrado o Acceso denegado.

Si la operación devuelve un ERROR_SUCCESS, entonces procederemos a crear el valor, así que ese estará como primer “case”; si la operación devuelve un ERROR_FILE_NOT_FOUND, la clave no estará, así que procederemos a crearla con RegCreateKeyEx; si la operación devuelve un ERROR_ACCESS_DENIED, no se tendrán los permisos suficientes para efectuarla, así que solo lo indicaremos desde un mensaje y por último, si no es ninguna de todas las anteriores (“default”), devolveremos un error genérico como los de Windows.

*Nota: Es necesario claro está, validar también los resultados internos de cada “case”.

En este orden de ideas, el código quedaría:

switch (Result)
        {
        case ERROR_SUCCESS:

            //La clave existe.
            R2 = RegSetValueEx(phkResult, lpValueName, Reserved,
                dwType, (const BYTE *) &lpData, cbData);

            //Validar que se haya creado
            if (R2 == ERROR_SUCCESS)
            {
                MessageBox(NULL,
L
"La clave existía, se creó el valor.", L"Explorando la API", MB_ICONINFORMATION); } else if (R2 == ERROR_ACCESS_DENIED) { MessageBox(NULL,
L
"La clave existía, pero hay acceso denegado", L"Explorando la API", MB_ICONERROR); } else { MessageBox(NULL, L"Error creando el valor", L"Explorando la API", MB_ICONERROR); } break; //Fin primer case case ERROR_FILE_NOT_FOUND: //La clave no existe R2 = RegCreateKeyEx(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired,
lpSecurityAttributes, &phkResult, &lpdwDisposition);
if (lpdwDisposition == REG_CREATED_NEW_KEY) { R2 = RegSetValueEx(phkResult, lpValueName,
Reserved,dwType, (
const BYTE *) &lpData,
cbData);
switch (R2) { case ERROR_SUCCESS: MessageBox(NULL,
L
"La clave no existía, se creó con valor.", L"Explorando la API", MB_ICONINFORMATION); break; case ERROR_ACCESS_DENIED: MessageBox(NULL,
L
"Se creó clave, acceso denegado al valor", L"Explorando la API", MB_ICONINFORMATION); break; default: MessageBox(NULL,
L
"Se creó clave, error al crear valor", L"Explorando la API", MB_ICONINFORMATION); break; } } //Aquí no debe llegar si ya estaba, pero se valida. else if (lpdwDisposition == REG_OPENED_EXISTING_KEY) { R2 = RegSetValueEx(phkResult, lpValueName,
Reserved,dwType, (
const BYTE *) &lpData,
cbData);
switch (R2) { case ERROR_SUCCESS: MessageBox(NULL,
L
"Clave modificada, valor creado", L"Explorando la API", MB_ICONINFORMATION); break; case ERROR_ACCESS_DENIED: MessageBox(NULL,
L
"Clave modificada, acceso denegado al valor", L"Explorando la API", MB_ICONINFORMATION); break; default: MessageBox(NULL,
L
"Clave modifcada, error al crear valor.", L"Explorando la API", MB_ICONINFORMATION); break; } } else //Fin de REG_OPENED_EXISTING_KEY { MessageBox(NULL, L"Error creando la clave.", L"Explorando la API", MB_ICONERROR); } break; //Fin del segundo case case ERROR_ACCESS_DENIED: //Acceso denegado al abrir la clave MessageBox(NULL,
L
"No se abrió la clave, Acceso Denegado", L"Explorando la API", MB_ICONERROR); break; default: //Otro tipo de error no contemplado MessageBox(NULL, L"Error al abrir la clave.", L"Explorando la API", MB_ICONEXCLAMATION); break; //Fin de default } //Fin del switch

Independiente del swith, es necesario cerrar la operación en la sub-clave con RegCloseKey:

//Cierra operación en Registro
        RegCloseKey(phkResult);

Explorando resultados

Saliendo del lado desarrollador, Process Monitor nos puede ayudar a explorar el comportamiento en dos de los casos más comunes dentro del swith, que se deba crear todo, o solo modificar, es decir, entrar al primer o segundo case.

– Si el resultado es ERROR_FILE_NOT_FOUND, Process Monitor lo reportaría así:

ROP1

Tal cual se lo indicamos, la primera operación que hace se ve como RegOpenKey, sobre la sub-clave DemoKey, pero como tiene un resultado de NAME NOT FOUND, es decir, que no la encontró, pasa a llamar a RegCreateKey para escribirla, y al obtener resultado SUCCESS, finaliza creando el valor DemoValue con la operación RegSetValue.

En algún punto además, cerrará la operación también correctamente sobre la sub-clave:

image

El mensaje para el usuario, de acuerdo a lo programado, se mostraría así:

image

– Si el resultado por el contrario es ERROR_SUCCESS, Process Monitor lo reportaría así:

ROP2

Primero, realizando la operación de RegOpenKey, intentaría abrir la sub-clave de DemoKey, al recibir SUCCESS, establecería la información correspondiente y llamaría ahora a la operación de RegSetValue para escribir el valor de DemoValue también con SUCCESS como resultado.

El mensaje se mostraría así:

image

Bastante interesante el Registro, ¿no les parece?

Para los que deseen, he subido la solución completa a una carpeta de SkyDrive, y la pueden descargar desde aquí:

Espero sea de utilidad. ¡Comentarios bienvenidos!

PD. No olviden seguirme en Twitter: www.twitter.com/secalderonr

Saludos,

Checho

Los archivos de la USB que se convertían en accesos directos en Windows, Attrib, Process Monitor y su solución

El problema que voy a describir en este post, muy seguramente todos lo han vivido en algún momento, sobre todo si utilizan mucho dispositivos USB en diferentes equipos, indiferente además de si estudian o no algo relacionado con tecnología pues se podría decir que es uno de los comportamientos de malware más comunes. Sin embargo, pasaré a detallarlo aquí como normalmente lo hago con los diferentes problemas para brindarle una solución a los que entren buscándola, aprender un poco más del funcionamiento yo, y por supuesto seguir generando diferentes contenidos sobre lo que me apasiona.

*Nota: Me apoyaré durante todo el artículo en una USB que contenía este malware, así que podría variar un poco con respecto a lo que ustedes puedan ver si se infectan, pero la solución va por el mismo camino.

El problema

Al conectar el dispositivo en un equipo con Windows 8.1, según la descripción y acorde con lo primero que vi, habían ciertos archivos que a pesar de ser de diferentes tipos como PDFs, Documentos de Word y música, se volvieron Accesos Directos y solo presentaban un icono en blanco:

V1

Cuando hice doble clic en uno de ellos para ver si había ejecución normal, apareció una ventana del Símbolo del Sistema con el nombre del archivo como título por algunos segundos, al parecer realizando alguna operación oculta:

image

Después de esto, el archivo iniciaba normalmente con su programa asociado:

image

Si ese archivo se guardaba así fuese con otro nombre en la misma unidad, después de unos segundos también se volvía acceso directo, con los mismos comportamientos que el orginal. Por otro lado, si el aparente acceso directo se copiaba a un directorio externo y se intentaba ejecutar, ya no abría el documento original, y en vez de eso, había un par de errores:

image

image

A pesar de que en general era el mismo mensaje genérico, el primero estaba buscando al parecer un script llamado “qecddxldm.vbs” y el segundo al mismo archivo que intentaba abrir, en este caso: “inteligencia.docx”.

Si el archivo se abría y luego se le indicaba Guardar como para ubicarlo en otro directorio que no fuese el de la propia unidad, el formato se mantenía bien y continuaba funcionando. Esto me indicaba en primera instancia que el problema se reproducía solo en el dispositivo USB.

La causa

Claramente algo estaba pasando al ejecutarse los archivos y mientras mostraba la consola, así que para averiguarlo, era necesario indagar un poco más a profundidad lo que estaba ocurriendo por debajo. Para esto, nada mejor que Process Monitor de Sysinternals.

El procedimiento como ya lo he ejemplificado en otros artículos similares, consiste en ejecutar Process Monitor, limpiar la primera traza utilizando CTRL + X y posteriormente reproducir el problema o comportamiento, que en este caso sería volver a ejecutar alguno de los archivos hasta que se abra con el programa con el que debe estar asociado.

Utilicé el mismo documento de “inteligencia.docx” para poder seguir con el ejemplo que ya había mostrado en las primeras capturas.

Como no sabía por dónde empezar, lo que hice fue simplemente parar el monitoreo de Process Monitor después de reproducir para no tener más información innecesaria, y desde el cuadro de búsqueda (CTRL + F) le iniqué “ingeligencia.docx” hacia abajo para mirar las primeras referencias que se hicieran sobre el documento desde el momento en que Process Monitor se ejecutó:

image

Afortunadamente, el primer resultado tenía mucho que decir al respecto, pues no era nada común:

image

Por alguna razón, el Explorador de Windows estaba abriendo el proceso de “cmd.exe”, tenía un resultado satisfactorio y además referenciaba en alguna parte el nombre completo de “inteligencia.docx”. Después de esto, se iniciaba el proceso y se creaba el hilo. Para ver dónde estaba utilizando esta operación el nombre del archivo, abrí la ventana de Propiedades de Process Monitor haciendo doble clic sobre la primera línea, y en la pestaña de Event pude obtener el primer gran resultado:

VV1

El evento esta reportando la siguiente línea de comandos:

“C:Windowssystem32cmd.exe” /c start qecddxsldm.vbs&start inteligencia.docx&exit

Eso era lo que estaba ejecutando el proceso de “cmd.exe”, indicado como PID (Process ID), que en este caso tenía como número 3232, operación que era la siguiente según el log de Process Monitor mostrado en la captura anterior.

Ahora, lo que estaba haciendo toda la línea era utilizar la bandera de /c para ejecutar el comando que se le especifique en una cadena y luego terminarlo, START para abrir una nueva ventana que permita ejecutar el comando o programa, y finalmente el archivo qecddxsldm.vbs estaba haciendo toda la tarea. A continuación, se iniciaba con el START nuevamente ya el documento real (inteligencia.docx) y terminaba todo. Básicamente, esto se traduce en la ejeución del Símbolo del Sistema y la apertura normal del documento que estaba viendo.

Para referenciar tanto al .DOCX como al .VBS sin indicar directorio, tenía que estar en la misma ubicación, y eso resolvía el enigma del por qué copiar el acceso directo a otra parte no daba resultado en la ejecución. Procedí entonces a habilitar los Archivos Ocultos y Protegidos por el Sistema desde las Opciones de Carpeta, y ahora la visión de la unidad era un poco diferente:

image

Los accesos directos sólo estaba ahí para hacer una redirección al Script malicioso y para no levantar mayores sospechaz, lanzaba el archivo original, que estaba oculto como un archivo protegido por el sistema.

El segundo problema y su causal

En un principio creí que remover el atributo de Oculto al archivo solucionaría el problema en principio de la visualización, pero al momento de ir a las respectivas propiedades, me encontré con que esto no lo podía hacer de forma gráfica:

image

La única razón por la que un archivo muestre este tipo de características, es decir, que esté como oculto y no se pueda manipular ese atributo desde el Explorador, es porque se le indicó estar oculto como un atributo de archivo de sistema. La forma más fácil en la que podemos cambiar esto, es utilizar la herramienta de Attrib.exe, embebida en Windows.

Para mirar si esto era suficiente entonces, y antes de eliminar el Script que había traido el Malware, procedí entonces a ejecutar: Attrib –S –H /S /D /L <USB>*.* donde <USB> correspondía a la letra asignada al dispositivo. Para mi caso, que era la “E:” sería:

Attrib –S –H /S /D /L E:*.*

image

*Nota: El argumento ““ indica que se va a quitar el atributo especificado, “S” es para Archivos de Archivos del Sistema, “H” para especificar el de “Oculto”, /S para que se aplique a todos los archivos que correspondan a lo que se está indicando y todas las subcarpetas, /D para que se procesen carpetas y finalmente /L para que se trabaje en atributos del Vínculo Simbólico en caso de que exista en la unidad. Para ver la descripción de cada uno, pueden ejecutar desde el Símbolo del Sistema: Attrib /?

La buena noticia, es que como era de esperarse, los archivos pasaron a mostrarse nuevamente como debía ser después de la ejecución del comando:

image

La mala noticia, es que bastaba un par de minutos para que los archivos se volvieran a ocultar solos:

image

La solución

Para saber por qué los archivos se volvían a ocultar nuevamente, corrí otra vez Process Monitor, esta vez dejando como tiempo solo el espacio en que se volvían a poner con atributos escondidos y buscando otra vez por nombre de alguno de los archivos. Por supuesto, utilicé “Inteligencia.docx”.

El primer resultado fue del Explorer.exe enumerando los archivos de la unidad, así que no me servía, pero el segundo resultado era del proceso Wscript.exe, que nada tenía que estar haciendo si no era ejecutar un Script de Windows. Como el Query no me decía nada, utilicé otra característica de Process Monitor llamada Process Tree, que cataloga como Process Explorer todos los procesos en ejecución, y me indica qué cosas pudo estar haciendo cada uno durante el tiempo activo. Busqué Wscript.exe y encontré esto:

2V

El Script que en principio estaba solo en la Unidad USB, qecddxsldm.vbs, se estaba corriendo desde el directorio Roaming correspondiente a mi perfil de usuario, de esta forma los archivos volvían a estar ocultos.

Navegué entonces hasta el directorio de Roaming e intenté eliminar manualmente el Script, pero no pude hacer, pues según Windows, estaba siendo utilizado por Wscript.exe:

image

Ejecuté entonces Process Explorer y efectivamente Wscript.exe se encontraba en ejecución, siempre referenciando además el Script:

image

Es importante notar que aunque el directoiro donde se lanzó es la unidad USB, el Script lo consumía desde la carpeta Roaming.

Terminé el proceso entonces con Process Explorer haciendo clic en el botón inferior de Kill Process y pude eliminar el primer Script de la carpeta Roaming.

Seguido a esto, es necesario eliminar el Script de la unidad USB para que no lo esté copiando constamente. Vale aclarar que hasta el final intentará engañar:

image

Basta con hacer clic en el botón y se quitará completamente.

Por último, desde el Símbolo del Sistema con privilegios elevados, es necesario volver a ejecutar Attrib con sus argumentos para que los archivos se les quite lo oculto, es decir:

Attrib –S –H /S /D /L E:*.*

image

Además de esto, quitar todos los falsos accesos directos generados, sea manualmente, o bien a través de línea de comandos utilizando: DEL <USB>*.lnk. Donde <USB> corresponde otra vez al dispositivo. Para este caso:

DEL E:*.lnk

image

*Nota: Puede que no todos los que tengan este problema deban eliminar el Script (.vbs), pues en algunas ocasiones algún Antivirus ya lo ha hecho, pero no devuelve el estado de los archivos, así que habría que hacerlo manual como lo acabé de indicar.

El Servicio “intocable” de Windows Defender en Windows 8.1 Preview

Se aplica a: Windows 8.1 Pro Preview, Windows 8.1 Enterprise Preview.

El caso que pasaré a explicar durante todo este artículo, ha sido uno de los que más trabajo me ha costado solucionar, pero a la vez de los que más aporte a mi conocimiento me ha entregado y hasta ayer no podía determinar si era un bug o algo extraño de Windows, pero afortunadamente pude clarificarlo, así que paso a exponerlo:

He de empezar por recordar que Windows Defender existe hace muchos años dentro de Windows, pero hasta nuestro flamante Windows 7, era solo una solución Anti-Espía pues desde que salió Windows 8 hace poco más de un año –contando las liberaciones previas- Windows Defender fusionó todo lo que Microsoft ofrece con Security Essentials y pasó a ser una solución completa e integrada de Antivirus. Esto quiere decir que ya no es necesario adquirir software de protección de terceros, o corporativo –incluyendo EndPoint de MSFT- a menos que se esté en un entorno grande que requiera administración centralizada, aunque Defender también cuenta con una gran cantidad de políticas de grupo propias.

Aun así, particularmente hay quien confía por diferentes argumentos en otras soluciones, sepa o no que en Windows 8/8.1 está Windows Defender, por lo que es normal que si el antivirus no hace alguna validación a nivel de usuario o kernel sobre la versión del sistema operativo, pueda correr después de la actualización de Windows 8 a Windows 8.1. Pues bien, fue en uno de estos escenarios donde este artículo empezó a tomar vida, específicamente en los Foros de Windows 8.1 de Microsoft Community en inglés, se abrió un caso donde un usuario tenía instalado Malwarebytes PRO en su Windows 8 y después de actualizar a Windows 8.1, quizo acceder a la consola de Windows Defender pero se encontró con el siguiente mensaje al intentar funcionar con él:

image

Español:No se puede iniciar el servicio, porque está deshabilitado o porque no tiene dispositivos habilitados asociados a él. Haga clic en Ayuda para obtener más información sobre este problema. Código de error: 0x80070422.”

Inglés: "The service cannot be started, either because it is disabled or because it has not enabled devices associated with it. Click help for more information about this problem. Error code: 0x80070422."

Todas las configuraciones de los Servicios – como casi todo en Windows- se almacenan en el Registro, específicamente, en la sub-clave Services ubicada en:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices

Con esto presente, una de los primeros caminos, y en general de los más eficaces para diagnosticar y solucionar problemas con la ejecución de Servicios de Windows, es observar el contenido que deberían tener los valores del correspondiente Servicio dentro de la sub-clave de Registro, pues siempre hay unos predeterminados que garantizan la funcionalidad. La forma más fácil para esto, es ir hasta la sub-clave, hacer clic derecho y seleccionar Exportar para que se cree el archivo .REG en un directorio que indiquemos. Esto lo debemos hacer desde un equipo funcional, es decir, que esté trabajando el Servicio y desde el equipo donde presenta el problema.

El siguiente paso es utilizar alguna aplicación que nos permita comparar exactamente cada valor y su correspondiente contenido, y como WinDiff que estaba incluido en el SDK de Windows despareció, la alternativa más recomendada por mi parte es KDiff3, una sencilla y útil herramienta de comparación, donde podemos indicar hasta tres archivos buscándolos en su respectivo directorio.

Lo que hice entonces fue pedir el archivo de registro desde el equipo donde ocurría el problema, exportar el registro de mi equipo funcional también y abrirlos desde KDiff3:

image

*Nota: La sub-clave que corresponde a Windows Defender es:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesWinDefend

El resultado correspondiente al primer archivo lo ubicará en la izquierda, y en segundo archivo sobre la derecha respectivamente. KDiff nos indicará en diferentes colores y con un subrayado amarillo dónde encuentra la diferencia, sea en nombre, o contenido (Es Case Sensitive además). En este caso, el resultado fue bastante claro, pues sólo existía diferencia en el contenido de un valor llamado Start:

image

Como ven, en la izquierda (Registro bueno), el valor tenía contenido de “2”, y en la derecha (Registro malo), el contenido era “4”. ¿Qué quiere decir esto? Empecemos a entrar en detalle:

Cuando nosotros abrimos la Consola de Servicios, y entramos a las propiedades de cualquiera de los cientos que hay, podemos notar que existen 4 tipos de inicio: Automático (Inicio retrasado), Automático, Manual y Deshabilitado.

Ser1

El orden por supuesto es de arriba hacia abajo, y esta configuración se almacena en el Valor de Start, ubicado en la sub-clave correspondiente a cada servicio. Los datos serían:

Automático (Inicio retrasado): 1
Automático: 2
Manual: 3
Deshabilitado: 4

El estado natural de Windows Defender es dos (2), que indica Automático, y por ende, en ejecución pero, el equipo donde estaba apareciendo el mensaje al intentar iniciarlo tenía el contenido de cuatro (4), es decir, el Servicio de Windows Defender se encontraba Deshabilitado.

La solución para este tipo de casos, suele ser cambiar el contenido del Valor (Si se identifica uno solo) o para mayor seguridad, importar nuevamente toda la sub-clave de registro exportada desde un sistema funcional. Lo que le propuse en primer instancia a la persona que expuso el problema fue descargar toda la sub-clave de registro que yo le había subido previamente a SkyDrive como normalmente lo hago, el problema es que no me fijé antes y cuando la intentó importar, obtuvo un error de permisos desde el Editor de Registro similar al siguiente:

image

Este tipo de errores suele darse cuando no tienes los permisos necesarios para escribir en la determinada sub-clave de registro, o bien porque aunque los tengas, no eres el propietario. Para el caso de WinDefend, aunque los que pertenezcan al grupo de Administradores tienen control total, el propieatario es el usuario SYSTEM:

image

*Nota: Para ver los permisos, hay que hacer clic derecho sobre la sub-clave, y seleccionar Permisos. Para ver el propietario, clic en el botón Opciones avanzadas en la parte inferior de la ventana de Permisos.

No suele ser recomendable modificar esto, pero en casos de Troubleshooting, es necesario hacerlo, así que le recomendé al usuario cambiar el propietario para que especificara su propio usuario, y luego verificar que todos los permisos estuvieran en control total para que pudiera importar el archivo de registro, o editar el contenido del valor Start, pero seguía con mensajes de acceso denegado:

image

Español:No se puede editar Start: error al escribir el nuevo contenido de valor.”

Intenté entonces hacerlo yo pues en algunas ocasiones es necesario pasar por cada sub-clave verificando el propietario y control total, pero por más que edité, mantenía también el acceso denegado… aquí fue donde me empecé a preocupar, y en mi propia máquina fui hasta la Consola de Servicios a ver cómo es que se veía el Servicio de Windows Defender, pero para mi sorpresa, me encontré con algo que no había visto nunca antes:

image

Como ven, todas las posibles opciones que tiene un Servicio desde la Consola estaban completamente deshabilitadas, es decir, no podía ni siquiera deterlo yo mismo de la forma nativa y soportada. Esto no solo se veía así en mi equipo, sino en instalaciones nuevas y limpias tanto de Windows 8.1 Pro Preview como de Enterprise Preview. En otras palabras, nativamente en Windows 8.1 no se puede modificar el Servicio de Windows Defender desde la Consola; aquí empezó el verdadero dilema.

De alguna forma el Valor de Start se le había cambiado a la persona, ¿Pero cómo? Sabía que la solución estaba en volverlo a poner en dos (2), ¿pero de qué forma? Desde aquí tomé el caso personal así que empecé a buscar caminos alternativos para descubrir cómo se podía modificar la sub-clave de Registro WinDefend correspondiente al Servicio; por supuesto, pasaré a mostrar todos mis intentos fallidos a continuación:

Primer intento: PsExec para ejecución con usuario SYSTEM

Dentro de las impresionantes herramientas de Windows Sysinternals, existe una llamada PsExec, que permite ejecutar procesos de forma remota sin mayores complicaciones, y dentro de su sintaxis, es posible ejecutar también cualquier proceso utilizando el usuario de SYSTEM, que tiene mayores privilegios que el tan conocido Administrador integrado.

Si con mi usuario perteneciente al grupo de administradores en modo aprobación de administrador no podía hacer modificaciones de ninguna forma a la sub-clave de registro, tal vez ejecutando el Editor de Registro (Regedit.exe) con PsExec, y teniendo privilegios de SYSTEM, podría cambiar el contenido del valor Start.

Una vez se descargue y descomprima PsExec, Desde un Símbolo del Sistema con privilegios elevados (Clic derecho, Ejecutar como administrador), ubicados en la ruta donde se descargó, basta con ejecutar: PsExec –sid Regedit.exe

image

El Editor de Registro ahora tendrá privilegios totales, e incluso se puede verificar con Process Explorer desde la pestaña de Security en las propiedades de Regedit.exe:

image

Sin embargo, cuando muy confiando fui a intentar modificar el valor de cuatro (4) a dos (2), de nuevo acceso denegado:

image

Primer intento fallido.

Segundo intento: Utilizando la herramienta de SC.exe con PsExec

Windows incluye una herramienta llamada SC.exe que se comunica con el Service Control Manager, y claro está, con los Servicios para realizar diferentes tareas administrativas sobre éstos.

Aprovechando PsExec también, ejecuté el CMD.exe con el usuario SYSTEM y desde aquí intenté detener el servicio con la herramienta SC.exe, pues esta vez no intentaría realizar un cambio sobre el Registro directamente, sino que lo intentaría hacer sobre el propio Servicio. El comando es: SC.exe Stop WinDefend

Para mi mala fortuna, este fue el resultado:

image

Nuevamente, a pesar de estar sobre SYSTEM, el resultado fue Access is denied. ¿Cómo es que se me denegaba al acceso al usuario más fuerte de todos?

Segundo intento fallido.

Tercer intento: Utilizando las funciones de Servicios desde la API de Windows

De forma desesperada, mi último intento tenía que ser interactuar yo mismo con el Service Control Manager desde la API de Windows, de esta forma, yo controlaría todo el proceso, y como se supone que Windows nativamente lo hace de esta forma, quizá podría tener resultados positivos.

Las Funciones de Registro, proveen la forma correcta de trabajar con los Servicios desde la API, y el proceso sería:

Abrir el Service Control Manager con OpenSCManager.
Abrir el servicio que se va a controlar con OpenService.
Utilizar la función de ControlServiceEx con el parámetro de SERVICE_CONTROL_STOP para detener el servicio.
Operaciones adicionales para reiniciar y cerrar, que no vale la pena por ahora tocar.

No entraré mucho en detalle sobre el código, porque la idea es escribir sobre cada una de estas funciones cuando termine la serie de operaciones con el Registro más adelante y no es el foco de este post.

A grandes razgos, el pequeño código que escribí abría el Service Control Manager, verificaba que se abriera correctamente y si esto sucedía, pasaba a abrir el Servicio con la función OpenService, hacer la misma verificación y si pasaba, detener el servicio con la función ControlServiceEx. Este es el fragmento que realizaba todo hasta la abierta del Servicio:

SC_HANDLE serviceDbHandle = OpenSCManager(lpMachineName,
                               lpDatabaseName, dwDesiredAccess);

        if (serviceDbHandle == NULL )
        {
            MessageBox(NULL,
L
"No se abrió el Service Control Manager", L"Servicio", MB_ICONEXCLAMATION); }
else
        {
            
            SC_HANDLE serviceHandle = OpenService(serviceDbHandle,
                lpServiceName, dwDesiredAccess2);

            if (serviceHandle == NULL )
            {
                //GetLastError(void);
                MessageBox(NULL, L"No se abrió el Servicio",
                           L"Servicio", MB_ICONEXCLAMATION);
            }

Noten que si serviceHandle, que contiene el puntero al Service Control Manager, que se encuentra en el equipo local – Es decir, sabe que trabajará sobre los servicios locales- y que devolverá el resultado de la operación OpenService como NULL si no se abre por X o Y razón (Que incluye Acceso Denegado), mostraría el mensaje: “No se abrió el Servicio”, y de lo contrario, es decir, que se pudiera abrir, pasaría a detenerlo.

El resultado, como no me lo esperaba, fue:

image

En otras palabras, Windows no pudo abrir el Servicio, ni siquiera desde la API y si no se abría, no podría modificarlo.

Tercer intento fallllido.

Hasta aquí habían llegado mis pruebas, pues incluso haciendo otras pruebas que no describiré aquí como hacer uso de Autoruns, o de herramientas de terceros para intentar tomar permisos, o modificar el Serivicio, siempre obtenía Acceso Denegado.

La conclusión era por supuesto, que desde Windows 8.1 por lo menos, no es posible modificar el Servicio de Windows Defender.

Sin embargo, no me di por vencido, pues quedaba una última cosa por hacer, que para fortuna de todos, resultó ser el único camino positivo para volver el estado del servicio a como debería de estar.

¿Y la solución es?

Como dije, desde Windows 8.1 había confirmado que no es posible modificar el servicio de ninguna forma, aunque lo más extraño, es que si se instala un Antivirus, sera de terceros o de Microsoft (EndPoint Protection), Windows Defender se desactiva sin ningún tipo de problema e internamente, el valor de Start se modifica de dos (2) a tres (3):

1

El caso aquí es que el usuario deseaba tener Windows Defender funcional, y esto solo era un escape.

¿Qué se puede hacer? La “solución” pasa por algo que corresponde más al tema de Implementación de Windows, pero es más que perfecta para escenarios complejos de solución de problemas y me estoy refiriendo a un Entorno de Preinstalación, como se le llama oficialmente: Windows PE.

Recordemos que Windows PE representa un mini sistema operativo que corre en memoria RAM, y se usa normalmente para iniciar el proceso de instalación de Windows, pero a la vez es bastante flexible como para nosotros integrar aplicaciones o realizar diferentes operaciones como una fundamental que es capturar una imagen de sistema operativo (.WIM).

Lo estupendo de Windows PE aquí, es que al ser sistema operativo, yo puedo ejecutar aplicaciones, acceder a funciones de red, entre otras, y para este caso, es posible acceder a casi todo lo que tiene mi sistema local, aún siendo otro sistema operativo, como el Editor de Registro. Sin embargo, el Windows PE se debe crear y configurar, además de hacerse un procedimiento específico desde el Entorno de Preinstalación al iniciar el equipo, así que procederé a explicar el paso a paso como una mitigación para las personas que les presente este mismo comportamiento en Windows 8.1:

Creando un Windows PE

Para generar un Windows PE, necesitamos primero que todo:

– Instalar los compomentes de implementación (Deployment Tools, Windows Preinstallation Environment (PE)) desde el ADK para Windows 8.1. Si no lo tienen, pueden descargarlo desde el sistio oficial de Microsoft:

http://www.microsoft.com/en-us/download/details.aspx?id=39306

Desde la Pantalla de Inicio, ejecutamos la consola de Deployment and Imaging Tools Environment como administrador (Clic derecho, ejecutar como administrador). Necesitamos copiar los archivos necesarios del Windows PE localmente, y hay que tener en cuenta aquí la arquitectura del equipo donde haremos el cambio, es decir, si es de 32 o de 64 bits.

Si es de 32 bits, ejecutamos: Copype x86 C:WinPE

Si es de 64 bits, ejecutamos: Copype AMD64 C:WinPE

image

Veremos copiar muchos archivos necesarios para construir el Entorno de Preinstalación, y al terminar, construiremos la imagen ISO haciendo uso de la nueva herramienta MakeWinPEMediaISO incluida en el ADK desde Windows 8.

Ejecutamos desde la misma consola:

MakeWinPEMedia /ISO C:WinPE C:WinPE.ISO

image

A continuación, debemos grabar el ISO llamado WinPE.ISO que nos quedó en la unidad raíz C: en un CD/DVD o memoria USB. Para las dos primeras alternativas podemos utilizar el asistente integrado en Windows para grabar en un medio y para la última, requerimos hacer los mismos pasos como si fueramos a configurar el dispositivo para instalar Windows. Si no sabemos el procedimiento, les dejo un enlace donde explico el paso a paso:

http://www.fermu.com/es/articulos/windows/articulos-y-tutoriales/831-preparar-dispositivo-usb-manualmente-para-instalaci%C3%B3n-de-windows-8

*Nota: Cabe aclarar que en vez de copiar los archivos de instalación de Windows, copiamos todos los de C:WinPE.

Modificando el estado del Servicio desde el Windows PE

Volviendo otra vez al caso, y como paso a seguir, es necesario iniciar el equipo donde necesitamos cambiar el valor de registro desde el Windows PE y realizar lo siguiente:

1. Cuando aparezca el Símbolo del Sistema, estaremos en la unidad X: que representa la unidad del sistema virtual del Windows PE, así que nos debemos ubicar primero en la unidad del sistema operativo local, que muy seguramente será la D: pues en un entorno de WinPE, probablemente el C: pase a ser la partición reservada del sistema.

Para identificar la unidad del sistema operativo local, solo debemos encontrar la letra (En caso de no ser la D:) donde existan los directorios protegidos por el sistema operativo como Windows, Archivos de Programa, Usuarios, etc.

Navegamos hasta la unidad con el comando de CD, y luego hasta el directorio de Windows y ejecutamos Regedit.exe, así:

D:

cd Windows

Regedit.exe

image

*Nota: Si por alguna razón están en un Windows PE para 32 bits, y no les abre el Editor de Registro desde el directorio de Windows, pueden devolverse hasta la raíz D: y ejecutar Regedit.exe nuevamente.

Cuando el Editor de Registro nos abra, notaremos todas las mismas claves con las que ya tal vez estemos familiarizados, pero corresponden a las del Windows PE y no a las del sistema operativo local, así que debemos recurrir a los famoso Hives de Registros que si recordamos, contienen todas las claves y subclaves con las que Windows funciona desde que se instala. La más común que hemos visto modificar es la de NTUSER.DAT de la carpeta C:UsersDefault que nos permite editar personalizaciones para el perfil predeterminado de Windows, pero HKEY_LOCAL_MACHINE también tiene una para todo lo que esté en la sub-clave de SOFTWARE y otra para la de SYSTEM. Nos corresponde la segunda.

*Nota: Intentaré preparar un artículo aparte sobre todos los Hives de Windows con el fin de detallar el tema.

Desde el Editor de Registro, nos situamos en la clave HKEY_LOCAL_MACHINE y hacemos clic en el menú File y seleccionamos Load Hive…

image

Navegamos hasta la partición del sistema local, que como les dije, en la mayoría de los casos será D:WindowsSystem32Config, seleccionamos la de SYSTEM y clic en el botón de Open:

image

En la ventana de Load Hive, le indicamos el nombre de Sys (Puede ser cualquiera) y clic en el botón de OK para que se cargue el Hive:

image

Dentro de la sub-clave de Sys, veremos todo lo que corresponde a HKEY_LOCAL_MACHINE de nuestro sistema local, así que debemos por fin navegar hasta la sub-clave que contiene la configuración del Servicio de Windows Defender, es decir:

HKEY_LOCAL_MACHINESysControlSet001ServicesWinDefend

Ahora que tenemos poder absoluto sobre estas modificaciones del sistema local, desde Windows PE, procedemos a hacer doble clic en el valor de Start, que para este caso como expuse tiene contenido de “4” y desde la ventana de Edit DWORD (32-bit) Value se lo cambiamos a “2”:

image

Como verá, haciendo clic en el botón OK ahora no indicará acceso denegado y nuestro valor habrá quedado cambiado:

image

Después de esto, seleccionamos nuevamente la sub-clave que cargamos Sys, vamos al menú de File nuevamente y clic en Unload Hive… para que el Hive se guarde y no se tenga peligro a fallos en el inicio de Windows:

image

*Nota: Debemos hacer clic en el botón de Sí (Yes) cuando Windows lo solicite la confirmación de la descarga del Hive:

image

¡Todo listo! Basta con cerrar el Editor de Registro, el Símbolo del Sistema y una vez dejemos reiniciar a Windows completamente, el Servicio de Windows Defender estará funcionando otra vez y por ende, la Consola propia también:

image

Este mismo procedimiento se lo expuse al usuario en el Foro y por fin, Windows Defender estuvo funcional nuevamente.

¿Entonces, es un Bug?

La respuesta corta es: NO.

Aunque en un principio, y tal cual mencioné al principio, hasta antes de este post estaba muy convencido que lo era, logré escalar el caso hasta Mark Russinovich de Microsoft, que finalmente me aclaró el porqué esto sucede en 8.1:

Básicamente, Windows Defender tiene un controlador en modo-kernel (wdfilter.sys) que registra un filtro de Registry Callback que protege las sub-claves de Windows Defender.

La rutina de Registry Callback puede bloquear operaciones a nivel de Registro, y como esto funcional a nivel de modo-kernel, es bastante complicado de detectar, y para el caso de 8 e inferiores, no parece estar liberado la actualización del controlador a bajo nivel.

Aquí pueden leer más sobre Registry Callback:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff545879(v=vs.85).aspx

Conclusión, aquí aplica aquella frase: “No es un bug, es una característica”.

¡Comentarios bienvenidos!

PD. No olviden seguirme en Twitter: https://twitter.com/secalderonr

Saludos,

Checho

Explorando la API de Windows en C++: Mi primer Valor de Registro utilizando las funciones RegCreateKeyEx y RegSetValueEx

TechDays-Figure-with-Laptop_7A06897A

Hace un tiempo empecé un pequeño proyecto personal en cuanto al contenido adicional en el blog referente a la API de Windows, iniciando por ahora en la exploración de las funciones referentes al Registro de Windows y el primer artículo tocó la de RegCreateKeyEx, mostrando cómo utilizarla en C++ para crear una simple clave de Registro. Todo esto con el fin de empezar a conocer un poco más cómo funciona realmente Windows y sacar provecho de esto.

Hoy me concentraré en otra de las funciones más utilizadas, la de RegSetValueEx, agregando que como verla sola queda un poco incompleto el proceso, la uniré con la de RegCreateKeyEx para dar un poco más de valor al post.

*Nota: Cabe aclarar que el siguiente contenido lo estoy haciendo bajo una perspectiva de novato y aprendiz, por lo que tal vez puedan encontrar errores; pero la intención, como dije en el post pasado, es generar mi propia biblioteca de contenido en español y de la forma más clara que pueda.

La función RegSetValueEx

Si nos vamos atrás, y recordamos La Estructura del Registro de Windows como nos indica la documentación oficial, la información está dividida o estructura en un formato de árbol, y cada uno de los nodos que lo componen (HKCR, HKCU, HKLM, HKU, HKCC) se les conoce como Claves (Keys); cada Clave a su vez, contiene toda una estructura interna que se les referencia como Sub-claves (Subkeys), que pueden contener entradas de datos reconocidas como Valores (Values). Éstos últimos pueden ser creados por la función RegSetValueEx, y por lo general pueden tener diferentes tipos de contenidos, como por ejemplo: Binarios, Cadenas, de tipo DWORD, entre otros. El tipo de valor a crear dependerá del objetivo de la operación o información que Windows vaya a tomar de él. Por lo general, uno de los más famosos y comunes es el valor de tipo entero de 32 bits DWORD.

La documentación oficial de esta función nos dice que debemos crear las siguientes variables de entrada o salida que serán utilizadas:

HKEY hKey: Como en la mayoría de las funciones de Registro, es solo un apuntador a una clave abierta, aunque en este caso, es necesario tener en cuenta que deben genera derechos de acceso de KEY_SET_VALUE si es que se retorna con la función de RegCreateKeyEx.

Por supuesto, podemos utilizar también las Claves predefinidas que pertenecen al árbol de Registro:

HKEY_CLASSES_ROOT

HKEY_CURRENT_CONFIG

HKEY_CURRENT_USER

HKE_LOCAL_MACHINE

HKEY_USERS 

LPCTSTR lpValueName: No es más que el nombre del valor que se desea establecer.

DWORD Reserved: Como en la anterior función, es un parámetro reservado y siempre debe ser cero ( 0 ).

DWORD dwType: Es el tipo de valor que se va a generar. Toda la lista disponible está en este artículo de MSDN:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms724884(v=vs.85).aspx

const BYTE *lpData: En términos básicos, aquí va el contenido que se va a establecer, y por eso hace referencia a un arreglo de BYTES. Suele ser –por lo menos en mi propio caso- la variable más difícil de interpretar, sobre todo si se crea y declara desde el principio como arreglo.

*Nota: Tengamos en cuenta que la declaración de lpData puede variar mucho dependiendo del tipo de valor que vamos a crear. Por ejemplo, si fuese un DWORD, podríamos simplemente declararlo como tal y referenciarlo en la función, o como en este caso, un valor de tipo REG_SZ, tendríamos que enviarle el contenido creando un array de tipo TCHAR, etc, etc.

DWORD cbData: Es el tamaño de la información pasado por la variable lpData. Lo normal aquí es utilizar la función sizeof para que Windows se encargue del trabajo.

*Importante: Para tener más claridad sobre la declaración general de la función RegSetValueEx, pueden ver el siguiente artículo de Juan Carlos Ruiz (Technical Evangelist, Microsoft Colombia) que muy amablemente me aclaró muchísimas dudas mientras pasaba por el primer enfrentamiento:

http://blogs.msdn.com/b/juank/archive/2013/07/27/un-vistazo-a-la-funcion-de-regsetvalueex-de-la-api-de-windows.aspx?v=2

Teniendo todo lo anterior presente, si en mi proyecto de C++ fuese a crear un Valor llamado DemoValue,  tipo DWORD 32 bits, de contenido “1” y en la clave HKEY_CURRENT_USER, la declaración sería algo así:

//Declaración de variables necesarias para RegSetValueEx

    HKEY hKey = HKEY_CURRENT_USER;
    LPCTSTR lpValueName = L"DemoValue";
    DWORD Reserved = 0;
    DWORD dwType = REG_DWORD;
    DWORD lpData = 1;
    DWORD cbData = sizeof(lpData);

En la función después, bastaría con indicar cada variable declarada en su lugar, por ejemplo, para el mismo Valor anterior, quedaría así:

long R = RegSetValueEx(hKey, lpValueName, Reserved,
                  dwType, (const BYTE *)&lpData, cbData);

Todo se devuelve a un valor llamado “R” de tipo long, con el objetivo de poder trabajar sobre el resultado de la operación, pues si no hay problema, el valor retornante sería: ERROR_SUCCESS y con esto podría proceder con otras especificaciones dentro del código.

Ahora, el único problema, es que si sólo utilizamos la función RegSetValueEx, no habrá forma de crear el Valor por fuera de las Claves predefinidas, por ejemplo, si el valor DemoValue no se quiere escribir en HKCU, sino en HKEY_CURRENT_USERDemoKey, sería imposible, pues la función sólo aceptará las predefinidas, o bien, un apuntador a alguna clave abierta por la función RegCreateKeyEx. Para hacerlo más interesante, y suplir la necesidad primordial de escribir en las Sub-claves veamos cómo podemos combinar la función RegCreateKeyEx vista en el primer post de esta serie, con RegSetValueEx:

RegCreateKeyEx y RegSetValueEx, mejor juntas

Pues bien, lo que haremos será simplemente tomar ventaja de lo aprendido con la función RegCreateKeyEx para crear una sub-clave de registro, y en esa sub-clave, escribir el respectivo Valor y contenido con la función de este post, RegSetValueEx.

Primero, recordemos que todo proyecto de Win32 debe tener como cabecera <Windows.h>, y como función principal WinMain, siguiendo esta declaración:

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow){
};

A continuación, y para estar todos en el mismo contexto, crearemos como ejemplo una nueva sub-clave llamada DemoKey, dentro de InsideWindows, que se creará con la misma función en la clave de HKEY_CURRENT_USER. En una línea, sería:

HKEY_CURRENT_USERInsideWindowsDemoKey

En la sub-clave DemoKey, crearemos nuestro valor llamado DemoValue, de tipo REG_SZ (Para variar un poco el ejemplo dado por Juan Carlos), es decir, String y le daremos como contenido %SystemDrive%UsersDemo para simular un directorio real de Windows. La línea completa, con la sub-clave, quedaría:

HKEY_CURRENT_USERInsideWindowsDemoKeyDemoValue

Para no repetir lo mismo del artículo anterior, pasemos directamente a la declaración de las primeras variables necesarias para RegCreateKeyEx, que con la información anterior sería:

HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"InsideWindows\DemoKey";
DWORD Reserved = 0;
LPTSTR lpClass = NULL;
DWORD dwOptions = REG_OPTION_NON_VOLATILE;
REGSAM samDesired = KEY_SET_VALUE;
LPSECURITY_ATTRIBUTES lpSecurityAtrributes = NULL;
HKEY phkResult;
DWORD lpdwDisposition;

Pasando a la declaración necesaria para RegSetValueEx, con la información anterior, sería:

LPCTSTR lpValueName = L"DemoValue";
DWORD dwType = REG_SZ;
TCHAR lpData[]=TEXT("%SystemDrive%\Users\Demo");
DWORD cbData = sizeof(lpData);

*Nota: Pueden notar que falta hKey y Reserved para la segunda declaración, pero como es el mismo contenido de los que se necesitan para RegCreateKeyEx, sobra volverlos a declarar, así que basta con usarlos nuevamente en la segunda función.

Procedemos entonces a crear la sub-clave referenciando todas las variables declaradas:

//Declarando la función "RegCreateKeyEx".
    RegCreateKeyEx(hKey,
        lpSubKey, Reserved, lpClass,
        dwOptions, samDesired, lpSecurityAtrributes,
        &phkResult, &lpdwDisposition);

Teniendo presente que lpdwDisposition devuelve el resultado de la sub-clave que se creó o se abrió, lo ideal es utilizar esto para dar paso a que Windows escriba el respectivo valor utilizando una sencilla, pero útil sentencia de condición: If. Debemos controlar REG_CREATED_NEW_KEY y REG_OPENED_EXISTING_KEY en una misma pregunta, pues en ambos casos el valor se crea. La condición sería:

if (lpdwDisposition == REG_CREATED_NEW_KEY ||
        lpdwDisposition == REG_OPENED_EXISTING_KEY){

Dado esto, generamos el valor con la siguiente función, referenciando también todas las variables ya declaradas dentro del condicional:

long R = RegSetValueEx(phkResult, lpValueName, Reserved,
                          dwType, (const BYTE *)&lpData, cbData);

*Nota: Como ven, el primer parámetro, que debe ser de tipo HKEY, le estoy enviando phkResult, que contiene el apuntador a la clave que se creó o se abrió, para que el valor se escriba donde debe ser.

Después, si queremos darle un poco de más interés a la mini aplicación, según el resultado que entrega RegSetValueEx, podremos mostrar un Mensaje que nos confirme o deniegue la creación del valor y cerrar el primer If:

if (R == ERROR_SUCCESS){

            MessageBox(NULL, L"El valor se creó correctamente.",
                L"Explorando la API", MB_ICONINFORMATION);
        }
        else{

            MessageBox(NULL, L"Error creando el valor.",
                L"Explorando la API", MB_ICONERROR);

        }

    } //Cierra primer "If".

Por último, debemos controlar –aunque sea en principio con un error genérico- el hecho de que la sub-clave en principio podría no crearse con un “else”:

else //Condicional "Sino" para el primer "If".
    {
        MessageBox(NULL, L"Error creando la clave",
L"Explorando la API", MB_ICONERROR); }

Recordemos además que todo trabajo que se hace sobre una clave o sub-clave debe cerrarse con la función RegCloseKey, utilizando la misma variable de phkResult, así:

RegCloseKey(phkResult); //Cierra la clave

Los que deseen, pueden descargar todo el proyecto listo de Visual Studio desde aquí:

Enlace de SkyDrive: http://sdrv.ms/13R6Kyz

El resultado

Probando todo el código anterior, en caso de ser satisfactoria la creación de la clave y el respectivo valor, podríamos ver el siguiente mensaje al ejecutar el programa:

image

En el Registro de Windows, este sería el resultado:

image

Process Monitor nos confirmaría toda la operación en caso de que siguiéramos la ejecución de la aplicación:

image

Espero les sea de utilidad. ¡Comentarios bienvenidos!

Saludos,

Checho