Record basic OS statistics, such as API calls and strings.
| 7 | from typing import Any, List, MutableMapping, Mapping, Optional, Set |
| 8 | |
| 9 | class QlOsStats: |
| 10 | """Record basic OS statistics, such as API calls and strings. |
| 11 | """ |
| 12 | |
| 13 | def __init__(self): |
| 14 | self.syscalls: MutableMapping[str, List] = {} |
| 15 | self.strings: MutableMapping[str, Set] = {} |
| 16 | |
| 17 | self.position = 0 |
| 18 | |
| 19 | def clear(self): |
| 20 | """Reset collected stats. |
| 21 | """ |
| 22 | |
| 23 | self.syscalls.clear() |
| 24 | self.strings.clear() |
| 25 | |
| 26 | self.position = 0 |
| 27 | |
| 28 | @staticmethod |
| 29 | def _banner(caption: str) -> List[str]: |
| 30 | bar = '-' * 24 |
| 31 | |
| 32 | return ['', caption, bar] |
| 33 | |
| 34 | def summary(self) -> List[str]: |
| 35 | ret = [] |
| 36 | |
| 37 | ret.extend(QlOsStats._banner('syscalls called')) |
| 38 | |
| 39 | for key, values in self.syscalls.items(): |
| 40 | ret.append(f'{key}:') |
| 41 | ret.extend(f' {json.dumps(value):s}' for value in values) |
| 42 | |
| 43 | ret.extend(QlOsStats._banner('strings ocurrences')) |
| 44 | |
| 45 | for key, values in self.strings.items(): |
| 46 | ret.append(f'{key}: {", ".join(str(word) for word in values)}') |
| 47 | |
| 48 | return ret |
| 49 | |
| 50 | def log_api_call(self, address: int, name: str, params: Mapping, retval: Any, retaddr: int) -> None: |
| 51 | """Record API calls along with their details. |
| 52 | |
| 53 | Args: |
| 54 | address : location of the calling instruction |
| 55 | name : api function name |
| 56 | params : mapping of the parameters name to their effective values |
| 57 | retval : value returned by the api function |
| 58 | retaddr : address to which the api function returned |
| 59 | """ |
| 60 | |
| 61 | if name.startswith('hook_'): |
| 62 | name = name[5:] |
| 63 | |
| 64 | self.syscalls.setdefault(name, []).append({ |
| 65 | 'params' : params, |
| 66 | 'retval' : retval, |