Documentation
¶
Overview ¶
Package resurgo identifies functions in executable binaries through static analysis using instruction-level disassembly. It provides two complementary approaches:
Prologue Detection ¶
Detects function entry points by recognizing common prologue patterns including classic frame pointer setup (push rbp; mov rbp, rsp), no-frame-pointer functions (sub rsp, imm), push-only prologues, and LEA-based stack allocation.
Use DetectPrologues to analyze raw bytes directly, or DetectProloguesFromELF to extract and analyze the .text section of an ELF binary.
Call Site Analysis ¶
Identifies functions by detecting CALL and JMP instructions and extracting their target addresses. This approach works on heavily optimized code where prologues may be omitted and is compiler-agnostic. It provides confidence scoring based on instruction type (call vs jump) and addressing mode (direct vs indirect).
Use DetectCallSites to analyze raw bytes, or DetectCallSitesFromELF for ELF binaries. Results are filtered to only include targets within the .text section.
Combined Analysis ¶
For highest-confidence function detection, use DetectFunctions which combines both prologue and call site analysis. Functions detected by both methods receive the highest confidence rating. This is particularly effective for recovering functions in stripped binaries or heavily optimized code.
Confidence Scoring ¶
The confidence level indicates the reliability of a detection:
- High: Direct CALL instructions or prologue + called/jumped to
- Medium: Unconditional JMP or prologue-only
- Low: Conditional jumps (usually intra-function branches)
- None: Register-indirect (cannot be statically resolved)
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AddressingMode ¶ added in v0.3.0
type AddressingMode string
AddressingMode represents how the target address is specified.
const ( AddressingModePCRelative AddressingMode = "pc-relative" AddressingModeAbsolute AddressingMode = "absolute" AddressingModeRegisterIndirect AddressingMode = "register-indirect" )
Recognized addressing modes for call site instructions.
type CallSiteEdge ¶ added in v0.3.0
type CallSiteEdge struct {
SourceAddr uint64 `json:"source_addr"`
TargetAddr uint64 `json:"target_addr"`
Type CallSiteType `json:"type"`
AddressMode AddressingMode `json:"address_mode"`
Confidence Confidence `json:"confidence"`
}
CallSiteEdge represents a detected call site (call or jump to a function).
func DetectCallSites ¶ added in v0.3.0
func DetectCallSites(code []byte, baseAddr uint64, arch Arch) ([]CallSiteEdge, error)
DetectCallSites analyzes raw machine code bytes and returns detected call sites (CALL and JMP instructions with their targets). baseAddr is the virtual address corresponding to the start of code. arch selects the architecture-specific detection logic. This function performs no I/O and works with any binary format.
Example ¶
package main
import (
"fmt"
"log"
"github.com/maxgio92/resurgo"
)
func main() {
// x86-64 machine code: call $+0x20 (E8 1B 00 00 00)
// At address 0x1000, calls target at 0x1000 + 5 + 0x1B = 0x1020
code := []byte{0xE8, 0x1B, 0x00, 0x00, 0x00}
edges, err := resurgo.DetectCallSites(code, 0x1000, resurgo.ArchAMD64)
if err != nil {
log.Fatal(err)
}
for _, e := range edges {
fmt.Printf("[%s] 0x%x -> 0x%x (%s, %s)\n",
e.Type, e.SourceAddr, e.TargetAddr, e.AddressMode, e.Confidence)
}
}
Output: [call] 0x1000 -> 0x1020 (pc-relative, high)
func DetectCallSitesFromELF ¶ added in v0.3.0
func DetectCallSitesFromELF(r io.ReaderAt) ([]CallSiteEdge, error)
DetectCallSitesFromELF parses an ELF binary from the given reader, extracts the .text section, and returns detected call sites. The architecture is inferred from the ELF header.
Example ¶
package main
import (
"fmt"
"log"
"os"
"github.com/maxgio92/resurgo"
)
func main() {
f, err := os.Open("/usr/bin/ls")
if err != nil {
log.Fatal(err)
}
defer f.Close()
edges, err := resurgo.DetectCallSitesFromELF(f)
if err != nil {
log.Fatal(err)
}
// Show first 5 high-confidence call edges
count := 0
for _, e := range edges {
if e.Type == resurgo.CallSiteCall && e.Confidence == resurgo.ConfidenceHigh {
fmt.Printf("[%s] 0x%x -> 0x%x (%s)\n",
e.Type, e.SourceAddr, e.TargetAddr, e.AddressMode)
count++
if count >= 5 {
break
}
}
}
}
type CallSiteType ¶ added in v0.3.0
type CallSiteType string
CallSiteType represents the type of call site instruction.
const ( CallSiteCall CallSiteType = "call" CallSiteJump CallSiteType = "jump" )
Recognized call site instruction types.
type Confidence ¶ added in v0.3.0
type Confidence string
Confidence represents the reliability of a call site detection.
const ( ConfidenceHigh Confidence = "high" ConfidenceMedium Confidence = "medium" ConfidenceLow Confidence = "low" ConfidenceNone Confidence = "none" )
Confidence levels for call site detection.
type DetectionType ¶ added in v0.3.0
type DetectionType string
DetectionType represents how a function was detected.
const ( DetectionPrologueOnly DetectionType = "prologue-only" DetectionCallTarget DetectionType = "call-target" DetectionJumpTarget DetectionType = "jump-target" DetectionBoth DetectionType = "both" // Prologue + called/jumped to )
Recognized detection types.
type FunctionCandidate ¶ added in v0.3.0
type FunctionCandidate struct {
Address uint64 `json:"address"`
DetectionType DetectionType `json:"detection_type"`
PrologueType PrologueType `json:"prologue_type,omitempty"`
CalledFrom []uint64 `json:"called_from,omitempty"`
JumpedFrom []uint64 `json:"jumped_from,omitempty"`
Confidence Confidence `json:"confidence"`
}
FunctionCandidate represents a potential function detected through one or more signals (prologue detection, call site analysis, or both).
func DetectFunctions ¶ added in v0.3.0
func DetectFunctions(code []byte, baseAddr uint64, arch Arch) ([]FunctionCandidate, error)
DetectFunctions combines prologue detection and call site analysis to identify function entry points with higher confidence. Functions detected by both methods receive the highest confidence rating.
Example ¶
package main
import (
"fmt"
"log"
"github.com/maxgio92/resurgo"
)
func main() {
// x86-64 code with prologue and call:
// 0x1000: push rbp; mov rbp, rsp
// 0x1004: call 0x1020
// ...
// 0x1020: push rbp; mov rbp, rsp (called function)
code := make([]byte, 0x30)
code[0x00] = 0x55 // push rbp
code[0x01] = 0x48 // mov rbp, rsp
code[0x02] = 0x89
code[0x03] = 0xe5
code[0x04] = 0xE8 // call
code[0x05] = 0x17 // rel32 = 0x17
code[0x06] = 0x00
code[0x07] = 0x00
code[0x08] = 0x00
code[0x09] = 0xC3 // ret (establish function boundary)
code[0x20] = 0x55 // push rbp at target
code[0x21] = 0x48 // mov rbp, rsp
code[0x22] = 0x89
code[0x23] = 0xe5
candidates, err := resurgo.DetectFunctions(code, 0x1000, resurgo.ArchAMD64)
if err != nil {
log.Fatal(err)
}
for _, c := range candidates {
fmt.Printf("0x%x: %s (confidence: %s)\n",
c.Address, c.DetectionType, c.Confidence)
}
}
Output: 0x1000: prologue-only (confidence: medium) 0x1020: both (confidence: high)
func DetectFunctionsFromELF ¶ added in v0.3.0
func DetectFunctionsFromELF(r io.ReaderAt) ([]FunctionCandidate, error)
DetectFunctionsFromELF parses an ELF binary from the given reader, extracts the .text section, and returns detected function candidates using combined prologue detection and call site analysis. The architecture is inferred from the ELF header.
type Prologue ¶
type Prologue struct {
Address uint64 `json:"address"`
Type PrologueType `json:"type"`
Instructions string `json:"instructions"`
}
Prologue represents a detected function prologue.
func DetectPrologues ¶
DetectPrologues analyzes raw machine code bytes and returns detected function prologues. baseAddr is the virtual address corresponding to the start of code. arch selects the architecture-specific detection logic. This function performs no I/O and works with any binary format.
Example ¶
package main
import (
"fmt"
"log"
"github.com/maxgio92/resurgo"
)
func main() {
// x86-64 machine code: nop; push rbp; mov rbp, rsp
code := []byte{0x90, 0x55, 0x48, 0x89, 0xe5}
prologues, err := resurgo.DetectPrologues(code, 0x1000, resurgo.ArchAMD64)
if err != nil {
log.Fatal(err)
}
for _, p := range prologues {
fmt.Printf("[%s] 0x%x: %s\n", p.Type, p.Address, p.Instructions)
}
}
Output: [classic] 0x1001: push rbp; mov rbp, rsp
func DetectProloguesFromELF ¶
DetectProloguesFromELF parses an ELF binary from the given reader, extracts the .text section, and returns detected function prologues. The architecture is inferred from the ELF header.
Example ¶
package main
import (
"fmt"
"log"
"os"
"github.com/maxgio92/resurgo"
)
func main() {
f, err := os.Open("/usr/bin/ls")
if err != nil {
log.Fatal(err)
}
defer f.Close()
prologues, err := resurgo.DetectProloguesFromELF(f)
if err != nil {
log.Fatal(err)
}
for _, p := range prologues {
fmt.Printf("[%s] 0x%x: %s\n", p.Type, p.Address, p.Instructions)
}
}
type PrologueType ¶
type PrologueType string
PrologueType represents the type of function prologue.
const ( PrologueClassic PrologueType = "classic" PrologueNoFramePointer PrologueType = "no-frame-pointer" ProloguePushOnly PrologueType = "push-only" PrologueLEABased PrologueType = "lea-based" )
Recognized x86_64 function prologue patterns.
const ( PrologueSTPFramePair PrologueType = "stp-frame-pair" PrologueSTRLRPreIndex PrologueType = "str-lr-preindex" PrologueSubSP PrologueType = "sub-sp" PrologueSTPOnly PrologueType = "stp-only" )
Recognized ARM64 function prologue patterns.