-
Notifications
You must be signed in to change notification settings - Fork 503
Detect ETW Patching #1787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detect ETW Patching #1787
Conversation
@ikelos - I will help with this one as I am very familiar with the intent and it should go through the pe_symbols API to be complete. I will ping you again when it is ready. |
Thanks for the feedback, I've extended the usage of the |
Thank you so much @JakePeralta7 - sorry for not getting back with more specifics. This weekend got lost in other work. I will leave just a few comments through the code itself then this should be good to go. |
Great comments, I think I've solved all of the problems you have raised (I have to say that the code look much more readable 🤣) |
Looking very nice. Just two more comments on the latest push. After addressing those, I can run the tests plus test on my local samples with these functions hooked. |
I hope I got it right this time |
The code looks good now, but it needs to be fixed for black and ruff. You can install these through pip then do (In order):
^ This will lint the file
^ This will report any formatting or other coding issues that need to be fixed. Once these pass locally, then re-commit your code. |
The code analysis checks failed about the requirements as it looks like you copy/pasted the pslist requirement and changed the name= but not the component=. Just changed it to be the pe_symbols class instead:
|
@atcuno |
Ok I just re-triggered the tests. To fix the requirements error just make the line look like this: |
This is ready now @ikelos. Awesome work @JakePeralta7 !! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One little clear up just to avoid confusion around unnecessary hex/string conversions... Otherwise looks good, just a couple of general questions to think about for the future.
- Have you considered whether the functionality used could be used by more plugins and could therefore be pulled out into an appropriately parameterized
@classmethod
? - This may find false positives where databytes are read as if they're an opcode, it's likely overkill, but you could pull in capstone to do disassembly and check the actual opcodes (and only the opcodes)? For an example of this see
direct_system_calls
orskeleton_key_check
... - Possibly we should gather all the malware specific plugins and put them under the malware class (so
windows.malware.etwpatch
rather than justwindows.etwpatch
...
|
Co-authored-by: ikelos <[email protected]>
Co-authored-by: ikelos <[email protected]>
Co-authored-by: ikelos <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nearly there, just black being a bit specific in its tastes...
opcode = ( | ||
self.context.layers[proc_layer_name] | ||
.read(func_addr, 1)[0] | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opcode = ( | |
self.context.layers[proc_layer_name] | |
.read(func_addr, 1)[0] | |
) | |
opcode = self.context.layers[proc_layer_name].read( | |
func_addr, 1 | |
)[0] |
Sorry, black just being a bit specific about the formatting... 5:S
0xc3: "RET", | ||
0xe9: "JMP", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0xc3: "RET", | |
0xe9: "JMP", | |
0xC3: "RET", | |
0xE9: "JMP", |
Oh, beat me to it! 5;P |
This plugin identifies ETW patching by inspecting the first opcode of the following functions:
If the initial opcode is 0xC3 (RET) or 0xE9 (JMP), the function is flagged as patched.
Below is a screenshot demonstrating when the detection is triggered:

Also, I've added support for scanning specific processes.
This method only checks the first opcode. If an attacker patches elsewhere in the function in a way that corrupts it - the modification will not be detected.
Note: This is my first plugin - any feedback is welcome!