| 15 | } |
| 16 | |
| 17 | uintptr_t findInRange(const uintptr_t start, const uintptr_t end, const uint8_t *pattern, const char *mask) |
| 18 | { |
| 19 | const size_t mask_len = strlen(mask); |
| 20 | if (mask_len == 0 || start >= end || (end - start) < mask_len) |
| 21 | return 0; |
| 22 | |
| 23 | const uint8_t *scan_start = reinterpret_cast<const uint8_t *>(start); |
| 24 | const uint8_t *scan_end = reinterpret_cast<const uint8_t *>(end - mask_len); |
| 25 | |
| 26 | // Anchor memchr on the first required byte in the mask. |
| 27 | // This preserves wildcard-leading IDA pattern semantics. |
| 28 | size_t anchor_index = 0; |
| 29 | while (anchor_index < mask_len && mask[anchor_index] != 'x') |
| 30 | ++anchor_index; |
| 31 | |
| 32 | // All-wildcard mask matches at range start. |
| 33 | if (anchor_index == mask_len) |
| 34 | return start; |
| 35 | |
| 36 | const uint8_t anchor_byte = pattern[anchor_index]; |
| 37 | const uint8_t *anchor_scan_start = scan_start + anchor_index; |
| 38 | const uint8_t *anchor_scan_end = scan_end + anchor_index; |
| 39 | |
| 40 | for (const uint8_t *cur = anchor_scan_start; cur <= anchor_scan_end; ++cur) |
| 41 | { |
| 42 | cur = static_cast<const uint8_t *>(memchr(cur, anchor_byte, (anchor_scan_end - cur) + 1)); |
| 43 | if (!cur) |
| 44 | break; |
| 45 | |
| 46 | const uint8_t *candidate = cur - anchor_index; |
| 47 | if (compare(candidate, pattern, mask)) |
| 48 | return reinterpret_cast<uintptr_t>(candidate); |
| 49 | } |
| 50 | return 0; |
| 51 | } |
| 52 | |
| 53 | std::vector<uintptr_t> KittyScannerMgr::findBytesAll(const uintptr_t start, |
| 54 | const uintptr_t end, |
no test coverage detected