Skip to content

Conversation

@zandercodes
Copy link

Adding support for deobfuscate Sentry/Bugsink stack trace.

Example:
For Plaintext

Traceback (most recent call last):
  File ajB5WpM.go, line 1, in main
    
  File YVDM2UvBa1pK.go, line 1, in (*GcPJXBo0O).Msg
    
  File PmRYfUF7fV.go, line 1, in (*GcPJXBo0O).ia6J1v
    
  File QR8skLy.go, line 1, in (*GcPJXBo0O).jqLodorEA6
    
  File u9qkupM.go, line 1, in g6qBd3.WriteLevel
    
  File vAaFg7om.go, line 1, in (*TkPbGafI).WriteLevel
    
  File nQS6ZC5.go, line 1, in zZKJ7aezE
    
  File HY7R3HYUYbp0.go, line 1, in Sh0RufN
    
  File A8_tfqaEPrO.go, line 1, in zZKJ7aezE.func1
    
  File sAof1b2PSs.go, line 1, in NTSkDRlZS

in this

Traceback (most recent call last):
  File app/cmd/app/main.go, line 56, in main
    
  File github.com/rs/zerolog/event.go, line 110, in (*Event).Msg
    
  File github.com/rs/zerolog/event.go, line 151, in (*Event).msg
    
  File github.com/rs/zerolog/event.go, line 80, in (*Event).write
    
  File github.com/rs/zerolog/writer.go, line 98, in multiLevelWriter.WriteLevel
    
  File github.com/getsentry/sentry-go/zerolog/sentryzerolog.go, line 213, in (*Writer).WriteLevel
    
  File github.com/getsentry/sentry-go/zerolog/sentryzerolog.go, line 263, in parseLogEvent
    
  File github.com/buger/jsonparser/parser.go, line 1128, in ObjectEach
    
  File github.com/getsentry/sentry-go/zerolog/sentryzerolog.go, line 271, in parseLogEvent.func1
    
  File github.com/getsentry/sentry-go/stacktrace.go, line 29, in NewStacktrace

and for json:

{
  "exception": [
    {
      "value": "can't continue",
      "stacktrace": {
        "frames": [
          {
            "function": "main",
            "module": "main",
            "filename": "ajB5WpM.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "(*GcPJXBo0O).Msg",
            "module": "pNelqfz",
            "filename": "YVDM2UvBa1pK.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "(*GcPJXBo0O).ia6J1v",
            "module": "pNelqfz",
            "filename": "PmRYfUF7fV.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "(*GcPJXBo0O).jqLodorEA6",
            "module": "pNelqfz",
            "filename": "QR8skLy.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "g6qBd3.WriteLevel",
            "module": "pNelqfz",
            "filename": "u9qkupM.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "(*TkPbGafI).WriteLevel",
            "module": "AHvhwz",
            "filename": "vAaFg7om.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "zZKJ7aezE",
            "module": "AHvhwz",
            "filename": "nQS6ZC5.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "Sh0RufN",
            "module": "xojCOs6D",
            "filename": "HY7R3HYUYbp0.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "zZKJ7aezE.func1",
            "module": "AHvhwz",
            "filename": "A8_tfqaEPrO.go",
            "lineno": 1,
            "in_app": true
          },
          {
            "function": "NTSkDRlZS",
            "module": "NkEMIOCQ",
            "filename": "sAof1b2PSs.go",
            "lineno": 1,
            "in_app": true
          }
        ]
      }
    }
  ]
}

in this

{
  "exception": [
    {
      "value": "can't continue",
      "stacktrace": {
        "frames": [
          {
            "function": "main",
            "module": "main",
            "filename": "app/cmd/app/main.go",
            "lineno": 56,
            "in_app": true
          },
          {
            "function": "(*Event).Msg",
            "module": "github.com/rs/zerolog",
            "filename": "github.com/rs/zerolog/event.go",
            "lineno": 110,
            "in_app": true
          },
          {
            "function": "(*Event).msg",
            "module": "github.com/rs/zerolog",
            "filename": "github.com/rs/zerolog/event.go",
            "lineno": 151,
            "in_app": true
          },
          {
            "function": "(*Event).write",
            "module": "github.com/rs/zerolog",
            "filename": "github.com/rs/zerolog/event.go",
            "lineno": 80,
            "in_app": true
          },
          {
            "function": "multiLevelWriter.WriteLevel",
            "module": "github.com/rs/zerolog",
            "filename": "github.com/rs/zerolog/writer.go",
            "lineno": 98,
            "in_app": true
          },
          {
            "function": "(*Writer).WriteLevel",
            "module": "github.com/getsentry/sentry-go/zerolog",
            "filename": "github.com/getsentry/sentry-go/zerolog/sentryzerolog.go",
            "lineno": 213,
            "in_app": true
          },
          {
            "function": "parseLogEvent",
            "module": "github.com/getsentry/sentry-go/zerolog",
            "filename": "github.com/getsentry/sentry-go/zerolog/sentryzerolog.go",
            "lineno": 263,
            "in_app": true
          },
          {
            "function": "ObjectEach",
            "module": "github.com/buger/jsonparser",
            "filename": "github.com/buger/jsonparser/parser.go",
            "lineno": 1128,
            "in_app": true
          },
          {
            "function": "parseLogEvent.func1",
            "module": "github.com/getsentry/sentry-go/zerolog",
            "filename": "github.com/getsentry/sentry-go/zerolog/sentryzerolog.go",
            "lineno": 271,
            "in_app": true
          },
          {
            "function": "NewStacktrace",
            "module": "github.com/getsentry/sentry-go",
            "filename": "github.com/getsentry/sentry-go/stacktrace.go",
            "lineno": 29,
            "in_app": true
          }
        ]
      }
    }
  ]
}

@lu4p
Copy link
Member

lu4p commented Jun 12, 2025

I think if we want to support this reverse should detect automatically whether its a sentry stack trace.

Also this needs to be added to the reverse.txtar test.

@mvdan what's your opinion on this?

@zandercodes
Copy link
Author

I think if we want to support this reverse should detect automatically whether its a sentry stack trace.

Also this needs to be added to the reverse.txtar test.

@mvdan what's your opinion on this?

Yes, it would make sense to recognize this automatically, but this would require almost the entire reverse function to be rewritten.
And I have no idea how to add a test in txtar.
have never done anything with txtar.

@lu4p
Copy link
Member

lu4p commented Jun 12, 2025

Testscript is relatively straightforward it's basically just some commands at the top and then multiple files delimited by --- filename ---, details here
:
https://pkg.go.dev/github.com/rogpeppe/go-internal/testscript

Also have a look at https://github.com/burrowers/garble/blob/master/CONTRIBUTING.md

Basically you need to add a new block like this:

stdin main.stderr
exec garble reverse .
cmp stdout reverse.stdout

Where the stdin is a file you want to reverse and stout a new one with the output you expect.

Then just run go test -run=Script/reverse -u to update the output.

For syntax highlighting use: https://marketplace.visualstudio.com/items?itemName=twpayne.vscode-testscript

As for the entire reverse function having to be rewritten, can't you detect it somewhere at the beginning and then basically set some variable to trigger your current block.

@zandercodes zandercodes marked this pull request as draft June 12, 2025 22:03
@zandercodes zandercodes marked this pull request as ready for review June 12, 2025 23:46
@zandercodes
Copy link
Author

@lu4p I created the testdata in the file "reverse-sentry.txtar"

@lu4p
Copy link
Member

lu4p commented Jun 13, 2025

Great that you figured out how to use testscript!

You'll still need to remove the -sentry flag and detect it from input instead.

I would probably use simple regex which matches the format of a sentry traceback line. https://regexr.com/ is helpful

Also the test you wrote is currently not passing and you still need to test the json input.

@zandercodes
Copy link
Author

Great that you figured out how to use testscript!

You'll still need to remove the -sentry flag and detect it from input instead.

I would probably use simple regex which matches the format of a sentry traceback line. https://regexr.com/ is helpful

Also the test you wrote is currently not passing.

I thought if the command “go test -run=Script/reverse-sentry -u” worked and returned an OK everything would be fine.

vscode ➜ /workspaces/garble (master) $ go test -run=Script/reverse-sentry -u
PASS
ok      mvdan.cc/garble 1.969s

Ok, I have removed the Sentry flag and implement this directly in the reverse function

@lu4p
Copy link
Member

lu4p commented Jun 13, 2025

-u tells it to automatically update the output

You'll need to run it one more time without -u to verify your output is consistent.

You can look at the failing CI it shows a diff of expected and actual output

@zandercodes zandercodes marked this pull request as draft June 13, 2025 19:11
@mvdan
Copy link
Member

mvdan commented Jun 25, 2025

Adding this seems fine, but don't hide it behind a flag. If the number of replacements growing too large is a problem, we just need a better algorithm for them, but I think what we have now should scale well enough.

@zandercodes
Copy link
Author

Adding this seems fine, but don't hide it behind a flag. If the number of replacements growing too large is a problem, we just need a better algorithm for them, but I think what we have now should scale well enough.

If I have time in the next few days I will change the approach I implemented.
I think it would make the most sense to work with a kind of pattern which you can possibly specify as a flag, e.g. -format File %file%, line %line%, in %class% etc perhaps.
I will try something around and if I have a solution then release it for review.

@mvdan
Copy link
Member

mvdan commented Jul 2, 2025

That's fine. If you want to go that route, I'd consider regular expressions, which already support named groups to match with, and replace: https://pkg.go.dev/regexp/syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants