Upload files to "/"
This commit is contained in:
parent
342d9b1ad9
commit
580e9eb07a
136
spoof.asm
Normal file
136
spoof.asm
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
.code
|
||||||
|
|
||||||
|
; A function can be called like so
|
||||||
|
;
|
||||||
|
; Spoof(arg1, arg2, arg3, arg4, ¶m, 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
170
syscalls.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user