Renombrado de XAML
Las aplicaciones Windows Presentation Foundation (WPF) y, más recientemente, MAUI usan el lenguaje de marcado declarativo XAML y BAML (XAML compilado) para que los diseñadores visuales puedan crear directamente los elementos de la interfaz de usuario.
Babel Obfuscator puede analizar los recursos XAML y BAML y renombrar todos los miembros a los que hacen referencia, lo que aumenta el porcentaje de símbolos ofuscados y hace que el código XAML sea más difícil de leer. Además, Babel puede combinar varios archivos de ensamblado que contienen recursos XAML o BAML en un único archivo de ensamblado, lo que mejora la organización y simplifica el despliegue de la aplicación.
El renombrado de símbolos de XAML y BAML se activa con la opción --xaml en la línea de comandos. Esta opción tiene parámetros opcionales adicionales, que pueden usarse para reforzar la ofuscación de XAML (BAML).
Línea de comandos
babel.exe myapp.exe --xamlTarea Babel de MSBuild
<PropertyGroup>
<ObfuscateXaml>true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Babel Obfuscator admite algunos ajustes avanzados de XAML para configurar con más detalle el proceso de ofuscación de XAML, mediante pares clave-valor que se pasan después de la opción --xaml.
Entre los pares clave-valor disponibles están:
keys
En XAML, un recurso estático es un recurso que se define en tiempo de diseño y al que puede hacerse referencia desde otras partes de la aplicación, como controles o estilos. El recurso se identifica mediante un nombre de clave, que se usa para hacer referencia a él desde el código XAML.
Cuando está activada, Babel Obfuscator renombra los nombres de clave de los recursos estáticos del código XAML/BAML. Esto puede aumentar el nivel de ofuscación del código y hacer que a los atacantes les resulte más difícil entender la finalidad original de un recurso.
res
Cuando está activada, permite a Babel ofuscar los nombres de los recursos XAML/BAML. Esto significa que los nombres de los recursos usados en el código XAML/BAML, como imágenes o cadenas, se renombran para ocultar su finalidad original. Así, a los atacantes les puede resultar más difícil entender la estructura y la función del código XAML/BAML, lo que puede mejorar la seguridad general de su aplicación.
strip
Esta opción elimina la información de líneas y los espacios en blanco del código XAML/BAML ofuscado. Así se dificulta la ingeniería inversa del código original, porque se elimina información de depuración que podría ayudar a un atacante a reconstruir el código fuente original. Eliminar la información de líneas y los espacios en blanco también puede reducir el tamaño del archivo XAML/BAML ofuscado, que resulta más eficiente y se carga más rápido.
manual
De forma predeterminada, Babel Obfuscator ofusca automáticamente todos los miembros públicos a los que se hace referencia en el código XAML o BAML. Sin embargo, cuando se necesita un control más preciso, puede activarse la opción manual. Con ella, el usuario indica manualmente qué miembros públicos deben ofuscarse, mediante reglas rápidas o archivos de reglas XML. Esto da más control sobre el proceso de ofuscación, pero exige más configuración por parte del usuario.
babel.exe myapp.exe --xaml keys=on --xaml res=on --xaml strip=on<PropertyGroup>
<ObfuscateXaml>keys=true;strip=true;manual=false;res=true;true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Alinear los literales de cadena con los miembros renombrados vinculados a XAML
Cuando se compila un ensamblado WPF, el compilador suele incrustar cada página XAML como BAML (la forma binaria de XAML) en los recursos del ensamblado. Durante la fase de lectura, Babel inspecciona este BAML y, para cada declaración x:Name, intenta vincular el nombre con el campo de respaldo correspondiente del código subyacente, en el tipo del elemento raíz. Un campo para el que la vinculación tiene éxito se trata como vinculado a XAML durante el resto de la ejecución de la ofuscación.
Cuando se renombra uno de estos miembros vinculados a XAML, Babel realiza un paso adicional de alineación en el tipo que lo declara. Recorre todos los cuerpos de método del tipo y reescribe cada literal de cadena cuyo valor es igual al nombre original del miembro, sustituyéndolo por el nombre nuevo. La coincidencia es una simple igualdad de cadenas sobre el texto del literal, y la reescritura se aplica a todos esos literales del tipo, con independencia de cómo se usen después. Los únicos literales exentos de esta reescritura son los que se pasan a System.Resources.ResourceManager y los sitios de llamada excluidos expresamente mediante reglas de renombrado proporcionadas por el usuario.
El objetivo es que las búsquedas por nombre que WPF hace en tiempo de ejecución desde el código subyacente sigan funcionando después del renombrado. Patrones como this.FindName("tabPreise"), métodos auxiliares personalizados como GetControlByName<T>(string name) o cualquier otro código que resuelva un miembro o un elemento con nombre mediante el nombre de cadena que tenía en el código fuente siguen funcionando, porque los literales se han mantenido sincronizados con el campo renombrado. Como la detección es estructural y no se basa en atributos, esta alineación incluye automáticamente los métodos auxiliares definidos por el usuario, sin exigir que el método auxiliar lleve un atributo que lo solicite.
Por ejemplo, dado el siguiente código subyacente:
private TabItem tabPreise { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("tabPreise");
// ...
}Después de que Babel ofusque el ensamblado, el campo queda renombrado y el literal que lo nombra se alinea con el nombre nuevo:
private TabItem cm { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("cm");
// ...
}La alineación solo se produce cuando la vinculación BAML descrita más arriba tiene éxito. Si el tipo del elemento BAML no puede resolverse (normalmente porque el ensamblado que lo define no está en la ruta de búsqueda de Babel y el mecanismo de resolución emite la advertencia W00013 para ese ensamblado), la vinculación falla sin avisar y el miembro no se marca como vinculado a XAML. El renombrado del campo en sí no depende del indicador de XAML, así que el campo recibe igualmente su nombre nuevo; en cambio, los literales que nombran el campo original quedan intactos, y el ensamblado ofuscado contendrá IL incoherente. Cualquier búsqueda por nombre en tiempo de ejecución que dependiera de esos literales fallará en tiempo de ejecución.
Hay dos medidas de mitigación, por este orden:
-
Trate W00013 como un error que bloquea la compilación en los proyectos que contienen BAML incrustado. Añada a la ruta de búsqueda de Babel, con la opción
--addsearch, los directorios de todos los ensamblados a los que se hace referencia y que definen tipos de elementos XAML, de modo que el mecanismo de resolución de BAML pueda vincular todos los tipos de elemento. Con todos los tipos de elemento resueltos, el paso de alineación se ejecuta según lo previsto. -
Cuando lo que se quiere es conservar el nombre original (por ejemplo, cuando junto al ensamblado se distribuyen archivos
.xamlindependientes que hacen referencia al campo por su nombre original), excluya el campo del renombrado con una regla XML bloqueada:
<Rule name="keep-xname-tabPreise"
feature="renaming" exclude="true" locked="true">
<Target>Fields,Properties,Methods</Target>
<Pattern>MyNamespace.MyForm::tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::get_tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::set_tabPreise</Pattern>
</Rule>Como el nombre del campo no cambia, el paso de alineación no tiene nada que reescribir, y el ensamblado sigue siendo coherente tanto con el BAML como con los archivos XAML sueltos que hagan referencia a tabPreise.
Para tener una visión más amplia de cuándo W00013 es meramente informativa y cuándo se corresponde con un cambio real en la salida ofuscada, consulte W00013 en el proceso de vinculación de BAML en la referencia de línea de comandos.