AI自动化fscan二开

admin 2026-08-19 04:31:36 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍利用AI自动化对fscan进行二开以规避杀软检测。核心步骤包括:去除banner、命令行参数及内部字符串等敏感特征,并通过执行闭环确保修改彻底;采用资源加载器将fscan转为shellcode加载,通过动态加载隐藏导入表及API哈希隐藏字符串,最终实现免杀。该方法提供了可操作的技术路径,但需注意其潜在的法律风险。 综合评分: 86 文章分类: 渗透测试,红队,内网渗透,安全工具,免杀


cover_image

AI自动化fscan二开

云*3 云*3

乌雲安全

2026年7月20日 08:32 重庆

在小说阅读器读本章

去阅读

作者:云*3

来源:https://xz.aliyun.com/news/92390

一、去除fscan敏感特征以及编译

首先,让AI阅读相关fscan魔改的文章,然后制定二开计划。

根据网上搜索的文章,fscan的敏感特征为以下3个:banner特征、命令行参数、内部大量的字符串。

banner特征:  实验了几次,AI都能完美执行,直接注释调banner,当然这个也是去除敏感特征里面最简单的。

**命令行参数:**AI在修改过程中,实现了很多次,基本上都能完整的执行,但存在几个小问题,修改后的命令行参数可能会重合、修改参数没有全部修改导致杀软依旧能根据参数判断出有扫描特征,这些让AI第二次复查时,都能解决。

内部大量的存在“fscan字眼”字符串:这个Ai执行的最不好,执行时经常会出现大规模的特征字符串残留,虽然在大量残留下,我发现杀软依然无法进行有效检测,但为了精益求精,决定更进一步。

1)利用执行闭环去除敏感字符串

常规的检测逻辑就是,将字符串修改后—–>go编译项目——->用检测字符串工具string.exe去检查是否存在遗漏。

(备注:因为用garble混淆编译后是不可能能检查到残余字符串,只有在用go原生编译情况下,才能看出字符串是否完整修改)

我在这里定义了一个技能,其中涉及到这个检测逻辑的如下,让AI写了一个迭代流程。利用string.exe进行检查闭环,让Ai能够知道什么情况下自己能输出,什么情况下不能输出编译结果

编译 → strings.exe 查 "fscan" → 有输出?→ 源码定位 → 修改源码 → 回到编译                                        ↓ 无输出                                      ✅ 通过

示例具体操作:

# 1. 正常编译(不加 garble/UPX)go build -ldflags="-s -w" -trimpath -o test.exe .
# 2. powershell用 strings.exe 查 "fscan" 残留.\strings.exe test.exe | Select-String "fscan" | Where-Object { $_ -notmatch "gc|sync\.|panic|defer|sweep|runtime" }

不直接是 strings.exe test.exe | Select-String “fscan”的原因是:Select-String "fscan" 只会匹配包含 fscan 的所有行,里面混杂大量 Go runtime 无害日志(gc、sync、runtime 等),干扰你判断真正恶意硬编码特征;加 Where-Object 是过滤掉 Go 运行时自带的噪音行,只保留业务代码里真实写死的 fscan 字符串

利用闭环之前,发现存在多处fscan特征

利用闭环之后,未发现该特征

defscangui.exe是fscan在插件中定义的已知杀软进程,这个不算fscan特征

2)频繁出现报错,将反思放进skill,反复迭代

编译过程中出现大量报错,将反思放入skill中,使得能够反复迭代,最后利用该技能可以非常快的速度下改好fscan。

图示是当时遇到的问题,几次编译都严重破坏了源码

二、利用资源加载器落地

常规流程是:将fscan.exe转化为shellcode,然后用加载器加载到内存中,再利用加载器执行,使得行为更加隐蔽。

这里使用了一个前人的加载器demo,但从微步看到已经杀烂了。

调试信息中也有泄露,可以看到它的用户名应该是12275

于是对该加载器进行二开,来避免检测

1)利用执行闭环混淆导入表

1-1:动态加载隐藏导入表

导入表:Windows 下编译生成的 EXE/DLL 是PE 格式,导入表是 PE 里的一段数据,作用是记录程序运行时需要从哪些 DLL、调用哪些外部函数。

蓝队和杀软可以从导入表中找到高危信息,比如

GetCurrentProcess  #获取自身进程句柄,通常为了修改自身内存属性,比如把一段数据区的内存从可读改成 PAGE_EXECUTE_READWRITE(可执行)VirtualAlloc  #分配可执行内存,常用于shellcode,比如利用 PAGE_EXECUTE_READWRITE将shellcode赋予读写执行权限VirtualAlloc(        NULL,        fileSize,        MEM_COMMIT | MEM_RESERVE,        PAGE_EXECUTE_READWRITE    );

于是尝试用 自定义函数来隐藏导入表

可以在运行时使用 GetProcAddressGetModuleHandle 或 LoadLibrary 动态加载这些函数,因此在检查时它不会出现在导入表中。

| | | | | — | — | — | | 方式 | 导入表里有记录吗? | 为什么 | | 直接调用MessageBoxA(...) | ✅ 有 | 编译器能看到你用了,提前写进清单(所以静态分析可以分析到) | | 动态加载GetProcAddress | ❌ 没有 | 编译器看不到你具体要哪个函数,清单是空的(动态下才调用,静态就分析不到了) |

于是我们需要一个执行闭环,让AI混淆后,知道什么情况下才算混淆成功。我们引入dumpbin工具

dumpbin是 Visual Studio 自带的一个”二进制文件体检工具”,它是微软官方提供的,随 Visual Studio 一起安装,不需要额外下载。可以在命令行里面快速查看导入表信息。(其他几个工具全部都是界面工具,不太适合AI操作)

使用时,需要将dumpbin.exe设置为环境变量,方便使用

dumpbin /IMPORTS loader.exe

示例使用如下:

让AI混淆之后,自动用dumpbin进行检查,分析导入表是否成功混淆,设置工作流如下

目标:不干扰原先cpp文件逻辑的前提下重新混淆cpp文件,使得能达到导入表隐藏的效果要求:1、按照导入表隐藏.md的方法,使用自定义函数隐藏导入表2、只混淆对杀软认为有风险的导入表,比如GetCurrentProcess、VirtualAlloc步骤:混淆后编译生成新loader.exe,使用dumpbin /IMPORTS loader.exe进行检查,看看有没有隐藏导入表成功,成功后才执行后续步骤完成后运行一键转Shellcode工具.bat,将项目内fscan.exe放入后生成output.bin。然后执行loader.exe -h 127.0.0.1看是否能正常运行,直到能正常运行为止,一旦运行超时没有输出即刻重新混淆原始cpp,重新执行上述步骤

这里有个坑点:闭环执行需要逻辑上必须闭环,比如fscan生成shellcode的oubput.bin,如果直接让它操作output.bin,AI一旦出问题会觉得是流程有问题,而不是它代码写错了,然后一下子去操作fscan,一下子就去找其他东西,会非常有发散性,但最终总是无法解决问题。

代码片段如下

int main() {    const char* filename = "output.bin";    XXXXXXXXXXX
    // ========== 动态加载敏感 API,避免出现在 IAT 中 ==========    HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");    if (!hKernel32) {        printf("[!] 获取 kernel32.dll 句柄失败\n");        return 1;    }
    pCreateFileA           _CreateFileA           = (pCreateFileA)          GetProcAddress(hKernel32, "CreateFileA");    pGetFileSize           _GetFileSize           = (pGetFileSize)          GetProcAddress(hKernel32, "GetFileSize");    pVirtualAlloc          _VirtualAlloc          = (pVirtualAlloc)         GetProcAddress(hKernel32, "VirtualAlloc");    pReadFile              _ReadFile              = (pReadFile)             GetProcAddress(hKernel32, "ReadFile");    pVirtualFree           _VirtualFree           = (pVirtualFree)          GetProcAddress(hKernel32, "VirtualFree");    pCloseHandle           _CloseHandle           = (pCloseHandle)          GetProcAddress(hKernel32, "CloseHandle");    pFlushInstructionCache _FlushInstructionCache = (pFlushInstructionCache)GetProcAddress(hKernel32, "FlushInstructionCache");    pGetCurrentProcess     _GetCurrentProcess     = (pGetCurrentProcess)    GetProcAddress(hKernel32, "GetCurrentProcess");    pGetLastError          _GetLastError          = (pGetLastError)         GetProcAddress(hKernel32, "GetLastError");
    if (!_CreateFileA || !_GetFileSize || !_VirtualAlloc || !_ReadFile ||        !_VirtualFree || !_CloseHandle || !_FlushInstructionCache ||        !_GetCurrentProcess || !_GetLastError) {        printf("[!] 动态加载 API 失败\n");        return 1;    }

顺利完成混淆,之前结果

利用AI混淆之后结果,只剩了GetProcAddress和GetModuleHandleA,因为动态加载需要调用这两个API,如下所示,所以这两个API去不掉特征

fnVirtualAllocEx pVirtualAllocEx = GetProcAddress(GetModuleHandleA("KERNEL32.DLL"), "VirtualAllocEx");

该方法还有一个缺陷,虽然导入表中看不到了,但在字符串里面仍然能看到VirtualAlloc等APi,蓝队依然可以发现问题。该问题放到1-2进行解决

1-2:API 哈希隐藏字符串

前文可知,调用的字符串还是可以从exe当中识别到字符串,于是可以预先把敏感 API 名称和 DLL 名称用哈希算法转成固定数字,代码中只保留这些无意义的哈希值,运行时遍历系统内存中的字符串并实时计算哈希进行比对,从而彻底避免在文件中留下任何敏感字符串明文。

同样设置一个执行的闭环,完成后让AI自己用strings.exe来测试可用性。除了开始遇到点环境的问题,然后就一次性解决了。

目标:不干扰原先cpp文件逻辑的前提使用导入表混淆技能方案4,使得能达隐藏exe中的敏感字符串步骤:混淆后编译生成新loader.exe,使用dumpbin /IMPORTS loader.exe进行检查,看看有没有隐藏导入表成功,成功后才执行string.exe loader.exe | findstr CPP文件中混淆的API,看看有没有隐藏成功,成功后再执行下一步完成后运行一键转Shellcode工具.bat,将项目内fscan.exe放入后生成output.bin。然后执行loader.exe -h 127.0.0.1看是否能正常运行,直到能正常运行为止,一旦运行超时没有输出即刻重新混淆原始cpp,重新执行上述步骤

代码片段如下

// ========== 方案4: API哈希 — 隐藏导入表 ==========#define INITIAL_SEED 7
DWORD HASHA(const char* String) {    SIZE_T Index = 0;    DWORD Hash = 0;    SIZE_T Length = lstrlenA(String);
&nbsp; &nbsp;&nbsp;while&nbsp;(Index&nbsp;!=&nbsp;Length) {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Hash&nbsp;+=&nbsp;String[Index++];&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Hash&nbsp;+=&nbsp;Hash&nbsp;<<&nbsp;INITIAL_SEED;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;Hash&nbsp;^=&nbsp;Hash&nbsp;>>&nbsp;6;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;Hash&nbsp;+=&nbsp;Hash&nbsp;<<&nbsp;3;&nbsp; &nbsp;&nbsp;Hash&nbsp;^=&nbsp;Hash&nbsp;>>&nbsp;11;&nbsp; &nbsp;&nbsp;Hash&nbsp;+=&nbsp;Hash&nbsp;<<&nbsp;15;&nbsp; &nbsp;&nbsp;return&nbsp;Hash;}

测试结果:字符串成功隐藏

最终效果也是可以免杀


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:乌雲安全 云3 云3《AI自动化fscan二开》

AI自动化fscan二开 网络安全文章

AI自动化fscan二开

文章总结: 本文介绍利用AI自动化对fscan进行二开以规避杀软检测。核心步骤包括:去除banner、命令行参数及内部字符串等敏感特征,并通过执行闭环确保修改彻
评论:0   参与:  0