Files
go_pwner/rop.go
T
2026-07-18 21:37:15 +03:00

81 lines
2.3 KiB
Go

package winpwn
import (
"bufio"
"bytes"
"fmt"
"os/exec"
"regexp"
"strconv"
"strings"
)
// NewROPExternal is the explicit-tool-path variant of NewROP, for an rp-win
// build kept somewhere other than RP_WIN_EXE/defaultRPWinTool, or a
// different rp++ fork entirely (same output format).
func NewROPExternal(binaryPath string, toolPath string) (*ROP, error) {
return newROP(binaryPath, toolPath)
}
func (r *ROP) findGadgetsExternal() error {
// -f: target file
// -r 5: max gadget length in instructions
// --unique: dedupe identical instruction sequences
// --allow-branches: also report gadgets terminated by an indirect
// jmp/call (register or memory operand) and jmp-$ self-loops, not just
// ret/ret-imm16 -- the JOP transit primitives needed when the target
// has no clean `pop reg ; ret` for a given register.
cmd := exec.Command(r.toolPath, "-f", r.binaryPath, "-r", "5", "--unique", "--allow-branches")
var out, stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to run gadget finder %q: %w\n%s", r.toolPath, err, stderr.String())
}
// Регулярное выражение для парсинга вывода rp++
// Пример строки: "0x140001234: pop rcx ; ret ; (1 found)"
re := regexp.MustCompile(`^(0x[0-9a-fA-F]+):\s*(.+?)\s*(?:;\s*\(\d+ found\))?$`)
scanner := bufio.NewScanner(&out)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
matches := re.FindStringSubmatch(line)
if len(matches) >= 3 {
addrStr := matches[1]
instructions := matches[2]
// Конвертация hex-строки в uint64
addr, err := strconv.ParseUint(strings.TrimPrefix(addrStr, "0x"), 16, 64)
if err == nil {
r.gadgets = append(r.gadgets, Gadget{
Address: addr,
Instructions: instructions,
})
}
}
}
return nil
}
// Search ищет гаджет по подстроке (например, "pop rcx ; ret")
func (r *ROP) Search(instr string) ([]Gadget, error) {
var results []Gadget
searchStr := strings.ToLower(instr)
for _, g := range r.gadgets {
if strings.Contains(strings.ToLower(g.Instructions), searchStr) {
results = append(results, g)
}
}
if len(results) == 0 {
return nil, fmt.Errorf("gadget '%s' not found", instr)
}
return results, nil
}