Esta é uma questão muito interessante. Existem milhões de conjuntos de instruções por aí, mas apenas alguns deles muito usados.
A primeira coisa que eu observaria é a origem e o uso pretendido. Se você suspeita que foi projetado nos EUA, você estaria segmentando principalmente processadores com fichas técnicas disponíveis em inglês, por exemplo. Se ele foi projetado na Ásia, existem vários processadores que eles usam para dispositivos fabricados em massa que os engenheiros dos EUA raramente veem. Até a Europa possui alguns processadores que são mais comuns que outros.
Eu, então, daria uma olhada no tamanho e na funcionalidade do código (supondo que você saiba o que o código faz até certo ponto). Se tiver alguns megabytes de código, você pode descontar a maioria dos processadores de 8 bits incorporados e começar a procurar dispositivos maiores com memória externa. Se tiver alguns kilobytes ou menos, você prefere se concentrar em dispositivos menores e mais baratos. Se a funcionalidade for simples, pode até ser código para um processador de quatro bits.
Neste ponto, vale a pena olhar para a estrutura da memória. É provável que haja uma seção de programa e uma seção de dados no mínimo. Se for um arquivo binário (em comparação com o intel hex ou o registro da motorola), você terá poucas informações sobre o local em que certos blocos de dados estão sendo colocados na memória. Um editor hexadecimal pode mostrar alguns padrões. Se for fornecido em um formato de registro hexadecimal, você poderá obter mais informações sobre a estrutura de memória do processador a que se destina. Alguns processadores são redefinidos no local 0 da memória do programa, outros no local mais alto da memória. O programa pode incluir valores iniciais da EEPROM em um local de memória separado. Se for destinado a um processador seguro (como usado no setor bancário), pode até ter chaves de segurança para um local de memória estranho.
Dependendo do idioma em que foi programado, você pode ter algumas dicas adicionais. Se foi programado em C ou em uma linguagem procedural semelhante, as funções quase sempre começam com uma sequência de instruções para salvar determinados registros na pilha (muitos pushs) e logo antes de retornar muitos pops para retornar os valores originais da pilha . Se você conseguir fazer algum reconhecimento de padrões, encontrará muitas dessas seqüências por toda parte e poderá determinar quais instruções são mais prováveis de instruções push / pop, return etc., que podem restringir um pouco suas escolhas.
Se for um dispositivo incorporado com interrupções, pode haver uma tabela de vetores de interrupção, que parecerá um monte de saltos para diferentes locais de memória em um bloco grande, provavelmente em um local conveniente (endereço de 0x ??? 0, por exemplo) . As tabelas de salto são usadas em outros lugares também para outras coisas, mas se você puder localizar uma sequência de instruções que pareçam idênticas, exceto para qual seria o endereço para o qual ir, você poderá inferir a aparência de uma instrução de salto e restringir novamente suas escolhas para baixo.
Nesse ponto, eu começaria com as arquiteturas de processador mais comuns e veria se algo se correlaciona. x86, arm, mips, 8051, avr, pic, powerpc, Z80, 68k, 6502, etc, etc, etc. Existem listas de processadores e conjuntos de instruções comuns - pelo menos no mundo de língua inglesa - que podem ser úteis.
Não conheço nenhuma ferramenta automatizada que possa ajudar com isso, mas o MAME emula muitas arquiteturas de processador e um método possível é executar o código por vários processadores e observar os registros para ver se algo clica de acordo com o que você conhece o design.