Com linguagens de máquina virtual baseadas em bytecode, como Java, VB.NET, C #, ActionScript 3.0, etc., você ouve algumas vezes sobre como é fácil baixar um descompilador da Internet, executar o bytecode nele uma boa hora e muitas vezes, crie algo não muito distante do código-fonte original em questão de segundos. Supostamente esse tipo de linguagem é particularmente vulnerável a isso.
Recentemente, comecei a me perguntar por que você não ouve mais sobre isso sobre o código binário nativo, quando pelo menos sabe em qual idioma ele foi escrito originalmente (e, portanto, em qual idioma tentar descompilar). Por um longo tempo, achei que era apenas porque a linguagem de máquina nativa é muito mais louca e mais complexa do que o código de código típico.
Mas como é o bytecode? Se parece com isso:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
E como é o código de máquina nativo (em hexadecimal)? Obviamente, fica assim:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
E as instruções vêm de um estado de espírito um tanto semelhante:
1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX
Portanto, dada a linguagem para tentar decompilar algum binário nativo, digamos C ++, o que há de tão difícil nisso? As únicas duas idéias que vêm à mente imediatamente são: 1) é realmente muito mais complicado que o bytecode; ou 2) algo sobre o fato de os sistemas operacionais tenderem a paginar os programas e espalhar suas peças causa muitos problemas. Se uma dessas possibilidades estiver correta, explique. Mas de qualquer maneira, por que você nunca ouve isso basicamente?
NOTA
Estou prestes a aceitar uma das respostas, mas quero mencionar algo primeiro. Quase todo mundo está se referindo ao fato de que diferentes partes do código fonte original podem ser mapeadas para o mesmo código de máquina; nomes de variáveis locais são perdidos, você não sabe que tipo de loop foi usado originalmente etc.
No entanto, exemplos como os dois que acabamos de mencionar são meio triviais aos meus olhos. Algumas das respostas, no entanto, tendem a afirmar que a diferença entre o código de máquina e a fonte original é drasticamente muito mais do que algo tão trivial.
Mas, por exemplo, quando se trata de nomes de variáveis locais e tipos de loop, o bytecode também perde essas informações (pelo menos no ActionScript 3.0). Eu puxei essas coisas de volta através de um descompilador antes e realmente não me importava se uma variável era chamada strMyLocalString:String
ou loc1
. Eu ainda podia olhar nesse pequeno escopo local e ver como ele está sendo usado sem muitos problemas. E um for
loop é praticamente a mesma coisa que umwhile
loop, se você pensar sobre isso. Além disso, mesmo quando eu executava a fonte através do irrFuscator (que, diferentemente do secureSWF, não faz muito mais do que apenas randomizar variáveis de membros e nomes de funções), ainda parecia que você poderia começar a isolar determinadas variáveis e funções em classes menores, figura como eles são usados, atribua seus próprios nomes a eles e trabalhe a partir daí.
Para que isso seja um grande negócio, o código da máquina precisaria perder muito mais informações do que isso, e algumas das respostas vão para isso.