【警告】 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,标识常量类型。
别跑!我这里有一个你看得懂的版本- package cf.huzpsb.mcguard.parser;
- import java.util.ArrayList;
- import java.util.List;
- public class ClassParser {
- public static String[] parseClass(byte[] classFile) {
- try {
- int cpCount = Byte.toUnsignedInt(classFile[8]) * 256 + Byte.toUnsignedInt(classFile[9]);
- cpCount--;
- int offset = 10;
- List<String> cp = new ArrayList<>();
- for (int i = 0; i < cpCount; i++) {
- int tag = classFile[offset];
- offset++;
- switch (tag) {
- case 1: // Utf8
- int len = Byte.toUnsignedInt(classFile[offset]) * 256 + Byte.toUnsignedInt(classFile[offset + 1]);
- offset += 2;
- String s = new String(classFile, offset, len);
- cp.add(s);
- offset += len;
- break;
- case 7: // Class
- case 8:
- case 16: // MethodType
- case 19:
- case 20:
- offset += 2;
- break;
- case 3:
- case 4:
- case 9:
- case 10:
- case 11:
- case 12:
- case 17:
- case 18:
- offset += 4;
- break;
- case 15:
- offset += 3;
- break;
- case 5:
- case 6:
- offset += 8;
- i++;
- break;
- case 2:
- case 13:
- case 14:
- throw new Exception("非标准的常量池标签: " + tag);
- default:
- throw new Exception("无法识别的常量池标签: " + tag);
- }
- }
- return cp.toArray(new String[0]);
- } catch (Exception ex) {
- return null;
- }
- }
- }
复制代码 ▌Part 2 基于规则的常量池扫描
Why it works?
西江月·证明
即得易见平凡,仿照上例显然。
留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立,略去过程QED,由上可知证毕。 - package cf.huzpsb.mcguard.scan;
- import cf.huzpsb.mcguard.core.Level;
- import cf.huzpsb.mcguard.parser.ClassParser;
- import cf.huzpsb.mcguard.utils.Utils;
- import java.util.List;
- public class ScanClass {
- public static void scan(byte[] bytes, List<String> list, String name) {
- String[] results = ClassParser.parseClass(bytes);
- if (results == null) {
- if (Level.level >= 1)
- list.add("[错误] " + name + " 无法被解析。");
- return;
- }
- if (Utils.matchesInArray(results, "setOp") && !Utils.matchesInArray(results, "isOp")) {
- list.add("[严重] " + name + " 很有可能存在获取OP类后门 (r:set-only)。");
- }
- if (Utils.matchesInArray(results, "&e[&4Broadcast&e] &2[message]") && !Utils.matchesInArray(results, "com/Zrips/CMI/Modules/CustomText/CTextManager")) {
- list.add("[严重] " + name + " 很有可能存在获取OP类后门 (r:cmi-exploit)。");
- }
- if (Utils.matchesInArray(results, "java/awt/Robot")) {
- list.add("[严重] " + name + " 很有可能存在远程控制类后门 (r:awt)。");
- }
- if (Utils.matchesAll(results, "java/lang/ProcessBuilder", "start") ||
- Utils.matchesAll(results, "java/lang/Runtime", "exec")) {
- list.add("[严重] " + name + " 很有可能存在远程命令类后门 (r:processbuilder)。");
- }
- if (Utils.matchesInArray(results, "%E5%96%B5%E2%99%82%E5%91%9C")) {
- list.add("[严重] " + name + " 很有可能存在rce (r:yum-core)。");
- }
- if (Utils.matchesInArray(results, "Lnet/md_5/bungee/api/chat/TranslatableComponentDeserializer;")) {
- list.add("[严重] " + name + " 很有可能被感染 (r:ectasy)。");
- }
- if (Level.level < 1)
- return;
- if (Utils.matchesInArray(results, "onEnable") &&
- !Utils.matchesInArray(results, "org/bukkit/plugin/java/JavaPlugin")) {
- list.add("[严重] " + name + " 有一定可能存在注入类 (r:scalpel)。");
- }
- if (Utils.matchesAny(results, "setOp", "dispatchCommand") &&
- Utils.matchesAny(results, "getName", "org/bukkit/event/player/AsyncPlayerChatEvent", "org/bukkit/event/player/PlayerCommandPreprocessEvent") &&
- Utils.matchesAny(results, "startsWith", "endsWith", "contains", "matches", "equalsIgnoreCase")) {
- list.add("[中等] " + name + " 有一定可能存在获取OP类后门 (r:gt-name)。");
- }
- if (Utils.matchesAny(results, "java/net/HttpURLConnection", "java/net/URLConnection") &&
- Utils.matchesAny(results, "java/nio/file/Files", "java/io/FileOutputStream")) {
- list.add("[中等] " + name + " 很有可能存在下载类后门或自动更新 (r:write)。");
- }
- if (Utils.matchesAll(results, "java/util/Iterator", "getOnlinePlayers") &&
- Utils.matchesAny(results, "CREATIVE", "shutdown", "setOp")) {
- list.add("[中等] " + name + " 有一定可能存在报复类后门 (r:itall-sen)。");
- }
- if (Utils.matchesAll(results, "getConsoleSender", "getName", "equals", "dispatchCommand")) {
- list.add("[中等] " + name + " 有一定可能存在命令执行类后门 (r:disp)。");
- }
- if (Utils.matchesAll(results, "java/io/File", "setLastModified")) {
- list.add("[轻微] " + name + " 有一定可能存在注入 (r:modtime)。");
- }
- if (Level.level < 2)
- return;
- if (Utils.matchesInArray(results, "setOp")) {
- list.add("[轻微] " + name + " 有存在获取OP类后门的可能性 (r:set-method-ref)。");
- }
- if (Utils.matchesAll(results, "java/lang/System", "exit")) {
- list.add("[轻微] " + name + " 不常见的退出服务器方式 (r:exit)。");
- }
- if (Utils.matchesInArray(results, "getMethod")) {
- list.add("[轻微] " + name + " 不常见的反射 (r:getpubmethod)。");
- }
- if (Utils.containsInArray(results, "java/lang/reflect")) {
- if (Utils.matchesInArray(results, "setAccessible")) {
- list.add("[轻微] " + name + " 不常见的反射 (r:noseta)。");
- } else {
- if (!Utils.containsAny(results, "net.minecraft", "org.bukkit")) {
- list.add("[轻微] " + name + " 不常见的反射 (r:nnms/obc)。");
- }
- }
- if (Utils.containsInArray(results, "Methods")) {
- list.add("[轻微] " + name + " 不常见的反射 (r:mul-methods)。");
- }
- }
- }
- }
复制代码 没了!真的!level就是那个设置里面的“普通 专家 开发者”。
——END—— |