Skip to content

Add relocation-based string ranking to identify code-referenced addresses #60

Description

@unclesp1d3r

Overview

Parse relocation entries from supported binary formats (ELF .rela/.rel, PE relocation table, Mach-O LC_DYLD_INFO) to identify data addresses that are directly referenced by code. Mark extracted strings at these addresses with a "referenced" flag and boost their relevance scores.

Context

When binaries are compiled with position-independent code (PIE/PIC) or are relocatable, the linker generates relocation entries that map virtual addresses to their actual runtime locations. These relocation entries provide a high-confidence signal that specific data addresses (including string literals) are actively used by the code, without requiring expensive disassembly or control-flow analysis.

By parsing these relocation tables, we can:

  • Identify strings that are definitely referenced by code (zero false positives)
  • Prioritize these strings in the ranking algorithm
  • Provide this metadata to analysts for focused triage
  • Improve signal-to-noise ratio in stripped binaries where symbol tables are unavailable

This is particularly valuable because relocation data persists even in stripped binaries, making it a reliable source of ground truth about what data the code actually uses.

Benefits

  • Zero-cost analysis: No disassembly or emulation required for this subset
  • High confidence signal: Relocation entries are ground truth from the linker
  • Works on stripped binaries: Relocation info survives stripping
  • Format-agnostic approach: Applicable to ELF, PE, and Mach-O
  • Improves ranking: Dramatically reduces false positives in string extraction

Technical Details

ELF Relocations

ELF binaries contain relocation sections (, , , ) that specify:

  • : Virtual address where the relocation applies
  • : Type and symbol index
  • : Constant addend (for RELA-type relocations)

Relevant relocation types:

  • : Adjust for base address (common in PIE)
  • : Global offset table entries
  • : Procedure linkage table entries
  • : Direct address references

Implementation: Use to parse relocation entries and extract target addresses.

PE Relocations

PE binaries contain a Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC) that groups relocations by 4KB pages:

  • Each entry specifies a page RVA and a list of offsets within that page
  • Type field indicates relocation type (most commonly or )

Implementation: Parse the section via to identify relocated addresses.

Mach-O Relocations

Mach-O binaries use the or load commands to store compressed relocation data:

  • Rebase opcodes: Adjust pointers for ASLR
  • Binding opcodes: Link to external symbols
  • Lazy binding opcodes: Deferred symbol resolution

Implementation: Parse dyld info via and process rebase/bind opcodes to extract referenced addresses.

Proposed Solution

1. Extend type

Add a flag to the struct in :

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FoundString {
    // ... existing fields ...
    
    /// Whether this string is directly referenced by code via relocations
    #[serde(skip_serializing_if = "Option::is_none")]
    pub referenced: Option<bool>,
}

2. Add relocation parsing to container parsers

Extend to include relocation data:

pub struct ContainerInfo {
    // ... existing fields ...
    
    /// Addresses referenced by relocations
    pub relocation_targets: Vec<u64>,
}

Implement relocation parsing in:

  • : Parse , , , sections
  • : Parse section (Base Relocation Table)
  • : Parse load command rebase and bind entries

3. Cross-reference strings with relocation targets

During string extraction in :

  1. Extract all strings as usual
  2. Build a set of relocation target addresses from
  3. For each extracted string, check if its RVA/offset is in the relocation target set
  4. Set for matches

4. Update scoring algorithm

In , boost the score for strings with :

if found_string.referenced == Some(true) {
    score += 50; // Significant boost for code-referenced strings
}

5. Update output formats

Include the flag in JSON output and consider adding a visual indicator (e.g., prefix) in human-readable output for referenced strings.

Acceptance Criteria

  • struct includes field
  • includes field
  • ELF parser extracts relocation entries from and sections
  • PE parser extracts relocation entries from section
  • Mach-O parser extracts rebase/bind targets from
  • Extraction pipeline cross-references string addresses with relocation targets
  • Scoring algorithm boosts referenced strings significantly
  • Unit tests for each relocation parser with test binaries
  • Integration tests verify referenced strings are correctly flagged
  • Documentation updated with examples of relocation-based ranking

Related Work

Implementation Notes

  • Start with ELF as it has the most straightforward relocation format
  • Consider using crate's built-in relocation parsing where available
  • For stripped binaries, this may be the only reliable signal about string usage
  • Relocation data can be large in some binaries; consider streaming or filtering to reduce memory usage
  • Not all strings will be referenced (e.g., embedded data, resources, error messages in unused paths)

Activity

  1. added theissue type on Nov 10, 2025
  2. changed the issue type fromtoon Nov 10, 2025
  3. traycerai commented on Nov 10, 2025

    @traycerai

    Plan

    Observations

    The codebase structure supports binary parsing via goblin for ELF, PE, and Mach-O formats. FoundString in src/types.rs lacks a referenced field, and ContainerInfo needs relocation_targets. Container parsers extract sections, imports, and exports but not relocations. Extraction and classification modules are stubs. Goblin provides relocation APIs: elf::reloc for ELF, pe::relocation for PE, mach::relocation for Mach-O. Tests exist but need relocation-specific cases. Documentation in docs/src/ requires ranking updates.

    Approach

    1. Extend types: Add referenced: Option&lt;bool&gt; to FoundString and relocation_targets: Vec&lt;u64&gt; to ContainerInfo.\n2. Create src/container/relocation.rs for shared utilities.\n3. Implement extract_relocations in each parser, populating relocation_targets.\n4. In src/extraction/mod.rs, add mark_referenced_strings to flag matching strings.\n5. In src/classification/mod.rs, add scoring boost for referenced strings.\n6. Update JSON output in src/output/ to include the flag.\n7. Add unit/integration tests for relocation extraction and flagging.\n8. Document in docs/src/ranking.md and string-extraction.md.

    Reasoning

    I examined the project directory structure to understand the codebase layout. I reviewed the core types in src/types.rs to identify necessary extensions. I analyzed the container parsers in src/container/ (elf.rs, pe.rs, macho.rs) to see existing extraction logic. I checked the empty extraction and classification modules. I searched goblin documentation for relocation parsing capabilities across formats. This confirmed the feasibility of adding relocation-based hinting with minimal changes.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Add referenced: Option&lt;bool&gt;, defaulting to None, to the FoundString struct after the source field. Ensure it implements Serialize/Deserialize with #[serde(skip_serializing_if = "Option::is_none")].

    Add relocation_targets: Vec&lt;u64&gt; to the ContainerInfo struct after the exports field. This will store RVAs/virtual addresses referenced by relocations, populated by parsers.

    📄 src/container/mod.rs (MODIFY) 🔗

    References

    Add pub mod relocation; after the existing mod declarations.

    Re-export pub use relocation::{RelocationInfo, extract_target_addresses}; for common use.

    📄 src/container/relocation.rs (NEW) 🔗

    References

    Create a new module defining shared relocation utilities.

    Define #[derive(Debug, Clone)] pub struct RelocationInfo { pub source_rva: u64, pub target_rva: u64, pub reloc_type: String }.

    Add pub fn extract_target_addresses(relocs: &amp;[RelocationInfo]) -> Vec&lt;u64&gt; to collect unique target addresses.

    Include documentation on relocation-based hinting purpose.

    📄 src/container/elf.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, elf: &amp;Elf) -> Vec&lt;u64&gt;:

    • Iterate over elf.relocs or specific sections (.rela.dyn, .rela.plt, etc.) using goblin::elf::reloc.
    • For each reloc, create RelocationInfo with r_offset as target (add r_addend for RELA).
    • Filter relevant types (R_X86_64_64, R_X86_64_GLOB_DAT, etc.).
    • Return unique targets via extract_target_addresses.

    In parse, after extracting exports, call self.extract_relocations(&amp;elf) and set container_info.relocation_targets.

    📄 src/container/pe.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, pe: &amp;PE) -> Vec&lt;u64&gt;:

    • Access pe.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].
    • Parse relocation blocks: for each block, add page RVA to entry offsets.
    • Handle types like IMAGE_REL_BASED_HIGHLOW (32-bit) and IMAGE_REL_BASED_DIR64 (64-bit).
    • Create RelocationInfo for each, collect targets.
    • Return unique targets.

    In parse, after extracting exports, call self.extract_relocations(&amp;pe) and set container_info.relocation_targets.

    📄 src/container/macho.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, macho: &amp;MachO) -> Vec&lt;u64&gt;:

    • Parse macho.dyld_info for rebase/bind opcodes using goblin::mach::dyld::DyldInfo.
    • For rebase: extract adjusted addresses.
    • For bind: extract bound addresses.
    • Also check section relocations if present.
    • Create RelocationInfo, collect targets adjusted for segment bases.
    • Return unique targets.

    In parse_single_macho, after extracting exports, call self.extract_relocations(macho) and set container_info.relocation_targets.

    📄 src/extraction/mod.rs (MODIFY) 🔗

    References

    Add use crate::types::{FoundString, ContainerInfo}; and use std::collections::HashSet;.

    Implement `pub fn mark_referenced_strings(strings: &mut [FoundString], container_info: &ContainerInfo) {

    • Create HashSet from container_info.relocation_targets.
    • For each string, if string.rva matches a target, set string.referenced = Some(true); else Some(false).
      }

    Document usage: Call after initial string extraction but before classification.

    📄 src/classification/mod.rs (MODIFY) 🔗

    References

    Add use crate::types::FoundString;.

    Implement `pub fn calculate_score(string: &FoundString) -> i32 {

    • Base score from existing logic (tags, section, etc.).
    • If string.referenced == Some(true), add 50 to score.
    • Return total.
      }

    Update FoundString::score to use this in extraction pipeline.

    Document the +50 boost for code-referenced strings.

    📄 src/output/mod.rs (MODIFY) 🔗

    References

    Assuming JSON serialization, ensure FoundString serialization includes referenced field.

    In human-readable output, prefix referenced strings with '*' or '[REF]' indicator.

    Update any existing output functions to handle the new field.

    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load ELF fixture.
    • Parse with ElfParser.
    • Assert container_info.relocation_targets.len() > 0 (use binary with relocs).
    • Extract strings, mark referenced, assert some have referenced: Some(true).
    • Verify score boost in classification.
    📄 tests/integration_pe.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load PE fixture (with relocs if possible).
    • Parse with PeParser.
    • Assert relocation_targets populated or empty gracefully.
    • Mark strings, check flagging and score boost.
    📄 tests/integration_macho.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load Mach-O fixture.
    • Parse with MachoParser.
    • Assert relocation_targets.len() > 0.
    • Mark strings, verify referenced flagging and score boost.
    📄 docs/src/ranking.md (MODIFY) 🔗

    References

    Add section 'Relocation-Based Boost':

    • Explain identifying code-referenced strings via relocations.
    • Detail +50 score boost.
    • Note zero-cost for stripped binaries.
    • Include example: if referenced { score += 50; }.

    Update 'Scoring Formula' to incorporate this boost.

    📄 docs/src/string-extraction.md (MODIFY) 🔗

    References

    Add subsection under 'Post-Extraction Processing':

    • Describe mark_referenced_strings function.
    • Explain cross-referencing with ContainerInfo.relocation_targets.
    • Note integration after section-based extraction.

    Import In IDE

    VSCode Icon Cursor Icon Windsurf Icon

    🤖 Prompt for AI Agents
    I have created the following plan after thorough exploration and analysis of the codebase. Follow the below plan verbatim. Trust the files and references. Do not re-verify what's written in the plan. Explore only when absolutely necessary. First implement all the proposed file changes and then I'll review all the changes together at the end.
    
    ### Observations
    
    The codebase structure supports binary parsing via goblin for ELF, PE, and Mach-O formats. `FoundString` in `src/types.rs` lacks a `referenced` field, and `ContainerInfo` needs `relocation_targets`. Container parsers extract sections, imports, and exports but not relocations. Extraction and classification modules are stubs. Goblin provides relocation APIs: `elf::reloc` for ELF, `pe::relocation` for PE, `mach::relocation` for Mach-O. Tests exist but need relocation-specific cases. Documentation in `docs/src/` requires ranking updates.
    
    ### Approach
    
    1. Extend types: Add `referenced: Option&lt;bool&gt;` to `FoundString` and `relocation_targets: Vec&lt;u64&gt;` to `ContainerInfo`.\n2. Create `src/container/relocation.rs` for shared utilities.\n3. Implement `extract_relocations` in each parser, populating `relocation_targets`.\n4. In `src/extraction/mod.rs`, add `mark_referenced_strings` to flag matching strings.\n5. In `src/classification/mod.rs`, add scoring boost for referenced strings.\n6. Update JSON output in `src/output/` to include the flag.\n7. Add unit/integration tests for relocation extraction and flagging.\n8. Document in `docs/src/ranking.md` and `string-extraction.md`.
    
    ### Reasoning
    
    I examined the project directory structure to understand the codebase layout. I reviewed the core types in `src/types.rs` to identify necessary extensions. I analyzed the container parsers in `src/container/` (elf.rs, pe.rs, macho.rs) to see existing extraction logic. I checked the empty extraction and classification modules. I searched goblin documentation for relocation parsing capabilities across formats. This confirmed the feasibility of adding relocation-based hinting with minimal changes.
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Add `referenced: Option&lt;bool&gt;`, defaulting to `None`, to the `FoundString` struct after the `source` field. Ensure it implements Serialize/Deserialize with `#[serde(skip_serializing_if = "Option::is_none")]`.
    
    Add `relocation_targets: Vec&lt;u64&gt;` to the `ContainerInfo` struct after the `exports` field. This will store RVAs/virtual addresses referenced by relocations, populated by parsers.
    
    ### src/container/mod.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    
    Add `pub mod relocation;` after the existing mod declarations.
    
    Re-export `pub use relocation::{RelocationInfo, extract_target_addresses};` for common use.
    
    ### src/container/relocation.rs(NEW)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Create a new module defining shared relocation utilities.
    
    Define `#[derive(Debug, Clone)] pub struct RelocationInfo { pub source_rva: u64, pub target_rva: u64, pub reloc_type: String }`.
    
    Add `pub fn extract_target_addresses(relocs: &amp;[RelocationInfo]) -> Vec&lt;u64&gt;` to collect unique target addresses.
    
    Include documentation on relocation-based hinting purpose.
    
    ### src/container/elf.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, elf: &amp;Elf) -> Vec&lt;u64&gt;`:
    - Iterate over `elf.relocs` or specific sections (.rela.dyn, .rela.plt, etc.) using `goblin::elf::reloc`.
    - For each reloc, create `RelocationInfo` with `r_offset` as target (add `r_addend` for RELA).
    - Filter relevant types (R_X86_64_64, R_X86_64_GLOB_DAT, etc.).
    - Return unique targets via `extract_target_addresses`.
    
    In `parse`, after extracting exports, call `self.extract_relocations(&amp;elf)` and set `container_info.relocation_targets`.
    
    ### src/container/pe.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, pe: &amp;PE) -> Vec&lt;u64&gt;`:
    - Access `pe.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC]`.
    - Parse relocation blocks: for each block, add page RVA to entry offsets.
    - Handle types like IMAGE_REL_BASED_HIGHLOW (32-bit) and IMAGE_REL_BASED_DIR64 (64-bit).
    - Create `RelocationInfo` for each, collect targets.
    - Return unique targets.
    
    In `parse`, after extracting exports, call `self.extract_relocations(&amp;pe)` and set `container_info.relocation_targets`.
    
    ### src/container/macho.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, macho: &amp;MachO) -> Vec&lt;u64&gt;`:
    - Parse `macho.dyld_info` for rebase/bind opcodes using `goblin::mach::dyld::DyldInfo`.
    - For rebase: extract adjusted addresses.
    - For bind: extract bound addresses.
    - Also check section relocations if present.
    - Create `RelocationInfo`, collect targets adjusted for segment bases.
    - Return unique targets.
    
    In `parse_single_macho`, after extracting exports, call `self.extract_relocations(macho)` and set `container_info.relocation_targets`.
    
    ### src/extraction/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Add `use crate::types::{FoundString, ContainerInfo};` and `use std::collections::HashSet;`.
    
    Implement `pub fn mark_referenced_strings(strings: &amp;mut [FoundString], container_info: &amp;ContainerInfo) {
    - Create HashSet from `container_info.relocation_targets`.
    - For each string, if `string.rva` matches a target, set `string.referenced = Some(true)`; else `Some(false)`.
    }
    
    Document usage: Call after initial string extraction but before classification.
    
    ### src/classification/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Add `use crate::types::FoundString;`.
    
    Implement `pub fn calculate_score(string: &amp;FoundString) -> i32 {
    - Base score from existing logic (tags, section, etc.).
    - If `string.referenced == Some(true)`, add 50 to score.
    - Return total.
    }
    
    Update `FoundString::score` to use this in extraction pipeline.
    
    Document the +50 boost for code-referenced strings.
    
    ### src/output/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Assuming JSON serialization, ensure `FoundString` serialization includes `referenced` field.
    
    In human-readable output, prefix referenced strings with '*' or '[REF]' indicator.
    
    Update any existing output functions to handle the new field.
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/container/elf.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load ELF fixture.
    - Parse with `ElfParser`.
    - Assert `container_info.relocation_targets.len() > 0` (use binary with relocs).
    - Extract strings, mark referenced, assert some have `referenced: Some(true)`.
    - Verify score boost in classification.
    
    ### tests/integration_pe.rs(MODIFY)
    
    References: 
    
    - src/container/pe.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load PE fixture (with relocs if possible).
    - Parse with `PeParser`.
    - Assert `relocation_targets` populated or empty gracefully.
    - Mark strings, check flagging and score boost.
    
    ### tests/integration_macho.rs(MODIFY)
    
    References: 
    
    - src/container/macho.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load Mach-O fixture.
    - Parse with `MachoParser`.
    - Assert `relocation_targets.len() > 0`.
    - Mark strings, verify referenced flagging and score boost.
    
    ### docs/src/ranking.md(MODIFY)
    
    References: 
    
    - src/classification/mod.rs(MODIFY)
    
    Add section 'Relocation-Based Boost':
    - Explain identifying code-referenced strings via relocations.
    - Detail +50 score boost.
    - Note zero-cost for stripped binaries.
    - Include example: `if referenced { score += 50; }`.
    
    Update 'Scoring Formula' to incorporate this boost.
    
    ### docs/src/string-extraction.md(MODIFY)
    
    References: 
    
    - src/extraction/mod.rs(MODIFY)
    - src/types.rs(MODIFY)
    
    Add subsection under 'Post-Extraction Processing':
    - Describe `mark_referenced_strings` function.
    - Explain cross-referencing with `ContainerInfo.relocation_targets`.
    - Note integration after section-based extraction.

    Developer Humor

    > Why did the string go to relocation therapy?\n> It needed to find its address in the code!\n> 🔄➡️🎯\n> Now it's referenced and feeling boosted. +50 points!


    Execution Information

    Branch: main
    Commit: 37cfc7c


    💡 Tips

    Supported Commands (Inside Comments)

    • Use @traycerai generate to iterate on the previous version of the implementation plan.

    Supported Commands (Inside Description)

    • Add @traycerai ignore anywhere in the ticket description to prevent this ticket from being processed.
    • Add @traycerai branch:<branch-name> anywhere in the ticket description to specify the target branch for the implementation plan.

    Community

    • Join our Discord Community to get help, request features, and share feedback.
    • Follow us on X/Twitter for updates and announcements.
  4. unclesp1d3r commented on Nov 10, 2025

    @unclesp1d3r
    MemberAuthor

    @coderabbitai Enhance this issue body with additional context and a proposed solution. Improve the issue title and assign the proper labels and other metadata.

  5. changed the title [-]Relocation-Based Hinting[/-] [+]Add relocation-based string ranking to identify code-referenced addresses[/+] on Nov 10, 2025
  6. coderabbitai commented on Nov 10, 2025

    @coderabbitai
    Contributor

    Tip

    For best results, initiate chat on the files or code changes.

    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    # Fetch the current issue details
    gh issue view 60 --json title,body,labels,assignees,state,url
    
    # Get repository information
    gh repo view --json name,owner
    
    # Look for related files about relocation parsing or string extraction
    fd -e py -e rs -e go -e cpp -e c | head -20
    

    Length of output: 1056


    🏁 Script executed:

    #!/bin/bash
    # Look at the types to understand current data structures
    cat src/types.rs
    
    # Check extraction module for current string extraction logic
    cat src/extraction/mod.rs
    
    # Check ELF container implementation for any existing relocation handling
    head -100 src/container/elf.rs
    

    Length of output: 9289


    🏁 Script executed:

    #!/bin/bash
    # Check if there's any existing relocation handling in any of the container parsers
    rg -n "relocation|reloc|rela\.dyn|rela\.plt" --type rust
    
    # Look at the FoundString structure more closely to understand current metadata
    rg -n "referenced|flag" --type rust src/types.rs
    
    # Check the classification module to understand scoring system
    cat src/classification/mod.rs
    
    # Check the README for project context
    cat README.md
    

    Length of output: 7227


    🏁 Script executed:

    #!/bin/bash
    # Check what labels are available in the repository
    gh label list
    
    # Look at other enhancement issues to see the pattern
    gh issue list --label enhancement --limit 5 --json number,title,labels
    

    Length of output: 3531


    🏁 Script executed:

    #!/bin/bash
    # Update the issue with enhanced body, improved title, and proper metadata
    gh issue edit 60 \
      --title "Add relocation-based string ranking to identify code-referenced addresses" \
      --body "## Overview
    
    Parse relocation entries from supported binary formats (ELF .rela/.rel, PE relocation table, Mach-O LC_DYLD_INFO) to identify data addresses that are directly referenced by code. Mark extracted strings at these addresses with a \"referenced\" flag and boost their relevance scores.
    
    ## Context
    
    When binaries are compiled with position-independent code (PIE/PIC) or are relocatable, the linker generates relocation entries that map virtual addresses to their actual runtime locations. These relocation entries provide a **high-confidence signal** that specific data addresses (including string literals) are actively used by the code, without requiring expensive disassembly or control-flow analysis.
    
    By parsing these relocation tables, we can:
    - Identify strings that are **definitely** referenced by code (zero false positives)
    - Prioritize these strings in the ranking algorithm
    - Provide this metadata to analysts for focused triage
    - Improve signal-to-noise ratio in stripped binaries where symbol tables are unavailable
    
    This is particularly valuable because relocation data persists even in stripped binaries, making it a reliable source of ground truth about what data the code actually uses.
    
    ## Benefits
    
    - **Zero-cost analysis**: No disassembly or emulation required for this subset
    - **High confidence signal**: Relocation entries are ground truth from the linker
    - **Works on stripped binaries**: Relocation info survives stripping
    - **Format-agnostic approach**: Applicable to ELF, PE, and Mach-O
    - **Improves ranking**: Dramatically reduces false positives in string extraction
    
    ## Technical Details
    
    ### ELF Relocations
    
    ELF binaries contain relocation sections (`.rela.dyn`, `.rela.plt`, `.rel.dyn`, `.rel.plt`) that specify:
    - `r_offset`: Virtual address where the relocation applies
    - `r_info`: Type and symbol index
    - `r_addend`: Constant addend (for RELA-type relocations)
    
    Relevant relocation types:
    - `R_*_RELATIVE`: Adjust for base address (common in PIE)
    - `R_*_GLOB_DAT`: Global offset table entries
    - `R_*_JUMP_SLOT`: Procedure linkage table entries
    - `R_*_64/32`: Direct address references
    
    **Implementation**: Use `goblin::elf::reloc::Reloc` to parse relocation entries and extract target addresses.
    
    ### PE Relocations
    
    PE binaries contain a Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC) that groups relocations by 4KB pages:
    - Each entry specifies a page RVA and a list of offsets within that page
    - Type field indicates relocation type (most commonly `IMAGE_REL_BASED_HIGHLOW` or `IMAGE_REL_BASED_DIR64`)
    
    **Implementation**: Parse the `.reloc` section via `goblin::pe::relocation` to identify relocated addresses.
    
    ### Mach-O Relocations
    
    Mach-O binaries use the `LC_DYLD_INFO` or `LC_DYLD_INFO_ONLY` load commands to store compressed relocation data:
    - Rebase opcodes: Adjust pointers for ASLR
    - Binding opcodes: Link to external symbols
    - Lazy binding opcodes: Deferred symbol resolution
    
    **Implementation**: Parse dyld info via `goblin::mach::exports` and process rebase/bind opcodes to extract referenced addresses.
    
    ## Proposed Solution
    
    ### 1. Extend `FoundString` type
    
    Add a `referenced` flag to the `FoundString` struct in `src/types.rs`:
    
    \`\`\`rust
    #[derive(Debug, Clone, Serialize, Deserialize)]
    pub struct FoundString {
        // ... existing fields ...
        
        /// Whether this string is directly referenced by code via relocations
        #[serde(skip_serializing_if = \"Option::is_none\")]
        pub referenced: Option<bool>,
    }
    \`\`\`
    
    ### 2. Add relocation parsing to container parsers
    
    Extend `ContainerInfo` to include relocation data:
    
    \`\`\`rust
    pub struct ContainerInfo {
        // ... existing fields ...
        
        /// Addresses referenced by relocations
        pub relocation_targets: Vec<u64>,
    }
    \`\`\`
    
    Implement relocation parsing in:
    - `src/container/elf.rs`: Parse `.rela.dyn`, `.rela.plt`, `.rel.dyn`, `.rel.plt` sections
    - `src/container/pe.rs`: Parse `.reloc` section (Base Relocation Table)
    - `src/container/macho.rs`: Parse `LC_DYLD_INFO` load command rebase and bind entries
    
    ### 3. Cross-reference strings with relocation targets
    
    During string extraction in `src/extraction/mod.rs`:
    1. Extract all strings as usual
    2. Build a set of relocation target addresses from `ContainerInfo`
    3. For each extracted string, check if its RVA/offset is in the relocation target set
    4. Set `referenced = true` for matches
    
    ### 4. Update scoring algorithm
    
    In `src/classification/mod.rs`, boost the score for strings with `referenced = true`:
    
    \`\`\`rust
    if found_string.referenced == Some(true) {
        score += 50; // Significant boost for code-referenced strings
    }
    \`\`\`
    
    ### 5. Update output formats
    
    Include the `referenced` flag in JSON output and consider adding a visual indicator (e.g., `*` prefix) in human-readable output for referenced strings.
    
    ## Acceptance Criteria
    
    - [ ] `FoundString` struct includes `referenced: Option<bool>` field
    - [ ] `ContainerInfo` includes `relocation_targets: Vec<u64>` field
    - [ ] ELF parser extracts relocation entries from `.rela.*` and `.rel.*` sections
    - [ ] PE parser extracts relocation entries from `.reloc` section
    - [ ] Mach-O parser extracts rebase/bind targets from `LC_DYLD_INFO`
    - [ ] Extraction pipeline cross-references string addresses with relocation targets
    - [ ] Scoring algorithm boosts referenced strings significantly
    - [ ] Unit tests for each relocation parser with test binaries
    - [ ] Integration tests verify referenced strings are correctly flagged
    - [ ] Documentation updated with examples of relocation-based ranking
    
    ## Related Work
    
    - Issue #59: Import/Export Symbol Extraction (complementary metadata source)
    - Issue #62: DWARF Debug Information (alternative metadata for symbols)
    - Issue #63: Mach-O Load Command Strings (format-specific extraction)
    
    ## Implementation Notes
    
    - Start with ELF as it has the most straightforward relocation format
    - Consider using `goblin` crate's built-in relocation parsing where available
    - For stripped binaries, this may be the **only** reliable signal about string usage
    - Relocation data can be large in some binaries; consider streaming or filtering to reduce memory usage
    - Not all strings will be referenced (e.g., embedded data, resources, error messages in unused paths)
    "
    
    # Add labels
    gh issue edit 60 --add-label "enhancement,area:analyzer,lang:rust,needs:tests,priority:high,MVP"
    
    # Assign to unclesp1d3r
    gh issue edit 60 --add-assignee "unclesp1d3r"
    
    # Verify the changes
    gh issue view 60 --json title,body,labels,assignees
    

    Length of output: 9440


    @unclesp1d3r I've successfully enhanced issue #60 with comprehensive context and technical details. Here's what was updated:

    Changes Made:

    ✅ Title Enhanced

    Before: "Relocation-Based Hinting"
    After: "Add relocation-based string ranking to identify code-referenced addresses"

    ✅ Body Enhanced with:

    1. Overview - Clear summary of the feature
    2. Context - Detailed explanation of why relocation-based hinting is valuable, especially for stripped binaries
    3. Benefits - Zero-cost analysis, high-confidence signals, works on stripped binaries
    4. Technical Details - Format-specific implementation guidance:
      • ELF: .rela.dyn, .rela.plt, .rel.dyn, .rel.plt sections with goblin::elf::reloc::Reloc
      • PE: Base Relocation Table (.reloc section) via goblin::pe::relocation
      • Mach-O: LC_DYLD_INFO load commands with rebase/bind opcodes
    5. Proposed Solution - Step-by-step implementation plan:
      • Extend FoundString with referenced: Option<bool> field
      • Add relocation_targets: Vec<u64> to ContainerInfo
      • Implement relocation parsing in each container parser
      • Cross-reference extracted strings with relocation targets
      • Boost scoring for referenced strings (+50 points)
    6. Acceptance Criteria - Comprehensive checklist for completion
    7. Related Work - Links to issues Integrate Import/Export Symbol Extraction into String Analysis Pipeline #59, Extract strings from DWARF debug information (.debug_info, .debug_str, .debug_line) #62, Parse Mach-O Load Commands for Dynamic Library and Framework Path Extraction #63
    8. Implementation Notes - Practical considerations for development

    ✅ Labels Added:

    • enhancement - New feature request
    • area:analyzer - Binary analyzer functionality
    • lang:rust - Rust implementation
    • needs:tests - Requires test coverage
    • priority:high - High priority task
    • MVP - Minimum viable product feature

    ✅ Assigned to: @unclesp1d3r

    You can view the enhanced issue here: #60

    The issue now provides a complete roadmap for implementing relocation-based string ranking, which will significantly improve the signal-to-noise ratio in StringyMcStringFace's output, especially for stripped binaries where this may be the only reliable indicator of string usage.

  7. traycerai commented on Nov 10, 2025

    @traycerai

    I have updated the Implementation Plan to reflect the recent changes in the ticket.

    Previous Plan

    Observations

    The codebase is well-structured with a clear separation of concerns. The container parsers (ELF, PE, Mach-O) are fully implemented and use the goblin library for binary parsing. The FoundString struct in src/types.rs currently has fields for text, encoding, offset, RVA, section, length, tags, score, and source, but lacks a "referenced" flag. The extraction, classification, and ranking modules are currently empty stubs awaiting implementation. The goblin library provides relocation parsing APIs for all three binary formats: goblin::elf::reloc for ELF, goblin::pe::relocation for PE, and goblin::mach::relocation for Mach-O.

    Approach

    Add relocation-based hinting by:

    1. Extending FoundString with a referenced boolean field
    2. Creating a new relocation module to parse and extract relocation target addresses from each binary format
    3. Extending each container parser to extract relocation information
    4. Adding ContainerInfo field to store referenced addresses
    5. Creating address matching logic to mark strings as referenced
    6. Updating the ranking documentation to include the referenced boost (when ranking is implemented)

    This approach is minimal, format-agnostic, and integrates cleanly with the existing architecture without requiring disassembly.

    Reasoning

    I explored the codebase structure by listing directories, reading the core type definitions in src/types.rs, examining all three container parsers (src/container/elf.rs, pe.rs, macho.rs), reviewing the documentation (docs/src/ranking.md, string-extraction.md, architecture.md), checking integration tests, and searching the web for goblin's relocation parsing capabilities. This revealed that the infrastructure is ready for relocation-based hinting with minimal changes needed.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Add a referenced boolean field to the FoundString struct (around line 143-163). This field will indicate whether the string's address is referenced by code through relocation entries. Initialize it to false by default. This field should be included in the Serialize/Deserialize traits already present on the struct.
    Add a new field referenced_addresses to the ContainerInfo struct (around line 78-88). This should be a Vec<u64> or HashSet<u64> containing the set of addresses (RVAs or virtual addresses) that are referenced by relocation entries. This will be populated by the container parsers and used later to mark strings as referenced.

    📄 src/container (MODIFY) 🔗

    Create a new module file relocation.rs that defines common relocation-related types and utilities. This module should include:

    • A RelocationInfo struct with fields for source address, target address, and relocation type
    • Helper functions for extracting target addresses from relocations
    • Documentation explaining the purpose of relocation-based hinting

    This module will be used by all three format-specific parsers to handle relocations in a consistent way.

    📄 src/container/mod.rs (MODIFY) 🔗

    References

    Add pub mod relocation; declaration (around line 8, after the existing module declarations for elf, macho, and pe) to expose the new relocation module. Also re-export key types from the relocation module for easier access by other parts of the codebase.

    📄 src/container/elf.rs (MODIFY) 🔗

    References

    Add a new private method extract_relocations to the ElfParser implementation (around line 317, after the extract_exports method). This method should:

    • Use goblin::elf::reloc::RelocSection to iterate through relocation sections (.rela.dyn, .rela.plt, .rel.dyn, .rel.plt)
    • Extract target addresses from each relocation entry using the r_offset field
    • Handle both RELA (with addend) and REL (without addend) relocation types
    • Return a Vec<u64> of referenced addresses
    • Include error handling for malformed relocation data

    Then modify the parse method in the ContainerParser trait implementation (around line 324) to call extract_relocations and populate the referenced_addresses field in the returned ContainerInfo.

    📄 src/container/pe.rs (MODIFY) 🔗

    References

    Add a new private method extract_relocations to the PeParser implementation (around line 121, after the extract_exports method). This method should:

    • Access the base relocation table through pe.header.optional_header data directories
    • Parse base relocation blocks manually (goblin provides the directory location but not a high-level iterator)
    • Extract target RVAs from each relocation entry by combining the block's page RVA with individual entry offsets
    • Handle different relocation types (IMAGE_REL_BASED_HIGHLOW for 32-bit, IMAGE_REL_BASED_DIR64 for 64-bit)
    • Return a Vec<u64> of referenced RVAs
    • Include error handling for invalid relocation data

    Then modify the parse method in the ContainerParser trait implementation (around line 128) to call extract_relocations and populate the referenced_addresses field in the returned ContainerInfo.

    📄 src/container/macho.rs (MODIFY) 🔗

    References

    Add a new private method extract_relocations to the MachoParser implementation (around line 253, after the is_writable_section method). This method should:

    • Iterate through segments and their sections to find relocation entries
    • Use goblin::mach::relocation::RelocationInfo to parse relocation data
    • For LC_DYLD_INFO load commands, parse the rebase and binding information to identify referenced addresses
    • Extract target addresses from relocation entries, adjusting for segment base addresses
    • Return a Vec<u64> of referenced virtual addresses
    • Include error handling for malformed relocation data

    Then modify the parse_single_macho method (around line 181) to call extract_relocations and populate the referenced_addresses field in the returned ContainerInfo.

    📄 src/extraction/mod.rs (MODIFY) 🔗

    References

    Add a public function mark_referenced_strings that takes a mutable slice of FoundString and a reference to ContainerInfo. This function should:

    • Extract the referenced_addresses from ContainerInfo
    • For each string in the slice, check if its RVA (or offset if RVA is not available) matches any address in the referenced set
    • Set the referenced field to true for matching strings
    • Use efficient lookup (e.g., convert Vec to HashSet if not already)
    • Include documentation explaining the purpose and usage

    This function will be called after string extraction to mark strings that are referenced by code through relocations.

    📄 docs/src/ranking.md (MODIFY) 🔗

    Add a new section titled "Relocation-Based Boost" after the "Semantic Boost" section (around line 147). This section should document:

    • The purpose of relocation-based hinting (identifying strings referenced by code)
    • The boost value for referenced strings (suggest +15 points, similar to file paths)
    • An explanation that this is a zero-cost signal for stripped binaries with relocation info
    • A note that no disassembly is required for this subset of strings
    • Example code showing how the boost is applied in the scoring algorithm

    Also update the "Complete Scoring Implementation" section (around line 259) to include the relocation boost in the score calculation formula.

    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Add a new test function test_elf_relocation_extraction (around line 448, after the existing tests). This test should:

    • Load the ELF test fixture from tests/fixtures/test_binary_elf
    • Parse it using ElfParser
    • Verify that container_info.referenced_addresses is not empty (the test binary should have relocations)
    • Print the number of relocations found for debugging
    • Assert that at least some relocations were extracted
    • Include comments explaining what relocations are expected in the test binary

    This test validates that the ELF relocation extraction is working correctly.

    📄 tests/integration_pe.rs (MODIFY) 🔗

    References

    Add a new test function test_pe_relocation_extraction (around line 118, after the existing tests). This test should:

    • Load the PE test fixture from tests/fixtures/test_binary_pe.exe
    • Parse it using PeParser
    • Check if container_info.referenced_addresses contains any entries
    • Print the number of relocations found (PE executables may or may not have base relocations depending on compilation flags)
    • Include a comment noting that PE executables compiled with /FIXED may not have relocations
    • Assert that the parsing completes successfully even if no relocations are found

    This test validates that the PE relocation extraction handles both cases (with and without relocations) gracefully.

    📄 tests/integration_macho.rs (MODIFY) 🔗

    References

    Add a new test function test_macho_relocation_extraction (around line 111, after the existing tests). This test should:

    • Load the Mach-O test fixture from tests/fixtures/test_binary_macho
    • Parse it using MachoParser
    • Verify that container_info.referenced_addresses is populated
    • Print the number of relocations found for debugging
    • Assert that at least some relocations were extracted (Mach-O binaries typically have dyld info)
    • Include comments explaining the expected relocation sources (LC_DYLD_INFO, section relocations)

    This test validates that the Mach-O relocation extraction is working correctly.

    Diagram

    sequenceDiagram
        participant BP as Binary Parser
        participant ELF as ElfParser
        participant PE as PeParser
        participant Mach as MachoParser
        participant CI as ContainerInfo
        participant Ext as Extraction Module
        participant FS as FoundString
    
        BP->>ELF: parse(data)
        ELF->>ELF: extract_sections()
        ELF->>ELF: extract_imports()
        ELF->>ELF: extract_exports()
        ELF->>ELF: extract_relocations()
        Note over ELF: Parse .rela/.rel sections<br/>Extract target addresses
        ELF->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        BP->>PE: parse(data)
        PE->>PE: extract_sections()
        PE->>PE: extract_imports()
        PE->>PE: extract_exports()
        PE->>PE: extract_relocations()
        Note over PE: Parse base relocation table<br/>Extract target RVAs
        PE->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        BP->>Mach: parse(data)
        Mach->>Mach: extract_sections()
        Mach->>Mach: extract_imports()
        Mach->>Mach: extract_exports()
        Mach->>Mach: extract_relocations()
        Note over Mach: Parse LC_DYLD_INFO<br/>Extract target addresses
        Mach->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        Note over Ext: After string extraction
        Ext->>Ext: mark_referenced_strings(strings, container_info)
        loop For each string
            Ext->>FS: Check if RVA in referenced_addresses
            alt Address is referenced
                Ext->>FS: Set referenced = true
            else Not referenced
                Ext->>FS: Keep referenced = false
            end
        end
        
        Note over FS: Strings now marked<br/>with referenced flag<br/>for ranking boost
    
    Loading

    Import In IDE

    VSCode Icon Cursor Icon Windsurf Icon

    🤖 Prompt for AI Agents
    I have created the following plan after thorough exploration and analysis of the codebase. Follow the below plan verbatim. Trust the files and references. Do not re-verify what's written in the plan. Explore only when absolutely necessary. First implement all the proposed file changes and then I'll review all the changes together at the end.
    
    ### Observations
    
    The codebase is well-structured with a clear separation of concerns. The container parsers (ELF, PE, Mach-O) are fully implemented and use the goblin library for binary parsing. The `FoundString` struct in `src/types.rs` currently has fields for text, encoding, offset, RVA, section, length, tags, score, and source, but lacks a "referenced" flag. The extraction, classification, and ranking modules are currently empty stubs awaiting implementation. The goblin library provides relocation parsing APIs for all three binary formats: `goblin::elf::reloc` for ELF, `goblin::pe::relocation` for PE, and `goblin::mach::relocation` for Mach-O.
    
    ### Approach
    
    Add relocation-based hinting by:
    1. Extending `FoundString` with a `referenced` boolean field
    2. Creating a new relocation module to parse and extract relocation target addresses from each binary format
    3. Extending each container parser to extract relocation information
    4. Adding `ContainerInfo` field to store referenced addresses
    5. Creating address matching logic to mark strings as referenced
    6. Updating the ranking documentation to include the referenced boost (when ranking is implemented)
    
    This approach is minimal, format-agnostic, and integrates cleanly with the existing architecture without requiring disassembly.
    
    ### Reasoning
    
    I explored the codebase structure by listing directories, reading the core type definitions in `src/types.rs`, examining all three container parsers (`src/container/elf.rs`, `pe.rs`, `macho.rs`), reviewing the documentation (`docs/src/ranking.md`, `string-extraction.md`, `architecture.md`), checking integration tests, and searching the web for goblin's relocation parsing capabilities. This revealed that the infrastructure is ready for relocation-based hinting with minimal changes needed.
    
    ## Mermaid Diagram
    
    sequenceDiagram
        participant BP as Binary Parser
        participant ELF as ElfParser
        participant PE as PeParser
        participant Mach as MachoParser
        participant CI as ContainerInfo
        participant Ext as Extraction Module
        participant FS as FoundString
    
        BP->>ELF: parse(data)
        ELF->>ELF: extract_sections()
        ELF->>ELF: extract_imports()
        ELF->>ELF: extract_exports()
        ELF->>ELF: extract_relocations()
        Note over ELF: Parse .rela/.rel sections<br/>Extract target addresses
        ELF->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        BP->>PE: parse(data)
        PE->>PE: extract_sections()
        PE->>PE: extract_imports()
        PE->>PE: extract_exports()
        PE->>PE: extract_relocations()
        Note over PE: Parse base relocation table<br/>Extract target RVAs
        PE->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        BP->>Mach: parse(data)
        Mach->>Mach: extract_sections()
        Mach->>Mach: extract_imports()
        Mach->>Mach: extract_exports()
        Mach->>Mach: extract_relocations()
        Note over Mach: Parse LC_DYLD_INFO<br/>Extract target addresses
        Mach->>CI: Create with referenced_addresses
        CI-->>BP: ContainerInfo
    
        Note over Ext: After string extraction
        Ext->>Ext: mark_referenced_strings(strings, container_info)
        loop For each string
            Ext->>FS: Check if RVA in referenced_addresses
            alt Address is referenced
                Ext->>FS: Set referenced = true
            else Not referenced
                Ext->>FS: Keep referenced = false
            end
        end
        
        Note over FS: Strings now marked<br/>with referenced flag<br/>for ranking boost
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Add a `referenced` boolean field to the `FoundString` struct (around line 143-163). This field will indicate whether the string's address is referenced by code through relocation entries. Initialize it to `false` by default. This field should be included in the Serialize/Deserialize traits already present on the struct.
    Add a new field `referenced_addresses` to the `ContainerInfo` struct (around line 78-88). This should be a `Vec<u64>` or `HashSet<u64>` containing the set of addresses (RVAs or virtual addresses) that are referenced by relocation entries. This will be populated by the container parsers and used later to mark strings as referenced.
    
    ### src/container(MODIFY)
    
    Create a new module file `relocation.rs` that defines common relocation-related types and utilities. This module should include:
    - A `RelocationInfo` struct with fields for source address, target address, and relocation type
    - Helper functions for extracting target addresses from relocations
    - Documentation explaining the purpose of relocation-based hinting
    
    This module will be used by all three format-specific parsers to handle relocations in a consistent way.
    
    ### src/container/mod.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs
    
    Add `pub mod relocation;` declaration (around line 8, after the existing module declarations for elf, macho, and pe) to expose the new relocation module. Also re-export key types from the relocation module for easier access by other parts of the codebase.
    
    ### src/container/elf.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs
    - src/types.rs(MODIFY)
    
    Add a new private method `extract_relocations` to the `ElfParser` implementation (around line 317, after the `extract_exports` method). This method should:
    - Use `goblin::elf::reloc::RelocSection` to iterate through relocation sections (.rela.dyn, .rela.plt, .rel.dyn, .rel.plt)
    - Extract target addresses from each relocation entry using the `r_offset` field
    - Handle both RELA (with addend) and REL (without addend) relocation types
    - Return a `Vec<u64>` of referenced addresses
    - Include error handling for malformed relocation data
    
    Then modify the `parse` method in the `ContainerParser` trait implementation (around line 324) to call `extract_relocations` and populate the `referenced_addresses` field in the returned `ContainerInfo`.
    
    ### src/container/pe.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs
    - src/types.rs(MODIFY)
    
    Add a new private method `extract_relocations` to the `PeParser` implementation (around line 121, after the `extract_exports` method). This method should:
    - Access the base relocation table through `pe.header.optional_header` data directories
    - Parse base relocation blocks manually (goblin provides the directory location but not a high-level iterator)
    - Extract target RVAs from each relocation entry by combining the block's page RVA with individual entry offsets
    - Handle different relocation types (IMAGE_REL_BASED_HIGHLOW for 32-bit, IMAGE_REL_BASED_DIR64 for 64-bit)
    - Return a `Vec<u64>` of referenced RVAs
    - Include error handling for invalid relocation data
    
    Then modify the `parse` method in the `ContainerParser` trait implementation (around line 128) to call `extract_relocations` and populate the `referenced_addresses` field in the returned `ContainerInfo`.
    
    ### src/container/macho.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs
    - src/types.rs(MODIFY)
    
    Add a new private method `extract_relocations` to the `MachoParser` implementation (around line 253, after the `is_writable_section` method). This method should:
    - Iterate through segments and their sections to find relocation entries
    - Use `goblin::mach::relocation::RelocationInfo` to parse relocation data
    - For LC_DYLD_INFO load commands, parse the rebase and binding information to identify referenced addresses
    - Extract target addresses from relocation entries, adjusting for segment base addresses
    - Return a `Vec<u64>` of referenced virtual addresses
    - Include error handling for malformed relocation data
    
    Then modify the `parse_single_macho` method (around line 181) to call `extract_relocations` and populate the `referenced_addresses` field in the returned `ContainerInfo`.
    
    ### src/extraction/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Add a public function `mark_referenced_strings` that takes a mutable slice of `FoundString` and a reference to `ContainerInfo`. This function should:
    - Extract the `referenced_addresses` from `ContainerInfo`
    - For each string in the slice, check if its RVA (or offset if RVA is not available) matches any address in the referenced set
    - Set the `referenced` field to `true` for matching strings
    - Use efficient lookup (e.g., convert Vec to HashSet if not already)
    - Include documentation explaining the purpose and usage
    
    This function will be called after string extraction to mark strings that are referenced by code through relocations.
    
    ### docs/src/ranking.md(MODIFY)
    
    Add a new section titled "Relocation-Based Boost" after the "Semantic Boost" section (around line 147). This section should document:
    - The purpose of relocation-based hinting (identifying strings referenced by code)
    - The boost value for referenced strings (suggest +15 points, similar to file paths)
    - An explanation that this is a zero-cost signal for stripped binaries with relocation info
    - A note that no disassembly is required for this subset of strings
    - Example code showing how the boost is applied in the scoring algorithm
    
    Also update the "Complete Scoring Implementation" section (around line 259) to include the relocation boost in the score calculation formula.
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/container/elf.rs(MODIFY)
    - src/types.rs(MODIFY)
    
    Add a new test function `test_elf_relocation_extraction` (around line 448, after the existing tests). This test should:
    - Load the ELF test fixture from `tests/fixtures/test_binary_elf`
    - Parse it using `ElfParser`
    - Verify that `container_info.referenced_addresses` is not empty (the test binary should have relocations)
    - Print the number of relocations found for debugging
    - Assert that at least some relocations were extracted
    - Include comments explaining what relocations are expected in the test binary
    
    This test validates that the ELF relocation extraction is working correctly.
    
    ### tests/integration_pe.rs(MODIFY)
    
    References: 
    
    - src/container/pe.rs(MODIFY)
    - src/types.rs(MODIFY)
    
    Add a new test function `test_pe_relocation_extraction` (around line 118, after the existing tests). This test should:
    - Load the PE test fixture from `tests/fixtures/test_binary_pe.exe`
    - Parse it using `PeParser`
    - Check if `container_info.referenced_addresses` contains any entries
    - Print the number of relocations found (PE executables may or may not have base relocations depending on compilation flags)
    - Include a comment noting that PE executables compiled with /FIXED may not have relocations
    - Assert that the parsing completes successfully even if no relocations are found
    
    This test validates that the PE relocation extraction handles both cases (with and without relocations) gracefully.
    
    ### tests/integration_macho.rs(MODIFY)
    
    References: 
    
    - src/container/macho.rs(MODIFY)
    - src/types.rs(MODIFY)
    
    Add a new test function `test_macho_relocation_extraction` (around line 111, after the existing tests). This test should:
    - Load the Mach-O test fixture from `tests/fixtures/test_binary_macho`
    - Parse it using `MachoParser`
    - Verify that `container_info.referenced_addresses` is populated
    - Print the number of relocations found for debugging
    - Assert that at least some relocations were extracted (Mach-O binaries typically have dyld info)
    - Include comments explaining the expected relocation sources (LC_DYLD_INFO, section relocations)
    
    This test validates that the Mach-O relocation extraction is working correctly.

    Developer Humor

    🔗 Relocations point the way,\n> To strings that code will say.\n> No disassembly needed here,\n> The references are crystal clear!\n> 🎯 Zero-cost hints, hooray!


    Execution Information

    Branch: main
    Commit: bdd6206

    New Plan

    Observations

    The codebase structure supports binary parsing via goblin for ELF, PE, and Mach-O formats. FoundString in src/types.rs lacks a referenced field, and ContainerInfo needs relocation_targets. Container parsers extract sections, imports, and exports but not relocations. Extraction and classification modules are stubs. Goblin provides relocation APIs: elf::reloc for ELF, pe::relocation for PE, mach::relocation for Mach-O. Tests exist but need relocation-specific cases. Documentation in docs/src/ requires ranking updates.

    Approach

    1. Extend types: Add referenced: Option&lt;bool&gt; to FoundString and relocation_targets: Vec&lt;u64&gt; to ContainerInfo.\n2. Create src/container/relocation.rs for shared utilities.\n3. Implement extract_relocations in each parser, populating relocation_targets.\n4. In src/extraction/mod.rs, add mark_referenced_strings to flag matching strings.\n5. In src/classification/mod.rs, add scoring boost for referenced strings.\n6. Update JSON output in src/output/ to include the flag.\n7. Add unit/integration tests for relocation extraction and flagging.\n8. Document in docs/src/ranking.md and string-extraction.md.

    Reasoning

    I examined the project directory structure to understand the codebase layout. I reviewed the core types in src/types.rs to identify necessary extensions. I analyzed the container parsers in src/container/ (elf.rs, pe.rs, macho.rs) to see existing extraction logic. I checked the empty extraction and classification modules. I searched goblin documentation for relocation parsing capabilities across formats. This confirmed the feasibility of adding relocation-based hinting with minimal changes.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Add referenced: Option&lt;bool&gt;, defaulting to None, to the FoundString struct after the source field. Ensure it implements Serialize/Deserialize with #[serde(skip_serializing_if = "Option::is_none")].

    Add relocation_targets: Vec&lt;u64&gt; to the ContainerInfo struct after the exports field. This will store RVAs/virtual addresses referenced by relocations, populated by parsers.

    📄 src/container/mod.rs (MODIFY) 🔗

    References

    Add pub mod relocation; after the existing mod declarations.

    Re-export pub use relocation::{RelocationInfo, extract_target_addresses}; for common use.

    📄 src/container/relocation.rs (NEW) 🔗

    References

    Create a new module defining shared relocation utilities.

    Define #[derive(Debug, Clone)] pub struct RelocationInfo { pub source_rva: u64, pub target_rva: u64, pub reloc_type: String }.

    Add pub fn extract_target_addresses(relocs: &amp;[RelocationInfo]) -> Vec&lt;u64&gt; to collect unique target addresses.

    Include documentation on relocation-based hinting purpose.

    📄 src/container/elf.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, elf: &amp;Elf) -> Vec&lt;u64&gt;:

    • Iterate over elf.relocs or specific sections (.rela.dyn, .rela.plt, etc.) using goblin::elf::reloc.
    • For each reloc, create RelocationInfo with r_offset as target (add r_addend for RELA).
    • Filter relevant types (R_X86_64_64, R_X86_64_GLOB_DAT, etc.).
    • Return unique targets via extract_target_addresses.

    In parse, after extracting exports, call self.extract_relocations(&amp;elf) and set container_info.relocation_targets.

    📄 src/container/pe.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, pe: &amp;PE) -> Vec&lt;u64&gt;:

    • Access pe.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC].
    • Parse relocation blocks: for each block, add page RVA to entry offsets.
    • Handle types like IMAGE_REL_BASED_HIGHLOW (32-bit) and IMAGE_REL_BASED_DIR64 (64-bit).
    • Create RelocationInfo for each, collect targets.
    • Return unique targets.

    In parse, after extracting exports, call self.extract_relocations(&amp;pe) and set container_info.relocation_targets.

    📄 src/container/macho.rs (MODIFY) 🔗

    References

    Add use crate::container::relocation::RelocationInfo;.

    Implement fn extract_relocations(&amp;self, macho: &amp;MachO) -> Vec&lt;u64&gt;:

    • Parse macho.dyld_info for rebase/bind opcodes using goblin::mach::dyld::DyldInfo.
    • For rebase: extract adjusted addresses.
    • For bind: extract bound addresses.
    • Also check section relocations if present.
    • Create RelocationInfo, collect targets adjusted for segment bases.
    • Return unique targets.

    In parse_single_macho, after extracting exports, call self.extract_relocations(macho) and set container_info.relocation_targets.

    📄 src/extraction/mod.rs (MODIFY) 🔗

    References

    Add use crate::types::{FoundString, ContainerInfo}; and use std::collections::HashSet;.

    Implement `pub fn mark_referenced_strings(strings: &mut [FoundString], container_info: &ContainerInfo) {

    • Create HashSet from container_info.relocation_targets.
    • For each string, if string.rva matches a target, set string.referenced = Some(true); else Some(false).
      }

    Document usage: Call after initial string extraction but before classification.

    📄 src/classification/mod.rs (MODIFY) 🔗

    References

    Add use crate::types::FoundString;.

    Implement `pub fn calculate_score(string: &FoundString) -> i32 {

    • Base score from existing logic (tags, section, etc.).
    • If string.referenced == Some(true), add 50 to score.
    • Return total.
      }

    Update FoundString::score to use this in extraction pipeline.

    Document the +50 boost for code-referenced strings.

    📄 src/output/mod.rs (MODIFY) 🔗

    References

    Assuming JSON serialization, ensure FoundString serialization includes referenced field.

    In human-readable output, prefix referenced strings with '*' or '[REF]' indicator.

    Update any existing output functions to handle the new field.

    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load ELF fixture.
    • Parse with ElfParser.
    • Assert container_info.relocation_targets.len() > 0 (use binary with relocs).
    • Extract strings, mark referenced, assert some have referenced: Some(true).
    • Verify score boost in classification.
    📄 tests/integration_pe.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load PE fixture (with relocs if possible).
    • Parse with PeParser.
    • Assert relocation_targets populated or empty gracefully.
    • Mark strings, check flagging and score boost.
    📄 tests/integration_macho.rs (MODIFY) 🔗

    References

    Add test test_relocation_extraction:

    • Load Mach-O fixture.
    • Parse with MachoParser.
    • Assert relocation_targets.len() > 0.
    • Mark strings, verify referenced flagging and score boost.
    📄 docs/src/ranking.md (MODIFY) 🔗

    References

    Add section 'Relocation-Based Boost':

    • Explain identifying code-referenced strings via relocations.
    • Detail +50 score boost.
    • Note zero-cost for stripped binaries.
    • Include example: if referenced { score += 50; }.

    Update 'Scoring Formula' to incorporate this boost.

    📄 docs/src/string-extraction.md (MODIFY) 🔗

    References

    Add subsection under 'Post-Extraction Processing':

    • Describe mark_referenced_strings function.
    • Explain cross-referencing with ContainerInfo.relocation_targets.
    • Note integration after section-based extraction.

    Import In IDE

    VSCode Icon Cursor Icon Windsurf Icon

    🤖 Prompt for AI Agents
    I have created the following plan after thorough exploration and analysis of the codebase. Follow the below plan verbatim. Trust the files and references. Do not re-verify what's written in the plan. Explore only when absolutely necessary. First implement all the proposed file changes and then I'll review all the changes together at the end.
    
    ### Observations
    
    The codebase structure supports binary parsing via goblin for ELF, PE, and Mach-O formats. `FoundString` in `src/types.rs` lacks a `referenced` field, and `ContainerInfo` needs `relocation_targets`. Container parsers extract sections, imports, and exports but not relocations. Extraction and classification modules are stubs. Goblin provides relocation APIs: `elf::reloc` for ELF, `pe::relocation` for PE, `mach::relocation` for Mach-O. Tests exist but need relocation-specific cases. Documentation in `docs/src/` requires ranking updates.
    
    ### Approach
    
    1. Extend types: Add `referenced: Option&lt;bool&gt;` to `FoundString` and `relocation_targets: Vec&lt;u64&gt;` to `ContainerInfo`.\n2. Create `src/container/relocation.rs` for shared utilities.\n3. Implement `extract_relocations` in each parser, populating `relocation_targets`.\n4. In `src/extraction/mod.rs`, add `mark_referenced_strings` to flag matching strings.\n5. In `src/classification/mod.rs`, add scoring boost for referenced strings.\n6. Update JSON output in `src/output/` to include the flag.\n7. Add unit/integration tests for relocation extraction and flagging.\n8. Document in `docs/src/ranking.md` and `string-extraction.md`.
    
    ### Reasoning
    
    I examined the project directory structure to understand the codebase layout. I reviewed the core types in `src/types.rs` to identify necessary extensions. I analyzed the container parsers in `src/container/` (elf.rs, pe.rs, macho.rs) to see existing extraction logic. I checked the empty extraction and classification modules. I searched goblin documentation for relocation parsing capabilities across formats. This confirmed the feasibility of adding relocation-based hinting with minimal changes.
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Add `referenced: Option&lt;bool&gt;`, defaulting to `None`, to the `FoundString` struct after the `source` field. Ensure it implements Serialize/Deserialize with `#[serde(skip_serializing_if = "Option::is_none")]`.
    
    Add `relocation_targets: Vec&lt;u64&gt;` to the `ContainerInfo` struct after the `exports` field. This will store RVAs/virtual addresses referenced by relocations, populated by parsers.
    
    ### src/container/mod.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    
    Add `pub mod relocation;` after the existing mod declarations.
    
    Re-export `pub use relocation::{RelocationInfo, extract_target_addresses};` for common use.
    
    ### src/container/relocation.rs(NEW)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Create a new module defining shared relocation utilities.
    
    Define `#[derive(Debug, Clone)] pub struct RelocationInfo { pub source_rva: u64, pub target_rva: u64, pub reloc_type: String }`.
    
    Add `pub fn extract_target_addresses(relocs: &amp;[RelocationInfo]) -> Vec&lt;u64&gt;` to collect unique target addresses.
    
    Include documentation on relocation-based hinting purpose.
    
    ### src/container/elf.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, elf: &amp;Elf) -> Vec&lt;u64&gt;`:
    - Iterate over `elf.relocs` or specific sections (.rela.dyn, .rela.plt, etc.) using `goblin::elf::reloc`.
    - For each reloc, create `RelocationInfo` with `r_offset` as target (add `r_addend` for RELA).
    - Filter relevant types (R_X86_64_64, R_X86_64_GLOB_DAT, etc.).
    - Return unique targets via `extract_target_addresses`.
    
    In `parse`, after extracting exports, call `self.extract_relocations(&amp;elf)` and set `container_info.relocation_targets`.
    
    ### src/container/pe.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, pe: &amp;PE) -> Vec&lt;u64&gt;`:
    - Access `pe.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC]`.
    - Parse relocation blocks: for each block, add page RVA to entry offsets.
    - Handle types like IMAGE_REL_BASED_HIGHLOW (32-bit) and IMAGE_REL_BASED_DIR64 (64-bit).
    - Create `RelocationInfo` for each, collect targets.
    - Return unique targets.
    
    In `parse`, after extracting exports, call `self.extract_relocations(&amp;pe)` and set `container_info.relocation_targets`.
    
    ### src/container/macho.rs(MODIFY)
    
    References: 
    
    - src/container/relocation.rs(NEW)
    - src/types.rs(MODIFY)
    
    Add `use crate::container::relocation::RelocationInfo;`.
    
    Implement `fn extract_relocations(&amp;self, macho: &amp;MachO) -> Vec&lt;u64&gt;`:
    - Parse `macho.dyld_info` for rebase/bind opcodes using `goblin::mach::dyld::DyldInfo`.
    - For rebase: extract adjusted addresses.
    - For bind: extract bound addresses.
    - Also check section relocations if present.
    - Create `RelocationInfo`, collect targets adjusted for segment bases.
    - Return unique targets.
    
    In `parse_single_macho`, after extracting exports, call `self.extract_relocations(macho)` and set `container_info.relocation_targets`.
    
    ### src/extraction/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Add `use crate::types::{FoundString, ContainerInfo};` and `use std::collections::HashSet;`.
    
    Implement `pub fn mark_referenced_strings(strings: &amp;mut [FoundString], container_info: &amp;ContainerInfo) {
    - Create HashSet from `container_info.relocation_targets`.
    - For each string, if `string.rva` matches a target, set `string.referenced = Some(true)`; else `Some(false)`.
    }
    
    Document usage: Call after initial string extraction but before classification.
    
    ### src/classification/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Add `use crate::types::FoundString;`.
    
    Implement `pub fn calculate_score(string: &amp;FoundString) -> i32 {
    - Base score from existing logic (tags, section, etc.).
    - If `string.referenced == Some(true)`, add 50 to score.
    - Return total.
    }
    
    Update `FoundString::score` to use this in extraction pipeline.
    
    Document the +50 boost for code-referenced strings.
    
    ### src/output/mod.rs(MODIFY)
    
    References: 
    
    - src/types.rs(MODIFY)
    
    Assuming JSON serialization, ensure `FoundString` serialization includes `referenced` field.
    
    In human-readable output, prefix referenced strings with '*' or '[REF]' indicator.
    
    Update any existing output functions to handle the new field.
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/container/elf.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load ELF fixture.
    - Parse with `ElfParser`.
    - Assert `container_info.relocation_targets.len() > 0` (use binary with relocs).
    - Extract strings, mark referenced, assert some have `referenced: Some(true)`.
    - Verify score boost in classification.
    
    ### tests/integration_pe.rs(MODIFY)
    
    References: 
    
    - src/container/pe.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load PE fixture (with relocs if possible).
    - Parse with `PeParser`.
    - Assert `relocation_targets` populated or empty gracefully.
    - Mark strings, check flagging and score boost.
    
    ### tests/integration_macho.rs(MODIFY)
    
    References: 
    
    - src/container/macho.rs(MODIFY)
    - src/extraction/mod.rs(MODIFY)
    - src/classification/mod.rs(MODIFY)
    
    Add test `test_relocation_extraction`:
    - Load Mach-O fixture.
    - Parse with `MachoParser`.
    - Assert `relocation_targets.len() > 0`.
    - Mark strings, verify referenced flagging and score boost.
    
    ### docs/src/ranking.md(MODIFY)
    
    References: 
    
    - src/classification/mod.rs(MODIFY)
    
    Add section 'Relocation-Based Boost':
    - Explain identifying code-referenced strings via relocations.
    - Detail +50 score boost.
    - Note zero-cost for stripped binaries.
    - Include example: `if referenced { score += 50; }`.
    
    Update 'Scoring Formula' to incorporate this boost.
    
    ### docs/src/string-extraction.md(MODIFY)
    
    References: 
    
    - src/extraction/mod.rs(MODIFY)
    - src/types.rs(MODIFY)
    
    Add subsection under 'Post-Extraction Processing':
    - Describe `mark_referenced_strings` function.
    - Explain cross-referencing with `ContainerInfo.relocation_targets`.
    - Note integration after section-based extraction.

    Developer Humor

    > Why did the string go to relocation therapy?\n> It needed to find its address in the code!\n> 🔄➡️🎯\n> Now it's referenced and feeling boosted. +50 points!


    Execution Information

    Branch: main
    Commit: 37cfc7c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

MVPMinimum viable product featuresarea:analyzerBinary analyzer functionalityenhancementNew feature or requestlang:rustRust implementationneeds:testsNeeds test coveragepriority:highHigh priority taskstatus:backlogTask in backlog

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions