在 Java 中伪造堆栈跟踪

2024-02-10

当您在 Java 中使用 RMI 时,异常的远程堆栈跟踪将在您收到异常时添加到前面,有点像这样:

ERROR Client received error when doing stuff:
myapp.FooBarException: bla
 at server.myMethod()
 at rmi.callHandler() // and now, on the next line comes the client
 at rmi.sendCall();
 at client.doServerMethod()
 at Thread.run()

这种堆栈跟踪“伪造”是如何完成的?


我想要它做什么(除了感兴趣之外)?好吧,如果我能做到这一点,那会对我有帮助:

outer() {

  thread = new Thread(...
      inner();
      // inner() throws
      // RuntimeException
      //  at inner();
      //  at Runnable.run();
      //  at Thread.run();
      //  at outer();
      //  at lalalala();
      //  ...

  ).start();

  thread.join();

}

并使其抛出异常inner()将有outer()(以及链下游的方法)也在堆栈跟踪中,用于记录目的。


这有点简单:

Throwable 有方法getStackTrace() http://download.oracle.com/javase/6/docs/api/java/lang/Throwable.html#getStackTrace%28%29 and setStackTrace().

From 我的项目之一 http://www.fencing-game.de/(非开源,但也许有一天我会打开远程调用引擎):

    /**
     * Setzt den Stack-Trace zusammen. Das untere Ende (tiefer in der
     * Aufrufhierarchie, am Anfang des Arrays/der Ausgabe) ist das,
     * welches im Throwable schon drin ist, das obere Ende wird aus
     * dem aktuellen Stack genommen. Dazwischen
     * kommt ein "Remote-Aufruf-Markierer".
     */

为方便起见翻译如下:

合并堆栈跟踪。低端(在调用层次结构的更深处,在 数组的末尾/输出)是堆栈中已有的内容,即上端 将从当前堆栈中获取。在它们之间我们将放置一个远程呼叫标记.

    private void mergeStackTraces(Throwable error)
    {
        StackTraceElement[] currentStack =
            new Throwable().getStackTrace();
        int currentStackLimit = 5; // TODO: raussuchen
        StackTraceElement[] oldStack =
            error.getStackTrace();
        StackTraceElement[] zusammen =
            new StackTraceElement[currentStack.length - currentStackLimit +
                                  oldStack.length + 1];
        System.arraycopy(oldStack, 0, zusammen, 0, oldStack.length);
        zusammen[oldStack.length] =
            new StackTraceElement("══════════════════════════",
                                  "<remote call %" +callID+ ">",
                                  "", -3);
        System.arraycopy(currentStack, currentStackLimit,
                         zusammen, oldStack.length+1,
                         currentStack.length - currentStackLimit);
        error.setStackTrace(zusammen);
    }

(在服务器端,我已经切断了与方法调用本身无关的堆栈跟踪部分,即与消息处理相关的所有内容。)

这会产生如下组合堆栈跟踪:

java.lang.SecurityException: Das Passwort für Nutzer »Paul« ist falsch.
        at de.fencing_game.db.userdb.Db4oUserDB.login(Db4oUserDB.java:304)
        at de.fencing_game.server.impl.StandardServers$SSServer$1.run(StandardServers.java:316)
        at de.fencing_game.server.impl.StandardServers$SSServer$1.run(StandardServers.java:314)
        at java.security.AccessController.doPrivileged(Native Method)
        at de.fencing_game.server.impl.StandardServers$SSServer.login(StandardServers.java:313)
        at de.fencing_game.transport.server.ServerTransport$ConnectionInfo$4.login(ServerTransport.java:460)
        at ══════════════════════════.<remote call %2>()
        at $Proxy1.login(Unknown Source)
        at de.fencing_game.gui.basics.LoginUtils.login(LoginUtils.java:80)
        at de.fencing_game.gui.Lobby.connectTo(Lobby.java:302)
        at de.fencing_game.gui.Lobby$20.run(Lobby.java:849)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:647)
        at java.awt.EventQueue.access$000(EventQueue.java:96)
        at java.awt.EventQueue$1.run(EventQueue.java:608)
        at java.awt.EventQueue$1.run(EventQueue.java:606)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:617)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)

我想 RMI 系统做的事情非常相似(只是没有══════════════════════════).


Edit:对于您的用例,您必须在启动内部线程时保存外部线程的堆栈跟踪,然后在 run 方法中捕获异常并将外部堆栈跟踪附加到内部异常的堆栈跟踪。不过,我真的建议放置某种类型的分隔符。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Java 中伪造堆栈跟踪 的相关文章

随机推荐