🤬
  • ■ ■ ■ ■ ■
    README.md
    skipped 93 lines
    94 94   
    95 95  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.
    96 96   
    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
    98 106   
    99 107   
    100 108  ## Example run
    skipped 95 lines
  • ■ ■ ■ ■ ■
    ThreadStackSpoofer/header.h
    skipped 31 lines
    32 32   
    33 33  typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> HandlePtr;
    34 34   
     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 + 
    35 48  struct CallStackFrame
    36 49  {
    37 50   ULONG_PTR calledFrom;
    skipped 13 lines
    51 64   LPVOID pSymGetModuleBase64;
    52 65   bool initialized;
    53 66   CallStackFrame spoofedFrame[MaxStackFramesToSpoof];
    54  - CallStackFrame mimicFrame[MaxStackFramesToSpoof];
    55 67   size_t spoofedFrames;
    56  - size_t mimickedFrames;
     68 + ULONG_PTR legitTebBaseLow;
     69 + ULONG_PTR legitTebBaseHigh;
     70 + ULONG_PTR origTebBaseLow;
     71 + ULONG_PTR origTebBaseHigh;
    57 72  };
    58 73   
    59 74  struct HookedSleep
    skipped 37 lines
  • ■ ■ ■ ■ ■ ■
    ThreadStackSpoofer/main.cpp
    1 1   
    2 2  #include "header.h"
     3 +#include <intrin.h>
    3 4   
    4 5  HookedSleep g_hookedSleep;
    5 6  StackTraceSpoofingMetadata g_stackTraceSpoofing;
    skipped 4 lines
    10 11   const volatile DWORD dwMilliseconds = _dwMilliseconds;
    11 12   
    12 13   // Perform this (current) thread call stack spoofing.
    13  - spoofCallStack(true);
     14 + //spoofCallStack(true);
    14 15   
    15 16   log("\n===> MySleep(", std::dec, dwMilliseconds, ")\n");
    16 17   
     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 + 
    17 29   // Perform sleep emulating originally hooked functionality.
    18 30   ::SleepEx(dwMilliseconds, false);
    19 31   
     32 + 
     33 + teb->StackBase = (void*)g_stackTraceSpoofing.origTebBaseLow;
     34 + teb->StackLimit = (void*)g_stackTraceSpoofing.origTebBaseHigh;
     35 +
    20 36   // Restore original thread's call stack.
    21  - spoofCallStack(false);
     37 + //spoofCallStack(false);
    22 38  }
    23 39   
    24 40  bool fastTrampoline(bool installHook, BYTE* addressToHook, LPVOID jumpAddress, HookTrampolineBuffers* buffers /*= NULL*/)
    skipped 242 lines
    267 283   {
    268 284   for (size_t i = 0; i < numOfFrames; i++)
    269 285   {
    270  - if (i > g_stackTraceSpoofing.mimickedFrames)
    271  - {
    272  - CallStackFrame frame = { 0 };
    273  - g_stackTraceSpoofing.spoofedFrame[g_stackTraceSpoofing.spoofedFrames++] = frame;
    274  - break;
    275  - }
    276  - 
    277 286   auto& frame = frames[i];
    278  - auto& mimicframe = g_stackTraceSpoofing.mimicFrame[i];
    279 287   
    280 288   if (g_stackTraceSpoofing.spoofedFrames < MaxStackFramesToSpoof)
    281 289   {
    282 290   //
    283 291   // We will use CreateFileW as a fake return address to place onto the thread's frame on stack.
    284 292   //
    285  - //frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
    286  - frame.overwriteWhat = (ULONG_PTR)mimicframe.retAddr;
     293 + frame.overwriteWhat = (ULONG_PTR)::CreateFileW;
    287 294   
    288 295   //
    289 296   // We're saving original frame to later use it for call stack restoration.
    skipped 164 lines
    454 461   return (NULL != thread.get());
    455 462  }
    456 463   
    457  -/*
    458  -void _acquireLegitimateThreadStack(LPVOID param)
     464 + 
     465 +void WINAPI _acquireLegitimateThreadStack(LPVOID param)
    459 466  {
    460  - ULONG_PTR lowLimit = 0, highLimit = 0;
    461  - ULONG stackSize = highLimit - lowLimit;
    462  - GetCurrentThreadStackLimits(&lowLimit, &highLimit);
     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;
    463 470   
    464  - g_stackTraceSpoofing.legitimateStackContents.resize(stackSize, 0);
    465  - memcpy(g_stackTraceSpoofing.legitimateStackContents.data(), (const void*)lowLimit, stackSize);
     471 + ::SleepEx(INFINITE, false);
    466 472  }
    467  -*/
    468 473   
    469 474  bool acquireLegitimateThreadStack()
    470 475  {
    skipped 3 lines
    474 479   HandlePtr secondThread(::CreateThread(
    475 480   NULL,
    476 481   0,
    477  - (LPTHREAD_START_ROUTINE)::Sleep,
     482 + //(LPTHREAD_START_ROUTINE)::Sleep,
     483 + (LPTHREAD_START_ROUTINE)_acquireLegitimateThreadStack,
    478 484   (LPVOID)INFINITE,
    479 485   0,
    480 486   0
    skipped 1 lines
    482 488   
    483 489   Sleep(1000);
    484 490   
    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;
    488 492  }
    489  - 
    490 493   
    491 494  int main(int argc, char** argv)
    492 495  {
    skipped 56 lines
Please wait...
Page is in error, reload to recover