Add a toggle to enable/disable all debugger statements (separately from the breakpoint toggle)
Categories
(DevTools :: Debugger, enhancement, P3)
Tracking
(Not tracked)
People
(Reporter: nbp, Unassigned)
References
(Blocks 2 open bugs)
Details
(Keywords: dev-doc-needed)
Attachments
(1 file)
(deleted),
image/png
|
Details |
Today some JavaScript Obfuscator are using the debugger;
keyword to prevent reverse engineering the code, or editing value with a debugger. Unfortunately these mitigations cause performance issues which appear only in Firefox.
By offering a toggle to enable/disable debugger statements, and communicating about it, we will not fix this performance issue, but suggest to developers of these tools that this kind of mitigation is now useless. Thus, hopefully reducing the number of these from appearing on the Web.
The performance problem comes from the way the the debugger
statement is used.
It is used in a newly created function, called by a function which is calling it-self recursively, and executed in a try-catch. The performance problem then appears from the fact that Firefox seems to have a bigger JavaScript stack than Chrome[1] in this specific case, thus crashing later rather than sooner. (see Bug 1475013)
[1] In the debugger console:
var i = 0;
function f() { i++; f() }
f();
On my system:
Firefox: i == 45706
Chromium: i == 15728
Reporter | ||
Updated•5 years ago
|
Reporter | ||
Updated•5 years ago
|
Comment 1•5 years ago
|
||
I believe that the "disable all debugger statements" button already exists. There is a button in the top right of the debugger that disables breakpoints, debugger statements and other types of pausing.
Comment 2•5 years ago
|
||
That doesn't address the goal of this bug though, which would be to allow people to debug normally, while basically skipping the part where debugger;
statements cause a pause, thus removing the encouragement for projects to use them as an obfuscation mechanism.
Comment 3•5 years ago
|
||
hmm, i see. so breakpoints should still work, but debugger statements should be disabled...
could we address this by making it easy to disable specific debugger statements?
Comment 4•5 years ago
|
||
The hard part is evalled code, since that will create a brand new snippet with a new debugger that isn't disabled. Disabled-by-default seems to be the only way.
Comment 5•5 years ago
|
||
Could JS engine provide a config pref to solve this edge use case – disabling debugger statements? We probably need more time to evaluate our approach on how to expose this in DevTools.
Reporter | ||
Comment 6•5 years ago
|
||
I think this is doable, but Jim is likely to know better than me.
Comment 7•5 years ago
|
||
Can't we just do this in the server, today, by not setting an onDebuggerStatement handler in the first place?
Updated•5 years ago
|
Updated•4 years ago
|
Updated•3 years ago
|
Comment 8•3 years ago
|
||
The patch offered here https://github.com/firefox-devtools/debugger/issues/8228#issuecomment-508776592 does not work anymore
cp -n libxul.so{,.prePatch}; dd of=libxul.so if=<(printf "dbbbgggr") obs=1 conv=notrunc seek=$(strings -t d libxul.so | egrep "^[0-9]* (debugger|padStart)$"| grep padStart -A 0 -B 1 | head -n 1|cut -d" " -f1); diff <(xxd libxul.so) <(xxd libxul.so.prePatch)
Comment 9•3 years ago
|
||
... but it does work on v67, as-advertised. You may need to "stay with that version" though.
Comment 10•3 years ago
|
||
Are there any hopes about this feature?
Debugger call is nowadays abused everywhere to break debugging attempts and the only way to stop this requires a custom fix in the source code as explained here https://nullpt.rs/evading-anti-debugging-techniques/ .
This can be solved by adding a new option to disable/enable debugger call and set a customizable call name to trigger the breakpoint and bypass this anti debugger method.
Updated•3 years ago
|
Reporter | ||
Comment 11•3 years ago
|
||
There is a new feature which is present in Firefox 98 and would help as selectively ignore debugger statements:
- It is behind the about:config flag:
devtools.debugger.features.blackbox-lines
. - This feature is illustrated here: https://twitter.com/FirefoxDevTools/status/1486025607007948811
- Tracked by Bug 875034.
This does not answer specifically about this specific bugs, as this does not disable all debugger statements, but this can be used as a work-around in the mean time.
Comment 12•3 years ago
|
||
(In reply to Nicolas B. Pierron [:nbp] from comment #11)
This does not answer specifically about this specific bugs, as this does not disable all debugger statements, but this can be used as a work-around in the mean time.
I am not sure if your claim is actually true.
as explained here https://nullpt.rs/evading-anti-debugging-techniques/
there is eval-usage. I am not sure how can you blackbox a line which is techincally not a line, but a string to be eval'ed.
And then there are "other techniques" too ...
Comment 13•3 years ago
|
||
There is also a button available on Debugger toolbar allowing the user to disable all breakpoints including debugger;
keywords.
See the attached screenshot for the location.
Does that work for you?
Comment 14•3 years ago
|
||
(In reply to Jan Honza Odvarko [:Honza] (always need-info? me) from comment #13)
There is also a button available on Debugger toolbar allowing the user to disable all breakpoints including
debugger;
keywords.See the attached screenshot for the location.
Does that work for you?
To answer for stdedos+mozilla, it does disable all breakpoints including debugger;
statements, yes. Though doesn't address the use case described in comment 2.
A simple script for that is setInterval(function() { debugger; }, 0);
, though there are more sophisticated ones out there with the goal to block people from debugging and reverse-engineering foreign code.
Sebastian
Comment 15•3 years ago
|
||
I see, thank you Sebastian.
@stdedos+mozilla: what's your use case?
- Disable all (breakpoints +
debugger;
keywords) - Disable just the
debugger;
keywords (all occurrences) - Something else?
Honza
Comment 16•3 years ago
|
||
(In reply to Jan Honza Odvarko [:Honza] (always need-info? me) from comment #15)
I see, thank you Sebastian.
@stdedos+mozilla: what's your use case?
- Disable all (breakpoints +
debugger;
keywords)- Disable just the
debugger;
keywords (all occurrences)- Something else?
Honza
Apologies, I didn't get a chance to re-test the suggestion yesterday (I remember I didn't plain come here to cry about it, but I am not sure what was the case 2 months ago).
My use case is that I don't want "whoever decided" to while(sleep(0.1)) ; do debugger ; done
the life out of a page will get it their way :-p
Even if I don't want to mess with the js itself, DevTools being open means "automatic" debugger
hit & activation.
pls clear "my" needinfo flag yourself, if my answer satisfies your request
Comment 17•3 years ago
|
||
(In reply to stdedos+mozilla from comment #16)
My use case is that I don't want "whoever decided" to
while(sleep(0.1)) ; do debugger ; done
the life out of a page will get it their way :-p
Even if I don't want to mess with the js itself, DevTools being open means "automatic"debugger
hit & activation.
I see, make sense, thank you for the clarification.
pls clear "my" needinfo flag yourself, if my answer satisfies your request
Done
Comment 18•3 years ago
|
||
(In reply to Jan Honza Odvarko [:Honza] (always need-info? me) from comment #13)
Created attachment 9265126 [details]
image.pngThere is also a button available on Debugger toolbar allowing the user to disable all breakpoints including
debugger;
keywords.See the attached screenshot for the location.
Does that work for you?
To answer this question (after so much time, sorry about that!), it seems that this "cannot" apply to my case.
The "testbed" in question, is able to detect the DevTools being open in the tab, halt the operations of the page, and render the DevTools half-inoperable - be it at the start or any other time in the tab's timeline.
I don't even get to the point where I could possibly test the feature in question (and it doesn't matter if I pre-set it).
Chrome has no such problem - after it's armed with an anti-anti-debugger, that is (didn't test Firefox).
Tested on Firefox 97.0.2 (64-bit) @ Ubuntu 20.04.
Comment 19•2 years ago
|
||
(In reply to Jan Honza Odvarko [:Honza] (always need-info? me) from comment #15)
@stdedos+mozilla: what's your use case?
- Disable all (breakpoints +
debugger;
keywords)- Disable just the
debugger;
keywords (all occurrences)- Something else?
The debugger;
keyword is used in obfuscation protection loops to prevent users from opening the DevTools console, as explained in this page.
Here's an example of such code being used in the wild, see function check()
at line #2:
var tryCount = 0;var minimalUserResponseInMiliseconds = 200;
function check(){console.clear();before = new Date().getTime();debugger;after = new Date().getTime();
if(after - before > minimalUserResponseInMiliseconds){document.write(" Dont open Developer Tools. ");self.location.replace(window.location.protocol + window.location.href.substring(window.location.protocol.length));
}else{before = null;after = null;delete before;delete after;}setTimeout(check, 100);}check();
window.onload = function(){document.addEventListener("contextmenu", function(e){e.preventDefault();}, false);document.addEventListener("keydown", function(e) {
if(e.ctrlKey && e.shiftKey && e.keyCode == 73){disabledEvent(e);}
if(e.ctrlKey && e.shiftKey && e.keyCode == 74){disabledEvent(e);}
if(e.keyCode == 83 && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)) {disabledEvent(e);}
if(e.ctrlKey && e.keyCode == 85) {disabledEvent(e);}
if(event.keyCode == 123) {disabledEvent(e);}
}, false);function disabledEvent(e){if(e.stopPropagation){e.stopPropagation();} else if(window.event){window.event.cancelBubble = true;}e.preventDefault();return false;}};
Disabling the debugger;
keyword is not enough to resume execution in these cases.
So perhaps a new feature, being able to "silence" any function in the call stack (i.e. temporarily replacing its code with a no-op), so that when the first debugger;
call is made by the obfuscation code and pauses everything, the user can go to the call stack and mark the deepest (or second or third etc deepest) function in the call stack to be silenced, so that when you resume execution that function will not queue up another recursive call.
I think this might be an alternative to what's suggested in comment 11 about blackboxing, because to blackbox you need to be able to see and select the code lines, and in lots of cases this anti-debugging trick is hidden behind sophisticated obfuscation + inside an anonymous function, so the call stack is the only way to figure out which function this defensive debugger;
call is coming from.
Updated•2 years ago
|
Comment 20•2 years ago
|
||
I think having the ability to make "debugger" statements a no-op is a good first start.
Comment 21•2 years ago
|
||
To clarify, I mean all debugger statements.
Updated•1 year ago
|
Updated•1 year ago
|
Comment 23•1 year ago
|
||
Here's a blog post describing how they patched SpiderMonkey/Firefox to rename the "debugger" keyword, effectively disabling it:
Reporter | ||
Comment 24•1 year ago
|
||
As a hacky solution, I was thinking we could add an environment variable to avoid generating the code associated with debugger statement when such environment variable is set.
Description
•