هر پاورشلی، Powershell.exe نیست؛ Defense Evasion
نویسنده: یاسین عابدینی · دسته: RedTeam · تاریخ انتشار: ۱۴۰۵/۲/۲
معماری داخلی PowerShell: جدایی موتور از رابط کاربری
مقدمه
powershell.exe تنها یک wrapper ساده است. موتور واقعی PowerShell در
System.Management.Automation.dll قرار دارد که میتوان آن را مستقیماً از .NET فراخوانی کرد.
۱. معماری کلی
مفاهیم کلیدی:
- System.Management.Automation.dll: هسته اصلی که شامل parser، runtime، و cmdlet engine است
- powershell.exe: فقط یک host process که DLL را load میکند
- Runspace: محیط اجرای مجزا برای کدهای PowerShell
- Pipeline: مکانیزم اجرای دستورات به صورت زنجیرهای
مزایای استفاده مستقیم از DLL:
- دور زدن logging و monitoring سطح process
- اجرای بدون ایجاد فرآیند
powershell.exe - کنترل دقیقتر بر محیط اجرا
- امکان embedding در برنامههای .NET
۲. روش اول: Reflection-based Loading
# بارگذاری مستقیم assembly
$assembly = [Reflection.Assembly]::LoadFile(
'C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll'
)
# ایجاد instance از PowerShell engine
$ps = $assembly.GetType('System.Management.Automation.PowerShell')::Create()
# اضافه کردن script
[void]$ps.AddScript({
Get-Process | Where-Object {$_.CPU -gt 100}
})
# اجرا
$results = $ps.Invoke()
نکات فنی:
LoadFileبه مسیر کامل نیاز دارد- میتوان از
Loadبا Fully Qualified Name استفاده کرد Create()یک runspace پیشفرض میسازدAddScriptمیتواند ScriptBlock یا string بپذیرد
مسیرهای رایج DLL:
# .NET Framework 4.x
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\
# WinSxS (نسخههای قدیمی)
C:\Windows\WinSxS\msil_system.management.automation_*\
۳. روش دوم: C# Native Integration
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
public class PowerShellExecutor
{
public static string Execute(string script)
{
// ایجاد Runspace Configuration
RunspaceConfiguration config = RunspaceConfiguration.Create();
// ایجاد و باز کردن Runspace
using (Runspace runspace = RunspaceFactory.CreateRunspace(config))
{
runspace.Open();
// ایجاد Pipeline
using (Pipeline pipeline = runspace.CreatePipeline())
{
// اضافه کردن script
pipeline.Commands.AddScript(script);
// تبدیل خروجی به string
pipeline.Commands.Add("Out-String");
// اجرا
Collection<PSObject> results = pipeline.Invoke();
// پردازش نتایج
StringBuilder output = new StringBuilder();
foreach (PSObject obj in results)
{
output.AppendLine(obj.ToString());
}
return output.ToString();
}
}
}
}
۴. کامپایل و اجرا
# پیدا کردن مسیر System.Management.Automation.dll
$DLLPath = [PSObject].Assembly.Location
# پیدا کردن کامپایلر C#
$CscPath = [System.Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory() + 'csc.exe'
# کامپایل
& $CscPath `
/r:$DLLPath `
/r:System.dll `
/unsafe `
/platform:anycpu `
/target:exe `
/out:"PowerShellHost.exe" `
"PowerShellHost.cs"
# اجرا
.\PowerShellHost.exe
پارامترهای کامپایلر:
/r:- Reference به assembly/unsafe- اجازه unsafe code/platform:anycpu- سازگاری با x86 و x64/target:exeیا/target:winexe- نوع خروجی
۵. سناریوهای پیشرفته
۵.۱ استفاده از Parameters:
pipeline.Commands.AddScript("param($name) Write-Host \"Hello $name\"");
pipeline.Commands[0].Parameters.Add("name", "World");
۵.۲ Import کردن Modules:
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new[] { "ActiveDirectory", "DnsServer" });
Runspace runspace = RunspaceFactory.CreateRunspace(iss);
۶. ملاحظات امنیتی
از دیدگاه دفاعی:
- این تکنیکها میتوانند برای دور زدن Application Whitelisting استفاده شوند
- AMSI (Antimalware Scan Interface) همچنان میتواند محتوای script را اسکن کند
- Event Log 4104 (Script Block Logging) همچنان فعال است
راهکارهای تشخیص:
- مانیتور کردن load شدن
System.Management.Automation.dllدر processهای غیرمعمول - بررسی ETW events مربوط به PowerShell
- استفاده از Sysmon برای رصد Assembly Load
از دیدگاه تهاجمی:
- برای Constrained Language Mode bypass قابل استفاده است
- میتوان با Obfuscation ترکیب کرد
- امکان injection به processهای دیگر
۷. مثال کامل: Custom PowerShell Host
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
class CustomPSHost
{
static void Main(string[] args)
{
InitialSessionState iss = InitialSessionState.CreateDefault();
// محدود کردن دسترسیها
iss.LanguageMode = PSLanguageMode.RestrictedLanguage;
using (Runspace rs = RunspaceFactory.CreateRunspace(iss))
{
rs.Open();
while (true)
{
Console.Write("PS> ");
string cmd = Console.ReadLine();
if (cmd == "exit") break;
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = rs;
ps.AddScript(cmd);
try
{
var results = ps.Invoke();
foreach (var item in results)
Console.WriteLine(item);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
}
}
}