帖子

Memorial Edition

查看: 63|回复: 0

[插件开发教程] Write Up : MCG/Scan:轻量级字节码扫描的原理与实现

[复制链接]

男同大王

人气
15 点
金粒
463 粒
宝石
0 颗
爱心
1 颗
钻石
79 颗
贡献
0 点
发表于 15 小时前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Write Up : MCG/Scan:轻量级字节码扫描的原理与实现
MCG/Scan模块对字节码实现跨版本、抗混淆扫描的细节
【警告】
MCG是一个EOL项目,而本系列文章的公开无疑会再次降低MCG的安全性。无论如何,请不要再使用MCG
本系列文章旨在分享MCG的思路而不是源码;请不要尝试通过简单的复制粘贴来完成对MCG的重建。
本文涉及到大量JVM的无/少文档内部实现,其中有部分已经不适合最新版的实现。请自行查证最新版是否一致



▌Part 1 Class文件的常量池结构
1.1 Class文件结构
算了这不重要;我没解析。
LOL
1.2 常量池解析(部分)
常量池位于 Class 文件开头的魔数、版本号之后。先是一个u2 类型,表示常量池中常量项的数量(从 1 开始计数,实际有效索引为 1 到 constant_pool_count - 1);然后由多个 cp_info 结构组成,每个项的第一个字节是 tag,标识常量类型。
别跑!我这里有一个你看得懂的版本
  1. package cf.huzpsb.mcguard.parser;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. public class ClassParser {
  5.     public static String[] parseClass(byte[] classFile) {
  6.         try {
  7.             int cpCount = Byte.toUnsignedInt(classFile[8]) * 256 + Byte.toUnsignedInt(classFile[9]);
  8.             cpCount--;
  9.             int offset = 10;
  10.             List<String> cp = new ArrayList<>();
  11.             for (int i = 0; i < cpCount; i++) {
  12.                 int tag = classFile[offset];
  13.                 offset++;
  14.                 switch (tag) {
  15.                     case 1: // Utf8
  16.                         int len = Byte.toUnsignedInt(classFile[offset]) * 256 + Byte.toUnsignedInt(classFile[offset + 1]);
  17.                         offset += 2;
  18.                         String s = new String(classFile, offset, len);
  19.                         cp.add(s);
  20.                         offset += len;
  21.                         break;
  22.                     case 7: // Class
  23.                     case 8:
  24.                     case 16: // MethodType
  25.                     case 19:
  26.                     case 20:
  27.                         offset += 2;
  28.                         break;
  29.                     case 3:
  30.                     case 4:
  31.                     case 9:
  32.                     case 10:
  33.                     case 11:
  34.                     case 12:
  35.                     case 17:
  36.                     case 18:
  37.                         offset += 4;
  38.                         break;
  39.                     case 15:
  40.                         offset += 3;
  41.                         break;
  42.                     case 5:
  43.                     case 6:
  44.                         offset += 8;
  45.                         i++;
  46.                         break;
  47.                     case 2:
  48.                     case 13:
  49.                     case 14:
  50.                         throw new Exception("非标准的常量池标签: " + tag);
  51.                     default:
  52.                         throw new Exception("无法识别的常量池标签: " + tag);
  53.                 }
  54.             }
  55.             return cp.toArray(new String[0]);
  56.         } catch (Exception ex) {
  57.             return null;
  58.         }
  59.     }
  60. }
复制代码
▌Part 2 基于规则的常量池扫描
Why it works?
西江月·证明
即得易见平凡,仿照上例显然。
留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立,略去过程QED,由上可知证毕。
  1. package cf.huzpsb.mcguard.scan;

  2. import cf.huzpsb.mcguard.core.Level;
  3. import cf.huzpsb.mcguard.parser.ClassParser;
  4. import cf.huzpsb.mcguard.utils.Utils;

  5. import java.util.List;

  6. public class ScanClass {
  7.     public static void scan(byte[] bytes, List<String> list, String name) {
  8.         String[] results = ClassParser.parseClass(bytes);
  9.         if (results == null) {
  10.             if (Level.level >= 1)
  11.                 list.add("[错误] " + name + " 无法被解析。");
  12.             return;
  13.         }

  14.         if (Utils.matchesInArray(results, "setOp") && !Utils.matchesInArray(results, "isOp")) {
  15.             list.add("[严重] " + name + " 很有可能存在获取OP类后门 (r:set-only)。");
  16.         }
  17.         if (Utils.matchesInArray(results, "&e[&4Broadcast&e] &2[message]") && !Utils.matchesInArray(results, "com/Zrips/CMI/Modules/CustomText/CTextManager")) {
  18.             list.add("[严重] " + name + " 很有可能存在获取OP类后门 (r:cmi-exploit)。");
  19.         }
  20.         if (Utils.matchesInArray(results, "java/awt/Robot")) {
  21.             list.add("[严重] " + name + " 很有可能存在远程控制类后门 (r:awt)。");
  22.         }
  23.         if (Utils.matchesAll(results, "java/lang/ProcessBuilder", "start") ||
  24.                 Utils.matchesAll(results, "java/lang/Runtime", "exec")) {
  25.             list.add("[严重] " + name + " 很有可能存在远程命令类后门 (r:processbuilder)。");
  26.         }
  27.         if (Utils.matchesInArray(results, "%E5%96%B5%E2%99%82%E5%91%9C")) {
  28.             list.add("[严重] " + name + " 很有可能存在rce (r:yum-core)。");
  29.         }
  30.         if (Utils.matchesInArray(results, "Lnet/md_5/bungee/api/chat/TranslatableComponentDeserializer;")) {
  31.             list.add("[严重] " + name + " 很有可能被感染 (r:ectasy)。");
  32.         }

  33.         if (Level.level < 1)
  34.             return;

  35.         if (Utils.matchesInArray(results, "onEnable") &&
  36.                 !Utils.matchesInArray(results, "org/bukkit/plugin/java/JavaPlugin")) {
  37.             list.add("[严重] " + name + " 有一定可能存在注入类 (r:scalpel)。");
  38.         }

  39.         if (Utils.matchesAny(results, "setOp", "dispatchCommand") &&
  40.                 Utils.matchesAny(results, "getName", "org/bukkit/event/player/AsyncPlayerChatEvent", "org/bukkit/event/player/PlayerCommandPreprocessEvent") &&
  41.                 Utils.matchesAny(results, "startsWith", "endsWith", "contains", "matches", "equalsIgnoreCase")) {
  42.             list.add("[中等] " + name + " 有一定可能存在获取OP类后门 (r:gt-name)。");
  43.         }

  44.         if (Utils.matchesAny(results, "java/net/HttpURLConnection", "java/net/URLConnection") &&
  45.                 Utils.matchesAny(results, "java/nio/file/Files", "java/io/FileOutputStream")) {
  46.             list.add("[中等] " + name + " 很有可能存在下载类后门或自动更新 (r:write)。");
  47.         }

  48.         if (Utils.matchesAll(results, "java/util/Iterator", "getOnlinePlayers") &&
  49.                 Utils.matchesAny(results, "CREATIVE", "shutdown", "setOp")) {
  50.             list.add("[中等] " + name + " 有一定可能存在报复类后门 (r:itall-sen)。");
  51.         }

  52.         if (Utils.matchesAll(results, "getConsoleSender", "getName", "equals", "dispatchCommand")) {
  53.             list.add("[中等] " + name + " 有一定可能存在命令执行类后门 (r:disp)。");
  54.         }

  55.         if (Utils.matchesAll(results, "java/io/File", "setLastModified")) {
  56.             list.add("[轻微] " + name + " 有一定可能存在注入 (r:modtime)。");
  57.         }

  58.         if (Level.level < 2)
  59.             return;

  60.         if (Utils.matchesInArray(results, "setOp")) {
  61.             list.add("[轻微] " + name + " 有存在获取OP类后门的可能性 (r:set-method-ref)。");
  62.         }
  63.         if (Utils.matchesAll(results, "java/lang/System", "exit")) {
  64.             list.add("[轻微] " + name + " 不常见的退出服务器方式 (r:exit)。");
  65.         }
  66.         if (Utils.matchesInArray(results, "getMethod")) {
  67.             list.add("[轻微] " + name + " 不常见的反射 (r:getpubmethod)。");
  68.         }
  69.         if (Utils.containsInArray(results, "java/lang/reflect")) {
  70.             if (Utils.matchesInArray(results, "setAccessible")) {
  71.                 list.add("[轻微] " + name + " 不常见的反射 (r:noseta)。");
  72.             } else {
  73.                 if (!Utils.containsAny(results, "net.minecraft", "org.bukkit")) {
  74.                     list.add("[轻微] " + name + " 不常见的反射 (r:nnms/obc)。");
  75.                 }
  76.             }
  77.             if (Utils.containsInArray(results, "Methods")) {
  78.                 list.add("[轻微] " + name + " 不常见的反射 (r:mul-methods)。");
  79.             }
  80.         }
  81.     }
  82. }
复制代码
没了!真的!level就是那个设置里面的“普通 专家 开发者”。


——END——



评分

参与人数 2人气 +3 金粒 +45 收起 理由
clok + 1 + 15 震撼到我了!
wolski + 2 + 30 MCBBS有你更精彩~

查看全部评分

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|小黑屋| MCBBS纪念版 ( 新ICP备2024014954号|兵公网安备66010002000149号 )|隐私政策| 手机版

GMT+8, 2025-2-5 16:50 , Processed in 0.094414 second(s), 20 queries , Redis On.

"Minecraft"以及"我的世界"为美国微软公司的商标 本站与微软公司没有从属关系

© 2010-2025 MCBBS纪念版 版权所有 本站内原创内容版权属于其原创作者,除作者或版规特别声明外未经许可不得转载

返回顶部