Identificar el tipo de procesador del código binario sin procesar

19

No está realmente relacionado con las fichas, pero espero obtener algunas instrucciones a seguir desde aquí.

Tengo un fragmento de código, pero no sé para qué procesador está destinado. ¿Hay herramientas disponibles que puedan ayudarme a identificar el tipo de código? ¿Qué métodos estadísticos pueden ayudar? ¿Distribución de bytes? Distribución de pares, etc. ¿Cadenas de Markov tal vez?

mentalista
fuente
77
¿Podría darnos los primeros 200 bytes en hexadecimal sin procesar?
pingswept
Esta es una pregunta divertida. ¿Qué tipo de dispositivo estás pirateando?
DavidEGrayson
1
podría intentar alimentarlo con un par de desensambladores diferentes y ver qué sucede.
JustJeff
2
¡Voy a nombrar ese código en 100 bytes! = P
JustJeff
Gran pregunta Sin embargo, podría ser una mejor opción para StackOverflow.
Sharptooth

Respuestas:

16

Intenta ejecutarlo a través del archivo GNU. Si tiene un encabezado estándar, lo recogerá.

P.ej.

jrt@lin:~/src$ file foo
foo: ELF 32-bit LSB executable, Atmel AVR 8-bit, version 1 (SYSV), statically linked, not stripped
Toby Jaffey
fuente
Intenté eso. El archivo GNU dice que son "datos".
mentalista
3
¿Podría publicar algo de eso? ¿Intentó buscar ASCII en él con "cadenas"?
Toby Jaffey
9

Esta es una pregunta muy interesante. Existen millones de conjuntos de instrucciones, pero solo unos pocos de los más utilizados.

Lo primero que miraría es el origen y el uso previsto. Si sospecha que fue diseñado en los EE. UU., Principalmente se centraría en procesadores con hojas de datos disponibles en inglés, por ejemplo. Si fue diseñado en Asia, entonces hay una serie de procesadores que utilizan para dispositivos fabricados en masa que los ingenieros estadounidenses rara vez ven. Incluso Europa tiene algunos procesadores que son más comunes que otros.

Luego echaría un vistazo al tamaño y la funcionalidad del código (suponiendo que sepa lo que hace el código hasta cierto punto). Si se trata de unos pocos megabytes de código, puede descartar la mayoría de los procesadores integrados de 8 bits y comenzar a buscar dispositivos más grandes con memoria externa. Si son unos pocos kilobytes o menos, entonces querrás enfocarte en dispositivos más pequeños y baratos. Si la funcionalidad es simple, incluso podría ser un código para un procesador de cuatro bits.

En este punto, vale la pena mirar la estructura de la memoria. Es probable que haya una sección de programa y una sección de datos como mínimo. Si se trata de un archivo binario (en comparación con el registro de Intel hexadecimal o motorola), tiene poca información sobre dónde se están colocando ciertos fragmentos de datos en la memoria. Un editor hexadecimal puede mostrar algunos patrones. Si viene en un formato de registro hexadecimal, es posible que tenga más información sobre la estructura de memoria del procesador para el que está destinado. Algunos procesadores se reinician en la ubicación de memoria del programa 0, algunos en la ubicación de memoria más alta. El programa puede incluir valores iniciales de EEPROM en una ubicación de memoria separada. Si está destinado a un procesador seguro (como se usa en la banca), incluso podría tener claves de seguridad para una ubicación de memoria extraña.

Dependiendo del idioma en el que se programó, es posible que tenga algunas pistas adicionales. Si se programó en C o en un lenguaje de procedimiento similar, las funciones casi siempre comenzarán con una secuencia de instrucciones para guardar ciertos registros en la pila (muchos empujes) y luego justo antes de devolver muchas ventanas emergentes para devolver los valores originales de la pila . Si puede hacer algún reconocimiento de patrones, encontrará muchas de estas secuencias en todo momento y podrá determinar qué instrucciones son más probablemente instrucciones push / pop, retorno, etc., que podrían reducir un poco sus opciones.

Si es un dispositivo integrado con interrupciones, puede tener una tabla de vectores de interrupciones, que se verá como un montón de saltos a diferentes ubicaciones de memoria, todo en un bloque grande, probablemente en una ubicación conveniente (dirección de 0x ??? 0, por ejemplo) . Las tablas de salto también se usan en otras partes para otras cosas, pero si puede ubicar una secuencia de instrucciones que se vean idénticas, excepto cuál sería la dirección a la que saltar, podría inferir cómo se ve una instrucción de salto, y nuevamente sus elecciones abajo.

En ese punto, comenzaría con las arquitecturas de procesador más comunes y vería si algo se correlaciona. x86, arm, mips, 8051, avr, pic, powerpc, Z80, 68k, 6502, etc, etc., etc. Hay listas de procesadores comunes y conjuntos de instrucciones, al menos en el mundo de habla inglesa, que podrían ser útiles.

No conozco ninguna herramienta automatizada que ayude con esto, pero MAME emula una gran cantidad de arquitecturas de procesador, y un posible método es ejecutar el código a través de varios procesadores y ver los registros para ver si algo hace clic de acuerdo con lo que sabes sobre el diseño.

Adam Davis
fuente
"Incluso Europa tiene algunos procesadores que son más comunes que otros". Viviendo en Europa, esto nunca se me ocurrió. ¿Puedes dar ejemplos?
stevenvh
@stevenvh Debido a las compañías Acorn y Sinclair, los sistemas integrados basados ​​en 6502 y Z80 fueron muy populares. Y, por supuesto, el procesador ARM comenzó en Acorn Computers.
Adam Davis
5

Idea: ¿conoce la antigüedad del código fuente, es decir, en qué época / año se creó?

Si era lo suficientemente viejo, podría darte una pista sobre para qué procesador fue escrito. Puede tomar la edad / año en que fue escrito y determinar qué procesador (es) fueron populares en ese período de tiempo, e intentar cargar / ejecutar el archivo hexadecimal en esos.

Pensándolo bien, dada la proliferación masiva de procesadores en los últimos 20 años, esta podría ser una técnica de aguja en un pajar y no sería muy fructífera.

J. Polfer
fuente
4

Hace muchas lunas, cuando no había tantos núcleos de procesador diferentes, identifiqué el código Z80 varias veces a través del análisis de frecuencia . Para el Z80 CDes el código de máquina call subroutiney C9es return from subroutine(nunca lo olvidaré), y estos son a menudo los códigos más frecuentes. Sin embargo, esto requiere que esté familiarizado con las instrucciones establecidas en un nivel de código de máquina. Tener experiencia en el ensamblaje a mano ayuda (lo hice mucho, y todavía puedo contar hacia atrás en hexadecimal para calcular las compensaciones).

stevenvh
fuente
3

Si el archivo es para un PIC de 12 o 14 bits, cada par de bytes será una palabra de 12 o 14 bits, normalmente almacenada LSB primero, con los dos o cuatro bits más significativos libres.

Super gato
fuente
1

Si se compilara de un lenguaje como C o Pascal, habría ciertas secuencias estándar de binario que podría buscar. Con C, por ejemplo, casi todas las funciones comienzan con algo que guarda el puntero de la pila en un puntero de "marco" o "enlace". Para cualquier procesador dado, generalmente solo hay un par de formas de hacerlo. Entonces, podría responder "es este código para el procesador X" buscando el binario de X para estas secuencias.

Dicho esto, tuve un poco de suerte al diferenciar entre 8088, 6502 y 68000 binarios simplemente usando histogramas. Cualquier procesador tiene ciertos códigos de operación de instrucciones legales, y estos tienden a usarse un poco más a menudo que el promedio. Con una gran cantidad de binario, puede comenzar a ver ciertas tendencias. Sin embargo, esto se hace difícil por el hecho de que todos los operandos en una determinada pieza de binario tienden a no correlacionarse con el tipo de procesador dado, y esto esencialmente solo hace ruido en los datos de su histograma. Además, incluso dos programas diferentes para el mismo procesador pueden tener histogramas notablemente diferentes. Aún así, puede darte un lugar para comenzar.

JustJeff
fuente