data bytes c# binary-reproducibility

bytes - ¿Cómo producir siempre.exe idéntico byte-by-byte en la reconstrucción de la aplicación C#?



byte data c# (6)

Actualización: Roslyn parece tener un /feature:deterministic compilador /feature:deterministic para compilaciones reproducibles, aunque todavía no está funcionando al 100% .

Debería poder deshacerse del GUID de depuración deshabilitando la generación de PDB. De lo contrario, establecer el GUID en ceros está bien, solo los depuradores verán esa sección (ya no podrá depurar el ensamblaje, pero aún debería funcionar bien).

Los Detalles de la Implementación Privada son un poco más difíciles: son clases de ayuda internas generadas por el compilador para ciertas construcciones de lenguaje (inicializadores de matriz, sentencias de conmutador que usan cadenas, etc.). Debido a que solo se usan internamente, el nombre de la clase realmente no importa, por lo que puede asignarles un número corriente.

Lo haría pasando por la secuencia de metadatos #Strings y reemplazando todas las cadenas del formulario "<PrivateImplementationDetails> {GUID}" con "<PrivateImplementationDetails> {número de ejecución, rellenado con la misma longitud que un GUID}".

El flujo de metadatos de #Strings es simplemente la lista de cadenas utilizadas por los metadatos, codificadas en UTF-8 y separadas por / 0; por lo tanto, encontrar y reemplazar los nombres debería ser fácil una vez que sepa dónde se encuentra la secuencia #Strings dentro del archivo ejecutable.

Desafortunadamente, los "encabezados de flujo de metadatos" que contienen esta información están bastante ocultos dentro del formato de archivo. Tendrá que comenzar en el encabezado opcional de NT, encontrar el puntero al encabezado de tiempo de ejecución de CLI, resolverlo en una posición de archivo usando la tabla de la sección de PE (es un RVA, pero necesita una posición dentro del archivo), luego ir a La raíz de metadatos y leer los encabezados de flujo.

Primero le daré un poco de información sobre por qué hago esta pregunta:

Actualmente estoy trabajando en una industria estrictamente regulada y, como tal, nuestro código es revisado cuidadosamente por las casas de pruebas oficiales. Estas casas de prueba esperan poder construir el código y generar un archivo .exe o .dll que es EXACTAMENTE el mismo cada vez (¡sin cambiar ningún código obviamente!). Verifican el MD5 y el SHA1 de los ejecutables que crean para garantizar esto.

Hasta este punto, he estado predominantemente codificando en C ++, donde (después de algunos ajustes de configuración del proyecto) logré que los proyectos se reconstruyeran consistentemente en el mismo MD5 / SHA1. Ahora estoy usando C # en un proyecto y tengo grandes dificultades para lograr que los MD5 coincidan después de una reconstrucción. Soy consciente de que hay "Marcas de tiempo" en el encabezado de PE del archivo, y se han borrado a 0. También soy consciente de que existe un GUID para el archivo .exe, que nuevamente se ha borrado a 00 00 00 ... etc. Sin embargo, los archivos todavía no coinciden.

Estoy usando CFF Explorer para ver y editar el encabezado de PE para eliminar las marcas de fecha y hora. Después de usar una herramienta de comparación binaria, solo hay 2 bloques de bytes en los archivos .exe que son diferentes (ambos muy pequeños).

Uno de los bloques inconsistentes aparece justo antes de algún código binario, que en ASCII detalla la ruta del archivo *Project*/obj/Release/xxx.pdb .

EDITAR: ¡ Ahora se sabe que este es el GUID del archivo * .pdb, sin embargo, todavía no sé si puedo modificarlo sin causar ningún error.

El otro bloque aparece en medio de lo que parecen ser nombres de funciones, es decir. (una sección típica) AssemblyName.GetName.Version.get_Version.System.IO.Ports.SerialPort.Parity.Byte.<PrivateImplementationDetails>{

entonces el bloque de código diferente:

4A134ACE-D6A0-461B-A47C-3A4232D90816

seguido por:

"} .ValueType .__ StaticArrayInitTypeSize = 7. $$ method0x60000ab-1.RuntimeFieldHandle.InitializeArray` ... etc.

Cualquier idea o sugerencia sería bienvenida!


Con respecto al problema del GUID del PDB, si especifica que no se debe generar un PDB en la compilación para las versiones de lanzamiento, ¿el binario todavía contiene el GUID del sistema de archivos del PDB?

Para deshabilitar la generación de PDB:

  1. Haga clic derecho en su proyecto en el Explorador de soluciones y seleccione Propiedades.
  2. En el menú de la izquierda, seleccione Crear.
  3. Asegúrese de que la selección de Configuración sea Release (todavía querrá un PDB para la depuración).
  4. Haga clic en el botón Avanzado en la parte inferior derecha.
  5. En Información de salida / depuración, seleccione Ninguno.

Si está compilando desde la consola, use / debug- para obtener el mismo resultado.


Dijiste que después de algunos ajustes en el proyecto, podías hacer que las aplicaciones de C ++ se compilaran repetidamente a los mismos valores de SHA1 / MD5. Estoy en el mismo bote que tú en una industria con un laboratorio de pruebas de terceros que necesita reconstruir exactamente los mismos ejecutables repetidamente.

Al investigar cómo hacer que esto suceda en el VS2005, encontré tu publicación aquí. ¿Podría compartir los ajustes del proyecto que hizo para hacer que las aplicaciones de C ++ se construyan con los mismos valores SHA1 / MD5 de manera consistente? Sería de gran ayuda para mí y para cualquier otro que comparta este requisito.


Echa un vistazo a las respuestas de this pregunta. Especialmente en el enlace externo provisto en el tercero.

EDITAR:

En realidad quiero enlazar a this artículo.


No estoy seguro de esto, pero es solo una idea: ¿está utilizando algún tipo anónimo para el cual el compilador podría generar nombres detrás de escena, que podría ser diferente cada vez que se ejecuta el compilador? Solo una posibilidad que se me ocurrió. Probablemente uno para Jon Skeet ;-)

Actualización: Quizás también podría utilizar addins Reflector para la comparación y el desmontaje.


Use ildasm.exe para desarmar por completo ambos programas y comparar el IL. Luego, puede "limpiar" el código utilizando métodos basados ​​en texto y (de manera predecible) recompilarlo nuevamente.