### CMake Project Setup and C++ Standard Configuration Source: https://github.com/19h/aletheia/blob/master/CMakeLists.txt Initializes the CMake project, sets the C++ standard to C++23, and enables export of compile commands. This ensures modern C++ features are available and build information is accessible for tools. ```cmake cmake_minimum_required(VERSION 3.27) project(aletheia_plugin LANGUAGES CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) ``` -------------------------------- ### Initial SSA Code Example (Figure 2a) Source: https://github.com/19h/aletheia/blob/master/docs/out-of-ssa.md This snippet represents the initial SSA code structure for Block B1, B2, and B3, illustrating a basic SSA form before considering specific branch instructions. ```pseudocode Block B1 (`u_1 = φ(u_0, u_2)`, `u_2 = u_1 - 1`, `t_0 = u_2`, `Br(u_2, B_1, B_2)`). Block B2 (`t_1 = φ(t_0, t_2)`, `t_2 = t_1 + ...`, `Br(t_2, B_1, B_2)`). Block B3 (`... = u_2`). ``` -------------------------------- ### Configure IDA-runtime Binary End-to-End Test Source: https://github.com/19h/aletheia/blob/master/CMakeLists.txt This snippet sets up an executable for an end-to-end test using IDA Pro's libraries. It links against 'aletheia', 'logos', 'idiomata', 'idax::idax', and IDA-specific libraries. Compile definitions and include directories are set for 64-bit IDA and IDA library implementation. RPATH properties are configured for IDA installation directories. A test is added with specific environment variables for different operating systems. ```cmake add_executable(aletheia_idalib_test tests/test_idalib.cpp) target_link_libraries(aletheia_idalib_test PRIVATE aletheia logos idiomata idax::idax "${IDA_INSTALL_DIR}/${ALETHEIA_IDALIB_NAME}" "${IDA_INSTALL_DIR}/${ALETHEIA_IDA_NAME}" ) target_compile_definitions(aletheia_idalib_test PRIVATE __EA64__ IDALIB_IMPL) target_include_directories(aletheia_idalib_test PRIVATE "${IDASDK}/include") set_target_properties(aletheia_idalib_test PROPERTIES BUILD_RPATH "${IDA_INSTALL_DIR}" INSTALL_RPATH "${IDA_INSTALL_DIR}" ) add_test(NAME aletheia_idalib_test COMMAND aletheia_idalib_test "${CMAKE_CURRENT_SOURCE_DIR}/tests/targets/test_binary" ) if(WIN32) set_tests_properties(aletheia_idalib_test PROPERTIES ENVIRONMENT "IDADIR=${IDA_INSTALL_DIR};PATH=${IDA_INSTALL_DIR};$ENV{PATH}" ) elseif(NOT APPLE) set_tests_properties(aletheia_idalib_test PROPERTIES ENVIRONMENT "IDADIR=${IDA_INSTALL_DIR};LD_LIBRARY_PATH=${IDA_INSTALL_DIR}:$ENV{LD_LIBRARY_PATH}" ) else() set_tests_properties(aletheia_idalib_test PROPERTIES ENVIRONMENT "IDADIR=${IDA_INSTALL_DIR}" ) endif() ``` -------------------------------- ### Implement Custom Pipeline Stage in C++ Source: https://context7.com/19h/aletheia/llms.txt Demonstrates how to create a custom pipeline stage by inheriting from `aletheia::PipelineStage`. This involves defining the stage's name, its dependencies on other stages, and the execution logic. The example shows a custom optimization stage that processes assignment instructions. ```cpp #include class CustomOptimizationStage : public aletheia::PipelineStage { public: const char* name() const override { return "CustomOptimization"; } std::vector dependencies() const override { return {"SsaConstructor"}; // Requires SSA form } void execute(aletheia::DecompilerTask& task) override { if (!task.cfg()) return; for (aletheia::BasicBlock* block : task.cfg()->blocks()) { for (aletheia::Instruction* inst : block->instructions()) { // Process instructions... if (auto* assign = dynamic_cast(inst)) { optimize_assignment(assign, task.arena()); } } } } private: void optimize_assignment(aletheia::Assignment* assign, aletheia::DecompilerArena& arena); }; // Register the custom stage pipeline.add_stage(std::make_unique()); ``` -------------------------------- ### Fetch and Configure Z3 Dependency Source: https://github.com/19h/aletheia/blob/master/CMakeLists.txt Fetches the Z3 prover library from its Git repository and configures its build to be static, disabling executables, tests, examples, and documentation. This minimizes the Z3 build for integration purposes. ```cmake # ── Z3 dependency (Built from source) ─────────────────────────────────── FetchContent_Declare( z3 GIT_REPOSITORY https://github.com/Z3Prover/z3.git GIT_TAG z3-4.16.0 ) set(Z3_BUILD_LIBZ3_SHARED OFF CACHE BOOL "Build static Z3" FORCE) set(Z3_BUILD_EXECUTABLE OFF CACHE BOOL "Skip Z3 executable" FORCE) set(Z3_BUILD_TEST_EXECUTABLES OFF CACHE BOOL "Skip Z3 tests" FORCE) set(Z3_ENABLE_EXAMPLE_TARGETS OFF CACHE BOOL "Skip Z3 examples" FORCE) set(Z3_BUILD_DOCUMENTATION OFF CACHE BOOL "Skip Z3 docs" FORCE) set(WARNINGS_AS_ERRORS OFF CACHE BOOL "Disable warnings as errors" FORCE) FetchContent_MakeAvailable(z3) ``` -------------------------------- ### Construct and Traverse Control Flow Graph in C++ Source: https://context7.com/19h/aletheia/llms.txt Shows how to build and traverse a `aletheia::ControlFlowGraph`. This involves creating basic blocks, adding instructions to them, defining conditional branches, and establishing edges between blocks. The example demonstrates building a simple CFG with an entry, then, else, and merge blocks, and then traversing it in reverse post-order. ```cpp #include aletheia::DecompilerArena arena; // Create basic blocks aletheia::BasicBlock* entry = arena.create(0); aletheia::BasicBlock* then_block = arena.create(1); aletheia::BasicBlock* else_block = arena.create(2); aletheia::BasicBlock* merge = arena.create(3); // Add instructions to blocks entry->add_instruction(arena.create( arena.create("x", 8), arena.create(10, 8) )); // Create conditional branch aletheia::Condition* cond = arena.create( aletheia::OperationType::gt, arena.create("x", 8), arena.create(5, 8) ); entry->add_instruction(arena.create(cond)); // Create edges aletheia::Edge* true_edge = arena.create(entry, then_block, aletheia::EdgeType::True); aletheia::Edge* false_edge = arena.create(entry, else_block, aletheia::EdgeType::False); entry->add_successor(true_edge); entry->add_successor(false_edge); // Build CFG aletheia::ControlFlowGraph cfg; cfg.set_entry_block(entry); cfg.add_block(entry); cfg.add_block(then_block); cfg.add_block(else_block); cfg.add_block(merge); // Traverse CFG for (aletheia::BasicBlock* block : cfg.reverse_post_order()) { std::cout << "Block " << block->id() << " has " << block->instructions().size() << " instructions\n"; } ``` -------------------------------- ### DecompilerTask Initialization and Configuration (C++) Source: https://context7.com/19h/aletheia/llms.txt Demonstrates how to create and configure a DecompilerTask object, which holds the state for a decompilation process. It shows how to set SSA destruction mode and access core components like the arena and Z3 context. ```cpp #include // Create a decompilation task for a specific function address aletheia::DecompilerTask task(0x401000); // Configure SSA destruction mode via environment or programmatically task.set_out_of_ssa_mode(aletheia::OutOfSsaMode::LiftMinimal); // Access task components aletheia::DecompilerArena& arena = task.arena(); z3::context& z3_ctx = task.z3_ctx(); // After pipeline execution, check results if (task.failed()) { std::cerr << "Pipeline failed at stage: " << task.failure_stage() << " - " << task.failure_message() << "\n"; } else { aletheia::ControlFlowGraph* cfg = task.cfg(); aletheia::AbstractSyntaxForest* ast = task.ast(); } ``` -------------------------------- ### Locate IDA Pro Installation Directory Source: https://github.com/19h/aletheia/blob/master/CMakeLists.txt Attempts to find the IDA Pro installation directory by checking an explicit variable, the IDADIR environment variable, or common macOS application paths. This is crucial for building IDA-specific components. ```cmake # ── IDA installation (optional — needed for plugin, idalib tests, idump) ─ # Resolve IDA_INSTALL_DIR from explicit setting, IDADIR env, or well-known # platform paths. Targets that need the IDA runtime are guarded behind this. if(NOT DEFINED IDA_INSTALL_DIR) if(DEFINED ENV{IDADIR}) set(IDA_INSTALL_DIR "$ENV{IDADIR}") elseif(APPLE) foreach(_ver 9.3 9.2 9.1 9.0) set(_try "/Applications/IDA Professional ${_ver}.app/Contents/MacOS") if(EXISTS "${_try}/libida.dylib") set(IDA_INSTALL_DIR "${_try}") break() endif() endforeach() endif() endif() if(IDA_INSTALL_DIR) message(STATUS "IDA installation: ${IDA_INSTALL_DIR}") else() message(STATUS "IDA installation not found — plugin, idalib test, and idump targets will be skipped.") endif() ``` -------------------------------- ### Generate C-like Pseudocode from AST in C++ Source: https://context7.com/19h/aletheia/llms.txt Shows how to use the Aletheia::CodeVisitor to generate C-like pseudocode from a structured abstract syntax tree (AST). This involves setting up a DecompilerTask, running pipeline stages, and then iterating through the generated code lines. ```cpp #include aletheia::DecompilerTask task(function_address); // ... run pipeline stages ... if (task.ast() && task.ast()->root()) { aletheia::CodeVisitor visitor; std::vector code_lines = visitor.generate_code(task); for (const std::string& line : code_lines) { std::cout << line << "\n"; } } // Output example: // int sub_401000(int a1, int a2) { // int var_0; // var_0 = a1 + a2; // if (var_0 > 10) { // return var_0 * 2; // } // return 0; // } ``` -------------------------------- ### Lost Copy Problem: Initial SSA Translation Source: https://github.com/19h/aletheia/blob/master/docs/out-of-ssa.md Presents the initial representation of the lost-copy problem in SSA form. This serves as the starting point for out-of-SSA translation techniques discussed in the document. ```pseudocode Block B0: x1 = ... Block B1: x2 = φ(x1, x3) x3 = x2 + 1 if p then ``` -------------------------------- ### DecompilerPipeline: Managing Decompilation Stages (C++) Source: https://context7.com/19h/aletheia/llms.txt Shows how to construct and run a DecompilerPipeline, which orchestrates the sequential execution of various decompilation stages. This includes adding preprocessing, SSA construction, optimization, and restructuring stages. ```cpp #include #include #include #include #include aletheia::DecompilerPipeline pipeline; // Add preprocessing stages pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); // Add SSA construction pipeline.add_stage(std::make_unique()); // Add optimization stages pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); // Add SSA destruction and control flow restructuring pipeline.add_stage(std::make_unique()); pipeline.add_stage(std::make_unique()); // Execute the pipeline pipeline.run(task); // Check execution records for (const auto& record : task.stage_records()) { std::cout << record.stage_name << ": "; std::cout << (record.status == aletheia::StageExecutionStatus::Success ? "OK" : "FAILED") << "\n"; } ``` -------------------------------- ### Create and Query IR Instructions in C++ Source: https://context7.com/19h/aletheia/llms.txt Illustrates the creation of various IR instruction types, including assignments, returns, and phi functions for SSA, using the Aletheia::DecompilerArena. It also shows how to query definitions and requirements from instructions and create control flow instructions like break, continue, and comments. ```cpp #include aletheia::DecompilerArena arena; // Create assignment: result = a + b aletheia::Variable* result = arena.create("result", 8); aletheia::Operation* add = arena.create( aletheia::OperationType::add, std::vector{ arena.create("a", 8), arena.create("b", 8) }, 8 ); aletheia::Assignment* assign = arena.create(result, add); assign->set_address(0x401000); // Create return statement aletheia::Return* ret = arena.create( std::vector{result} ); // Create phi function for SSA aletheia::Variable* phi_dest = arena.create("merged", 8); aletheia::ListOperation* phi_sources = arena.create( std::vector{ arena.create("x_1", 8), arena.create("x_2", 8) }, 8 ); aletheia::Phi* phi = arena.create(phi_dest, phi_sources); // Query instruction definitions and requirements std::unordered_set defs, reqs; assign->collect_definitions(defs); // {result} assign->collect_requirements(reqs); // {a, b} // Create control flow instructions aletheia::BreakInstr* brk = arena.create(); aletheia::ContinueInstr* cont = arena.create(); aletheia::Comment* comment = arena.create("optimized division"); ``` -------------------------------- ### Run Headless Decompiler (idump) Source: https://github.com/19h/aletheia/blob/master/README.md Executes the 'idump' tool to decompile a binary file. This command decompiles all functions in 'firmware.bin' and outputs the structured C code to 'decompiled.c'. It leverages 'idalib' for headless operation. ```bash ./build/idump firmware.bin -o decompiled.c ``` -------------------------------- ### Swap Problem: CSSA Translation and Sequentialization Source: https://github.com/19h/aletheia/blob/master/docs/out-of-ssa.md Illustrates the translation of a swap problem from its initial SSA form to CSSA, followed by interference graph construction, coalescing, and final sequentialization to produce optimized code. This demonstrates how parallel copies are handled and transformed into sequential operations. ```pseudocode Block B0: a1 = ... b1 = ... Block B1: a2 = φ(a1, b2) b2 = φ(b1, a2) if p then -- Corresponding CSSA code -- Block B0: a1 = ... b1 = ... (u1, v1) = (a1, b1) Block B1: u0 = φ(u1, u2) v0 = φ(v1, v2) (a2, b2) = (u0, v0) (u2, v2) = (b2, a2) if p then -- After copy sequentialization -- Block B0: a2 = ... b2 = ... Block B1: n = b2 b2 = a2 a2 = n if p then ``` -------------------------------- ### Efficient Memory Allocation with DecompilerArena in C++ Source: https://context7.com/19h/aletheia/llms.txt Illustrates the usage of `aletheia::DecompilerArena` for high-performance memory allocation of Intermediate Representation (IR) nodes. This arena allocator provides O(1) allocation and bulk deallocation, avoiding garbage collection overhead. The example shows allocating variables, constants, operations, and more complex structures like assignments and Phi nodes. ```cpp #include #include aletheia::DecompilerArena arena(64 * 1024); // 64KB block size // Allocate IR nodes - no need for manual deletion aletheia::Variable* var = arena.create("rax", 8); aletheia::Constant* const_val = arena.create(0x42, 8); aletheia::Operation* add_op = arena.create( aletheia::OperationType::add, std::vector{var, const_val}, 8 ); // Create complex IR structures aletheia::Assignment* assign = arena.create( arena.create("result", 8), add_op ); // Create phi nodes for SSA std::vector phi_args = {var, const_val}; aletheia::ListOperation* phi_list = arena.create(phi_args, 8); aletheia::Phi* phi = arena.create( arena.create("merged", 8), phi_list ); // When done, reset frees all memory at once arena.reset(); ``` -------------------------------- ### Parallel Copy Sequentialization Algorithm (Text) Source: https://github.com/19h/aletheia/blob/master/docs/out-of-ssa.md Algorithm 1 describes the parallel copy sequentialization process. It takes a set of parallel copies as input and outputs a list of copies in sequential order, ensuring proper handling of variable assignments and dependencies. ```text Algorithm 1: Parallel copy sequentialization algorithm Data: Set P of parallel copies of the form a → b, a ≠ b, one extra fresh variable n Output: List of copies in sequential order 1 ready ← [] ; to_do ← [] ; pred(n) ← ⊥ ; 2 forall (a → b) ∈ P do 3 loc(b)← ⊥ ; pred(a) ← ⊥ ; /* initialization */ 4 forall (a → b) ∈ P do 5 loc(a) ← a ; /* needed and not copied yet */ 6 pred(b) ← a ; /* (unique) predecessor */ 7 to_do.push(b) ; /* copy into b to be done */ 8 forall (a → b) ∈ P do 9 if loc(b) = ⊥ then ready.push(b) ; /* b is not used and can be overwritten */ 10 while to_do ≠ [] do 11 while ready ≠ [] do 12 b ← ready.pop() ; /* pick a free location */ 13 a ← pred(b) ; c ← loc(a) ; /* available in c */ 14 emit_copy(c → b) ; /* generate the copy */ 15 loc(a) ← b ; /* now, available in b */ 16 if a = c and pred(a) ≠ ⊥ then ready.push(a) ; /* just copied, can be overwritten */ 17 b ← to_do.pop() ; /* look for remaining copy */ 18 if b = loc(pred(b)) then 19 emit_copy(b → n) ; /* break circuit with copy */ 20 loc(b) ← n ; /* now, available in n */ 21 ready.push(b) ; /* b can be overwritten */ ``` -------------------------------- ### Run Idiom Resolver Tests with CMake Source: https://github.com/19h/aletheia/blob/master/README.md Compiles and runs the pattern-matching idiom resolver tests. This command builds the 'test_idiom_resolver' executable and then executes it to verify the idiom resolution capabilities. ```bash cmake --build build --target test_idiom_resolver ./build/test_idiom_resolver ``` -------------------------------- ### Decompilation Pipeline in C++23 Source: https://github.com/19h/aletheia/blob/master/README.md Demonstrates the core decompilation process using Aletheia's C++23 API. It involves creating a task, lifting IDA instructions, running the DREAM pipeline, and generating pseudocode. Dependencies include aletheia headers and idax. ```cpp #include #include #include // Create a decompilation task for a specific function address aletheia::DecompilerTask task(function_address); // Lift native IDA instructions directly into Aletheia's IR via idax aletheia::Lifter lifter; lifter.lift(task); // Build and run the full DREAM restructuring pipeline auto pipeline = aletheia::DecompilerPipeline::create_structured_pipeline(); pipeline.run(task); if (!task.failed() && task.ast) { // Generate C-like pseudocode from the restructured AST aletheia::CodeVisitor visitor; task.ast->accept(visitor); for (const auto& line : visitor.get_lines()) { std::cout << line.text << "\n"; } } ``` -------------------------------- ### Headless Batch Decompilation with idump Source: https://context7.com/19h/aletheia/llms.txt A command-line tool for batch decompilation of entire binaries without requiring the IDA GUI. It can decompile a binary to a C file and supports various environment variable configurations for customizing the output. ```bash # Build the headless decompiler cmake -B build -DCMAKE_BUILD_TYPE=Release . cmake --build build --target idump # Decompile entire binary to C file ./build/idump firmware.bin -o decompiled.c # With environment configuration ALETHEIA_OUT_OF_SSA_MODE=lift_minimal \ ALETHEIA_VARIABLE_NAMING=system_hungarian \ ALETHEIA_INT_HEX_THRESHOLD=256 \ ./build/idump target.bin -o output.c --headless # Disable structuring for faster but less readable output ALETHEIA_IDUMP_DISABLE_STRUCTURING=1 ./build/idump target.bin # Force structured output even if lossy ALETHEIA_IDUMP_FORCE_STRUCTURED_OUTPUT=1 ./build/idump target.bin ``` -------------------------------- ### Map x86-64 Arithmetic and Logic Instructions Source: https://github.com/19h/aletheia/blob/master/AGENTS.md This section details the mapping of various x86-64 arithmetic and logic instructions. It covers operations like multiplication, bitwise operations (XOR, OR, AND, NOT), negation, increment, decrement, and addition/subtraction with carry. ```cpp // Example: Mapping imul (1/2/3 operand forms) // Example: Mapping xor, or, and, not, neg // Example: Mapping inc, dec, adc, sbb ``` -------------------------------- ### Build IDA Plugin with CMake Source: https://github.com/19h/aletheia/blob/master/README.md Builds the Aletheia IDA plugin using CMake. This command configures the build, then compiles the plugin. The resulting dynamic library should be placed in the IDA plugins directory. ```bash cmake -B build -DCMAKE_BUILD_TYPE=Release . cmake --build build --target aletheia_ida ```