Skip to content
← Todas las publicaciones
· Delta1 Labs Ofuscación.NETGuía

Ofuscar una app desplegada con ClickOnce: por qué el orden de las operaciones decide si siquiera arranca

Los manifiestos de ClickOnce guardan un hash de cada archivo. Si ofuscas después de generarlos, la app se niega a arrancar con un error de validación. Este es el orden de compilación exacto que hace convivir la ofuscación y ClickOnce.

Hay una forma concreta en que una app de ClickOnce falla tras añadir ofuscación que lleva a la gente por el camino equivocado: la app se instala bien, luego se niega a arrancar con un error de validación de archivo o de hash, y nada en tu código cambió. El instinto es sospechar que el ofuscador rompió el ensamblado. No lo hizo. ClickOnce hace exactamente lo que está diseñado para hacer — negarse a ejecutar un archivo cuyos bytes no coinciden con el hash que registró — y el error real es el orden en que se ejecutaron tus pasos de compilación. Acierta con el orden y la ofuscación y ClickOnce conviven sin dramas.

Por qué ClickOnce es inusualmente sensible

La mayoría de los mecanismos de despliegue copian archivos y los ejecutan. ClickOnce hace más: su manifiesto de aplicación registra, para cada archivo del despliegue, un hash criptográfico y un tamaño, y el runtime de ClickOnce verifica cada archivo contra ese registro antes de arrancar. Es una función de detección de manipulación y corrupción: garantiza que el usuario ejecuta exactamente lo que publicaste.

Esa garantía es justo con lo que choca la ofuscación. La ofuscación reescribe los bytes de tus ensamblados — renombrado, aplanamiento de flujo de control y cifrado de cadenas cambian todos el archivo. Si el hash del manifiesto para MyApp.dll se calculó sobre la DLL anterior a la ofuscación, la DLL posterior a la ofuscación que realmente publicas ya no coincide, y ClickOnce se detiene con un error de validación antes de que se ejecute una línea de tu código.

Obfuscate before manifests are hashed, not after Orden correcto: compilar ofuscar firmarnombre seguro/Authenticode mage: manifiestoshash de archivos finales Orden incorrecto (la app no arranca): compilar mage: manifiestoshash de archivos pre-ofusc. ofuscar → hash no coincide al arrancar

El orden de compilación correcto

La regla cabe en una frase: toda transformación de los ensamblados debe ocurrir antes de generar los manifiestos, y la generación de manifiestos debe ser lo último. En concreto:

  1. Compila el proyecto.
  2. Ofusca los ensamblados de salida.
  3. Vuelve a aplicar el nombre seguro si usaste delay-sign (una ofuscación que reemite el ensamblado debe preservar o reestablecer el nombre seguro — véase volver a firmar ensamblados ofuscados).
  4. Firma con Authenticode los binarios, si los firmas.
  5. Genera los manifiestos de aplicación y de implementación con mage/mageUI o los targets de ClickOnce de MSBuild — aquí es donde se calculan los hashes, sobre los archivos ya finales.
  6. Firma los manifiestos.

Si usas la Publicación de un clic de Visual Studio, la trampa es que la publicación hace el paso 5 por ti justo tras compilar, antes de que cualquier hook de ofuscación post-compilación se haya ejecutado. La solución es sacar la generación de manifiestos del paso de Publicación y ejecutar mage tú mismo tras la ofuscación (un pequeño script de CI), o ejecutar la ofuscación como parte de la compilación de modo que termine antes de que se ejecuten los targets de ClickOnce.

Un esquema mínimo de CI

# 1-2: build then obfuscate the output
dotnet build -c Release -o publish
nebula protect publish/MyApp.dll   # (plus other assemblies)

# 3-4: re-sign as needed
sn -R publish/MyApp.dll keypair.snk           # if delay-signed
signtool sign /f cert.pfx publish/MyApp.dll    # Authenticode (optional)

# 5: generate manifests over the FINAL files (hashes computed now)
mage -New Application -Processor msil -ToFile publish/MyApp.exe.manifest \
     -Name "MyApp" -Version 1.2.0.0 -FromDirectory publish
mage -New Deployment -Processor msil -Install true \
     -ToFile MyApp.application -AppManifest publish/MyApp.exe.manifest \
     -providerUrl "https://downloads.example.com/MyApp/"

# 6: sign the manifests
mage -Sign MyApp.application -CertFile cert.pfx

Como los hashes del paso 5 se toman sobre los ensamblados ofuscados y firmados, la verificación del runtime de ClickOnce pasa y la app arranca.

Cómo hacerlo con Nebula

Nebula encaja en el paso de ofuscación anterior y, como se ejecuta como etapa de compilación/CI (véase ofuscar solo en el servidor de compilación y las guías de Azure DevOps / GitHub Actions), es sencillo situarlo antes de la generación de manifiestos de ClickOnce. Preserva la firma con nombre seguro para que el paso de volver a firmar sea limpio, y sus reglas de conservación manejan cualquier reflexión de WinForms/WPF que haga tu app. La única regla específica de ClickOnce es el orden — acierta con eso y nada más cambia.

Empieza con la edición gratuita, o consulta los planes.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.