Upload files to "/"

This commit is contained in:
meowmycks 2025-04-12 23:46:41 -04:00
parent 342d9b1ad9
commit 580e9eb07a
2 changed files with 306 additions and 0 deletions

136
spoof.asm Normal file
View File

@ -0,0 +1,136 @@
.code
; A function can be called like so
;
; Spoof(arg1, arg2, arg3, arg4, &param, function, (PVOID)0);
;
; Param is a struct containing some necessary information for the call to have fake frames added.
; The 6th argument is a pointer to the function to execute
; The 7th argument specifies the number of args to pass to the stack. It has to be at an 8 byte size.
Spoof PROC
pop rax ; Real return address in rax
mov r10, rdi ; Store OG rdi in r10
mov r11, rsi ; Store OG rsi in r11
mov rdi, qword ptr [rsp + 32] ; Storing struct in rdi
mov rsi, qword ptr [rsp + 40] ; Storing function to call
; ---------------------------------------------------------------------
; Storing our original registers
; ---------------------------------------------------------------------
mov qword ptr [rdi + 24], r10 ; Storing OG rdi into param
mov qword ptr [rdi + 88], r11 ; Storing OG rsi into param
mov qword ptr [rdi + 96], r12 ; Storing OG r12 into param
mov qword ptr [rdi + 104], r13 ; Storing OG r13 into param
mov qword ptr [rdi + 112], r14 ; Storing OG r14 into param
mov qword ptr [rdi + 120], r15 ; Storing OG r15 into param
mov r12, rax ; OG code used r12 for ret addr
; ---------------------------------------------------------------------
; Prepping to move stack args
; ---------------------------------------------------------------------
xor r11, r11 ; r11 = # of args pushed
mov r13, qword ptr [rsp + 30h] ; r13 = total args to push
mov r14, 200h ; Initial offset
add r14, 8
add r14, qword ptr [rdi + 56] ; Add RUTS stack size
add r14, qword ptr [rdi + 48] ; Add BTIT stack size
add r14, qword ptr [rdi + 32] ; Add gadget frame size
sub r14, 20h ; Adjust for first stack arg
mov r10, rsp
add r10, 30h ; Stack args base address
looping_label:
xor r15, r15
cmp r11, r13
je finish_label
; ---------------------------------------------------------------------
; Calculate target stack position
; ---------------------------------------------------------------------
sub r14, 8
mov r15, rsp
sub r15, r14
; ---------------------------------------------------------------------
; Move stack argument
; ---------------------------------------------------------------------
add r10, 8
push qword ptr [r10]
pop qword ptr [r15]
; ---------------------------------------------------------------------
; Increment counter and loop
; ---------------------------------------------------------------------
add r11, 1
jmp looping_label
finish_label:
; ----------------------------------------------------------------------
; Create working space and setup fake frames
; ----------------------------------------------------------------------
sub rsp, 200h
push 0
; RtlUserThreadStart frame
sub rsp, qword ptr [rdi + 56]
mov r11, qword ptr [rdi + 64]
mov qword ptr [rsp], r11
; BaseThreadInitThunk frame
sub rsp, qword ptr [rdi + 32]
mov r11, qword ptr [rdi + 40]
mov qword ptr [rsp], r11
; Gadget frame -- `jmp QWORD PTR [rbx]`
sub rsp, qword ptr [rdi + 48]
mov r11, qword ptr [rdi + 80]
mov qword ptr [rsp], r11
; ----------------------------------------------------------------------
; Prepare for function call and fixup
; ----------------------------------------------------------------------
mov r11, rsi ; Function to call
mov qword ptr [rdi + 8], r12 ; Store real return address
mov qword ptr [rdi + 16], rbx ; Store original RBX
lea rbx, fixup_label ; Get fixup address
mov qword ptr [rdi], rbx ; Store fixup in struct
mov rbx, rdi ; Param struct pointer
; Prepare syscall (if needed)
mov r10, rcx
mov rax, qword ptr [rdi + 72]
jmp r11 ; Jump to target function
fixup_label:
mov rcx, rbx ; Restore param struct
; Cleanup stack frames
add rsp, 200h
add rsp, qword ptr [rbx + 48]
add rsp, qword ptr [rbx + 32]
add rsp, qword ptr [rbx + 56]
; Restore original registers
mov rbx, qword ptr [rcx + 16]
mov rdi, qword ptr [rcx + 24]
mov rsi, qword ptr [rcx + 88]
mov r12, qword ptr [rcx + 96]
mov r13, qword ptr [rcx + 104]
mov r14, qword ptr [rcx + 112]
mov r15, qword ptr [rcx + 120]
jmp qword ptr [rcx + 8] ; Jump to original return address
Spoof ENDP
END

170
syscalls.cpp Normal file
View File

@ -0,0 +1,170 @@
#include <includes.h>
// Super reliable way to find the base address of a given module
PBYTE FindModuleBase(const CHAR* moduleName) {
// Retrieve the loader data from the Process Environment Block (PEB)
PPEB_LDR_DATA loaderData = NtCurrentTeb()->ProcessEnvironmentBlock->Ldr;
PLIST_ENTRY moduleListHead = (PLIST_ENTRY)&loaderData->Reserved2[1]; //Reserved2[1] == InLoadOrderModuleList
PLIST_ENTRY currentEntry = moduleListHead->Blink;
// Iterate through the loaded modules backwards
while (currentEntry != moduleListHead) {
// Get the module entry
PLDR_DATA_TABLE_ENTRY_MODIFIED moduleEntry = CONTAINING_RECORD(currentEntry, LDR_DATA_TABLE_ENTRY_MODIFIED, InLoadOrderLinks);
currentEntry = currentEntry->Blink;
// Get the base address of the module
PBYTE moduleBase = (PBYTE)moduleEntry->OriginalBase;
// Access the NT headers of the module
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleBase;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(moduleBase + dosHeader->e_lfanew);
// Check if the module has an export directory
DWORD exportDirectoryRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (!exportDirectoryRVA) continue; // No export table? skip
// Access the export directory
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(moduleBase + exportDirectoryRVA);
if (!exportDirectory->NumberOfNames) continue; // No symbols? skip
// Extract the DLL name from the module entry
char dllName[MAX_PATH]; // Buffer to store the DLL name
snprintf(dllName, sizeof(dllName), "%wZ", moduleEntry->BaseDllName); // Extract BaseDllName
// Compare the decoded name with the current module name
if (strcmp(dllName, moduleName) == 0) return moduleBase; // Found the module, return its base address
}
// module not found
return nullptr;
}
// Resolve System Service Number (SSN), Address, and Offset for a System Call Name
SyscallEntry SSNLookup(PCHAR syscall) {
SyscallEntry entry = { 0 };
// Load the Export Address Table
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(hNtdll + ((PIMAGE_DOS_HEADER)hNtdll)->e_lfanew);
DWORD exportDirRVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (!exportDirRVA) return { 0 }; // No export table
PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)(hNtdll + exportDirRVA);
PDWORD pFunctions = (PDWORD)(hNtdll + pExportDir->AddressOfFunctions);
PDWORD pNames = (PDWORD)(hNtdll + pExportDir->AddressOfNames);
PWORD pNameOrdinals = (PWORD)(hNtdll + pExportDir->AddressOfNameOrdinals);
// Load the Exception Directory
DWORD exceptTableRVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
if (!exceptTableRVA) return { 0 }; // No exception directory
PIMAGE_RUNTIME_FUNCTION_ENTRY pRuntimeFuncTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(hNtdll + exceptTableRVA);
INT64 ssn = 0;
PBYTE address = 0;
// Search export address table
for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
PCHAR pFunctionName = (PCHAR)(hNtdll + pNames[i]);
// Search runtime function table
for (INT64 i = 0; pRuntimeFuncTable[i].BeginAddress; i++) {
for (INT64 j = 0; j < pExportDir->NumberOfFunctions; j++) {
if (pFunctions[pNameOrdinals[j]] == pRuntimeFuncTable[i].BeginAddress) {
PCHAR api = (PCHAR)(hNtdll + pNames[j]);
PCHAR s1 = api;
PCHAR s2 = syscall;
// Compare the syscall names
while (*s1 && (*s1 == *s2)) s1++, s2++;
INT64 cmp = (INT64)*(PBYTE)s1 - *(PBYTE)s2;
if (!cmp) {
address = (hNtdll + pRuntimeFuncTable[i].BeginAddress);
// Locate `syscall; ret` sequence
for (INT64 offset = 0; offset < 0x100; offset++) {// Scan up to 256 bytes
if (address[offset] == 0x0F && address[offset + 1] == 0x05 && address[offset + 2] == 0xC3) {
// Populate the SyscallEntry struct
entry.SSN = ssn;
entry.Address = address;
entry.Syscall = (PVOID)(address + offset);
return entry;
}
}
}
// If this is a syscall, increase the SSN value
if (*(USHORT*)api == 'wZ') ssn++;
}
}
}
}
return { 0 }; // Didn't find it
}
// Collect all instances of a given ROP gadget in a given module
std::vector<PVOID> CollectGadgets(const PBYTE gadget, SIZE_T gadgetSize, PBYTE hModule) {
std::vector<PVOID> gadgets;
if (!hModule || !gadget || gadgetSize == 0) return gadgets; // Validate input
PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(hModule);
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return gadgets; // Validate DOS header
PIMAGE_NT_HEADERS pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<BYTE*>(hModule) + pDosHeader->e_lfanew);
if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) return gadgets; // Validate NT headers
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
UINT_PTR moduleBase = reinterpret_cast<UINT_PTR>(hModule);
// Loop through each section in the module
for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++) {
// Check if the section is executable code
if ((pSectionHeader->Characteristics & IMAGE_SCN_CNT_CODE) &&
(pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE)) {
PBYTE sectionBase = reinterpret_cast<PBYTE>(moduleBase + pSectionHeader->VirtualAddress);
PBYTE sectionEnd = sectionBase + pSectionHeader->Misc.VirtualSize;
// Search within the section for the gadget pattern
for (PBYTE currentBytes = sectionBase; currentBytes <= sectionEnd - gadgetSize; ++currentBytes) {
if (!memcmp(currentBytes, gadget, gadgetSize)) {
gadgets.emplace_back(EncodePointer(reinterpret_cast<PVOID>(currentBytes))); // Construct each encoded address inside the vector
}
}
}
}
//printf("Found %u gadgets\n", gadgets.size());
return gadgets;
}
// Choose a random gadget
PVOID GoGoGadget(std::vector<PVOID> gadgets) {
if (gadgets.empty()) return nullptr; // Return nullptr if the vector is empty
// Randomly select and decode a gadget address
static std::mt19937 rng(static_cast<unsigned int>(std::time(nullptr)));
std::uniform_int_distribution<size_t> dist(0, gadgets.size() - 1);
return DecodePointer((gadgets)[dist(rng)]);
}
// Checks the bytes immediately before each gadget
VOID CheckGadgetPreBytes(const std::vector<PVOID>& gadgets, SIZE_T gadgetSize, SIZE_T lookbackSize) {
for (const auto& encodedGadget : gadgets) {
PBYTE gadgetAddress = reinterpret_cast<PBYTE>(DecodePointer(encodedGadget)); // Decode the pointer
// Ensure we can read preceding bytes safely
PBYTE precedingBytes = gadgetAddress - lookbackSize;
if (precedingBytes >= gadgetAddress) {
printf("Skipping address %p (out of range)\n", gadgetAddress);
continue; // Prevent underflow if the address is too low in memory
}
// Print address and bytes
printf("Address: %p -> ", gadgetAddress);
for (SIZE_T i = 0; i < lookbackSize + gadgetSize + 8; i++) { // Include gadget bytes and 4 bytes ahead of gadget too
printf("%02X ", precedingBytes[i]);
}
printf("\n");
}
}