Source-linked AI summary

Augmenting Decompiler Output with Learned Variable Names and Types

Qibin Chen, Jeremy Lacomis, Edward J. Schwartz, Claire Le Goues, Graham Neubig, Bogdan Vasilescu

arXiv:2108.06363v1cs.SEcs.PL

TL;DR

Decompilers cannot recover developer-written variable names and types lost during compilation, although those details aid program comprehension. DIRTY learns to predict names and types in decompiled code, and on a GitHub-mined C dataset it outperforms prior work, recovering original names 66.4% of the time and types 75.8% of the time.

  • Problem

    Compilation destroys names and types, which are useful for program comprehension but are typically absent from decompiler output.

    Source: §1 · p. 1
  • Method

    DIRTY uses a Transformer-based neural model to recommend variable names and types in decompiled code.

    Source: §1 · p. 2
  • Results

    66.4% of the time for original names and 75.8% for original types, DIRTY recovered developers’ choices and outperformed prior work.

    Source: §6 · p. 13
  • Takeaways & Limitations

    Meaningful variable types can serve as code documentation that helps improve readability and understandability.

    Source: §1 · p. 1

    DIRTY’s preliminary experiments with unseen structure types reduced overall prediction accuracy and slowed prediction, so handling those types is left to future work.

    Source: §5 · p. 13

Abstract

from arXiv · show

A common tool used by security professionals for reverse-engineering binaries found in the wild is the decompiler. A decompiler attempts to reverse compilation, transforming a binary to a higher-level language such as C. High-level languages ease reasoning about programs by providing useful abstractions such as loops, typed variables, and comments, but these abstractions are lost during compilation. Decompilers are able to deterministically reconstruct structural properties of code, but comments, variable names, and custom variable types are technically impossible to recover. In this paper we present DIRTY (DecompIled variable ReTYper), a novel technique for improving the quality of decompiler output that automatically generates meaningful variable names and types. Empirical evaluation on a novel dataset of C code mined from GitHub shows that DIRTY outperforms prior work approaches by a sizable margin, recovering the original names written by developers 66.4% of the time and the original types 75.8% of the time.

1 Introduction

Decompiler output is more readable than assembly but loses developer-written names and types, while data-layout ambiguity can make even type recovery difficult. DIRTY combines learned predictions with layout information to recover variable names and types at scale.

1 Introduction

  • Compilation removes names and types, so decompilers cannot fully reconstruct developer-written code even when they restore readable abstractions.These missing details contribute to program comprehension, and prior work has shown that names can be learned from repetitive patterns in human-written code.Source: §1 · p. 1
  • A lost struct type can turn two named point coordinates into float arrays, obscuring that they represent a point and which coordinate each index denotes.Types can act as code documentation that improves readability and understandability.Source: §1 · pp. 1–2
  • Padding can leave the decompiler unable to distinguish a three-byte array plus padding from a four-byte array whose last element is unused.The decompiler can identify where adjacent variables begin but cannot tell whether the intervening byte belongs to the array.Source: §1 · p. 2, Figure 2 · p. 2
  • Prior type-recovery systems typically support few manually defined types and known library calls, and do not address padding.Earlier approaches also differ in whether they recover only syntactic types or semantic type names.Source: §1 · p. 2
  • DIRTY mines source code to train a Transformer, using a Data Layout Encoder for padding and a joint Multi-Task architecture for renaming and retyping.The paper also introduces DIRT, a dataset of nearly 1 million unique functions and 368 million code tokens.Source: §1 · p. 2
  • DIRTY recovered developers’ original variable names 66.4% of the time and types 75.8% of the time, outperforming prior work.The system supports 48,888 types encountered in open-source C code, compared with REWARDS’ 150 type names across 84 standard-library calls.Source: §1 · p. 2

2 Model Design

DIRTY uses an encoder-decoder model to predict variable types from decompiled code, adding data-layout information and jointly predicting names. Its design combines contextual code representations with variable-level prediction and layout-aware type scoring.

2 Model Design

  • DIRTY represents decompiled code with an encoder-decoder neural network that predicts variable types and names.The section frames model design around generating predictions for variables in individual decompiled functions.Source: §2 · p. 3, §2.1 · p. 3

2.1 The Encoder-Decoder Architecture

  • The encoder-decoder architecture maps variable-length decompiled-code input to variable-length predictions, unlike fixed-length classification models.An encoder produces a fixed-length representation that the decoder converts into a variable-length output sequence.Source: §2.1 · p. 3

2.2 Transformers

  • Transformers capture long-range dependencies in code and enable more parallel GPU computation, supporting faster training on a dataset of 368 million decompiled code tokens.The model retains the original Transformer architecture rather than adopting later changes tailored to natural-language tasks.Source: §2.2 · p. 3

2.3 DIRTY’s Architecture

  • DIRTY pools token representations by variable, then autoregressively predicts types, using beam search to balance greedy speed against exhaustive search.Its fixed type library limits predictions to types seen during training.Source: §2.3 · pp. 4–5

2.4 Data Layout Encoder

  • The Data Layout Encoder uses variable layout to softly adjust type logits, reducing incompatible predictions without ruling types out when decompiler layouts are wrong.Its inputs include storage location, size, and member offsets.Source: §2.4 · p. 5

2.5 Multi-Task

  • DIRTY jointly predicts each variable’s type and name, interleaving the two predictions and using layout information only for type prediction.The authors choose types first because they believe type prediction is easier and reflects how developers define variables.Source: §2.5 · p. 6

3 Evaluation

The evaluation assesses DIRTY’s renaming and retyping performance, compares it with prior methods, and examines how dataset and model components and compiler optimizations affect accuracy. It also illustrates the system’s predictions with an example.

3.1 Experimental Setup

  • DIRT was built from 4,346,134 automatically compiled 64-bit x86 binaries and includes 997,632 decompiled training functions; it labels split decompiler variables as <Component> to enable type recovery.Splitting per binary prevents functions from the same binary appearing in both training and test sets. Name and type metrics require exact matches, and no human quality study was conducted.Source: §3.1 · pp. 6–7

3.2 RQ1: Overall Effectiveness

  • 75.8% of developer-written types are recovered by DIRTY, versus 37.9% by Hex-Rays; accuracy is 89.9% for seen functions and 56.4% for unseen functions.The comparison uses exact type matching, including data layout and field names where applicable.Source: Table 1 · p. 7, §3.2 · p. 7, §3.1 · p. 7
  • 68.6% of structural types are correctly predicted by DIRTY overall and 54.6% for unseen functions, compared with 9.7% for Frequency By Size and 28.7% for Hex-Rays.Structural types are more difficult than scalar types, and DIRTY’s examples show that incorrect predictions can still be semantically reasonable but syntactically unacceptable.Source: Table 1 · p. 7, §3.2 · pp. 7–8

3.3 RQ2: Comparison with Prior Work

  • On Coreutils, DIRTY slightly outperforms OSPREY [58] overall (76.8% vs 71.6%), while OSPREY leads on structures (26.6% vs 15.7%).DIRTYLight, trained for OSPREY’s simplified task, improves structural accuracy and outperforms OSPREY; the passage gives no exact DIRTYLight value.Source: §3.3 · p. 8, Table 3 · p. 9
  • DIRTY recovers variable names more accurately than DIRE [29] on both datasets: 81.4% vs. 72.8% on DIRE and 66.4% vs. 57.5% on DIRT.For functions not in training, DIRTY also leads on both datasets: 42.8% vs. 33.5% on DIRE and 36.9% vs. 31.8% on DIRT.Source: Table 4 · p. 9, §3.3 · p. 9

3.4 RQ3: Ablation Study

  • 75.8% overall retyping accuracy for DIRTY exceeds DIRTYS’s 74.5%, with a notably larger model-capacity benefit on structures.DIRTY has 167M parameters and DIRTYS 40M; computational limits prevented training a larger model.Source: §3.4 · pp. 9–10
  • 75.8% accuracy with the full training set falls to 67.9% with 20% of the data, and reducing the set from 40% to 20% causes a sharp drop.The relative gain from 20% to 100% data is 17.5% for unseen functions, greater than for seen functions, which largely include common library code.Source: Figure 7 · p. 10, §3.4 · p. 10
  • Adding the Data Layout encoder raises overall accuracy from 72.2% to 75.8%, with a larger gain on unseen than seen functions.Accuracy on unseen functions rises from 49.9% to 56.4%, compared with 88.8% to 89.9% on seen functions, supporting the encoder’s role in generalization.Source: Table 6 · p. 10, §3.4 · p. 10
  • DIRTY better preserves type data layout than DIRTYNDL, improving byte-allocation accuracy and suppressing errors such as predicting a double for a 16-byte struct.The Data Layout encoder helps guide predictions toward the correct struct type and its member layout.Source: §3.4 · p. 10, Table 7 · p. 11
  • The Multi-Task decoder has 0.8% lower retyping and 1.3% lower renaming accuracy overall, but gains 1.9% and 2.4% relatively on ✓Name and ✓Type.These conditional gains indicate more consistent name and type predictions; the footnote notes that the analysis accounts for the chance effect of one task being easier than average.Source: §3.4 · p. 10, Table 8 · p. 11
  • A Multi-Task decoder lets an expert change a variable’s type candidate and have the model adjust its name prediction, unlike specialized decoders.This offers flexibility in a cooperative human-model decompilation workflow.Source: §3.4 · pp. 10–11

3.5 RQ4: Compiler Optimization Levels

  • DIRTY’s full-type accuracy on coreutils drops from 48.2% at -O0 to 46.0% at -O1, with little difference among -O1, -O2, and -O3.The authors attribute the small optimization effect to Hex-Rays undoing some optimizations, leaving decompiled code similar across levels; DIRTY was trained on -O0 code.Source: §3.5 · p. 11, Table 9 · p. 11

3.6 Illustration

  • In Figure 8, DIRTY matches the developer’s names and types for a3 and v1, and suggests a2’s type correctly despite a different but related name.The authors note that the suggested Picture_0 * type carries useful semantic information even when its name differs.Source: §3.6 · p. 11, Figure 8 · p. 12
  • For a1, DIRTY predicts a different name and type, but the suggested MpegEncContext_0 * could still hint that the argument is a video context.The authors describe the suggested name s as probably not a useful improvement over a1.Source: §3.6 · p. 11, Figure 8 · p. 12

4 Related Work

Prior type-recovery work used program-analysis constraints or narrow sets of types, while related neural models often targeted other languages or tasks. DIRTY differs in its broad real-world C type inventory and its joint focus on names and types.

4 Related Work

  • DIRTY differs from REWARDS, TIE, Retypd [39], and OSPREY by learning from real-world types rather than constraints or a small hand-written type set.TIE, Retypd, and OSPREY predict only syntactic types; REWARDS supports 150 hand-written types, while DIRTY automatically builds a type database from real-world code.Source: §4 · p. 12
  • Neural type predictors for JavaScript and TypeScript [40] [52] [56] address a different setting because removing types can preserve semantics, unlike C decompilation with debug information.In the DIRT setting, debug information can change code layout as the decompiler adds structures and access syntax.Source: §4 · p. 12
  • TypeMiner used a simpler learner and a dataset of 23,482 variables and 17 primitive types, while DIRTY addresses a broader type-recovery setting.Escalada et al. [14] predicted function return types among 10 syntactic types using 2,339 real-program functions and 18,000 synthetic functions.Source: §4 · p. 12
  • Neural systems DIRE [29], DIRECT, and Nero [8] target variable names or procedure names, while DIRTY predicts variable names and types.Other approaches generate code structure from assembly or predict debug information or types directly from stripped binaries [27].Source: §4 · p. 12

5 Discussion

DIRTY’s current decoder is bounded by training-seen types and a 512-token input limit, and the discussion identifies decompiler compatibility and richer language types as further boundaries. The authors also describe layout-based recovery and cross-language use, while noting that their BPE experiment hurt accuracy and speed.

5 Discussion

  • DIRTY is conceptually applicable beyond Hex-Rays to decompilers that name variables using DWARF symbols, but Ghidra evaluation was infeasible because it often discarded those names after combining variables.Ghidra’s passes can combine a DWARF-named variable with others, leaving the combined variable without a direct match to the DWARF information.Source: §5 · p. 12
  • DIRTY can predict only types seen during training, although redundancy in large corpora empirically lets it recover structural types and layout helps with previously unseen code.The authors cite Section 3.4 results as corroborating the Data Layout Encoder’s particular importance on unseen code.Source: §5 · pp. 12–13
  • A BPE-based decoder for unseen structures was explored, but preliminary experiments reduced overall prediction accuracy and substantially slowed prediction.The authors leave unseen structure types to a tailored model and note that partial predictions would require finer-grained metrics such as tree distance.Source: §5 · p. 13
  • DIRTY can run on non-C programs by identifying the C type that best captures variable use, but those C types may not convey richer language-specific behavior.For example, recognizing C++ virtual-function tables as structs or arrays of code pointers does not reveal their connection to virtual functions.Source: §5 · p. 13
  • The evaluation measures common C++ class types such as std::string, but recovering higher-level properties—especially unseen ones—remains challenging and likely requires language-specific adaptations.Six percent of DIRT programs are written in C++; the authors identify support for higher-level languages as an open problem.Source: §5 · p. 13
  • Functions longer than 512 tokens are truncated; this excludes 8.8% of DIRT functions, and the authors recommend efficient Transformer implementations for larger inputs.DIRT functions average 220.3 tokens; Big Bird is named as a possible replacement when computational resources permit.Source: §5 · p. 13

6 Conclusion

Compilation destroys useful abstractions, including variable names and custom types, that decompilers cannot deterministically recover. DIRTY statistically models developer code to generate names and types, and its evaluation reports recovery of original names 66.4% of the time and original types 75.8% of the time.

6 Conclusion

  • Compilation irreversibly removes comments, variable names, and custom types, leaving decompilers able to reconstruct only some structural properties.The resulting loss of high-level abstractions complicates reverse engineering of binaries.Source: §6 · p. 13
  • DIRTY statistically models how developers write code to assign meaningful names and types to decompiled variables.The paper presents it as a deep learning-based technique for improving decompiler output.Source: §6 · p. 13
  • 66.4% of original names and 75.8% of original types were recovered, outperforming prior-work approaches on a novel GitHub-mined C dataset.Source: §6 · p. 13

A Experimental Setup

The experimental setup describes DIRTY’s model configuration, computing environment, software stack, and dataset-statistics table.

A Experimental Setup

  • DIRTY uses six-layer code and type encoders and a three-layer data-layout encoder; inference uses beam search with beam size 5.The setup also specifies eight attention heads, 512- and 256-dimensional hidden sizes, batch size 64, learning rate 1 × 10^-4, and 15 training epochs.Source: A Experimental Setup · p. 17, Table 10 · p. 17
  • Experiments ran on servers with two Intel Xeon Gold 6148 processors, 192GB RAM, and eight NVIDIA V100 GPUs; the authors estimate 120 GPU hours for the main experiments.Source: A Experimental Setup · p. 17
  • The implementation uses PyTorch 1.5.1 and Python 3.6, and the authors planned to release the dataset, code, and pretrained models.Source: A Experimental Setup · p. 17
  • Table 11 presents statistics for the DIRT datasets.Source: Table 11 · p. 17
Loading 2108.06363v1…