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 }