|
| 1 | +# asm |
| 2 | + |
| 3 | +## 分析类 |
| 4 | + |
| 5 | +分析类的代码 |
| 6 | + |
| 7 | +```java |
| 8 | +public class Test { |
| 9 | + public boolean aBoolean = true; |
| 10 | + |
| 11 | + public void render(){ |
| 12 | + System.out.println("hello asm"); |
| 13 | + } |
| 14 | +} |
| 15 | +``` |
| 16 | + |
| 17 | +MyClassVisitors类 |
| 18 | + |
| 19 | +```java |
| 20 | +import jdk.internal.org.objectweb.asm.ClassVisitor; |
| 21 | +import jdk.internal.org.objectweb.asm.FieldVisitor; |
| 22 | +import jdk.internal.org.objectweb.asm.MethodVisitor; |
| 23 | +import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| 24 | + |
| 25 | +public class MyClassVisitors extends ClassVisitor { |
| 26 | + public MyClassVisitors(){ |
| 27 | + super(ASM5); |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * 继承关系 |
| 32 | + * @param version |
| 33 | + * @param access |
| 34 | + * @param name |
| 35 | + * @param signature |
| 36 | + * @param superName |
| 37 | + * @param interfaces |
| 38 | + */ |
| 39 | + public void visit(int version,int access,String name,String signature,String superName,String[] interfaces){ |
| 40 | + System.out.println(name + "extends " + superName + "{"); |
| 41 | + super.visit(version,access,name,signature,superName,interfaces); |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * 属性变量 |
| 46 | + * @param access |
| 47 | + * @param name |
| 48 | + * @param desc |
| 49 | + * @param signature |
| 50 | + * @param value |
| 51 | + * @return |
| 52 | + */ |
| 53 | + @Override |
| 54 | + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { |
| 55 | + System.out.println(desc + " " + name); |
| 56 | + return super.visitField(access, name, desc, signature, value); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * 方法 |
| 61 | + * @param access |
| 62 | + * @param name |
| 63 | + * @param desc |
| 64 | + * @param signature |
| 65 | + * @param exceptions |
| 66 | + * @return |
| 67 | + */ |
| 68 | + @Override |
| 69 | + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { |
| 70 | + System.out.println(name + " " + desc); |
| 71 | + return super.visitMethod(access, name, desc, signature, exceptions); |
| 72 | + } |
| 73 | + |
| 74 | + @Override |
| 75 | + public void visitEnd() { |
| 76 | + System.out.println("}"); |
| 77 | + super.visitEnd(); |
| 78 | + } |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +主程序 |
| 83 | + |
| 84 | +```java |
| 85 | +import jdk.internal.org.objectweb.asm.ClassReader; |
| 86 | + |
| 87 | +/** |
| 88 | + * 通过asm框架分析类 |
| 89 | + */ |
| 90 | +public class AnalysisClass { |
| 91 | + public static void main(String[] args)throws Exception { |
| 92 | + MyClassVisitors myClassVisitors = new MyClassVisitors(); |
| 93 | + ClassReader classReader = new ClassReader(Test.class.getName()); |
| 94 | + classReader.accept(myClassVisitors,0); |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | + |
| 104 | + |
| 105 | +>该部分也是GI的核心。https://xz.aliyun.com/t/10363 |
| 106 | +
|
| 107 | +## 生成类 |
| 108 | + |
| 109 | +>感觉用于webshell中。 |
| 110 | +
|
| 111 | +```java |
| 112 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 113 | +import jdk.internal.org.objectweb.asm.MethodVisitor; |
| 114 | +import java.io.FileOutputStream; |
| 115 | +import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| 116 | + |
| 117 | +public class WriteClass { |
| 118 | + public static void main(String[] args) throws Exception { |
| 119 | + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
| 120 | + // java1.8 public修饰 路径 签名 父类 接口 |
| 121 | + classWriter.visit(V1_8, ACC_PUBLIC, "com/firebasky/utils/asm/learn/Learn2Test", null, "java/lang/Object", null); |
| 122 | + //public和static修饰 方法名 描述符 签名 异常 |
| 123 | + MethodVisitor render = classWriter.visitMethod(ACC_PUBLIC + ACC_STATIC, "render", "()V", null, null); |
| 124 | + //插入一个字段是方法里面插入 操作码 路径 名字 描述符 |
| 125 | + render.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); |
| 126 | + //插入一个ldc |
| 127 | + render.visitLdcInsn("Hello asm!"); |
| 128 | + //插入一个方法 操作码 路径 方法名 参数 是否为接口的方法 |
| 129 | + render.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); |
| 130 | + //插入返回值 |
| 131 | + render.visitInsn(RETURN); |
| 132 | + //设置栈和局部变量大小 |
| 133 | + render.visitMaxs(2, 1); |
| 134 | + //结束 |
| 135 | + render.visitEnd(); |
| 136 | + classWriter.visitEnd(); |
| 137 | + //生成文件 |
| 138 | + byte[] bytes = classWriter.toByteArray(); |
| 139 | + FileOutputStream outputStream = new FileOutputStream("d://1.class"); |
| 140 | + outputStream.write(bytes); |
| 141 | + outputStream.close(); |
| 142 | + } |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +生成的类 |
| 147 | + |
| 148 | +```java |
| 149 | +package com.firebasky.utils.asm.learn; |
| 150 | + |
| 151 | +public class Learn2Test { |
| 152 | + public static void render() { |
| 153 | + System.out.println("Hello asm!"); |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +``` |
| 158 | + |
| 159 | +## 加载或移除类成员 |
| 160 | + |
| 161 | +主程序 |
| 162 | + |
| 163 | +```java |
| 164 | +import jdk.internal.org.objectweb.asm.ClassReader; |
| 165 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 166 | + |
| 167 | +import java.io.FileOutputStream; |
| 168 | + |
| 169 | +public class Learn3 { |
| 170 | + public static void main(String[] args)throws Exception { |
| 171 | + ClassReader classReader = new ClassReader(Test.class.getName()); |
| 172 | + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
| 173 | + MyClassVisitor myClassVisitor = new MyClassVisitor(classWriter); |
| 174 | + classReader.accept(myClassVisitor,0); |
| 175 | + byte[] bytes = classWriter.toByteArray(); |
| 176 | + FileOutputStream outputStream = new FileOutputStream("d://1.class"); |
| 177 | + outputStream.write(bytes); |
| 178 | + outputStream.close(); |
| 179 | + } |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +MyClassVisitor类 |
| 184 | + |
| 185 | +```java |
| 186 | +import jdk.internal.org.objectweb.asm.ClassVisitor; |
| 187 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 188 | +import jdk.internal.org.objectweb.asm.FieldVisitor; |
| 189 | +import jdk.internal.org.objectweb.asm.MethodVisitor; |
| 190 | +import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| 191 | + |
| 192 | +public class MyClassVisitor extends ClassVisitor { |
| 193 | + |
| 194 | + public MyClassVisitor(ClassWriter classWriter) { |
| 195 | + super(ASM5, classWriter); |
| 196 | + } |
| 197 | + |
| 198 | + @Override |
| 199 | + public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { |
| 200 | + if(name.equals("aBoolean")){ |
| 201 | + return null; |
| 202 | + } |
| 203 | + return super.visitField(access, name, desc, signature, value); |
| 204 | + } |
| 205 | + |
| 206 | + @Override |
| 207 | + public MethodVisitor visitMethod(int access, String name, String desc, String signature,String[] exceptions) { |
| 208 | + if(name.equals("render")){ |
| 209 | + return null; |
| 210 | + } |
| 211 | + return super.visitMethod(access, name, desc, signature, exceptions); |
| 212 | + } |
| 213 | + |
| 214 | + @Override |
| 215 | + public void visitEnd() { |
| 216 | + super.visitField(ACC_PRIVATE,"name","Ljava/lang/String;",null,null).visitEnd(); |
| 217 | + super.visitMethod(ACC_PRIVATE,"name","(Ljava/lang/String;)V",null,null).visitEnd(); |
| 218 | + super.visitEnd(); |
| 219 | + } |
| 220 | +} |
| 221 | +``` |
| 222 | + |
| 223 | +修改之后的代码 |
| 224 | + |
| 225 | +```java |
| 226 | +package com.firebasky.utils.asm.learn; |
| 227 | + |
| 228 | +public class Test { |
| 229 | + private String name; |
| 230 | + |
| 231 | + public Test() { |
| 232 | + this.aBoolean = true; |
| 233 | + } |
| 234 | + private void name(String var1) { |
| 235 | + } |
| 236 | +} |
| 237 | + |
| 238 | +``` |
| 239 | + |
| 240 | +## 创建对象和数组 |
| 241 | + |
| 242 | +```java |
| 243 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 244 | +import jdk.internal.org.objectweb.asm.MethodVisitor; |
| 245 | + |
| 246 | +import java.io.FileOutputStream; |
| 247 | + |
| 248 | +import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| 249 | + |
| 250 | +public class Learn4 { |
| 251 | + public static void main(String[] args)throws Exception { |
| 252 | + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
| 253 | + MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
| 254 | + methodVisitor.visitTypeInsn(NEW,"java/lang/String"); |
| 255 | + methodVisitor.visitLdcInsn("xxx");//常量 |
| 256 | + methodVisitor.visitMethodInsn(INVOKEVIRTUAL,"java/lang/String","<init>","(Ljava/lang/String;)V",false); |
| 257 | + //生成文件 |
| 258 | + byte[] bytes = classWriter.toByteArray(); |
| 259 | + FileOutputStream outputStream = new FileOutputStream("d://1.class"); |
| 260 | + outputStream.write(bytes); |
| 261 | + outputStream.close(); |
| 262 | + } |
| 263 | +} |
| 264 | +``` |
| 265 | + |
| 266 | +数组 |
| 267 | + |
| 268 | +```java |
| 269 | +methodVisitor.visitIntInsn(SIPUSH,2);//数组长度 |
| 270 | +methodVisitor.visitIntInsn(NEWARRAY,T_BYTE);//类型是byte |
| 271 | +methodVisitor.visitInsn(DUP);//压 |
| 272 | +methodVisitor.visitIntInsn(SIPUSH,0);//插入数组0位置 |
| 273 | +methodVisitor.visitIntInsn(SIPUSH,1); |
| 274 | +methodVisitor.visitInsn(AASTORE);//保存 |
| 275 | +``` |
| 276 | + |
| 277 | +## 字符串混淆 |
| 278 | + |
| 279 | +就是在写入的时候做一个转换。 |
| 280 | + |
| 281 | +```java |
| 282 | +import jdk.internal.org.objectweb.asm.ClassReader; |
| 283 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 284 | + |
| 285 | +import java.io.FileOutputStream; |
| 286 | +import java.io.IOException; |
| 287 | + |
| 288 | +public class Learn5 { |
| 289 | + public static void main(String[] args) throws IOException { |
| 290 | + ClassReader classReader = new ClassReader(Test.class.getName()); |
| 291 | + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); |
| 292 | + MyClassVisitor1 myClassVisitor = new MyClassVisitor1(classWriter); |
| 293 | + classReader.accept(myClassVisitor,0); |
| 294 | + byte[] bytes = classWriter.toByteArray(); |
| 295 | + FileOutputStream outputStream = new FileOutputStream("d://1.class"); |
| 296 | + outputStream.write(bytes); |
| 297 | + outputStream.close(); |
| 298 | + } |
| 299 | +} |
| 300 | +``` |
| 301 | + |
| 302 | +MyClassVisitor1 |
| 303 | + |
| 304 | +```java |
| 305 | +import jdk.internal.org.objectweb.asm.ClassVisitor; |
| 306 | +import jdk.internal.org.objectweb.asm.ClassWriter; |
| 307 | +import jdk.internal.org.objectweb.asm.MethodVisitor; |
| 308 | +import java.nio.charset.StandardCharsets; |
| 309 | + |
| 310 | +import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| 311 | + |
| 312 | +/** |
| 313 | + * 拦截字符串修改 |
| 314 | + */ |
| 315 | +public class MyClassVisitor1 extends ClassVisitor { |
| 316 | + public MyClassVisitor1(ClassWriter classWriter) { |
| 317 | + super(ASM5, classWriter); |
| 318 | + } |
| 319 | + @Override |
| 320 | + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { |
| 321 | + return new MethodVisitor(api,super.visitMethod(access,name,desc,signature,exceptions)) { |
| 322 | + @Override |
| 323 | + public void visitLdcInsn(Object cst) { |
| 324 | + if(cst instanceof String){ |
| 325 | + byte[] bytes = ((String) cst).getBytes(StandardCharsets.UTF_8);//转换bytes |
| 326 | + mv.visitTypeInsn(NEW,"java/lang/String"); |
| 327 | + mv.visitInsn(DUP); |
| 328 | + mv.visitIntInsn(SIPUSH,bytes.length); |
| 329 | + mv.visitIntInsn(NEWARRAY,T_BYTE); |
| 330 | + for(int i = 0;i<bytes.length;i++){ |
| 331 | + mv.visitInsn(DUP); |
| 332 | + mv.visitIntInsn(SIPUSH,i); |
| 333 | + mv.visitIntInsn(SIPUSH,bytes[i]); |
| 334 | + mv.visitInsn(AASTORE); |
| 335 | + } |
| 336 | + mv.visitLdcInsn("UTF-8"); |
| 337 | + mv.visitMethodInsn(INVOKEVIRTUAL,"java/lang/String","<init>","([BLjava/lang/String;)V",false); |
| 338 | + }else { |
| 339 | + super.visitLdcInsn(cst); |
| 340 | + } |
| 341 | + } |
| 342 | + }; |
| 343 | + } |
| 344 | +} |
| 345 | +``` |
| 346 | + |
| 347 | +将字符串转换成bytes |
0 commit comments