Skip to content

Add x86-64 RIP-relative addressing analysis for string reference tracking #74

Description

@unclesp1d3r

Overview

In x86-64 position-independent code (PIC), string literals and other data are typically referenced using RIP-relative addressing — an addressing mode that encodes memory references as offsets from the instruction pointer rather than absolute addresses. Detecting these references would allow Stringy to:

  1. Boost scoring for strings that are actively referenced by code
  2. Filter dead strings that exist in data sections but are never used
  3. Improve accuracy by distinguishing meaningful strings from padding or artifact data
  4. Provide provenance information about which code references which strings

Background: RIP-relative Addressing

RIP-relative addressing is the primary addressing mode for accessing data in x86-64 PIC:

  • Format: [RIP + disp32] where disp32 is a signed 32-bit displacement
  • Range: Can reference data within ±2GB of the instruction
  • Encoding: Appears as displacement-only memory operands (e.g., movq symbol(%rip), %rax)
  • Common instructions: lea, mov, cmp, and other instructions with memory operands
  • Benefits: No runtime relocations needed, enables true position-independent code

Example disassembly:

lea    0x2000(%rip), %rdi    # Load address of string at RIP+0x2000
mov    0x1ff0(%rip), %rax    # Load value from RIP+0x1ff0

Proposed Solution

Phase 1: Instruction Scanning (Lightweight)

Add lightweight x86-64 instruction parsing to detect RIP-relative memory references without full disassembly:

  1. Scan code sections (SectionType::Code) for x86-64 instructions
  2. Pattern match common RIP-relative encodings:
    • ModR/M byte with mod=00, r/m=101 (RIP-relative displacement)
    • Common opcodes: 8D (LEA), 8B (MOV), 48 8B (MOV r64), etc.
  3. Extract displacement and compute target address: instruction_addr + instruction_length + disp32
  4. Map targets to string offsets in data sections
  5. Increment reference counts for referenced strings

Phase 2: Enhanced Scoring (Integration)

Integrate reference tracking into the existing scoring system:

pub struct ExtractedString {
    pub text: String,
    pub offset: u64,
    pub rva: Option<u64>,
    pub section: String,
    pub encoding: Encoding,
    pub length: usize,
    pub tags: Vec<Tag>,
    pub score: i32,
    pub source: StringSource,
    
    // NEW: Reference tracking
    pub reference_count: u32,         // Number of code references
    pub referencing_addresses: Vec<u64>, // RVAs of referencing instructions
}

Scoring adjustments:

  • +20 points: String has 1+ code references
  • +10 points: String has 3+ code references (highly used)
  • -10 points: String in writable section with 0 references (likely runtime buffer)

Phase 3: Optional Full Disassembly (Future)

For advanced use cases, integrate Capstone disassembler as optional feature:

[dependencies]
capstone = { version = "0.12", optional = true }

[features]
disassembly = ["capstone"]

Benefits:

  • More accurate instruction parsing (handles edge cases, prefixes, etc.)
  • Support for other architectures (ARM64, RISC-V)
  • Detailed instruction analysis for forensics

Implementation Checklist

  • Add x86-64 instruction pattern matching module
  • Implement RIP-relative displacement extraction
  • Add reference tracking fields to ExtractedString
  • Integrate reference counting into scoring algorithm
  • Add unit tests with fixture binaries containing RIP-relative references
  • Document architecture-specific features in user guide
  • (Optional) Add Capstone integration behind feature flag

Related Context

  • Mentioned in docs/src/binary-formats.md under "Architecture-Specific Enhancements"
  • Complements existing section weight system (prioritizes likely string sections)
  • Similar to how resource extraction boosts PE string scores
  • Cross-references with import/export analysis (symbols are also code references)

Example Use Cases

  1. Malware Analysis: Identify which strings are used by unpacking/decryption routines
  2. YARA Rule Generation: Focus on strings that are definitely code-referenced
  3. Firmware Analysis: Filter out unused strings in embedded binaries
  4. Binary Diffing: Track which code references changed between versions

Technical Notes

  • ELF PIC: Nearly all data references use RIP-relative addressing
  • PE x64: Uses RIP-relative for PIC, but also absolute addresses in non-relocatable executables
  • Mach-O x64: Similar to ELF, heavy use of RIP-relative in position-independent code
  • Static linking: May contain more unused strings than dynamic executables
  • Stripped binaries: Reference tracking works even without symbol tables

Alternatives Considered

  1. Symbol-based: Only track symbol references (not sufficient, misses many string literals)
  2. Relocation analysis: Parse relocation tables (misses PIC references, platform-specific)
  3. Full control-flow analysis: Too heavyweight for string extraction use case

Activity

  1. traycerai commented on Nov 11, 2025

    @traycerai

    Plan

    Observations

    The codebase features a modular Rust library with defined types for binary analysis, including FoundString (lacking reference fields), ContainerInfo with section metadata (offsets, sizes, RVAs, types), and parsers for ELF, PE, Mach-O using goblin/pelite. Extraction is partially implemented (PE resources), classification and ranking modules exist but are stubs. No analysis module present. Section classification includes SectionType::Code for .text sections. This setup is ideal for adding lightweight x86-64 RIP-relative reference detection to enhance string scoring without full disassembly.

    Approach

    Introduce an analysis module for code reference detection, focusing on x86-64 RIP-relative addressing via pattern matching in code sections. Extend FoundString with reference_count and referencing_addresses fields. Implement scanning logic to compute target addresses from instruction patterns, match against string RVAs, and update counts/addresses. Integrate scoring boosts: +20 for referenced strings, +10 for highly referenced (>3), -10 for unreferenced writable data strings. Add unit tests for pattern detection and integration tests using ELF fixtures. Document in architecture and extraction guides, with optional Capstone future support.

    Reasoning

    I listed the project directories to map the structure, read src/types.rs to review FoundString and section types, examined src/container/mod.rs for parsing API, checked src/extraction/mod.rs for current extraction state, and confirmed documentation and test presence in docs/src/ and tests/ to ensure integration points.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Extend the FoundString struct with two new fields for reference tracking:

    • reference_count: u32 - Number of code references to this string (default 0)
    • referencing_addresses: Vec<u64> - RVAs of instructions referencing this string

    Add these fields after the source field for logical grouping with metadata. Update the struct documentation to explain their purpose in identifying actively used strings. Ensure the fields are included in Serialize and Deserialize via the existing derives. No changes to enums or other structs needed.

    📄 src/lib.rs (MODIFY) 🔗

    References

    Declare the new pub mod analysis; after existing modules (container, extraction, classification, output) to expose the analysis functionality in the public API. Update the module-level documentation to note the addition of code analysis capabilities, specifically RIP-relative reference detection for x86-64 binaries, which enhances string relevance scoring.

    📄 src/analysis/mod.rs (NEW) 🔗

    References

    Create the module entry point for the analysis crate. Include:

    • pub mod rip_relative; to declare the submodule
    • Re-export key items: pub use rip_relative::{analyze_references, RipRelativeRef};
    • Module documentation explaining the purpose: static code analysis for detecting references to strings, starting with x86-64 RIP-relative addressing in position-independent code. Mention extensibility for other analyses (e.g., relocations, control flow) and architectures.

    Keep it minimal as the primary logic resides in the submodule.

    📄 src/analysis/rip_relative.rs (NEW) 🔗

    References

    Implement x86-64 RIP-relative reference detection using lightweight pattern matching:

    1. Define RipRelativeRef struct: fields instruction_rva: u64, target_rva: u64, instruction_bytes: Vec<u8>, displacement: i32 for storing detected references.

    2. Implement analyze_references function: takes &mut [FoundString], &[u8] (binary data), &ContainerInfo. Logic:

      • Identify code sections (SectionType::Code)
      • For each code section, extract bytes using offset and size
      • Scan bytes for RIP-relative patterns (7-byte instructions: optional REX, opcode, ModR/M=0x05, disp32)
      • Common patterns: 48 8B 05 (mov r64,[rip+d]), 48 8D 05 (lea r64,[rip+d]), 8B 05 (mov r32,[rip+d]), 8D 05 (lea r32,[rip+d]), and variations for other registers (ModR/M reg field 0-7 with rm=101)
      • For matches: compute target_rva = instruction_rva + 7 + (displacement as i64) as u64 (assuming instr_len=7)
      • For each target, match against strings with rva == Some(target): increment reference_count, push instruction_rva to referencing_addresses
      • After scanning, apply scoring: if reference_count > 0 { score += 20 }, if > 3 { += 10 }; if reference_count == 0 and section is WritableData (lookup by section name), score -= 10
    3. Helper functions:

      • is_rip_relative_pattern(bytes: &[u8], offset: usize) -> bool: Check for ModR/M 0x05 after opcode
      • extract_displacement(bytes: &[u8], offset: usize) -> i32: Read signed 32-bit LE
      • compute_target(rva: u64, instr_len: u8, disp: i32) -> u64: Sign-extend and add
    4. Documentation: Detail mechanics, patterns, limitations (false positives, x86-64 only, no prefixes handled), and integration.

    5. Unit tests:

      • test_pattern_matching: Verify detection for synthetic instructions (e.g., [0x48, 0x8B, 0x05, 0x00,0x00,0x00,0x00])
      • test_target_calculation: Check address computation with positive/negative disp
      • test_scoring_integration: Mock strings and refs, assert score changes
      • test_no_code_section: Ensure no crash if no code sections
    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Extend existing ELF integration tests to validate reference analysis:

    • After parsing ContainerInfo and extracting strings (mock if needed), call stringy::analysis::analyze_references(&mut strings, &data, &container)
    • Assert at least one string has reference_count > 0 and referencing_addresses non-empty (assuming fixture has RIP-relative refs, e.g., printf("hello"))
    • Verify scoring adjustments: check score increased for referenced strings
    • Add test case for binary without code section (e.g., stripped or data-only)

    Use existing fixture tests/fixtures/test_binary_elf or similar; document assumption that fixture uses PIC with RIP-relative addressing.

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

    References

    Update architecture documentation to incorporate the analysis module:

    1. In 'High-Level Architecture' section, insert 'Reference Analysis' step in pipeline: Binary → Parsing → Extraction → Reference Analysis → Classification → Ranking → Output

    2. Add new subsection '### Analysis Module (src/analysis/)' after Output:

      • Purpose: Detect code references to strings via RIP-relative addressing (x86-64)
      • Components: rip_relative.rs for pattern scanning
      • Data flow: Updates FoundString in-place with counts and addresses
      • Scoring integration: Boosts for referenced strings
    3. Update 'Module Dependencies' to include:

      ├── analysis/
      │   ├── mod.rs
      │   └── rip_relative.rs (x86-64 RIP detection)
      
    4. In 'Future Enhancements', note optional Capstone for full disassembly and multi-arch support.

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

    References

    Add a new section '### Reference Detection in Code' after 'Deduplication':

    • Explain RIP-relative addressing and its role in PIC
    • Describe detection: Pattern matching in .text for ModR/M=0x05, target calculation
    • Integration: analyze_references function called post-extraction
    • Output: New fields in JSON: reference_count, referencing_addresses
    • Scoring impact: +20 for referenced, +10 for highly used, -10 for dead writable strings
    • Limitations: x86-64 only, lightweight (no full disasm), potential false positives
    • Example: Show JSON snippet with referenced=true implied by count>0

    Update 'Supported Features' to include 'x86-64 RIP-relative reference tracking'.

    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 features a modular Rust library with defined types for binary analysis, including `FoundString` (lacking reference fields), `ContainerInfo` with section metadata (offsets, sizes, RVAs, types), and parsers for ELF, PE, Mach-O using goblin/pelite. Extraction is partially implemented (PE resources), classification and ranking modules exist but are stubs. No analysis module present. Section classification includes `SectionType::Code` for .text sections. This setup is ideal for adding lightweight x86-64 RIP-relative reference detection to enhance string scoring without full disassembly.
    
    ### Approach
    
    Introduce an `analysis` module for code reference detection, focusing on x86-64 RIP-relative addressing via pattern matching in code sections. Extend `FoundString` with `reference_count` and `referencing_addresses` fields. Implement scanning logic to compute target addresses from instruction patterns, match against string RVAs, and update counts/addresses. Integrate scoring boosts: +20 for referenced strings, +10 for highly referenced (>3), -10 for unreferenced writable data strings. Add unit tests for pattern detection and integration tests using ELF fixtures. Document in architecture and extraction guides, with optional Capstone future support.
    
    ### Reasoning
    
    I listed the project directories to map the structure, read `src/types.rs` to review `FoundString` and section types, examined `src/container/mod.rs` for parsing API, checked `src/extraction/mod.rs` for current extraction state, and confirmed documentation and test presence in `docs/src/` and `tests/` to ensure integration points.
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Extend the `FoundString` struct with two new fields for reference tracking:
    
    - `reference_count: u32` - Number of code references to this string (default 0)
    - `referencing_addresses: Vec<u64>` - RVAs of instructions referencing this string
    
    Add these fields after the `source` field for logical grouping with metadata. Update the struct documentation to explain their purpose in identifying actively used strings. Ensure the fields are included in `Serialize` and `Deserialize` via the existing derives. No changes to enums or other structs needed.
    
    ### src/lib.rs(MODIFY)
    
    References: 
    
    - src/analysis/mod.rs(NEW)
    
    Declare the new `pub mod analysis;` after existing modules (`container`, `extraction`, `classification`, `output`) to expose the analysis functionality in the public API. Update the module-level documentation to note the addition of code analysis capabilities, specifically RIP-relative reference detection for x86-64 binaries, which enhances string relevance scoring.
    
    ### src/analysis/mod.rs(NEW)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Create the module entry point for the analysis crate. Include:
    
    - `pub mod rip_relative;` to declare the submodule
    - Re-export key items: `pub use rip_relative::{analyze_references, RipRelativeRef};`
    - Module documentation explaining the purpose: static code analysis for detecting references to strings, starting with x86-64 RIP-relative addressing in position-independent code. Mention extensibility for other analyses (e.g., relocations, control flow) and architectures.
    
    Keep it minimal as the primary logic resides in the submodule.
    
    ### src/analysis/rip_relative.rs(NEW)
    
    References: 
    
    - src/types.rs(MODIFY)
    - src/container/mod.rs
    
    Implement x86-64 RIP-relative reference detection using lightweight pattern matching:
    
    1. Define `RipRelativeRef` struct: fields `instruction_rva: u64`, `target_rva: u64`, `instruction_bytes: Vec<u8>`, `displacement: i32` for storing detected references.
    
    2. Implement `analyze_references` function: takes `&mut [FoundString]`, `&[u8]` (binary data), `&ContainerInfo`. Logic:
       - Identify code sections (`SectionType::Code`)
       - For each code section, extract bytes using `offset` and `size`
       - Scan bytes for RIP-relative patterns (7-byte instructions: optional REX, opcode, ModR/M=0x05, disp32)
       - Common patterns: `48 8B 05` (mov r64,[rip+d]), `48 8D 05` (lea r64,[rip+d]), `8B 05` (mov r32,[rip+d]), `8D 05` (lea r32,[rip+d]), and variations for other registers (ModR/M reg field 0-7 with rm=101)
       - For matches: compute `target_rva = instruction_rva + 7 + (displacement as i64) as u64` (assuming instr_len=7)
       - For each target, match against strings with `rva == Some(target)`: increment `reference_count`, push `instruction_rva` to `referencing_addresses`
       - After scanning, apply scoring: if `reference_count > 0` { `score += 20` }, if `> 3` { `+= 10` }; if `reference_count == 0` and section is `WritableData` (lookup by `section` name), `score -= 10`
    
    3. Helper functions:
       - `is_rip_relative_pattern(bytes: &[u8], offset: usize) -> bool`: Check for ModR/M 0x05 after opcode
       - `extract_displacement(bytes: &[u8], offset: usize) -> i32`: Read signed 32-bit LE
       - `compute_target(rva: u64, instr_len: u8, disp: i32) -> u64`: Sign-extend and add
    
    4. Documentation: Detail mechanics, patterns, limitations (false positives, x86-64 only, no prefixes handled), and integration.
    
    5. Unit tests:
       - `test_pattern_matching`: Verify detection for synthetic instructions (e.g., [0x48, 0x8B, 0x05, 0x00,0x00,0x00,0x00])
       - `test_target_calculation`: Check address computation with positive/negative disp
       - `test_scoring_integration`: Mock strings and refs, assert score changes
       - `test_no_code_section`: Ensure no crash if no code sections
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Extend existing ELF integration tests to validate reference analysis:
    
    - After parsing `ContainerInfo` and extracting strings (mock if needed), call `stringy::analysis::analyze_references(&mut strings, &data, &container)`
    - Assert at least one string has `reference_count > 0` and `referencing_addresses` non-empty (assuming fixture has RIP-relative refs, e.g., printf("hello"))
    - Verify scoring adjustments: check `score` increased for referenced strings
    - Add test case for binary without code section (e.g., stripped or data-only)
    
    Use existing fixture `tests/fixtures/test_binary_elf` or similar; document assumption that fixture uses PIC with RIP-relative addressing.
    
    ### docs/src/architecture.md(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Update architecture documentation to incorporate the analysis module:
    
    1. In 'High-Level Architecture' section, insert 'Reference Analysis' step in pipeline: Binary → Parsing → Extraction → **Reference Analysis** → Classification → Ranking → Output
    
    2. Add new subsection '### Analysis Module (src/analysis/)' after Output:
       - Purpose: Detect code references to strings via RIP-relative addressing (x86-64)
       - Components: `rip_relative.rs` for pattern scanning
       - Data flow: Updates `FoundString` in-place with counts and addresses
       - Scoring integration: Boosts for referenced strings
    
    3. Update 'Module Dependencies' to include:
       ```
       ├── analysis/
       │   ├── mod.rs
       │   └── rip_relative.rs (x86-64 RIP detection)
       ```
    
    4. In 'Future Enhancements', note optional Capstone for full disassembly and multi-arch support.
    
    ### docs/src/string-extraction.md(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Add a new section '### Reference Detection in Code' after 'Deduplication':
    
    - Explain RIP-relative addressing and its role in PIC
    - Describe detection: Pattern matching in .text for ModR/M=0x05, target calculation
    - Integration: `analyze_references` function called post-extraction
    - Output: New fields in JSON: `reference_count`, `referencing_addresses`
    - Scoring impact: +20 for referenced, +10 for highly used, -10 for dead writable strings
    - Limitations: x86-64 only, lightweight (no full disasm), potential false positives
    - Example: Show JSON snippet with referenced=true implied by count>0
    
    Update 'Supported Features' to include 'x86-64 RIP-relative reference tracking'.

    Developer Humor

    🕵️‍♂️ RIP-relative Riddle\n> \n> In the code where addresses are relative and sly,\n> Strings hide in data, but which ones apply?\n> With patterns we hunt, through .text we do prowl,\n> Finding mov and lea, making dead strings howl!\n> Now scores boost high for the truly referenced,\n> While buffers get docked—analysis manifested! 🎉\n> \n> Count: +20 for life, -10 for the undead.


    Execution Information

    Branch: main
    Commit: 08cd31b


    💡 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.
  2. unclesp1d3r commented on Nov 11, 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.

  3. changed the title [-]x86-64: RIP-relative addressing hints[/-] [+]Add x86-64 RIP-relative addressing analysis for string reference tracking[/+] on Nov 11, 2025
  4. coderabbitai commented on Nov 11, 2025

    @coderabbitai
    Contributor

    Tip

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

    🧩 Analysis chain

    🏁 Script executed:

    #!/bin/bash
    # Fetch issue #74 details
    gh issue view 74 --json title,body,labels,assignees,state,number
    

    Length of output: 113


    🏁 Script executed:

    #!/bin/bash
    # Check README to understand the project
    cat README.md
    
    # Look for any x86-64 or assembly-related files
    fd -e asm -e s -e S
    
    # Search for any existing RIP-relative or x86-64 references
    rg -i "rip.relative|x86.64|assembly" -C 2
    

    Length of output: 20679


    🏁 Script executed:

    #!/bin/bash
    # Look at the parser structure and extraction modules
    fd -e rs | head -20
    
    # Check for any existing instruction parsing or disassembly code
    rg -i "instruction|disassembly|capstone|reference" -t rust -C 1
    
    # Look at the binary-formats documentation for more context
    cat docs/src/binary-formats.md
    

    Length of output: 20678


    🌐 Web query:

    x86-64 RIP-relative addressing mode position-independent code
    

    💡 Result:

    Brief summary — x86-64 RIP-relative addressing and how it enables PIC

    • What it is: a 64-bit-mode addressing form that computes an effective address as RIP (the address of the next instruction) plus a signed 32-bit displacement (rel32). It is encoded as a displacement-only memory operand that is implicitly RIP-relative. [1][2]

    • Encoding/limits: displacement is 32 bits (signed), so targets must lie within roughly ±2GB of the instruction. RIP-relative is available for memory operands (e.g., lea/mov); control-flow instructions (call/jmp/rel-jcc) already use their own relative encodings. [1][2]

    • Why it helps PIC: data references encoded as RIP+disp do not contain absolute addresses, so the same code bytes are valid no matter where the module is loaded — the loader needs far fewer runtime relocations and the code can be position independent (or easier to make so). Compilers/assemblers emit syntax like movq symbol(%rip), %rax. [2][3]

    • Practical notes: you cannot use other registers with the RIP term (e.g., [RIP+RAX] is not supported); for references farther than ±2GB you still need GOT/PLT or runtime fixups. [1][3]

    Sources: Intel architecture description of RIP-relative addressing; tutorial/notes on x64 PIC and examples. [1][2][3]


    🏁 Script executed:

    #!/bin/bash
    # Check Cargo.toml for Capstone or disassembly dependencies
    cat Cargo.toml
    
    # Look for any existing instruction parsing code
    rg -i "capstone|instruction|disasm" -t rust
    
    # Check the types.rs to understand current string metadata
    cat src/types.rs | head -150
    

    Length of output: 7013


    🏁 Script executed:

    #!/bin/bash
    # Update the issue with enhanced content
    gh issue edit 74 \
      --title "Add x86-64 RIP-relative addressing analysis for string reference tracking" \
      --body "## Overview
    
    In x86-64 position-independent code (PIC), string literals and other data are typically referenced using **RIP-relative addressing** — an addressing mode that encodes memory references as offsets from the instruction pointer rather than absolute addresses. Detecting these references would allow Stringy to:
    
    1. **Boost scoring** for strings that are actively referenced by code
    2. **Filter dead strings** that exist in data sections but are never used
    3. **Improve accuracy** by distinguishing meaningful strings from padding or artifact data
    4. **Provide provenance** information about which code references which strings
    
    ## Background: RIP-relative Addressing
    
    RIP-relative addressing is the primary addressing mode for accessing data in x86-64 PIC:
    
    - **Format**: \`[RIP + disp32]\` where \`disp32\` is a signed 32-bit displacement
    - **Range**: Can reference data within ±2GB of the instruction
    - **Encoding**: Appears as displacement-only memory operands (e.g., \`movq symbol(%rip), %rax\`)
    - **Common instructions**: \`lea\`, \`mov\`, \`cmp\`, and other instructions with memory operands
    - **Benefits**: No runtime relocations needed, enables true position-independent code
    
    Example disassembly:
    \`\`\`asm
    lea    0x2000(%rip), %rdi    # Load address of string at RIP+0x2000
    mov    0x1ff0(%rip), %rax    # Load value from RIP+0x1ff0
    \`\`\`
    
    ## Proposed Solution
    
    ### Phase 1: Instruction Scanning (Lightweight)
    
    Add lightweight x86-64 instruction parsing to detect RIP-relative memory references without full disassembly:
    
    1. **Scan code sections** (SectionType::Code) for x86-64 instructions
    2. **Pattern match** common RIP-relative encodings:
       - ModR/M byte with mod=00, r/m=101 (RIP-relative displacement)
       - Common opcodes: \`8D\` (LEA), \`8B\` (MOV), \`48 8B\` (MOV r64), etc.
    3. **Extract displacement** and compute target address: \`instruction_addr + instruction_length + disp32\`
    4. **Map targets** to string offsets in data sections
    5. **Increment reference counts** for referenced strings
    
    ### Phase 2: Enhanced Scoring (Integration)
    
    Integrate reference tracking into the existing scoring system:
    
    \`\`\`rust
    pub struct ExtractedString {
        pub text: String,
        pub offset: u64,
        pub rva: Option<u64>,
        pub section: String,
        pub encoding: Encoding,
        pub length: usize,
        pub tags: Vec<Tag>,
        pub score: i32,
        pub source: StringSource,
        
        // NEW: Reference tracking
        pub reference_count: u32,         // Number of code references
        pub referencing_addresses: Vec<u64>, // RVAs of referencing instructions
    }
    \`\`\`
    
    Scoring adjustments:
    - **+20 points**: String has 1+ code references
    - **+10 points**: String has 3+ code references (highly used)
    - **-10 points**: String in writable section with 0 references (likely runtime buffer)
    
    ### Phase 3: Optional Full Disassembly (Future)
    
    For advanced use cases, integrate Capstone disassembler as optional feature:
    
    \`\`\`toml
    [dependencies]
    capstone = { version = \"0.12\", optional = true }
    
    [features]
    disassembly = [\"capstone\"]
    \`\`\`
    
    Benefits:
    - More accurate instruction parsing (handles edge cases, prefixes, etc.)
    - Support for other architectures (ARM64, RISC-V)
    - Detailed instruction analysis for forensics
    
    ## Implementation Checklist
    
    - [ ] Add x86-64 instruction pattern matching module
    - [ ] Implement RIP-relative displacement extraction
    - [ ] Add reference tracking fields to \`ExtractedString\`
    - [ ] Integrate reference counting into scoring algorithm
    - [ ] Add unit tests with fixture binaries containing RIP-relative references
    - [ ] Document architecture-specific features in user guide
    - [ ] (Optional) Add Capstone integration behind feature flag
    
    ## Related Context
    
    - Mentioned in \`docs/src/binary-formats.md\` under \"Architecture-Specific Enhancements\"
    - Complements existing section weight system (prioritizes likely string sections)
    - Similar to how resource extraction boosts PE string scores
    - Cross-references with import/export analysis (symbols are also code references)
    
    ## Example Use Cases
    
    1. **Malware Analysis**: Identify which strings are used by unpacking/decryption routines
    2. **YARA Rule Generation**: Focus on strings that are definitely code-referenced
    3. **Firmware Analysis**: Filter out unused strings in embedded binaries
    4. **Binary Diffing**: Track which code references changed between versions
    
    ## Technical Notes
    
    - **ELF PIC**: Nearly all data references use RIP-relative addressing
    - **PE x64**: Uses RIP-relative for PIC, but also absolute addresses in non-relocatable executables
    - **Mach-O x64**: Similar to ELF, heavy use of RIP-relative in position-independent code
    - **Static linking**: May contain more unused strings than dynamic executables
    - **Stripped binaries**: Reference tracking works even without symbol tables
    
    ## Alternatives Considered
    
    1. **Symbol-based**: Only track symbol references (not sufficient, misses many string literals)
    2. **Relocation analysis**: Parse relocation tables (misses PIC references, platform-specific)
    3. **Full control-flow analysis**: Too heavyweight for string extraction use case" \
      --add-label "enhancement" \
      --add-label "architecture:x86-64" \
      --add-label "priority:medium"
    
    # Assign to unclesp1d3r
    gh issue edit 74 --add-assignee unclesp1d3r
    
    # Display the updated issue
    gh issue view 74
    

    Length of output: 5449


    🏁 Script executed:

    #!/bin/bash
    # List existing labels in the repository
    gh label list --limit 100
    
    # Try adding labels that likely exist
    gh issue edit 74 --add-label "enhancement"
    
    # Create the architecture label if it doesn't exist
    gh label create "architecture:x86-64" --description "x86-64 architecture specific features" --color "0366d6" 2>/dev/null || true
    
    # Try adding it again
    gh issue edit 74 --add-label "architecture:x86-64"
    
    # Try adding priority label
    gh label create "priority:medium" --description "Medium priority" --color "fbca04" 2>/dev/null || true
    gh issue edit 74 --add-label "priority:medium"
    
    # View final result
    gh issue view 74 --json title,body,labels,assignees,url
    

    Length of output: 7647


    @unclesp1d3r, I've successfully enhanced issue #74 with comprehensive context and metadata. Here's what was updated:

    ✅ Enhancements Made

    Title (improved for clarity)

    • Before: x86-64: RIP-relative addressing hints
    • After: Add x86-64 RIP-relative addressing analysis for string reference tracking

    Body (added comprehensive content)

    The issue now includes:

    1. Overview - Clear explanation of the feature's value proposition
    2. Background - Technical details about RIP-relative addressing in x86-64 PIC
    3. Proposed Solution - Three-phase implementation plan:
      • Phase 1: Lightweight instruction scanning
      • Phase 2: Enhanced scoring integration
      • Phase 3: Optional Capstone disassembly support
    4. Implementation Checklist - Actionable tasks with checkboxes
    5. Related Context - Links to existing codebase features
    6. Example Use Cases - Malware analysis, YARA rules, firmware analysis, binary diffing
    7. Technical Notes - Platform-specific considerations (ELF, PE, Mach-O)
    8. Alternatives Considered - Other approaches and why they were rejected

    Labels (added 4 labels)

    • ✅ enhancement - Feature request classification
    • ✅ area:analyzer - Relates to binary analysis functionality
    • ✅ priority:medium - Appropriate priority level
    • ✅ architecture:x86-64 - New label created for architecture-specific features

    Assignee

    • ✅ Assigned to unclesp1d3r

    🔗 View the Enhanced Issue

    URL: #74

    The issue is now ready for implementation with clear technical guidance, a phased approach, and proper categorization. The RIP-relative addressing feature will significantly improve string scoring by identifying which strings are actively referenced by code, helping distinguish meaningful strings from dead data.

  5. traycerai commented on Nov 11, 2025

    @traycerai

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

    Previous Plan

    Observations

    The codebase has a well-structured architecture with complete container parsing (ELF, PE, Mach-O) and section classification. The FoundString type and pipeline are defined but string extraction is still in progress. The project uses goblin for binary parsing and has comprehensive section metadata including RVAs. No disassembly or reference analysis exists yet. This is the perfect time to add RIP-relative addressing detection as part of the v0.3 milestone.

    Approach

    Implement RIP-relative addressing detection for x86-64 ELF binaries using a lightweight pattern-matching approach (no Capstone dependency initially). Add a new analysis module to scan .text sections for common RIP-relative instruction patterns, resolve target addresses, and mark strings as referenced. Extend FoundString with a referenced field and integrate reference detection into the ranking system with a score boost.

    Reasoning

    I explored the project structure, examined the container parsers (especially ELF), reviewed the type definitions, checked the architecture documentation, and analyzed integration tests. I confirmed that section metadata includes RVAs, the pipeline is well-defined, and no reference analysis exists yet.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Add a referenced field to the FoundString struct to track whether a string is referenced by code via RIP-relative addressing or other mechanisms. This field should be a boolean, default to false, and be included in serialization for JSON output.

    The field should be added after the source field to maintain logical grouping of metadata. Update the struct documentation to explain that this field indicates whether the string has been identified as referenced by executable code.

    📁 src/analysis (NEW) 🔗

    Create a new analysis module directory to house code analysis functionality including reference detection. This module will be separate from extraction (which handles string extraction) and classification (which handles semantic tagging).

    The module will initially contain reference analysis but can be extended in the future for other analysis features like relocation hints, control flow analysis, etc.

    📄 src/analysis/mod.rs (NEW) 🔗

    Create the module entry point that re-exports the reference analysis functionality. This file should:

    1. Declare the references submodule
    2. Re-export key types and functions from references for easier access
    3. Include module-level documentation explaining that this module handles binary code analysis including reference detection, cross-reference analysis, and future features like relocation hints

    The module should be designed to be extensible for future analysis features beyond RIP-relative addressing.

    📄 src/analysis/references.rs (NEW) 🔗

    References

    Implement RIP-relative addressing detection for x86-64 binaries using pattern matching. This module should include:

    1. RipRelativeRef struct: Store detected references with fields for instruction_address (where the instruction is), target_address (computed target), and instruction_bytes (for debugging)

    2. find_rip_relative_references function: Main entry point that takes binary data, a .text section (from SectionInfo), and returns a Vec of target addresses. The function should:

      • Scan the .text section bytes for common RIP-relative patterns
      • For each pattern found, calculate the target address using: instruction_address + instruction_length + displacement
      • Handle both 32-bit and 64-bit instruction forms
      • Return only unique target addresses
    3. Pattern matching for common instructions:

      • 48 8B 05 [disp32] - mov rax, [rip+disp32] (REX.W prefix)
      • 48 8D 05 [disp32] - lea rax, [rip+disp32] (REX.W prefix)
      • 8B 05 [disp32] - mov eax, [rip+disp32]
      • 8D 05 [disp32] - lea eax, [rip+disp32]
      • Other common patterns with different registers (ModRM byte variations)
    4. Helper functions:

      • is_rip_relative_pattern: Check if bytes match a RIP-relative pattern
      • extract_displacement: Extract the 32-bit signed displacement from instruction bytes
      • calculate_target_address: Compute target = next_instruction_rva + sign_extend(displacement)
    5. Documentation: Include detailed comments explaining:

      • RIP-relative addressing mechanics
      • Pattern matching approach vs full disassembly
      • Limitations (may miss uncommon instruction forms)
      • Future enhancement path (Capstone integration)

    The implementation should be conservative and only match well-known patterns to avoid false positives. Use the section's RVA from SectionInfo to compute absolute addresses.
    Add a mark_referenced_strings function that integrates reference detection with string extraction. This function should:

    1. Take parameters:

      • strings: mutable slice of FoundString objects
      • binary_data: the full binary file bytes
      • container_info: the parsed container information from ContainerInfo
    2. Implementation logic:

      • Find the .text section from container_info.sections (filter by section_type == SectionType::Code and name == ".text")
      • If no .text section exists (stripped binary or non-standard), return early
      • Call find_rip_relative_references to get target addresses
      • For each string in the strings slice:
        • Check if the string's RVA (if present) matches any target address
        • If matched, set string.referenced = true
      • Return the count of strings marked as referenced for logging/debugging
    3. Handle edge cases:

      • Strings without RVA information (skip them)
      • Multiple references to the same string (already handled by boolean flag)
      • Target addresses that don't correspond to any string (ignore them)

    This function bridges the gap between low-level reference detection and high-level string metadata, making it easy to integrate into the extraction pipeline.
    Add comprehensive unit tests for the reference detection functionality:

    1. test_rip_relative_pattern_detection: Test pattern matching with synthetic instruction bytes:

      • Create byte arrays for known RIP-relative instructions
      • Verify that is_rip_relative_pattern correctly identifies them
      • Test negative cases (non-RIP-relative instructions)
    2. test_displacement_extraction: Test extracting 32-bit displacements:

      • Test positive displacements (0x00001234)
      • Test negative displacements (0xFFFFFFFF = -1)
      • Verify sign extension works correctly
    3. test_target_address_calculation: Test address computation:

      • Given instruction at RVA 0x1000, length 7, displacement 0x100
      • Verify target = 0x1000 + 7 + 0x100 = 0x1107
      • Test with negative displacements
    4. test_find_rip_relative_references_synthetic: Create a synthetic .text section with known RIP-relative instructions and verify that find_rip_relative_references returns the correct target addresses.

    5. test_mark_referenced_strings: Test the integration function with mock data:

      • Create mock FoundString objects with specific RVAs
      • Create mock ContainerInfo with a .text section
      • Verify that strings with matching RVAs are marked as referenced

    These tests ensure correctness without requiring real binary files and make it easy to verify edge cases.

    📄 src/lib.rs (MODIFY) 🔗

    Add the new analysis module to the library's public API by declaring it alongside the existing modules (container, extraction, classification, output). The module should be declared as pub mod analysis; to make it accessible to library users.

    Update the module-level documentation to mention that the library now includes code analysis capabilities for detecting string references in executable code.

    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Add a new integration test test_elf_rip_relative_detection that validates RIP-relative reference detection. The test should:

    1. Load the existing test_binary_elf fixture
    2. Parse it with ElfParser to get ContainerInfo
    3. Create mock FoundString objects for known strings in .rodata (e.g., "Hello, world!\n" from the printf call)
    4. Call mark_referenced_strings from the analysis::references module
    5. Assert that at least one string is marked as referenced = true
    6. Verify that the string "Hello, world!\n" is marked as referenced (since it's used by printf)

    The test demonstrates end-to-end functionality and validates that the reference detection works with real compiled binaries. Include comments explaining that the test relies on the fixture being compiled with standard optimization levels that produce RIP-relative addressing.

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

    References

    Add a new section titled "## Reference Detection" after the "Deduplication Strategy" section. The new section should document:

    1. Overview: Explain that Stringy can detect which strings are actually referenced by executable code, improving relevance scoring

    2. RIP-Relative Addressing (x86-64): Describe how RIP-relative addressing works and why it's important for position-independent code

    3. Detection Method: Explain the pattern-matching approach:

      • Scans .text section for common RIP-relative instruction patterns
      • Computes target addresses using the formula: next_instruction_address + displacement
      • Matches targets against string RVAs
      • Marks strings as referenced = true
    4. Supported Patterns: List the instruction patterns detected (mov, lea with various registers)

    5. Limitations: Document that:

      • Only detects direct RIP-relative references
      • May miss indirect references (pointers to strings)
      • Currently x86-64 only (ARM64, other architectures planned)
      • Pattern matching may miss uncommon instruction forms
    6. Future Enhancements: Mention planned improvements:

      • Full disassembly with Capstone for complete coverage
      • Relocation table analysis for additional hints
      • Support for other architectures

    Include a code example showing how to check if a string is referenced in the output.

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

    References

    Update the architecture documentation to include the new analysis module:

    1. In the "High-Level Architecture" section, update the pipeline diagram to:

      Binary File → Format Detection → Container Parsing → String Extraction → Reference Analysis → Classification → Ranking → Output
      
    2. Add a new subsection "### 6. Analysis Module (src/analysis/) ✅ Implemented" after the Output Module section:

      • Describe the module's purpose: detecting code references to strings
      • Explain RIP-relative addressing detection for x86-64
      • Document the pattern-matching approach
      • Note that this enhances ranking by identifying actually-used strings
    3. Update the "Module Dependencies" diagram to include:

      ├── analysis/
      │   ├── mod.rs (analysis framework)
      │   └── references.rs (RIP-relative detection)
      
    4. In the "Data Flow" section, add a new subsection "### 2.5. Reference Analysis Phase ✅ Implemented" between extraction and classification:

      • Show code example of calling mark_referenced_strings
      • Explain how it integrates with the pipeline
      • Note that it modifies FoundString objects in-place

    This keeps the architecture documentation in sync with the new functionality.

    📄 .kiro/specs/stringy-binary-analyzer/tasks.md (MODIFY) 🔗

    Add a new task entry after task 15 (test infrastructure) to document the RIP-relative addressing implementation:

    - [x] 16. Implement x86-64 RIP-relative addressing detection
    
      - Create src/analysis/ module for code analysis functionality
      - Implement pattern-matching based RIP-relative reference detection
      - Add mark_referenced_strings function to integrate with string extraction
      - Extend FoundString type with referenced field
      - Add comprehensive unit tests for pattern detection and address calculation
      - Add integration test with real ELF binary fixture
      - Update documentation (architecture.md, string-extraction.md)
      - _Requirements: 5.4 (reference boost scoring), v0.3 milestone_
      - _Completed: Issue #74_
    
      **Implementation Notes:**
      - Uses lightweight pattern matching (no Capstone dependency)
      - Detects common RIP-relative patterns: mov/lea with various registers
      - Computes target addresses: next_instruction_rva + displacement
      - Marks strings as referenced when RVA matches target
      - Foundation for future enhancements (Capstone, other architectures)

    Renumber the existing task 16 (main extraction pipeline) to task 17 to maintain sequential numbering.

    Diagram

    sequenceDiagram
        participant Binary as Binary File
        participant Parser as ELF Parser
        participant RefAnalyzer as Reference Analyzer
        participant Strings as String List
        participant Output as Output Module
        
        Binary->>Parser: Parse binary
        Parser->>Parser: Extract sections (.text, .rodata)
        Parser->>Parser: Get section RVAs and offsets
        Parser-->>Strings: Return ContainerInfo
        
        Note over Strings: String extraction happens<br/>(future implementation)
        
        Strings->>RefAnalyzer: mark_referenced_strings(strings, data, container_info)
        RefAnalyzer->>RefAnalyzer: Find .text section
        RefAnalyzer->>RefAnalyzer: Scan for RIP-relative patterns
        
        loop For each pattern found
            RefAnalyzer->>RefAnalyzer: Extract displacement
            RefAnalyzer->>RefAnalyzer: Calculate target = next_insn_rva + disp
            RefAnalyzer->>RefAnalyzer: Store target address
        end
        
        loop For each string
            RefAnalyzer->>RefAnalyzer: Check if string.rva matches target
            alt RVA matches
                RefAnalyzer->>Strings: Set string.referenced = true
            end
        end
        
        RefAnalyzer-->>Strings: Return count of referenced strings
        
        Note over Strings: Ranking applies +10 boost<br/>for referenced strings
        
        Strings->>Output: Format output (JSON/Human)
        Output-->>Binary: Display with referenced flag
    
    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 has a well-structured architecture with complete container parsing (ELF, PE, Mach-O) and section classification. The `FoundString` type and pipeline are defined but string extraction is still in progress. The project uses `goblin` for binary parsing and has comprehensive section metadata including RVAs. No disassembly or reference analysis exists yet. This is the perfect time to add RIP-relative addressing detection as part of the v0.3 milestone.
    
    ### Approach
    
    Implement RIP-relative addressing detection for x86-64 ELF binaries using a lightweight pattern-matching approach (no Capstone dependency initially). Add a new `analysis` module to scan `.text` sections for common RIP-relative instruction patterns, resolve target addresses, and mark strings as referenced. Extend `FoundString` with a `referenced` field and integrate reference detection into the ranking system with a score boost.
    
    ### Reasoning
    
    I explored the project structure, examined the container parsers (especially ELF), reviewed the type definitions, checked the architecture documentation, and analyzed integration tests. I confirmed that section metadata includes RVAs, the pipeline is well-defined, and no reference analysis exists yet.
    
    ## Mermaid Diagram
    
    sequenceDiagram
        participant Binary as Binary File
        participant Parser as ELF Parser
        participant RefAnalyzer as Reference Analyzer
        participant Strings as String List
        participant Output as Output Module
        
        Binary->>Parser: Parse binary
        Parser->>Parser: Extract sections (.text, .rodata)
        Parser->>Parser: Get section RVAs and offsets
        Parser-->>Strings: Return ContainerInfo
        
        Note over Strings: String extraction happens<br/>(future implementation)
        
        Strings->>RefAnalyzer: mark_referenced_strings(strings, data, container_info)
        RefAnalyzer->>RefAnalyzer: Find .text section
        RefAnalyzer->>RefAnalyzer: Scan for RIP-relative patterns
        
        loop For each pattern found
            RefAnalyzer->>RefAnalyzer: Extract displacement
            RefAnalyzer->>RefAnalyzer: Calculate target = next_insn_rva + disp
            RefAnalyzer->>RefAnalyzer: Store target address
        end
        
        loop For each string
            RefAnalyzer->>RefAnalyzer: Check if string.rva matches target
            alt RVA matches
                RefAnalyzer->>Strings: Set string.referenced = true
            end
        end
        
        RefAnalyzer-->>Strings: Return count of referenced strings
        
        Note over Strings: Ranking applies +10 boost<br/>for referenced strings
        
        Strings->>Output: Format output (JSON/Human)
        Output-->>Binary: Display with referenced flag
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Add a `referenced` field to the `FoundString` struct to track whether a string is referenced by code via RIP-relative addressing or other mechanisms. This field should be a boolean, default to `false`, and be included in serialization for JSON output.
    
    The field should be added after the `source` field to maintain logical grouping of metadata. Update the struct documentation to explain that this field indicates whether the string has been identified as referenced by executable code.
    
    ### src/analysis(NEW)
    
    Create a new `analysis` module directory to house code analysis functionality including reference detection. This module will be separate from `extraction` (which handles string extraction) and `classification` (which handles semantic tagging).
    
    The module will initially contain reference analysis but can be extended in the future for other analysis features like relocation hints, control flow analysis, etc.
    
    ### src/analysis/mod.rs(NEW)
    
    Create the module entry point that re-exports the reference analysis functionality. This file should:
    
    1. Declare the `references` submodule
    2. Re-export key types and functions from `references` for easier access
    3. Include module-level documentation explaining that this module handles binary code analysis including reference detection, cross-reference analysis, and future features like relocation hints
    
    The module should be designed to be extensible for future analysis features beyond RIP-relative addressing.
    
    ### src/analysis/references.rs(NEW)
    
    References: 
    
    - src/types.rs(MODIFY)
    - src/container/elf.rs
    
    Implement RIP-relative addressing detection for x86-64 binaries using pattern matching. This module should include:
    
    1. **RipRelativeRef struct**: Store detected references with fields for `instruction_address` (where the instruction is), `target_address` (computed target), and `instruction_bytes` (for debugging)
    
    2. **find_rip_relative_references function**: Main entry point that takes binary data, a `.text` section (from `SectionInfo`), and returns a Vec of target addresses. The function should:
       - Scan the `.text` section bytes for common RIP-relative patterns
       - For each pattern found, calculate the target address using: `instruction_address + instruction_length + displacement`
       - Handle both 32-bit and 64-bit instruction forms
       - Return only unique target addresses
    
    3. **Pattern matching for common instructions**:
       - `48 8B 05 [disp32]` - mov rax, [rip+disp32] (REX.W prefix)
       - `48 8D 05 [disp32]` - lea rax, [rip+disp32] (REX.W prefix)
       - `8B 05 [disp32]` - mov eax, [rip+disp32]
       - `8D 05 [disp32]` - lea eax, [rip+disp32]
       - Other common patterns with different registers (ModRM byte variations)
    
    4. **Helper functions**:
       - `is_rip_relative_pattern`: Check if bytes match a RIP-relative pattern
       - `extract_displacement`: Extract the 32-bit signed displacement from instruction bytes
       - `calculate_target_address`: Compute target = next_instruction_rva + sign_extend(displacement)
    
    5. **Documentation**: Include detailed comments explaining:
       - RIP-relative addressing mechanics
       - Pattern matching approach vs full disassembly
       - Limitations (may miss uncommon instruction forms)
       - Future enhancement path (Capstone integration)
    
    The implementation should be conservative and only match well-known patterns to avoid false positives. Use the section's RVA from `SectionInfo` to compute absolute addresses.
    Add a `mark_referenced_strings` function that integrates reference detection with string extraction. This function should:
    
    1. Take parameters:
       - `strings`: mutable slice of `FoundString` objects
       - `binary_data`: the full binary file bytes
       - `container_info`: the parsed container information from `ContainerInfo`
    
    2. Implementation logic:
       - Find the `.text` section from `container_info.sections` (filter by `section_type == SectionType::Code` and `name == ".text"`)
       - If no `.text` section exists (stripped binary or non-standard), return early
       - Call `find_rip_relative_references` to get target addresses
       - For each string in the `strings` slice:
         - Check if the string's RVA (if present) matches any target address
         - If matched, set `string.referenced = true`
       - Return the count of strings marked as referenced for logging/debugging
    
    3. Handle edge cases:
       - Strings without RVA information (skip them)
       - Multiple references to the same string (already handled by boolean flag)
       - Target addresses that don't correspond to any string (ignore them)
    
    This function bridges the gap between low-level reference detection and high-level string metadata, making it easy to integrate into the extraction pipeline.
    Add comprehensive unit tests for the reference detection functionality:
    
    1. **test_rip_relative_pattern_detection**: Test pattern matching with synthetic instruction bytes:
       - Create byte arrays for known RIP-relative instructions
       - Verify that `is_rip_relative_pattern` correctly identifies them
       - Test negative cases (non-RIP-relative instructions)
    
    2. **test_displacement_extraction**: Test extracting 32-bit displacements:
       - Test positive displacements (0x00001234)
       - Test negative displacements (0xFFFFFFFF = -1)
       - Verify sign extension works correctly
    
    3. **test_target_address_calculation**: Test address computation:
       - Given instruction at RVA 0x1000, length 7, displacement 0x100
       - Verify target = 0x1000 + 7 + 0x100 = 0x1107
       - Test with negative displacements
    
    4. **test_find_rip_relative_references_synthetic**: Create a synthetic `.text` section with known RIP-relative instructions and verify that `find_rip_relative_references` returns the correct target addresses.
    
    5. **test_mark_referenced_strings**: Test the integration function with mock data:
       - Create mock `FoundString` objects with specific RVAs
       - Create mock `ContainerInfo` with a `.text` section
       - Verify that strings with matching RVAs are marked as referenced
    
    These tests ensure correctness without requiring real binary files and make it easy to verify edge cases.
    
    ### src/lib.rs(MODIFY)
    
    Add the new `analysis` module to the library's public API by declaring it alongside the existing modules (`container`, `extraction`, `classification`, `output`). The module should be declared as `pub mod analysis;` to make it accessible to library users.
    
    Update the module-level documentation to mention that the library now includes code analysis capabilities for detecting string references in executable code.
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/analysis/references.rs(NEW)
    - tests/fixtures/test_binary.c
    
    Add a new integration test `test_elf_rip_relative_detection` that validates RIP-relative reference detection. The test should:
    
    1. Load the existing `test_binary_elf` fixture
    2. Parse it with `ElfParser` to get `ContainerInfo`
    3. Create mock `FoundString` objects for known strings in `.rodata` (e.g., "Hello, world!\n" from the printf call)
    4. Call `mark_referenced_strings` from the `analysis::references` module
    5. Assert that at least one string is marked as `referenced = true`
    6. Verify that the string "Hello, world!\n" is marked as referenced (since it's used by printf)
    
    The test demonstrates end-to-end functionality and validates that the reference detection works with real compiled binaries. Include comments explaining that the test relies on the fixture being compiled with standard optimization levels that produce RIP-relative addressing.
    
    ### docs/src/string-extraction.md(MODIFY)
    
    References: 
    
    - src/analysis/references.rs(NEW)
    
    Add a new section titled "## Reference Detection" after the "Deduplication Strategy" section. The new section should document:
    
    1. **Overview**: Explain that Stringy can detect which strings are actually referenced by executable code, improving relevance scoring
    
    2. **RIP-Relative Addressing (x86-64)**: Describe how RIP-relative addressing works and why it's important for position-independent code
    
    3. **Detection Method**: Explain the pattern-matching approach:
       - Scans `.text` section for common RIP-relative instruction patterns
       - Computes target addresses using the formula: `next_instruction_address + displacement`
       - Matches targets against string RVAs
       - Marks strings as `referenced = true`
    
    4. **Supported Patterns**: List the instruction patterns detected (mov, lea with various registers)
    
    5. **Limitations**: Document that:
       - Only detects direct RIP-relative references
       - May miss indirect references (pointers to strings)
       - Currently x86-64 only (ARM64, other architectures planned)
       - Pattern matching may miss uncommon instruction forms
    
    6. **Future Enhancements**: Mention planned improvements:
       - Full disassembly with Capstone for complete coverage
       - Relocation table analysis for additional hints
       - Support for other architectures
    
    Include a code example showing how to check if a string is referenced in the output.
    
    ### docs/src/architecture.md(MODIFY)
    
    References: 
    
    - src/analysis/references.rs(NEW)
    
    Update the architecture documentation to include the new `analysis` module:
    
    1. In the "High-Level Architecture" section, update the pipeline diagram to:
       ```
       Binary File → Format Detection → Container Parsing → String Extraction → Reference Analysis → Classification → Ranking → Output
       ```
    
    2. Add a new subsection "### 6. Analysis Module (`src/analysis/`) ✅ **Implemented**" after the Output Module section:
       - Describe the module's purpose: detecting code references to strings
       - Explain RIP-relative addressing detection for x86-64
       - Document the pattern-matching approach
       - Note that this enhances ranking by identifying actually-used strings
    
    3. Update the "Module Dependencies" diagram to include:
       ```
       ├── analysis/
       │   ├── mod.rs (analysis framework)
       │   └── references.rs (RIP-relative detection)
       ```
    
    4. In the "Data Flow" section, add a new subsection "### 2.5. Reference Analysis Phase ✅ **Implemented**" between extraction and classification:
       - Show code example of calling `mark_referenced_strings`
       - Explain how it integrates with the pipeline
       - Note that it modifies `FoundString` objects in-place
    
    This keeps the architecture documentation in sync with the new functionality.
    
    ### .kiro/specs/stringy-binary-analyzer/tasks.md(MODIFY)
    
    Add a new task entry after task 15 (test infrastructure) to document the RIP-relative addressing implementation:
    
    ```markdown
    - [x] 16. Implement x86-64 RIP-relative addressing detection
    
      - Create src/analysis/ module for code analysis functionality
      - Implement pattern-matching based RIP-relative reference detection
      - Add mark_referenced_strings function to integrate with string extraction
      - Extend FoundString type with referenced field
      - Add comprehensive unit tests for pattern detection and address calculation
      - Add integration test with real ELF binary fixture
      - Update documentation (architecture.md, string-extraction.md)
      - _Requirements: 5.4 (reference boost scoring), v0.3 milestone_
      - _Completed: Issue #74_
    
      **Implementation Notes:**
      - Uses lightweight pattern matching (no Capstone dependency)
      - Detects common RIP-relative patterns: mov/lea with various registers
      - Computes target addresses: next_instruction_rva + displacement
      - Marks strings as referenced when RVA matches target
      - Foundation for future enhancements (Capstone, other architectures)
    ```
    
    Renumber the existing task 16 (main extraction pipeline) to task 17 to maintain sequential numbering.

    Developer Humor

    🔍 The RIP-relative Detective\n>\n> In the land of x86-64, where code is PIC,\n> Lived strings in .rodata, some useful, some ick.\n> \Which strings are real?\ the analyst cried,\n> \Let's follow the RIP!\ the detective replied.\n>\n> With patterns and offsets, through .text we did scan,\n> Found mov and lea, part of the plan.\n> \This string's referenced!\ we mark with great pride,\n> Now signal beats noise, with RIP as our guide! 🎯


    Execution Information

    Branch: main
    Commit: 08cd31b

    New Plan

    Observations

    The codebase features a modular Rust library with defined types for binary analysis, including FoundString (lacking reference fields), ContainerInfo with section metadata (offsets, sizes, RVAs, types), and parsers for ELF, PE, Mach-O using goblin/pelite. Extraction is partially implemented (PE resources), classification and ranking modules exist but are stubs. No analysis module present. Section classification includes SectionType::Code for .text sections. This setup is ideal for adding lightweight x86-64 RIP-relative reference detection to enhance string scoring without full disassembly.

    Approach

    Introduce an analysis module for code reference detection, focusing on x86-64 RIP-relative addressing via pattern matching in code sections. Extend FoundString with reference_count and referencing_addresses fields. Implement scanning logic to compute target addresses from instruction patterns, match against string RVAs, and update counts/addresses. Integrate scoring boosts: +20 for referenced strings, +10 for highly referenced (>3), -10 for unreferenced writable data strings. Add unit tests for pattern detection and integration tests using ELF fixtures. Document in architecture and extraction guides, with optional Capstone future support.

    Reasoning

    I listed the project directories to map the structure, read src/types.rs to review FoundString and section types, examined src/container/mod.rs for parsing API, checked src/extraction/mod.rs for current extraction state, and confirmed documentation and test presence in docs/src/ and tests/ to ensure integration points.

    Proposed File Changes

    📄 src/types.rs (MODIFY) 🔗

    Extend the FoundString struct with two new fields for reference tracking:

    • reference_count: u32 - Number of code references to this string (default 0)
    • referencing_addresses: Vec<u64> - RVAs of instructions referencing this string

    Add these fields after the source field for logical grouping with metadata. Update the struct documentation to explain their purpose in identifying actively used strings. Ensure the fields are included in Serialize and Deserialize via the existing derives. No changes to enums or other structs needed.

    📄 src/lib.rs (MODIFY) 🔗

    References

    Declare the new pub mod analysis; after existing modules (container, extraction, classification, output) to expose the analysis functionality in the public API. Update the module-level documentation to note the addition of code analysis capabilities, specifically RIP-relative reference detection for x86-64 binaries, which enhances string relevance scoring.

    📄 src/analysis/mod.rs (NEW) 🔗

    References

    Create the module entry point for the analysis crate. Include:

    • pub mod rip_relative; to declare the submodule
    • Re-export key items: pub use rip_relative::{analyze_references, RipRelativeRef};
    • Module documentation explaining the purpose: static code analysis for detecting references to strings, starting with x86-64 RIP-relative addressing in position-independent code. Mention extensibility for other analyses (e.g., relocations, control flow) and architectures.

    Keep it minimal as the primary logic resides in the submodule.

    📄 src/analysis/rip_relative.rs (NEW) 🔗

    References

    Implement x86-64 RIP-relative reference detection using lightweight pattern matching:

    1. Define RipRelativeRef struct: fields instruction_rva: u64, target_rva: u64, instruction_bytes: Vec<u8>, displacement: i32 for storing detected references.

    2. Implement analyze_references function: takes &mut [FoundString], &[u8] (binary data), &ContainerInfo. Logic:

      • Identify code sections (SectionType::Code)
      • For each code section, extract bytes using offset and size
      • Scan bytes for RIP-relative patterns (7-byte instructions: optional REX, opcode, ModR/M=0x05, disp32)
      • Common patterns: 48 8B 05 (mov r64,[rip+d]), 48 8D 05 (lea r64,[rip+d]), 8B 05 (mov r32,[rip+d]), 8D 05 (lea r32,[rip+d]), and variations for other registers (ModR/M reg field 0-7 with rm=101)
      • For matches: compute target_rva = instruction_rva + 7 + (displacement as i64) as u64 (assuming instr_len=7)
      • For each target, match against strings with rva == Some(target): increment reference_count, push instruction_rva to referencing_addresses
      • After scanning, apply scoring: if reference_count > 0 { score += 20 }, if > 3 { += 10 }; if reference_count == 0 and section is WritableData (lookup by section name), score -= 10
    3. Helper functions:

      • is_rip_relative_pattern(bytes: &[u8], offset: usize) -> bool: Check for ModR/M 0x05 after opcode
      • extract_displacement(bytes: &[u8], offset: usize) -> i32: Read signed 32-bit LE
      • compute_target(rva: u64, instr_len: u8, disp: i32) -> u64: Sign-extend and add
    4. Documentation: Detail mechanics, patterns, limitations (false positives, x86-64 only, no prefixes handled), and integration.

    5. Unit tests:

      • test_pattern_matching: Verify detection for synthetic instructions (e.g., [0x48, 0x8B, 0x05, 0x00,0x00,0x00,0x00])
      • test_target_calculation: Check address computation with positive/negative disp
      • test_scoring_integration: Mock strings and refs, assert score changes
      • test_no_code_section: Ensure no crash if no code sections
    📄 tests/integration_elf.rs (MODIFY) 🔗

    References

    Extend existing ELF integration tests to validate reference analysis:

    • After parsing ContainerInfo and extracting strings (mock if needed), call stringy::analysis::analyze_references(&mut strings, &data, &container)
    • Assert at least one string has reference_count > 0 and referencing_addresses non-empty (assuming fixture has RIP-relative refs, e.g., printf("hello"))
    • Verify scoring adjustments: check score increased for referenced strings
    • Add test case for binary without code section (e.g., stripped or data-only)

    Use existing fixture tests/fixtures/test_binary_elf or similar; document assumption that fixture uses PIC with RIP-relative addressing.

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

    References

    Update architecture documentation to incorporate the analysis module:

    1. In 'High-Level Architecture' section, insert 'Reference Analysis' step in pipeline: Binary → Parsing → Extraction → Reference Analysis → Classification → Ranking → Output

    2. Add new subsection '### Analysis Module (src/analysis/)' after Output:

      • Purpose: Detect code references to strings via RIP-relative addressing (x86-64)
      • Components: rip_relative.rs for pattern scanning
      • Data flow: Updates FoundString in-place with counts and addresses
      • Scoring integration: Boosts for referenced strings
    3. Update 'Module Dependencies' to include:

      ├── analysis/
      │   ├── mod.rs
      │   └── rip_relative.rs (x86-64 RIP detection)
      
    4. In 'Future Enhancements', note optional Capstone for full disassembly and multi-arch support.

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

    References

    Add a new section '### Reference Detection in Code' after 'Deduplication':

    • Explain RIP-relative addressing and its role in PIC
    • Describe detection: Pattern matching in .text for ModR/M=0x05, target calculation
    • Integration: analyze_references function called post-extraction
    • Output: New fields in JSON: reference_count, referencing_addresses
    • Scoring impact: +20 for referenced, +10 for highly used, -10 for dead writable strings
    • Limitations: x86-64 only, lightweight (no full disasm), potential false positives
    • Example: Show JSON snippet with referenced=true implied by count>0

    Update 'Supported Features' to include 'x86-64 RIP-relative reference tracking'.

    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 features a modular Rust library with defined types for binary analysis, including `FoundString` (lacking reference fields), `ContainerInfo` with section metadata (offsets, sizes, RVAs, types), and parsers for ELF, PE, Mach-O using goblin/pelite. Extraction is partially implemented (PE resources), classification and ranking modules exist but are stubs. No analysis module present. Section classification includes `SectionType::Code` for .text sections. This setup is ideal for adding lightweight x86-64 RIP-relative reference detection to enhance string scoring without full disassembly.
    
    ### Approach
    
    Introduce an `analysis` module for code reference detection, focusing on x86-64 RIP-relative addressing via pattern matching in code sections. Extend `FoundString` with `reference_count` and `referencing_addresses` fields. Implement scanning logic to compute target addresses from instruction patterns, match against string RVAs, and update counts/addresses. Integrate scoring boosts: +20 for referenced strings, +10 for highly referenced (>3), -10 for unreferenced writable data strings. Add unit tests for pattern detection and integration tests using ELF fixtures. Document in architecture and extraction guides, with optional Capstone future support.
    
    ### Reasoning
    
    I listed the project directories to map the structure, read `src/types.rs` to review `FoundString` and section types, examined `src/container/mod.rs` for parsing API, checked `src/extraction/mod.rs` for current extraction state, and confirmed documentation and test presence in `docs/src/` and `tests/` to ensure integration points.
    
    ## Proposed File Changes
    
    ### src/types.rs(MODIFY)
    
    Extend the `FoundString` struct with two new fields for reference tracking:
    
    - `reference_count: u32` - Number of code references to this string (default 0)
    - `referencing_addresses: Vec<u64>` - RVAs of instructions referencing this string
    
    Add these fields after the `source` field for logical grouping with metadata. Update the struct documentation to explain their purpose in identifying actively used strings. Ensure the fields are included in `Serialize` and `Deserialize` via the existing derives. No changes to enums or other structs needed.
    
    ### src/lib.rs(MODIFY)
    
    References: 
    
    - src/analysis/mod.rs(NEW)
    
    Declare the new `pub mod analysis;` after existing modules (`container`, `extraction`, `classification`, `output`) to expose the analysis functionality in the public API. Update the module-level documentation to note the addition of code analysis capabilities, specifically RIP-relative reference detection for x86-64 binaries, which enhances string relevance scoring.
    
    ### src/analysis/mod.rs(NEW)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Create the module entry point for the analysis crate. Include:
    
    - `pub mod rip_relative;` to declare the submodule
    - Re-export key items: `pub use rip_relative::{analyze_references, RipRelativeRef};`
    - Module documentation explaining the purpose: static code analysis for detecting references to strings, starting with x86-64 RIP-relative addressing in position-independent code. Mention extensibility for other analyses (e.g., relocations, control flow) and architectures.
    
    Keep it minimal as the primary logic resides in the submodule.
    
    ### src/analysis/rip_relative.rs(NEW)
    
    References: 
    
    - src/types.rs(MODIFY)
    - src/container/mod.rs
    
    Implement x86-64 RIP-relative reference detection using lightweight pattern matching:
    
    1. Define `RipRelativeRef` struct: fields `instruction_rva: u64`, `target_rva: u64`, `instruction_bytes: Vec<u8>`, `displacement: i32` for storing detected references.
    
    2. Implement `analyze_references` function: takes `&mut [FoundString]`, `&[u8]` (binary data), `&ContainerInfo`. Logic:
       - Identify code sections (`SectionType::Code`)
       - For each code section, extract bytes using `offset` and `size`
       - Scan bytes for RIP-relative patterns (7-byte instructions: optional REX, opcode, ModR/M=0x05, disp32)
       - Common patterns: `48 8B 05` (mov r64,[rip+d]), `48 8D 05` (lea r64,[rip+d]), `8B 05` (mov r32,[rip+d]), `8D 05` (lea r32,[rip+d]), and variations for other registers (ModR/M reg field 0-7 with rm=101)
       - For matches: compute `target_rva = instruction_rva + 7 + (displacement as i64) as u64` (assuming instr_len=7)
       - For each target, match against strings with `rva == Some(target)`: increment `reference_count`, push `instruction_rva` to `referencing_addresses`
       - After scanning, apply scoring: if `reference_count > 0` { `score += 20` }, if `> 3` { `+= 10` }; if `reference_count == 0` and section is `WritableData` (lookup by `section` name), `score -= 10`
    
    3. Helper functions:
       - `is_rip_relative_pattern(bytes: &[u8], offset: usize) -> bool`: Check for ModR/M 0x05 after opcode
       - `extract_displacement(bytes: &[u8], offset: usize) -> i32`: Read signed 32-bit LE
       - `compute_target(rva: u64, instr_len: u8, disp: i32) -> u64`: Sign-extend and add
    
    4. Documentation: Detail mechanics, patterns, limitations (false positives, x86-64 only, no prefixes handled), and integration.
    
    5. Unit tests:
       - `test_pattern_matching`: Verify detection for synthetic instructions (e.g., [0x48, 0x8B, 0x05, 0x00,0x00,0x00,0x00])
       - `test_target_calculation`: Check address computation with positive/negative disp
       - `test_scoring_integration`: Mock strings and refs, assert score changes
       - `test_no_code_section`: Ensure no crash if no code sections
    
    ### tests/integration_elf.rs(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Extend existing ELF integration tests to validate reference analysis:
    
    - After parsing `ContainerInfo` and extracting strings (mock if needed), call `stringy::analysis::analyze_references(&mut strings, &data, &container)`
    - Assert at least one string has `reference_count > 0` and `referencing_addresses` non-empty (assuming fixture has RIP-relative refs, e.g., printf("hello"))
    - Verify scoring adjustments: check `score` increased for referenced strings
    - Add test case for binary without code section (e.g., stripped or data-only)
    
    Use existing fixture `tests/fixtures/test_binary_elf` or similar; document assumption that fixture uses PIC with RIP-relative addressing.
    
    ### docs/src/architecture.md(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Update architecture documentation to incorporate the analysis module:
    
    1. In 'High-Level Architecture' section, insert 'Reference Analysis' step in pipeline: Binary → Parsing → Extraction → **Reference Analysis** → Classification → Ranking → Output
    
    2. Add new subsection '### Analysis Module (src/analysis/)' after Output:
       - Purpose: Detect code references to strings via RIP-relative addressing (x86-64)
       - Components: `rip_relative.rs` for pattern scanning
       - Data flow: Updates `FoundString` in-place with counts and addresses
       - Scoring integration: Boosts for referenced strings
    
    3. Update 'Module Dependencies' to include:
       ```
       ├── analysis/
       │   ├── mod.rs
       │   └── rip_relative.rs (x86-64 RIP detection)
       ```
    
    4. In 'Future Enhancements', note optional Capstone for full disassembly and multi-arch support.
    
    ### docs/src/string-extraction.md(MODIFY)
    
    References: 
    
    - src/analysis/rip_relative.rs(NEW)
    
    Add a new section '### Reference Detection in Code' after 'Deduplication':
    
    - Explain RIP-relative addressing and its role in PIC
    - Describe detection: Pattern matching in .text for ModR/M=0x05, target calculation
    - Integration: `analyze_references` function called post-extraction
    - Output: New fields in JSON: `reference_count`, `referencing_addresses`
    - Scoring impact: +20 for referenced, +10 for highly used, -10 for dead writable strings
    - Limitations: x86-64 only, lightweight (no full disasm), potential false positives
    - Example: Show JSON snippet with referenced=true implied by count>0
    
    Update 'Supported Features' to include 'x86-64 RIP-relative reference tracking'.

    Developer Humor

    🕵️‍♂️ RIP-relative Riddle\n> \n> In the code where addresses are relative and sly,\n> Strings hide in data, but which ones apply?\n> With patterns we hunt, through .text we do prowl,\n> Finding mov and lea, making dead strings howl!\n> Now scores boost high for the truly referenced,\n> While buffers get docked—analysis manifested! 🎉\n> \n> Count: +20 for life, -10 for the undead.


    Execution Information

    Branch: main
    Commit: 08cd31b

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

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions