Skip to content

Evade Microsoft Defender detection when injecting #18

@alexrp

Description

I just observed Microsoft Defender flagging the hook sample locally:

Unhandled exception: System.ComponentModel.Win32Exception (225): An error occurred trying to start process 'C:\Users\alex\source\repos\vezel\ruptura\src\samples\hook\bin\Debug\win-x64\hook.exe' with working directory 'C:\Users\alex\source\repos\vezel\ruptura\src\samples\hook'. Operation did not complete successfully because the file contains a virus or potentially unwanted software.
   at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
   at Microsoft.DotNet.Cli.Utils.Command.Execute(Action`1 processStarted)
   at Microsoft.DotNet.Tools.Run.RunCommand.Execute()
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.DotNet.Cli.Parser.<>c__DisplayClass16_0.<<UseParseErrorReporting>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass12_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__18_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass16_0.<<UseParseDirective>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass8_0.<<UseExceptionHandler>b__0>d.MoveNext()

We open a process, allocate memory in the process, write code to the memory, mark the memory executable, and then create a thread that executes that memory. It's not too surprising that this gets flagged since it's a classic way of injecting malicious code into a process.

I believe it's either our CreateProcess call (in System.Diagnostics.Process) or CreateRemoteThread call (in Vezel.Ruptura.Injection.TargetProcess) that tips Microsoft Defender off. Or maybe both. It's well-documented that Microsoft Defender hooks APIs such as these.

One workaround might be direct system calls. We would extract the actual system call numbers from ntdll.dll to avoid hardcoding them; they do change between Windows updates. We would then assemble some functions in the injecting process which perform the system calls. I don't think Microsoft Defender has any way of detecting this, and it's relatively simple.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

area: injectionIssues related to the assembly injection APIs.state: approvedEnhancements and tasks that have been approved.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions