# Descompilador

Un descompilador és un programa informàtic que torna a traduir un fitxer executable a codi font d'alt nivell. A diferència d'un compilador, que converteix codi d'alt nivell en codi màquina, un descompilador realitza el procés invers. Mentre que els desensambladors tradueixen els executables al llenguatge assemblador, els descompiladors van un pas més enllà reconstruint el desmuntatge en llenguatges de nivell superior com C. Tanmateix, els descompiladors sovint no poden recrear perfectament el codi font original i poden produir codi ofuscat o menys llegible.

## Introducció

La descompilació és el procés de transformació del codi executable en un format d'alt nivell llegible per l'home mitjançant un descompilador. Aquest procés s'utilitza habitualment per a tasques que impliquen enginyeria inversa de la lògica darrere del codi executable, com ara recuperar el codi font perdut o no disponible. Els descompiladors s'enfronten a reptes inherents a causa de la pèrdua d'informació crítica durant el procés de compilació, com ara noms de variables, comentaris i estructura de codi.
Alguns factors poden afectar l'èxit de la descompilació. Executables que contenen metadades detallades, com ara les utilitzades per Java i. NET, són més fàcils de fer enginyeria inversa perquè sovint conserven estructures de classe, signatures de mètodes i informació de depuració. Els fitxers executables sense aquest context són molt més difícils de traduir en codi font significatiu.
Alguns desenvolupadors de programari poden ofuscar, empaquetar o xifrar parts dels seus programes executables, fent que el codi descompilat sigui molt més difícil d'interpretar. Aquestes tècniques sovint es fan per dissuadir l'enginyeria inversa, fent que el procés sigui més difícil i requereix molt de temps.

## Disseny

Els descompiladors es poden considerar com una sèrie de fases, cadascuna de les quals aporta aspectes específics del procés de descompilació global.

### Carregador

La primera fase de descompilació carrega i analitza el codi màquina d'entrada o el format de fitxer binari del programa de llenguatge intermedi. Hauria de poder descobrir fets bàsics sobre el programa d'entrada, com ara l'arquitectura (Pentium, PowerPC, etc.) i el punt d'entrada. En molts casos, hauria de ser capaç de trobar l'equivalent de la funció main d'un programa C, que és l'inici del codi escrit per l'usuari. Això exclou el codi d'inicialització en temps d'execució, que no s'ha de descompilar si és possible. Si estan disponibles, també es carreguen les taules de símbols i les dades de depuració. La portada pot ser capaç d'identificar les biblioteques utilitzades encara que estiguin enllaçades amb el codi, això proporcionarà interfícies de biblioteca. Si pot determinar el compilador o els compiladors utilitzats, pot proporcionar informació útil per identificar els idiomes del codi.

### Desensamblatge

La següent fase lògica és el desassemblador de les instruccions del codi màquina en una representació intermèdia (IR) independent de la màquina. Per exemple, la instrucció de la màquina Pentium
es podria traduir a l'IR

### Modismes

Les seqüències idiomàtiques de codi màquina són seqüències de codi la semàntica combinada del qual no és immediatament evident a partir de la semàntica individual de les instruccions. Ja sigui com a part de la fase de desmuntatge, o com a part d'anàlisis posteriors, aquestes seqüències idiomàtiques s'han de traduir a un IR equivalent conegut. Per exemple, el codi de muntatge x86 :
es podria traduir a
eax := abs(eax);
Algunes seqüències idiomàtiques són independents de la màquina; alguns inclouen només una instrucció. Per exemple, xor eax, eax esborra el registre eax (el posa a zero). Això es pot implementar amb una regla de simplificació independent de la màquina, com ara a = 0.
En general, el millor és retardar la detecció de seqüències idiomàtiques si és possible, a etapes posteriors que es veuen menys afectades per l'ordre de les instruccions. Per exemple, la fase de programació d'instruccions d'un compilador pot inserir altres instruccions en una seqüència idiomàtica o canviar l'ordre de les instruccions en la seqüència. Un procés de concordança de patrons en la fase de desmuntatge probablement no reconeixeria el patró alterat. Les fases posteriors agrupen les expressions d'instrucció en expressions més complexes i les modifiquen en una forma canònica (estandarditzada), fent més probable que fins i tot l'idioma alterat coincideixi amb un patró de nivell superior més endavant en la descompilació.
És especialment important reconèixer els idiomes del compilador per a les trucades de subrutines, el maneig d'excepcions i les declaracions de commutació. Alguns idiomes també tenen un suport ampli per a cadenes o nombres enters llargs.

### Anàlisi del programa

Es poden aplicar diverses anàlisis de programes a l'IR. En particular, la propagació d'expressions combina la semàntica de diverses instruccions en expressions més complexes. Per exemple,
podria donar lloc a la següent IR després de la propagació de l'expressió:
m[ebx+12] := m[ebx+12] - (m[ebx+4] + m[ebx+8]);
L'expressió resultant s'assembla més a un llenguatge d'alt nivell i també ha eliminat l'ús del registre de la màquina eax. Les anàlisis posteriors poden eliminar el registre ebx.

### Anàlisi del flux de dades

Els llocs on es defineixen i utilitzen els continguts del registre s'han de localitzar mitjançant l'anàlisi del flux de dades. La mateixa anàlisi es pot aplicar a les ubicacions que s'utilitzen per a dades temporals i locals. Aleshores es pot formar un nom diferent per a cada conjunt connectat de definicions de valors i usos. És possible que s'utilitzi la mateixa ubicació de la variable local per a més d'una variable en diferents parts del programa original. Encara pitjor, és possible que l'anàlisi del flux de dades identifiqui un camí pel qual un valor pot fluir entre dos d'aquests usos tot i que mai no passaria ni importaria en realitat. En casos dolents, això pot comportar la necessitat de definir una ubicació com una unió de tipus. El descompilador pot permetre a l'usuari trencar explícitament aquestes dependències no naturals que donaran lloc a un codi més clar. Això, per descomptat, significa que una variable s'utilitza potencialment sense ser inicialitzada i, per tant, indica un problema al programa original.

### Anàlisi de tipus

Un bon descompilador de codi màquina realitzarà anàlisi de tipus. Aquí, la manera com s'utilitzen els registres o les ubicacions de memòria genera restriccions sobre el possible tipus de ubicació. Per exemple, una instrucció and implica que l'operand és un nombre enter; els programes no utilitzen aquesta operació en valors de coma flotant (excepte en codi de biblioteca especial) o en punters. Una instrucció add dóna com a resultat tres restriccions, ja que els operands poden ser tots dos enters, o un enter i un punter (amb resultats enters i punters respectivament; la tercera restricció prové de l'ordenació dels dos operands quan els tipus són diferents).
Es poden reconèixer diverses expressions d'alt nivell que desencadenen el reconeixement d'estructures o matrius. No obstant això, és difícil distingir moltes de les possibilitats, a causa de la llibertat que permeten el codi màquina o fins i tot alguns llenguatges d'alt nivell com el C amb càlculs i aritmètica de punters.
L'exemple de la secció anterior podria donar com a resultat el següent codi d'alt nivell:

### Estructuració

La penúltima fase de descompilació implica l'estructuració de l'IR en construccions de nivell superior, com ara bucles while i declaracions condicionals if/then/else. Per exemple, el codi de màquina
es podria traduir a:
El codi no estructurat és més difícil de traduir en codi estructurat que el codi ja estructurat. Les solucions inclouen replicar algun codi o afegir variables booleanes.

### Generació de codi

La fase final és la generació del codi d'alt nivell a la part posterior del descompilador. De la mateixa manera que un compilador pot tenir diversos back-ends per generar codi màquina per a diferents arquitectures, un descompilador pot tenir diversos back-ends per generar codi d'alt nivell en diferents llenguatges d'alt nivell.
Just abans de la generació del codi, pot ser desitjable permetre una edició interactiva de l'IR, potser utilitzant algun tipus d'interfície gràfica d'usuari. Això permetria a l'usuari introduir comentaris i noms de variables i funcions no genèrics. Tanmateix, aquests s'introdueixen gairebé amb la mateixa facilitat en una edició posterior a la descompilació. És possible que l'usuari vulgui canviar aspectes estructurals, com ara convertir un bucle while en un bucle for. Aquests es modifiquen menys fàcilment amb un editor de text senzill, tot i que les eines de refactorització del codi font poden ajudar amb aquest procés. És possible que l'usuari hagi d'introduir informació que no s'ha pogut identificar durant la fase d'anàlisi de tipus, per exemple, modificant una expressió de memòria a una matriu o expressió d'estructura. Finalment, pot ser que s'hagi de corregir un IR incorrecte o fer canvis per fer que el codi de sortida sigui més llegible.

## Referències

* ↑ «What is decompile?» (en anglès). [Consulta: 30 desembre 2024].
* ↑ «What is decompilation?» (en anglès). [Consulta: 30 desembre 2024].
* ↑ «What does a decompiler do?» (en anglès). [Consulta: 30 desembre 2024].
* ↑ «What is a Decompiler? - Definition & Uses» (en anglès). [Consulta: 30 desembre 2024].