Application security engineer here. When we compile our java code, we obfuscate it using KlassMaster and have it remove line numbers (see KlassMaster docs) because of a handwavy explanation "it makes reverse engineering harder".

I'd like to fact-check that this is actually increasing reverse-engineering difficulty enough to warrant the amount of dev time that's wasted trying to debug useless stack traces.

  • Just a note. It says it is intended for beta releases. That feature does not sound production ready. Personally, I would wait until it is and it has been through its rounds of testing; gained user approvals; and fixes made to any disapproval. What do the reviews say? – TamusJRoyce Sep 6 '18 at 23:57
  • 1
    @TamusJRoyce That sentence seems specific to increasing the size of your bytecode, no? Besides, we're using the REMOVE feature, not the SCRAMBLE feature. – Mike Ounsworth Sep 7 '18 at 0:09

Stripping line numbers has a minimal impact on the difficulty of reverse engineering code. If it is causing you problems, I would recommend disabling it.

Col-E's answer is a red herring because it is fairly easy for a reverse engineer to insert synthetic line numbers into the bytecode to disambiguate stack traces (assuming they don't just rename the methods in the first place). These obviously won't match the original source code line numbers, but if all you want is a way to disambiguate stack traces, that is easy to accomplish.

TamusJRoyce's answer is also mistaken. Javac does not do the sort of optimizations that GCC does, which is why unobfuscated Java can be decompiled so cleanly. The only notable optimization I know of that Javac does at compile time is inlining and simplifying constant expressions.

| improve this answer | |
  • Thank you! Could you expand the first paragraph a bit; share some of your expertise on why KlassMaster bothered to remove line numbers, and why it doesn't really slow you down? – Mike Ounsworth Sep 7 '18 at 1:45
  • 1
    @Mike It was probably thrown in in the "couldn't hurt" mindset. They are easy to strip, so you might as well do it. As for why the impact is negligible, the short answer is that line numbers are pretty much only useful if the code is already unobfuscated and even then it just makes the decompiled code a little prettier. For obfuscated code, they might give you some hints about what the original code looked like, but it's not generally worth the effort to look at them and ZKM tends to mangle things too much for that to matter anyway. – Antimony Sep 7 '18 at 1:47
  • For what it's worth, Krakatau, the decompiler I wrote, completely ignores line number tables even if they are present. – Antimony Sep 7 '18 at 1:48
  • Accepting for your comment more than for the actual answer :P – Mike Ounsworth Sep 7 '18 at 1:58
  • Agreed. There is a big difference in static compilation and run-time optimization when considering reverse engineering. run-time optimization is where the gcc-like optimizations occur. But that is moot / unimportant. – TamusJRoyce Sep 23 '18 at 12:31

The KlassMaster docs actually summarize the reason why fairly well.

Since the class com.mycompany.c will typically have been obfuscated to contain many overloaded methods with the names a and b, diagnosing the problem and reproducing the bug will be very time consuming for your developers and very frustrating for your customers.

They provide a stacktrace below this summary. I'll focus on these four lines:

at com.mycompany.c.a(c.java)
at com.mycompany.c.a(c.java)
at com.mycompany.c.b(c.java)
at com.mycompany.c.a(c.java)

Clearly in these stacktrace elements the class is always the same c, but what about the method? Lines 1, 2, and 4 give the method name of a but the issue is that you cannot be sure if these all point to the same method due the name overloading (multiple methods with the same name but different return / parameter types).

This is where line-numbers come in. Since you are a developer with source-code access you can easily jump to the line number that the stacktrace provides. An attacker will not have the source-code but they can just as easily look at the class's bytecode to make a table that associates different line numbers with their methods (and more specifically, where in the method bytecode the issue occured). This would allow them to bypass the purpose of name overloading since they can lookup what method is associated with a line in any given stacktrace element.

If you were to remove line-numbers then an attacker cannot take any given stacktrace element and instantly know what method it links to. The attacker's best option in this case would be to start at a known position in the stacktrace and manually follow the bytecode to determine which of the overloaded methods is being shown in the stacktrace.

If decompilation is your highest priority concern rather than a situation like the above, then you should keep the debug information for your sake. Java decompilers can produce fairly accurate code even on obfuscated assemblies regardless of whether debug information is included or not.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.