如何在java程序中禁用堆栈跟踪生成?

我想禁用在抛出exception时生成的堆栈跟踪。 我用过,

Runtime.getRuntime().traceInstructions(false); Runtime.getRuntime().traceMethodCalls(false); 

但我仍然可以看到跟踪生成。 你怎么能这样做? 此外,我需要检测是否有人正在调试我的课程。

我想禁用所有exception跟踪。 我不能使用混淆,因为我的产品是一个将用于开发的SDK。 我还提供了一个Runtime,当人们想要部署使用我的SDK构建的应用程序时使用它。 我的要求是任何使用我的Runtime jar的人都不应该能够调试编写的代码……或者至少我会通过避免从我的运行时jar生成堆栈跟踪来使调试变得困难。

我找到的一种方法是所有来自我的运行时jar的exception,我只是捕获它们并在exception对象上设置一个空的StackTraceElement数组并重新抛出它…

为何如此要求? 假设你使用我的SDK开发一个应用程序。(SDK jar不能与你的应用程序捆绑在一起..我已经限制了它,那就是最终:) !!)现在要在你的客户端机器上运行你的应用程序,你(或客户端)需要安装客户端计算机上的运行时并运行您的应用程序。 现在,如果您的客户使用我的运行时jar子开始开发自己的应用程序,该怎么办 这对我的生意构成威胁….这就是为什么这个可怕的要求。

为什么禁用堆栈跟踪?
通过禁用堆栈跟踪生成或方法调用跟踪生成我想用我的Runtime jar开发代码很困难,这就是为什么我以这种方式开始我的问题…建议一些其他解决方案来实现这样的要求……

如果禁用堆栈跟踪生成,JVM中有一些复杂的部分(至少是Sun的JVM实现)不起作用(我在实现一些reflection支持方法时看到了这一点)。 所以我认为堆栈跟踪生成根本不能被禁用。 Runtime.trace*()方法是关于其他东西的(调试工具比堆栈跟踪更彻底)。

一般而言,只有通过字节码检测(在加载时使用额外指令修改字节码),才能透明地分析任何Java代码。 对这种分析的唯一已知防御(我假设你试图保持你的代码内部机密)是混淆。 请参阅ProGuard 。 混淆会使堆栈跟踪对任何过度好奇的用户都无用(而且,遗憾的是,由于同样的原因,它也会使调试变得非常困难)。

我也很想知道你为什么要这样做,但如果你真的有理由,你至少有两个选择:

如果要为自己的Exception实现禁用堆栈跟踪生成,可以简单地覆盖fillInStackTrace方法:

 public static class MyException extends Exception { @Override public Throwable fillInStackTrace() { return this; } } 

如果要为所有exception禁用它,可以使用字节代码检测代理来替换Throwable类中的fillInStackTrace方法。 但这只适用于Java 6,因为不允许在Java 5中使用检测使用Java方法替换本机方法(fillInStackTrace)。

  1. 我认为代码不可能知道它正在被调试,除非通过间接(和不可靠)的方式来测量执行代码序列所需的时间。

  2. 无法禁用所有堆栈跟踪。 您可以通过重写Throwable.fillInStackTrace()来禁用您自己定义的exception类的stracktraces。 但这对于你无法改变的课程不起作用。

但是如果你正在考虑做这些事情以防止逆向工程,即使你能做到这一点,你也会浪费你的时间。 对于黑客来说,识别应用程序的反向反向工程代码并编辑相关的字节码文件以禁用它是很简单的。

编辑 – 我已经修改了我对你要做的事情的看法。 鉴于您正在做的是分发一个SDK,您期望客户将其嵌入到自己的应用程序中,禁用整个Java应用程序的堆栈跟踪将被视为客户敌对行为 IMO。 作为保护“宝贵”IP的副作用,您使客户/开发人员难以调试自己的代码。 即使代码在调用堆栈上没有您宝贵的方法!

如果我是客户,我可能更愿意发送混淆代码而不是这样。 但最有可能的是,我会非常努力地找到一个替代软件供应商,该供应商并未将其付费客户视为小偷

是否要为所有例外禁用它?

如果不知道你想要实现什么,我会说这是走错路。 如果你期望抛出exception,你很乐意忽略它,你应该明确地捕获并处理它(处理它只是意味着忽略它,或者记录没有完整堆栈跟踪的短消息)。

Throwable.setStackTrace(StackTraceElement [] stackTrace)将在调用后阻止对stackTrace的任何添加:

 Throwable t = new Throwable(); StackTraceElement[] myStackTrace = new StackTraceElement[] { new StackTraceElement("MySDKClass","MySDKMethod","MySDKFile",0) }; t.setStackTrace(trace); 

您可以将所有例外重定向到其他位置,例如:

 Thread.setDefaultUncaughtExceptionHandler( (t, e) -> System.err.println("There's nothing to see here")); 

或者干脆:

 Thread.setDefaultUncaughtExceptionHandler(null); 

注意:除非您想给同事们带来困难,否则永远不要在制作中使用上述代码