为什么java代理会卡住并且不执行任何操作?

问题描述 投票:0回答:1

我正在为大学写一篇学期论文。任务是编写两个程序,其中一个程序收集一些信息,用数字密钥对其进行签名,并将加密数据和密钥保存到单独的文件中。下一个程序收集相同的信息,读取加密的数据和密钥,并验证数字签名。

第二步是编写一个使用 java.lang.instrument.Instrumentation 的代理;还可能使用 javaassist 等第三方库进行字节码替换,以便程序始终给出成功的验证结果

我尝试在教程的帮助下实现这一点,但我的程序卡在了更改阶段

这里是需要改的字节码的分析

static void checkSign(java.lang.String, java.lang.String, java.lang.String) throws java.lang.Exception;
    Code:
       0: new           #206                // class java/io/BufferedReader
       3: dup
       4: new           #258                // class java/io/FileReader
       7: dup
       8: aload_0
       9: invokespecial #260                // Method java/io/FileReader."<init>":(Ljava/lang/String;)V
      12: invokespecial #219                // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
      15: astore_3
      16: aload_3
      17: invokevirtual #225                // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
      20: astore        4
      22: invokestatic  #262                // Method java/util/Base64.getDecoder:()Ljava/util/Base64$Decoder;
      25: aload         4
      27: invokevirtual #268                // Method java/util/Base64$Decoder.decode:(Ljava/lang/String;)[B
      30: astore        5
      32: aload_3
      33: invokevirtual #245                // Method java/io/BufferedReader.close:()V
      36: new           #206                // class java/io/BufferedReader
      39: dup
      40: new           #258                // class java/io/FileReader
      43: dup
      44: aload_1
      45: invokespecial #260                // Method java/io/FileReader."<init>":(Ljava/lang/String;)V
      48: invokespecial #219                // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
      51: astore        6
      53: aload         6
      55: invokevirtual #225                // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
      58: astore        7
      60: aload         6
      62: invokevirtual #245                // Method java/io/BufferedReader.close:()V
      65: invokestatic  #262                // Method java/util/Base64.getDecoder:()Ljava/util/Base64$Decoder;
      68: aload         7
      70: invokevirtual #268                // Method java/util/Base64$Decoder.decode:(Ljava/lang/String;)[B
      73: astore        8
      75: ldc_w         #274                // String RSA
      78: invokestatic  #276                // Method java/security/KeyFactory.getInstance:(Ljava/lang/String;)Ljava/security/KeyFactory;
      81: astore        9
      83: new           #281                // class java/security/spec/X509EncodedKeySpec
      86: dup
      87: aload         8
      89: invokespecial #283                // Method java/security/spec/X509EncodedKeySpec."<init>":([B)V
      92: astore        10
      94: aload         9
      96: aload         10
      98: invokevirtual #286                // Method java/security/KeyFactory.generatePublic:(Ljava/security/spec/KeySpec;)Ljava/security/PublicKey;
     101: checkcast     #290                // class java/security/interfaces/RSAPublicKey
     104: astore        11
     106: ldc_w         #274                // String RSA
     109: invokestatic  #292                // Method javax/crypto/Cipher.getInstance:(Ljava/lang/String;)Ljavax/crypto/Cipher;
     112: astore        12
     114: aload         12
     116: iconst_2
     117: aload         11
     119: invokevirtual #297                // Method javax/crypto/Cipher.init:(ILjava/security/Key;)V
     122: aload         12
     124: aload         5
     126: invokevirtual #301                // Method javax/crypto/Cipher.doFinal:([B)[B
     129: astore        13
     131: new           #17                 // class java/lang/String
     134: dup
     135: aload         13
     137: invokespecial #304                // Method java/lang/String."<init>":([B)V
     140: astore        14
     142: aload         14
     144: aload_2
     145: invokevirtual #237                // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     148: ifeq          163
     151: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     154: ldc_w         #305                // String Verification successfully!
     157: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     160: goto          171
     163: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
     166: ldc           #204                // String Verification failed!
     168: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     171: return

这是我的经纪人

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class AgentMain {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Ha, ha! This program was hacked ;-)");
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                    ProtectionDomain protectionDomain, byte[] classfileBuffer) {

                if (className.equals("Defender")) {
                    try {
                        System.out.println("I'm here");
                        ClassPool cp = ClassPool.getDefault();
                        System.out.println("Class pool created");
                        CtClass cc = cp.get("Defender"); 

                        CtMethod method = cc.getDeclaredMethod("checkSign");

                        String newBody = "{" +
                                "    System.out.println(\"Verification successfully!\");" +
                                "}";

                        method.setBody(newBody);

                        return cc.toBytecode();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
               
                return classfileBuffer;
            }
        });
    }
}

我特意安排了“我在这里”消息的输出,以了解错误在哪里。

将所有类编译成jar后,我用命令运行它

java -javaagent:HackAgent.jar -jar Defender.jar

但结果我明白了

result

我做错了什么?

java bytecode java-bytecode-asm javassist javaagents
1个回答
0
投票

这个问题显然是那个问题的后续问题,该问题已关闭,因为您只提供了原始代码,但没有解释您试图解决问题的内容。在这里,情况恰恰相反。不管怎样,把这两个问题结合起来,我看到你自己尝试了一些东西,而不仅仅是指望完全为你工作,这是值得赞扬的。因此,尽管它不是 Javassist 而是 AspectJ 答案,但我想向您展示如何解决问题。我尝试使用你的原始代码。

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class DefenderAspect {
  @Around("cflow(execution(void checkSign(String, String, String)) && args(*, *, hash)) && call(String.new(byte[]))")
  public String replaceDecryptedSignString(String hash) {
    return hash;
  }
}

切入点告诉 AspectJ 选择

String(byte[])
构造函数调用(如果它们位于
checkSign
方法的控制流中)。它还将第三个参数
hash
绑定到通知方法参数,并使用它来简单地返回构造函数调用应该返回的内容,以满足
dectyptedSignString.equals(hash)
语句中的
if
条件。

该解决方案适用于编译后和加载时编织。

当然,就像我在评论中所说的那样,您可以使用 ASM、Byte Buddy、BCEL、Javassist 或类似框架设计类似的解决方案。 AspectJ 只是我选择的工具,因为我喜欢它优雅的语法。

© www.soinside.com 2019 - 2024. All rights reserved.