|
1 | 1 | # This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0 |
2 | 2 | # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 |
3 | 3 |
|
| 4 | +# Full details on the techniques used in these plugins to detect EDR-evading malware |
| 5 | +# can be found in our 20 page whitepaper submitted to DEFCON along with the presentation |
| 6 | +# https://www.volexity.com/wp-content/uploads/2024/08/Defcon24_EDR_Evasion_Detection_White-Paper_Andrew-Case.pdf |
| 7 | + |
4 | 8 | import logging |
5 | 9 |
|
6 | 10 | from typing import Dict, Tuple, List, Generator |
@@ -162,20 +166,30 @@ def _generator(self) -> Generator[Tuple[int, Tuple[str, str, int]], None, None]: |
162 | 166 | # code_bytes[dll_name][func_name][func_bytes] |
163 | 167 | code_bytes = self._gather_code_bytes(kernel, found_symbols) |
164 | 168 |
|
| 169 | + # walk the functions that were evaluated |
165 | 170 | for functions in code_bytes.values(): |
| 171 | + # cbb is the distinct groups of bytes (instructions) |
| 172 | + # for this function across processes |
166 | 173 | for func_name, cbb in functions.items(): |
| 174 | + # the dict key here is the raw instructions, which is not helpful to look at |
| 175 | + # the values are the list of tuples for the (proc_id, proc_name) pairs for this set of bytes (instructions) |
167 | 176 | cb = list(cbb.values()) |
168 | 177 |
|
169 | | - # same implementation in all |
| 178 | + # if all processes map to the same implementation, then no malware is present |
170 | 179 | if len(cb) == 1: |
171 | 180 | yield 0, (func_name, "", len(cb[0])) |
172 | 181 | else: |
173 | | - # find the processes that are hooked for reporting |
| 182 | + # if there are differing implementations then it means |
| 183 | + # that malware has overwritten system call(s) in infected processes |
| 184 | + # max_idx and small_idx find which implementation of a system call has the least processes |
| 185 | + # as all observed malware and open source projects only infected a few targets, leaving the |
| 186 | + # rest with the original EDR hooks in place |
174 | 187 | max_idx = 0 if len(cb[0]) > len(cb[1]) else 1 |
175 | 188 | small_idx = (~max_idx) & 1 |
176 | 189 |
|
177 | 190 | ps = [] |
178 | 191 |
|
| 192 | + # gather processes on small_idx since these are the malware infected ones |
179 | 193 | for pid, pname in cb[small_idx]: |
180 | 194 | ps.append("{:d}:{}".format(pid, pname)) |
181 | 195 |
|
|
0 commit comments