#include #include #include // Функция для парсинга PEB и поиска WinExec FARPROC FindWinExec() { // Получаем PEB через FS регистр #ifdef _WIN64 PPEB pPEB = (PPEB)__readgsqword(0x60); #else PPEB pPEB = (PPEB)__readfsdword(0x30); #endif // Получаем LDR (Loader Data) PPEB_LDR_DATA pLDR = pPEB->Ldr; // Проходим по списку загруженных модулей LIST_ENTRY* pModuleList = &pLDR->InMemoryOrderModuleList; LIST_ENTRY* pEntry = pModuleList->Flink; // Ищем kernel32.dll while (pEntry != pModuleList) { PLDR_DATA_TABLE_ENTRY pModule = CONTAINING_RECORD(pEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); // Проверяем имя модуля WCHAR* moduleName = pModule->BaseDllName.Buffer; if (moduleName && wcsstr(moduleName, L"kernel32.dll")) { HMODULE hKernel32 = (HMODULE)pModule->DllBase; // Ищем WinExec в kernel32.dll FARPROC pWinExec = GetProcAddress(hKernel32, "WinExec"); if (pWinExec) { printf("[+] Found WinExec at: 0x%p\n", pWinExec); return pWinExec; } } pEntry = pEntry->Flink; } return NULL; } // Функция для открытия и парсинга .exe файла void ParseExeFile(const char* filename) { HANDLE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { printf("[-] Failed to open file: %s\n", filename); return; } // Читаем DOS заголовок IMAGE_DOS_HEADER dosHeader; DWORD bytesRead; if (!ReadFile(hFile, &dosHeader, sizeof(dosHeader), &bytesRead, NULL)) { printf("[-] Failed to read DOS header\n"); CloseHandle(hFile); return; } // Проверяем сигнатуру DOS if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) { printf("[-] Invalid DOS signature\n"); CloseHandle(hFile); return; } // Переходим к PE заголовку SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN); // Читаем PE сигнатуру DWORD peSignature; ReadFile(hFile, &peSignature, sizeof(peSignature), &bytesRead, NULL); if (peSignature != IMAGE_NT_SIGNATURE) { printf("[-] Invalid PE signature\n"); CloseHandle(hFile); return; } // Читаем файловый заголовок IMAGE_FILE_HEADER fileHeader; ReadFile(hFile, &fileHeader, sizeof(fileHeader), &bytesRead, NULL); printf("[+] File is a valid PE executable\n"); printf("[+] Number of sections: %d\n", fileHeader.NumberOfSections); printf("[+] Size of optional header: %d\n", fileHeader.SizeOfOptionalHeader); // Читаем опциональный заголовок IMAGE_OPTIONAL_HEADER32 optionalHeader; ReadFile(hFile, &optionalHeader, sizeof(optionalHeader), &bytesRead, NULL); printf("[+] Entry point: 0x%X\n", optionalHeader.AddressOfEntryPoint); printf("[+] Image base: 0x%X\n", optionalHeader.ImageBase); // Читаем секции printf("\n[+] Sections:\n"); for (int i = 0; i < fileHeader.NumberOfSections; i++) { IMAGE_SECTION_HEADER sectionHeader; ReadFile(hFile, §ionHeader, sizeof(sectionHeader), &bytesRead, NULL); printf(" %s - VA: 0x%X, Size: 0x%X\n", sectionHeader.Name, sectionHeader.VirtualAddress, sectionHeader.SizeOfRawData); } CloseHandle(hFile); } // Функция-победитель (win) void win(void) { printf("flag{ret2win_but_its_WINDOWS}\n"); // Находим WinExec через PEB FARPROC pWinExec = FindWinExec(); if (pWinExec) { // Запускаем калькулятор через WinExec typedef void (*WinExec_t)(LPCSTR, UINT); WinExec_t WinExec_func = (WinExec_t)pWinExec; WinExec_func("mspaint.exe", SW_SHOW); printf("[+] paint launched!\n"); } } // Уязвимая функция void vulnerable_function() { char buf[16]; printf("enter your data:\n"); scanf("%s", buf); printf("try again\n"); } int main(int argc, char* argv[]) { printf("=== Windows Buffer Overflow CTF Challenge ===\n\n"); // Если передан аргумент, парсим .exe файл if (argc > 1) { printf("[*] Parsing PE file: %s\n", argv[1]); ParseExeFile(argv[1]); printf("\n"); } // Демонстрируем поиск WinExec через PEB printf("[*] Finding WinExec via PEB parsing...\n"); FARPROC pWinExec = FindWinExec(); if (pWinExec) { printf("[+] WinExec found at: 0x%p\n", pWinExec); } printf("\n"); // Вызываем уязвимую функцию vulnerable_function(); return 0; }