| 156 | const size_t bytes_to_next_page = kPageSize - page_offset; |
| 157 | |
| 158 | // Skip to the next page boundary or past read bytes (whichever advances further) |
| 159 | current_remote += std::max(bytes_read, bytes_to_next_page); |
| 160 | continue; |
| 161 | } |
| 162 | |
| 163 | const uintptr_t local_base = reinterpret_cast<uintptr_t>(buf.data()); |
| 164 | const uintptr_t local_end = local_base + bytes_read; |
| 165 | |
| 166 | uintptr_t found_local = findInRange(local_base, local_end, reinterpret_cast<const uint8_t *>(bytes), mask); |
| 167 | if (found_local) |
| 168 | { |
| 169 | const size_t offset = found_local - local_base; |
| 170 | return current_remote + offset; |
| 171 | } |
| 172 | |
| 173 | // Slide the window forward based on actual bytes read to handle chunk boundaries |
| 174 | current_remote += (bytes_read - pattern_len + 1); |
| 175 | } |
| 176 | |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | std::vector<uintptr_t> KittyScannerMgr::findHexAll(uintptr_t start, |
| 181 | uintptr_t end, |
| 182 | std::string hex, |
| 183 | const std::string &mask) const |
| 184 | { |
| 185 | std::vector<uintptr_t> results; |
| 186 | |
| 187 | if (!_pMem || start >= end || mask.empty() || (end - start) < mask.length() || |
| 188 | !KittyUtils::String::validateHex(hex)) |
| 189 | return results; |
| 190 | |
| 191 | const size_t scan_size = mask.length(); |
| 192 | if ((hex.length() / 2) != scan_size) |
| 193 | return results; |
| 194 | |
| 195 | std::vector<char> pattern(scan_size, 0); |
| 196 | KittyUtils::Data::fromHex(hex, &pattern[0]); |