/* TL;DR: Главное отличие 64-битного ROP на Windows от Linux — это Calling
Convention (соглашение о вызовах). В Linux первый аргумент передается через
регистр RDI, а в Windows — через RCX. Поэтому вместо гаджета pop rdi мы будем
искать pop rcx. Кроме того, вызовы WinAPI жестко требуют выравнивания стека по
границе 16 байт, иначе программа упадет внутри system("cmd.exe").

Ниже представлены адаптированные исходники для твоего CTF-клуба. Чтобы твой
парсер PEFile в go_pwner смог найти функцию win по имени (без символов отладки),
я добавил ей атрибут экспорта __declspec(dllexport) — это классический прием для
Windows-тасков, заменяющий парсинг ELF Symbols. Уязвимый файл (rop0_win.c)

Компилировать этот файл нужно с отключенным ASLR (аналог PIE в Linux), чтобы
базовый адрес был статичным. Для MinGW-w64 используй флаги: gcc rop0_win.c -o
rop0_win.exe -fno-pie -no-pie -fno-stack-protector. */

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

void setup() {
  // Отключение буферизации для корректной работы через пайпы
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stdin, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
}

// Экспортируем функцию в таблицу PE, чтобы её можно было найти через твой
// PE-парсер
__declspec(dllexport) void win(int secret) {
  char buf[32];

  // В Windows x64 значение secret будет взято из регистра RCX
  if (secret == 0xdeadbeef) {
    printf("you just got shell\n");
    system("cmd.exe"); // Меняем /bin/sh на классический cmd
  } else {
    printf("wrong argument: 0x%x\n", secret);
    ExitProcess(1);
  }
}

void vulnerable() {
  char buf[32];
  DWORD bytesRead;
  HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);

  printf("NX is ON! You cannot execute shellcode on the stack.\n");
  printf("Can you return to win() and set RCX to 0xdeadbeef?\n");
  printf("Input: ");

  // Используем WinAPI для сырого побайтового чтения
  ReadFile(hStdin, buf, 256, &bytesRead, NULL);

  printf("Returning...\n");
}

int main() {
  setup();
  vulnerable();
  return 0;
}
