KittyScanner.cpp
1 #include "KittyScanner.hpp" 2 #include "KittyMemoryEx.hpp" 3 4 // refs 5 // https://github.com/learn-more/findpattern-bench 6 7 bool compare(const uint8_t *data, const uint8_t *pattern, const char *mask) 8 { 9 for (; *mask; ++mask, ++data, ++pattern) 10 { 11 if (*mask == 'x' && *data != *pattern) 12 return false; 13 } 14 return !*mask; 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 first_byte = pattern[0]; 24 const uint8_t *scan_start = reinterpret_cast<const uint8_t *>(start); 25 const uint8_t *scan_end = reinterpret_cast<const uint8_t *>(end - mask_len); 26 27 for (const uint8_t *cur = scan_start; cur <= scan_end; ++cur) 28 { 29 cur = static_cast<const uint8_t *>(memchr(cur, first_byte, (scan_end - cur) + 1)); 30 if (!cur) 31 break; 32 33 if (compare(cur, pattern, mask)) 34 return reinterpret_cast<uintptr_t>(cur); 35 } 36 return 0; 37 } 38 39 std::vector<uintptr_t> KittyScannerMgr::findBytesAll(const uintptr_t start, 40 const uintptr_t end, 41 const char *bytes, 42 const std::string &mask) const 43 { 44 std::vector<uintptr_t> local_list; 45 46 if (!_pMem || start >= end || !bytes || mask.empty()) 47 return local_list; 48 49 std::vector<char> buf(end - start, 0); 50 if (!_pMem->Read(start, &buf[0], buf.size())) 51 { 52 KITTY_LOGE("findBytesAll: Failed to read into buffer."); 53 return local_list; 54 } 55 56 uintptr_t curr_search_address = (uintptr_t)&buf[0]; 57 uintptr_t search_end = (uintptr_t(&buf[0]) + buf.size()); 58 do 59 { 60 uintptr_t found = findInRange(curr_search_address, 61 search_end, 62 reinterpret_cast<const uint8_t *>(bytes), 63 mask.data()); 64 if (!found) 65 break; 66 67 local_list.push_back(found); 68 curr_search_address = found + 1; 69 } while (true); 70 71 if (local_list.empty()) 72 return local_list; 73 74 std::vector<uintptr_t> remote_list; 75 for (auto &it : local_list) 76 { 77 remote_list.push_back((it - (uintptr_t(&buf[0]))) + start); 78 } 79 80 return remote_list; 81 } 82 83 uintptr_t KittyScannerMgr::findBytesFirst(const uintptr_t start, 84 const uintptr_t end, 85 const char *bytes, 86 const std::string &mask) const 87 { 88 if (!_pMem || start >= end || !bytes || mask.empty()) 89 return 0; 90 91 std::vector<char> buf(end - start, 0); 92 if (!_pMem->Read(start, &buf[0], buf.size())) 93 { 94 KITTY_LOGE("findBytesFirst: Failed to read into buffer."); 95 return 0; 96 } 97 98 uintptr_t local = findInRange((uintptr_t)&buf[0], 99 (uintptr_t(&buf[0]) + buf.size()), 100 reinterpret_cast<const uint8_t *>(bytes), 101 mask.data()); 102 return local ? ((local - (uintptr_t(&buf[0]))) + start) : 0; 103 } 104 105 std::vector<uintptr_t> KittyScannerMgr::findHexAll(const uintptr_t start, 106 const uintptr_t end, 107 std::string hex, 108 const std::string &mask) const 109 { 110 std::vector<uintptr_t> list; 111 112 if (!_pMem || start >= end || mask.empty() || !KittyUtils::String::validateHex(hex)) 113 return list; 114 115 const size_t scan_size = mask.length(); 116 if ((hex.length() / 2) != scan_size) 117 return list; 118 119 std::vector<char> pattern(scan_size); 120 KittyUtils::Data::fromHex(hex, &pattern[0]); 121 122 list = findBytesAll(start, end, pattern.data(), mask); 123 return list; 124 } 125 126 uintptr_t KittyScannerMgr::findHexFirst(const uintptr_t start, 127 const uintptr_t end, 128 std::string hex, 129 const std::string &mask) const 130 { 131 if (!_pMem || start >= end || mask.empty() || !KittyUtils::String::validateHex(hex)) 132 return 0; 133 134 const size_t scan_size = mask.length(); 135 if ((hex.length() / 2) != scan_size) 136 return 0; 137 138 std::vector<char> pattern(scan_size); 139 KittyUtils::Data::fromHex(hex, &pattern[0]); 140 141 return findBytesFirst(start, end, pattern.data(), mask); 142 } 143 144 std::vector<uintptr_t> KittyScannerMgr::findIdaPatternAll(const uintptr_t start, 145 const uintptr_t end, 146 const std::string &pattern) 147 { 148 std::vector<uintptr_t> list; 149 150 if (!_pMem || start >= end) 151 return list; 152 153 std::string mask; 154 std::vector<char> bytes; 155 156 const size_t pattren_len = pattern.length(); 157 for (std::size_t i = 0; i < pattren_len; i++) 158 { 159 if (pattern[i] == ' ') 160 continue; 161 162 if (pattern[i] == '?') 163 { 164 bytes.push_back(0); 165 mask += '?'; 166 } 167 else if (pattren_len > i + 1 && std::isxdigit(pattern[i]) && std::isxdigit(pattern[i + 1])) 168 { 169 bytes.push_back(std::stoi(pattern.substr(i++, 2), nullptr, 16)); 170 mask += 'x'; 171 } 172 } 173 174 if (bytes.empty() || mask.empty() || bytes.size() != mask.size()) 175 return list; 176 177 list = findBytesAll(start, end, bytes.data(), mask); 178 return list; 179 } 180 181 uintptr_t KittyScannerMgr::findIdaPatternFirst(const uintptr_t start, const uintptr_t end, const std::string &pattern) 182 { 183 if (!_pMem || start >= end) 184 return 0; 185 186 std::string mask; 187 std::vector<char> bytes; 188 189 const size_t pattren_len = pattern.length(); 190 for (std::size_t i = 0; i < pattren_len; i++) 191 { 192 if (pattern[i] == ' ') 193 continue; 194 195 if (pattern[i] == '?') 196 { 197 bytes.push_back(0); 198 mask += '?'; 199 } 200 else if (pattren_len > i + 1 && std::isxdigit(pattern[i]) && std::isxdigit(pattern[i + 1])) 201 { 202 bytes.push_back(std::stoi(pattern.substr(i++, 2), nullptr, 16)); 203 mask += 'x'; 204 } 205 } 206 207 if (bytes.empty() || mask.empty() || bytes.size() != mask.size()) 208 return 0; 209 210 return findBytesFirst(start, end, bytes.data(), mask); 211 } 212 213 std::vector<uintptr_t> KittyScannerMgr::findDataAll(const uintptr_t start, 214 const uintptr_t end, 215 const void *data, 216 size_t size) const 217 { 218 std::vector<uintptr_t> list; 219 220 if (!_pMem || start >= end || !data || size < 1) 221 return list; 222 223 std::string mask(size, 'x'); 224 225 list = findBytesAll(start, end, (const char *)data, mask); 226 return list; 227 } 228 229 uintptr_t KittyScannerMgr::findDataFirst(const uintptr_t start, 230 const uintptr_t end, 231 const void *data, 232 size_t size) const 233 { 234 if (!_pMem || start >= end || !data || size < 1) 235 return 0; 236 237 std::string mask(size, 'x'); 238 239 return findBytesFirst(start, end, (const char *)data, mask); 240 } 241 242 /* ======================= ElfScanner ======================= */ 243 244 // refs https://gist.github.com/resilar/24bb92087aaec5649c9a2afc0b4350c8 245 246 ElfScanner::ElfScanner(IKittyMemOp *pMem, uintptr_t elfBase, const std::vector<KittyMemoryEx::ProcMap> &maps) 247 { 248 _pMem = nullptr; 249 _elfBase = 0; 250 _ehdr = {}; 251 _phdr = 0; 252 _loads = 0; 253 _loadBias = 0; 254 _loadSize = 0; 255 _dynamic = 0; 256 _stringTable = 0; 257 _symbolTable = 0; 258 _strsz = 0; 259 _syment = sizeof(KT_ElfW(Sym)); 260 _fixedBySoInfo = false; 261 _symbols_init = false; 262 _dsymbols_init = false; 263 264 if (!pMem || !elfBase) 265 return; 266 267 _pMem = pMem; 268 _elfBase = elfBase; 269 270 // verify address 271 auto elfBaseMap = KittyMemoryEx::getAddressMap(_pMem->processID(), elfBase, maps); 272 if (!elfBaseMap.isValid() || !elfBaseMap.readable || elfBase != elfBaseMap.startAddress) 273 { 274 KITTY_LOGD("ElfScanner: (%p) is not a valid ELF base address.", (void *)elfBase); 275 return; 276 } 277 278 // read ELF header 279 if (_pMem->Read(_elfBase, &_ehdr, sizeof(_ehdr)) != sizeof(_ehdr)) 280 { 281 KITTY_LOGD("ElfScanner: Failed to read ELF (%p) header.", (void *)_elfBase); 282 return; 283 } 284 285 // verify ELF header 286 if (memcmp(_ehdr.e_ident, "\177ELF", 4) != 0) 287 { 288 KITTY_LOGD("ElfScanner: (%p) is not a valid ELF.", (void *)_elfBase); 289 return; 290 } 291 292 // check ELF bit 293 if (_ehdr.e_ident[EI_CLASS] != KT_ELF_EICLASS) 294 { 295 KITTY_LOGD("ElfScanner: ELF class mismatch (%p).", (void *)_elfBase); 296 return; 297 } 298 299 if (_ehdr.e_ident[EI_DATA] != ELFDATA2LSB) 300 { 301 KITTY_LOGD("ElfScanner: (%p) data encoding is not little endian.", (void *)elfBase); 302 return; 303 } 304 305 if (_ehdr.e_ident[EI_VERSION] != EV_CURRENT) 306 { 307 KITTY_LOGD("ElfScanner: (%p) ELF header version mismatch.", (void *)elfBase); 308 return; 309 } 310 311 if (_ehdr.e_type != ET_EXEC && _ehdr.e_type != ET_DYN) 312 { 313 KITTY_LOGD("ElfScanner: (%p) is not a executable or dynamic " 314 "library.", 315 (void *)elfBase); 316 return; 317 } 318 319 // check common header values 320 if (!_ehdr.e_phoff || !_ehdr.e_phnum || !_ehdr.e_phentsize) 321 { 322 KITTY_LOGD("ElfScanner: Invalid header values (%p).", (void *)_elfBase); 323 return; 324 } 325 326 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), _elfBase + _ehdr.e_phoff, maps).readable) 327 { 328 KITTY_LOGD("ElfScanner: Invalid phdr (%p + %p) = %p.", 329 (void *)_elfBase, 330 (void *)_ehdr.e_phoff, 331 (void *)(_elfBase + _ehdr.e_phoff)); 332 return; 333 } 334 335 _phdr = _elfBase + _ehdr.e_phoff; 336 337 // read all program headers 338 std::vector<char> phdrs_buf(_ehdr.e_phnum * _ehdr.e_phentsize); 339 if (!_pMem->Read(_phdr, &phdrs_buf[0], phdrs_buf.size())) 340 { 341 KITTY_LOGD("ElfScanner: Failed to read ELF (%p) program headers.", (void *)_elfBase); 342 return; 343 } 344 345 // find load bias 346 uintptr_t min_vaddr = UINTPTR_MAX, max_vaddr = 0; 347 uintptr_t load_vaddr = 0, load_memsz = 0, load_filesz = 0; 348 for (KT_ElfW(Half) i = 0; i < _ehdr.e_phnum; i++) 349 { 350 KT_ElfW(Phdr) phdr_entry = {}; 351 memcpy(&phdr_entry, phdrs_buf.data() + (i * _ehdr.e_phentsize), _ehdr.e_phentsize); 352 _phdrs.push_back(phdr_entry); 353 354 if (phdr_entry.p_type == PT_LOAD) 355 { 356 _loads++; 357 358 load_vaddr = phdr_entry.p_vaddr; 359 load_memsz = phdr_entry.p_memsz; 360 load_filesz = phdr_entry.p_filesz; 361 362 if (phdr_entry.p_vaddr < min_vaddr) 363 min_vaddr = phdr_entry.p_vaddr; 364 365 if (phdr_entry.p_vaddr + phdr_entry.p_memsz > max_vaddr) 366 max_vaddr = phdr_entry.p_vaddr + phdr_entry.p_memsz; 367 } 368 } 369 370 if (!_loads) 371 { 372 KITTY_LOGD("ElfScanner: No loads entry for ELF (%p).", (void *)_elfBase); 373 return; 374 } 375 376 if (!max_vaddr) 377 { 378 KITTY_LOGD("ElfScanner: Failed to find load size for ELF (%p).", (void *)_elfBase); 379 return; 380 } 381 382 min_vaddr = KT_PAGE_START(min_vaddr); 383 max_vaddr = KT_PAGE_END(max_vaddr); 384 385 _loadBias = _elfBase - min_vaddr; 386 _loadSize = max_vaddr - min_vaddr; 387 388 uintptr_t seg_start = load_vaddr + _loadBias; 389 uintptr_t seg_mem_end = KT_PAGE_END((seg_start + load_memsz)); 390 uintptr_t seg_file_end = KT_PAGE_END((seg_start + load_filesz)); 391 uintptr_t bss_start = 0, bss_end = 0; 392 if (seg_mem_end > seg_file_end) 393 { 394 bss_start = seg_file_end; 395 bss_end = seg_mem_end; 396 } 397 398 for (const auto &it : maps) 399 { 400 if (it.startAddress >= _elfBase && it.endAddress <= (_elfBase + _loadSize)) 401 { 402 if (it.startAddress == _elfBase) 403 { 404 _baseSegment = it; 405 } 406 407 _segments.push_back(it); 408 409 if (it.readable && !it.executable && 410 (it.pathname == "[anon:.bss]" || (elfBaseMap.inode != 0 && it.inode == 0) || 411 (it.startAddress >= bss_start && it.endAddress <= bss_end))) 412 { 413 _bssSegments.push_back(it); 414 } 415 } 416 417 if (it.endAddress >= (_elfBase + _loadSize)) 418 break; 419 } 420 421 // read all dynamics 422 for (auto &phdr : _phdrs) 423 { 424 if (phdr.p_type == PT_DYNAMIC) 425 { 426 if (phdr.p_vaddr == 0 || phdr.p_memsz == 0) 427 break; 428 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), _loadBias + phdr.p_vaddr, maps).readable) 429 break; 430 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), _loadBias + phdr.p_vaddr + (phdr.p_memsz - 1), maps) 431 .readable) 432 break; 433 434 _dynamic = _loadBias + phdr.p_vaddr; 435 436 std::vector<KT_ElfW(Dyn)> dyn_buff(phdr.p_memsz / sizeof(KT_ElfW(Dyn))); 437 if (!_pMem->Read(_dynamic, &dyn_buff[0], phdr.p_memsz)) 438 { 439 KITTY_LOGD("ElfScanner: Failed to read dynamic for ELF (%p).", (void *)_elfBase); 440 break; 441 } 442 443 for (auto &dyn : dyn_buff) 444 { 445 if (dyn.d_tag == DT_NULL) 446 break; 447 448 // set required dynamics for symbol lookup 449 switch (dyn.d_tag) 450 { 451 // mandatory 452 case DT_STRTAB: // string table 453 _stringTable = dyn.d_un.d_ptr; 454 break; 455 // mandatory 456 case DT_SYMTAB: // symbol table 457 _symbolTable = dyn.d_un.d_ptr; 458 break; 459 // mandatory 460 case DT_STRSZ: // string table size 461 _strsz = dyn.d_un.d_val; 462 break; 463 // mandatory 464 case DT_SYMENT: // symbol entry size 465 _syment = dyn.d_un.d_val; 466 break; 467 default: 468 break; 469 } 470 471 _dynamics.push_back(dyn); 472 } 473 474 break; 475 } 476 } 477 478 auto fix_table_address = [&](uintptr_t &table_addr) { 479 if (table_addr && table_addr < _loadBias) 480 table_addr += _loadBias; 481 482 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), table_addr, maps).readable) 483 table_addr = 0; 484 }; 485 486 fix_table_address(_stringTable); 487 fix_table_address(_symbolTable); 488 489 _filepath = elfBaseMap.pathname; 490 _realpath = elfBaseMap.pathname; 491 if (!elfBaseMap.pathname.empty() && elfBaseMap.offset != 0) 492 { 493 KittyUtils::Zip::ZipEntryInfo ent{}; 494 if (KittyUtils::Zip::findEntryInfoByDataOffset(elfBaseMap.pathname, elfBaseMap.offset, &ent) && 495 !ent.fileName.empty()) 496 { 497 _realpath += '!'; 498 _realpath += ent.fileName; 499 } 500 } 501 } 502 503 #ifdef __ANDROID__ 504 ElfScanner::ElfScanner(IKittyMemOp *pMem, const kitty_soinfo_t &soinfo, const std::vector<KittyMemoryEx::ProcMap> &maps) 505 { 506 _pMem = nullptr; 507 _elfBase = 0; 508 _ehdr = {}; 509 _phdr = 0; 510 _loads = 0; 511 _loadBias = 0; 512 _loadSize = 0; 513 _dynamic = 0; 514 _stringTable = 0; 515 _symbolTable = 0; 516 _strsz = 0; 517 _syment = 0; 518 _fixedBySoInfo = false; 519 _symbols_init = false; 520 _dsymbols_init = false; 521 522 if (!pMem) 523 return; 524 525 _pMem = pMem; 526 _elfBase = soinfo.base; 527 _phdr = soinfo.phdr; 528 _loadBias = soinfo.bias; 529 _loadSize = soinfo.size; 530 _dynamic = soinfo.dyn; 531 _stringTable = soinfo.strtab; 532 _symbolTable = soinfo.symtab; 533 _strsz = soinfo.strsz; 534 _syment = sizeof(KT_ElfW(Sym)); 535 _filepath = soinfo.path; 536 _realpath = soinfo.realpath; 537 538 bool isLinker = KittyUtils::String::endsWith(soinfo.path, "/linker") || 539 KittyUtils::String::endsWith(soinfo.path, "/linker64"); 540 if (!isLinker && (_elfBase == 0 || _loadSize == 0 || _loadBias == 0 || _phdr == 0 || _dynamic == 0 || 541 _stringTable == 0 || _symbolTable == 0)) 542 { 543 KITTY_LOGD("ElfScanner: Invalid soinfo!"); 544 KITTY_LOGD( 545 "ElfScanner: elfBase: %p | bias: %p | phdr: %p | dyn: %p | strtab=%p | symtab=%p | strsz=%p | syment=%p", 546 (void *)_elfBase, 547 (void *)_loadBias, 548 (void *)_phdr, 549 (void *)_dynamic, 550 (void *)_stringTable, 551 (void *)_symbolTable, 552 (void *)_strsz, 553 (void *)_syment); 554 *this = ElfScanner(); 555 return; 556 } 557 558 // fix for linker 559 if (_elfBase == 0) 560 _elfBase = KittyMemoryEx::getAddressMap(_pMem->processID(), soinfo.bias, maps).startAddress; 561 if (_elfBase == 0) 562 _elfBase = KittyMemoryEx::getAddressMap(_pMem->processID(), soinfo.phdr, maps).startAddress; 563 if (_elfBase == 0) 564 _elfBase = KittyMemoryEx::getAddressMap(_pMem->processID(), soinfo.dyn, maps).startAddress; 565 if (_elfBase == 0) 566 _elfBase = KittyMemoryEx::getAddressMap(_pMem->processID(), soinfo.symtab, maps).startAddress; 567 if (_elfBase == 0) 568 _elfBase = KittyMemoryEx::getAddressMap(_pMem->processID(), soinfo.strtab, maps).startAddress; 569 570 // verify address 571 auto elfBaseMap = KittyMemoryEx::getAddressMap(_pMem->processID(), _elfBase, maps); 572 if (!elfBaseMap.isValid() || !elfBaseMap.readable || _elfBase != elfBaseMap.startAddress) 573 { 574 KITTY_LOGD("ElfScanner: Invalid base(%p) for soinfo(%p)", (void *)_elfBase, (void *)soinfo.ptr); 575 *this = ElfScanner(); 576 return; 577 } 578 579 // read ELF header 580 if (_pMem->Read(_elfBase, &_ehdr, sizeof(_ehdr)) != sizeof(_ehdr)) 581 { 582 KITTY_LOGD("ElfScanner: Failed to read ELF header for soinfo(%p).", (void *)_elfBase); 583 return; 584 } 585 586 // check if header is corrupted 587 // some games like farlight have corrupted header and needs to be fixed by soinfo 588 if (!isLinker && (memcmp(_ehdr.e_ident, "\177ELF", 4) != 0 || _ehdr.e_ident[EI_CLASS] != KT_ELF_EICLASS || 589 _ehdr.e_ident[EI_DATA] != ELFDATA2LSB || _ehdr.e_ident[EI_VERSION] != EV_CURRENT || 590 (_ehdr.e_type != ET_EXEC && _ehdr.e_type != ET_DYN) || _ehdr.e_ehsize != sizeof(KT_ElfW(Ehdr)) || 591 _ehdr.e_phentsize != sizeof(KT_ElfW(Phdr)) || _ehdr.e_phnum != soinfo.phnum || 592 _ehdr.e_phoff != (soinfo.phdr - soinfo.base))) 593 { 594 KITTY_LOGD("ElfScanner: soinfo(%p) has corrupted header, fixing by soinfo...", (void *)soinfo.ptr); 595 596 _ehdr.e_ident[EI_MAG0] = 0x7F; 597 _ehdr.e_ident[EI_MAG1] = 'E'; 598 _ehdr.e_ident[EI_MAG2] = 'L'; 599 _ehdr.e_ident[EI_MAG3] = 'F'; 600 _ehdr.e_ident[EI_CLASS] = KT_ELF_EICLASS; 601 _ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 602 _ehdr.e_ident[EI_VERSION] = EV_CURRENT; 603 _ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 604 _ehdr.e_ident[EI_ABIVERSION] = 0; 605 606 _ehdr.e_type = ET_DYN; 607 _ehdr.e_machine = soinfo.e_machine; 608 _ehdr.e_version = EV_CURRENT; 609 _ehdr.e_entry = 0; 610 _ehdr.e_phoff = soinfo.phdr ? (soinfo.phdr - soinfo.base) : 0; 611 _ehdr.e_phnum = soinfo.phnum; 612 _ehdr.e_ehsize = sizeof(KT_ElfW(Ehdr)); 613 _ehdr.e_phentsize = sizeof(KT_ElfW(Phdr)); 614 _ehdr.e_shoff = 0; 615 _ehdr.e_shentsize = sizeof(KT_ElfW(Shdr)); 616 _ehdr.e_shnum = 0; 617 _ehdr.e_shstrndx = 0; 618 _ehdr.e_flags = 0; 619 620 _fixedBySoInfo = true; 621 } 622 623 // fix for linker 624 if (_phdr == 0) 625 _phdr = _elfBase + _ehdr.e_phoff; 626 627 auto phdrMap = KittyMemoryEx::getAddressMap(_pMem->processID(), _phdr, maps); 628 if (!phdrMap.readable || phdrMap.startAddress < _elfBase || 629 (_loadSize && phdrMap.endAddress > (_elfBase + _loadSize))) 630 { 631 KITTY_LOGD("ElfScanner: Invalid phdr(%p) for soinfo(%p).", (void *)_phdr, (void *)soinfo.ptr); 632 *this = ElfScanner(); 633 return; 634 } 635 636 if (!isLinker) 637 { 638 auto dynMap = KittyMemoryEx::getAddressMap(_pMem->processID(), _dynamic, maps); 639 if (!(dynMap.readable && dynMap.startAddress >= _elfBase && dynMap.endAddress <= (_elfBase + _loadSize))) 640 { 641 KITTY_LOGD("ElfScanner: Invalid dyn(%p) for soinfo(%p).", (void *)_dynamic, (void *)soinfo.ptr); 642 *this = ElfScanner(); 643 return; 644 } 645 } 646 647 // fix for ldplayer 648 auto biasMap = KittyMemoryEx::getAddressMap(_pMem->processID(), _loadBias, maps); 649 if (!(biasMap.readable && biasMap.startAddress >= _elfBase && biasMap.endAddress <= (_elfBase + _loadSize))) 650 { 651 KITTY_LOGD("ElfScanner: Invalid bias(%p) for soinfo(%p).", (void *)_loadBias, (void *)soinfo.ptr); 652 _loadBias = 0; 653 } 654 655 // read all program headers 656 std::vector<char> phdrs_buf(_ehdr.e_phnum * _ehdr.e_phentsize); 657 if (!_pMem->Read(_phdr, &phdrs_buf[0], phdrs_buf.size())) 658 { 659 KITTY_LOGE("ElfScanner: Failed to read ELF (%p) program headers.", (void *)_elfBase); 660 return; 661 } 662 663 uintptr_t min_vaddr = UINTPTR_MAX, max_vaddr = 0; 664 uintptr_t load_vaddr = 0, load_memsz = 0, load_filesz = 0; 665 for (KT_ElfW(Half) i = 0; i < _ehdr.e_phnum; i++) 666 { 667 KT_ElfW(Phdr) phdr_entry = {}; 668 memcpy(&phdr_entry, phdrs_buf.data() + (i * _ehdr.e_phentsize), _ehdr.e_phentsize); 669 _phdrs.push_back(phdr_entry); 670 671 if (phdr_entry.p_type == PT_LOAD) 672 { 673 _loads++; 674 675 load_vaddr = phdr_entry.p_vaddr; 676 load_memsz = phdr_entry.p_memsz; 677 load_filesz = phdr_entry.p_filesz; 678 679 if (phdr_entry.p_vaddr < min_vaddr) 680 min_vaddr = phdr_entry.p_vaddr; 681 682 if (phdr_entry.p_vaddr + phdr_entry.p_memsz > max_vaddr) 683 max_vaddr = phdr_entry.p_vaddr + phdr_entry.p_memsz; 684 } 685 } 686 687 if (!_loads) 688 { 689 KITTY_LOGE("ElfScanner: No loads entry for ELF (%p).", (void *)_elfBase); 690 *this = ElfScanner(); 691 return; 692 } 693 694 if (!max_vaddr) 695 { 696 KITTY_LOGE("ElfScanner: Failed to find load size for ELF (%p).", (void *)_elfBase); 697 *this = ElfScanner(); 698 return; 699 } 700 701 min_vaddr = KT_PAGE_START(min_vaddr); 702 max_vaddr = KT_PAGE_END(max_vaddr); 703 704 // fix for linker 705 { 706 if (_loadBias == 0) 707 _loadBias = _elfBase - min_vaddr; 708 709 if (_loadSize == 0) 710 _loadSize = max_vaddr - min_vaddr; 711 } 712 713 uintptr_t seg_start = load_vaddr + _loadBias; 714 uintptr_t seg_mem_end = KT_PAGE_END((seg_start + load_memsz)); 715 uintptr_t seg_file_end = KT_PAGE_END((seg_start + load_filesz)); 716 uintptr_t bss_start = 0, bss_end = 0; 717 if (seg_mem_end > seg_file_end) 718 { 719 bss_start = seg_file_end; 720 bss_end = seg_mem_end; 721 } 722 723 for (const auto &it : maps) 724 { 725 if (it.startAddress >= _elfBase && it.endAddress <= (_elfBase + _loadSize)) 726 { 727 if (it.startAddress == _elfBase) 728 { 729 _baseSegment = it; 730 } 731 732 _segments.push_back(it); 733 734 if (it.readable && !it.executable && 735 (it.pathname == "[anon:.bss]" || (elfBaseMap.inode != 0 && it.inode == 0) || 736 (it.startAddress >= bss_start && it.endAddress <= bss_end))) 737 { 738 _bssSegments.push_back(it); 739 } 740 } 741 742 if (it.endAddress >= (_elfBase + _loadSize)) 743 break; 744 } 745 746 // read all dynamics 747 for (auto &phdr : _phdrs) 748 { 749 if (phdr.p_type == PT_DYNAMIC) 750 { 751 // fix for linker 752 if (_dynamic == 0 && phdr.p_vaddr) 753 _dynamic = _loadBias + phdr.p_vaddr; 754 755 if (_dynamic == 0 || phdr.p_memsz == 0) 756 break; 757 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), _dynamic, maps).readable) 758 break; 759 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), _dynamic + (phdr.p_memsz - 1), maps).readable) 760 break; 761 762 std::vector<KT_ElfW(Dyn)> dyn_buff(phdr.p_memsz / sizeof(KT_ElfW(Dyn))); 763 if (!_pMem->Read(_dynamic, &dyn_buff[0], phdr.p_memsz)) 764 { 765 KITTY_LOGD("ElfScanner: Failed to read dynamic for ELF (%p).", (void *)_elfBase); 766 break; 767 } 768 769 for (auto &dyn : dyn_buff) 770 { 771 if (dyn.d_tag == DT_NULL) 772 break; 773 774 switch (dyn.d_tag) 775 { 776 case DT_STRTAB: 777 if (_stringTable == 0) 778 _stringTable = dyn.d_un.d_ptr; 779 break; 780 case DT_SYMTAB: 781 if (_symbolTable == 0) 782 _symbolTable = dyn.d_un.d_ptr; 783 break; 784 case DT_STRSZ: 785 if (_strsz == 0) 786 _strsz = dyn.d_un.d_val; 787 break; 788 case DT_SYMENT: 789 _syment = dyn.d_un.d_val; 790 break; 791 default: 792 break; 793 } 794 795 _dynamics.push_back(dyn); 796 } 797 798 break; 799 } 800 } 801 802 auto fix_table_address = [&](uintptr_t &table_addr) { 803 if (table_addr && table_addr < _loadBias) 804 table_addr += _loadBias; 805 806 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), table_addr, maps).readable) 807 table_addr = 0; 808 }; 809 810 fix_table_address(_symbolTable); 811 fix_table_address(_stringTable); 812 } 813 #endif 814 815 std::unordered_map<std::string, uintptr_t> ElfScanner::symbols() 816 { 817 if (!_symbols_init && _loadBias && _stringTable && _symbolTable && _strsz && _syment) 818 { 819 _symbols_init = true; 820 821 auto get_sym_address = [&](const KT_ElfW(Sym) * sym_ent) -> uintptr_t { 822 return sym_ent->st_value < _loadBias ? _loadBias + sym_ent->st_value : sym_ent->st_value; 823 }; 824 825 size_t symtab_sz = ((_stringTable > _symbolTable) ? (_stringTable - _symbolTable) 826 : (_symbolTable - _stringTable)); 827 std::vector<char> symtab_buff(symtab_sz, 0); 828 std::vector<char> strtab_buff(_strsz, 0); 829 830 if (_pMem->Read(_symbolTable, symtab_buff.data(), symtab_buff.size()) && 831 _pMem->Read(_stringTable, strtab_buff.data(), strtab_buff.size())) 832 { 833 uintptr_t sym_start = uintptr_t(symtab_buff.data()); 834 uintptr_t sym_end = uintptr_t(symtab_buff.data() + symtab_buff.size()); 835 uintptr_t sym_str_end = uintptr_t(strtab_buff.data() + strtab_buff.size()); 836 for (auto sym_entry = sym_start; (sym_entry + _syment) < sym_end; sym_entry += _syment) 837 { 838 const KT_ElfW(Sym) *curr_sym = reinterpret_cast<KT_ElfW(Sym) *>(sym_entry); 839 840 if (curr_sym->st_name >= _strsz) 841 break; 842 843 if (intptr_t(curr_sym->st_name) <= 0 || intptr_t(curr_sym->st_value) <= 0 || 844 intptr_t(curr_sym->st_size) <= 0) 845 continue; 846 847 if (KT_ELF_ST_TYPE(curr_sym->st_info) != STT_OBJECT && KT_ELF_ST_TYPE(curr_sym->st_info) != STT_FUNC) 848 continue; 849 850 uintptr_t sym_str_addr = uintptr_t(strtab_buff.data() + curr_sym->st_name); 851 if (!sym_str_addr || sym_str_addr >= sym_str_end) 852 continue; 853 854 std::string sym_str = std::string(reinterpret_cast<const char *>(sym_str_addr)); 855 if (!sym_str.empty() && sym_str.data()) 856 _symbolsMap[sym_str] = get_sym_address(curr_sym); 857 } 858 } 859 } 860 861 return _symbolsMap; 862 } 863 864 std::unordered_map<std::string, uintptr_t> ElfScanner::dsymbols() 865 { 866 if (!_dsymbols_init && _loadBias && !_filepath.empty()) 867 { 868 _dsymbols_init = true; 869 870 auto get_sym_address = [&](const KT_ElfW(Sym) * sym_ent) -> uintptr_t { 871 return sym_ent->st_value < _loadBias ? _loadBias + sym_ent->st_value : sym_ent->st_value; 872 }; 873 874 KittyUtils::Zip::ZipEntryMMap mmap_info = {}; 875 if (isZipped()) 876 { 877 if (!KittyUtils::Zip::mmapEntryByDataOffset(_filepath, _baseSegment.offset, &mmap_info)) 878 return _dsymbolsMap; 879 } 880 else 881 { 882 KittyIOFile elfFile(_filepath, O_RDONLY); 883 if (!elfFile.open()) 884 { 885 KITTY_LOGD("Failed to open file <%s> err(%s)", _filepath.c_str(), elfFile.lastStrError().c_str()); 886 return _dsymbolsMap; 887 } 888 size_t elfSize = elfFile.info().st_size; 889 if (elfSize <= 0) 890 { 891 elfFile.close(); 892 KITTY_LOGD("stat failed for <%s>", _filepath.c_str()); 893 return _dsymbolsMap; 894 } 895 mmap_info.mappingBase = mmap(nullptr, elfSize, PROT_READ, MAP_PRIVATE, elfFile.fd(), 0); 896 mmap_info.mappingSize = elfSize; 897 mmap_info.data = reinterpret_cast<uint8_t *>(mmap_info.mappingBase); 898 mmap_info.size = mmap_info.mappingSize; 899 elfFile.close(); 900 } 901 902 if (mmap_info.size == 0 || !mmap_info.data || mmap_info.data == ((void *)-1)) 903 { 904 KITTY_LOGD("Failed to mmap <%s>", realPath().c_str()); 905 return _dsymbolsMap; 906 } 907 908 auto cleanup = [&] { munmap(mmap_info.mappingBase, mmap_info.mappingSize); }; 909 910 KT_ElfW(Ehdr) *ehdr = reinterpret_cast<KT_ElfW(Ehdr) *>(mmap_info.data); 911 912 if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) 913 { 914 KITTY_LOGD("<%s> is not a valid ELF", realPath().c_str()); 915 cleanup(); 916 return _dsymbolsMap; 917 } 918 919 if (ehdr->e_phoff == 0 || ehdr->e_phentsize == 0 || ehdr->e_phnum == 0 || 920 ehdr->e_phoff + ehdr->e_phnum * sizeof(KT_ElfW(Phdr)) > mmap_info.size) 921 { 922 KITTY_LOGD("Invalid program header table in <%s>", filePath().c_str()); 923 cleanup(); 924 return _dsymbolsMap; 925 } 926 927 if (ehdr->e_shoff == 0 || ehdr->e_shentsize == 0 || ehdr->e_shnum == 0 || 928 ehdr->e_shoff + ehdr->e_shnum * sizeof(KT_ElfW(Shdr)) > mmap_info.size) 929 { 930 KITTY_LOGD("Invalid section header table in <%s>", filePath().c_str()); 931 cleanup(); 932 return _dsymbolsMap; 933 } 934 935 const KT_ElfW(Shdr) *shdr = reinterpret_cast<KT_ElfW(Shdr) *>(reinterpret_cast<char *>(mmap_info.data) + 936 ehdr->e_shoff); 937 const KT_ElfW(Shdr) *shstrtab_shdr = shdr + ehdr->e_shstrndx; 938 const char *sectionstr = reinterpret_cast<char *>(reinterpret_cast<char *>(mmap_info.data) + 939 shstrtab_shdr->sh_offset); 940 for (uint16_t i = 0; i < ehdr->e_shnum; ++i) 941 { 942 if (shdr[i].sh_type != SHT_SYMTAB) 943 continue; 944 945 std::string section_name = std::string(reinterpret_cast<const char *>(sectionstr + shdr[i].sh_name)); 946 if (section_name.compare(".symtab") != 0) 947 continue; 948 949 if ((shdr[i].sh_offset + shdr[i].sh_size) > mmap_info.size || shdr[i].sh_link >= ehdr->e_shnum || 950 (shdr[shdr[i].sh_link].sh_offset + shdr[shdr[i].sh_link].sh_size) > mmap_info.size) 951 continue; 952 953 const KT_ElfW(Sym) *symtab = reinterpret_cast<KT_ElfW(Sym) *>(reinterpret_cast<char *>(mmap_info.data) + 954 shdr[i].sh_offset); 955 const size_t symCount = shdr[i].sh_size / shdr[i].sh_entsize; 956 const KT_ElfW(Shdr) *strtabShdr = &shdr[shdr[i].sh_link]; 957 const char *strtab = reinterpret_cast<char *>(reinterpret_cast<char *>(mmap_info.data) + 958 strtabShdr->sh_offset); 959 960 for (size_t j = 0; j < symCount; ++j) 961 { 962 const KT_ElfW(Sym) *curr_sym = &symtab[j]; 963 if (!curr_sym || curr_sym->st_name >= strtabShdr->sh_size) 964 continue; 965 966 if (intptr_t(curr_sym->st_value) <= 0 || intptr_t(curr_sym->st_size) <= 0) 967 continue; 968 969 if (KT_ELF_ST_TYPE(curr_sym->st_info) != STT_OBJECT && KT_ELF_ST_TYPE(curr_sym->st_info) != STT_FUNC) 970 continue; 971 972 std::string sym_str = std::string(reinterpret_cast<const char *>(strtab + curr_sym->st_name)); 973 if (!sym_str.empty() && sym_str.data()) 974 _dsymbolsMap[sym_str] = get_sym_address(curr_sym); 975 } 976 } 977 cleanup(); 978 } 979 return _dsymbolsMap; 980 } 981 982 uintptr_t ElfScanner::findSymbol(const std::string &symbolName) 983 { 984 const auto &syms = symbols(); 985 auto it = syms.find(symbolName); 986 return it != syms.end() ? it->second : 0; 987 } 988 989 uintptr_t ElfScanner::findDebugSymbol(const std::string &symbolName) 990 { 991 const auto &syms = dsymbols(); 992 auto it = syms.find(symbolName); 993 return it != syms.end() ? it->second : 0; 994 } 995 996 bool ElfScannerMgr::isValidELF(uintptr_t elfBase) const 997 { 998 if (!_pMem || !elfBase) 999 return false; 1000 1001 char magic[4] = {0}; 1002 return _pMem->Read(elfBase, magic, sizeof(magic)) && memcmp(magic, "\177ELF", 4) == 0; 1003 } 1004 1005 ElfScanner &ElfScannerMgr::getProgramElf() 1006 { 1007 if (!_pMem) 1008 return _programElf; 1009 1010 if (!_programElf.isValid() || !_programElf.dynamic()) 1011 { 1012 std::string path = KittyUtils::String::fmt("/proc/%d/exe", _pMem->processID()); 1013 char exePath[0xff] = {}; 1014 int ret = int(readlink(path.c_str(), exePath, 0xff)); 1015 if (ret == -1 || exePath[0] == '\0') 1016 { 1017 int err = errno; 1018 KITTY_LOGE("Failed to readlink \"%s\", error(%d): %s.", path.c_str(), err, strerror(err)); 1019 return _programElf; 1020 } 1021 1022 const auto allMaps = KittyMemoryEx::getAllMaps(_pMem->processID()); 1023 std::vector<KittyMemoryEx::ProcMap> exeMaps; 1024 1025 #ifdef __ANDROID__ 1026 // Fix for google emulator which has two app_process 1027 // Make sure to always get native one 1028 { 1029 std::string exeName = KittyUtils::Path::fileName(exePath); 1030 std::string binDir = KittyUtils::Path::fileDirectory(KittyUtils::Path::fileDirectory(exePath)); 1031 exeMaps = KittyMemoryEx::getMaps(_pMem->processID(), 1032 KittyMemoryEx::EProcMapFilter::Equal, 1033 binDir + "/" + exeName, 1034 allMaps); 1035 if (exeMaps.empty()) 1036 { 1037 exeMaps = KittyMemoryEx::getMaps(_pMem->processID(), 1038 KittyMemoryEx::EProcMapFilter::Equal, 1039 exePath, 1040 allMaps); 1041 } 1042 } 1043 #else 1044 exeMaps = KittyMemoryEx::getMaps(_pMem->processID(), KittyMemoryEx::EProcMapFilter::Equal, exePath, allMaps); 1045 #endif 1046 1047 for (const auto &it : exeMaps) 1048 { 1049 if (!it.readable || it.writeable) 1050 continue; 1051 1052 _programElf = ElfScanner(_pMem, it.startAddress, allMaps); 1053 if (_programElf.isValid() && _programElf.dynamic()) 1054 break; 1055 } 1056 } 1057 1058 return _programElf; 1059 } 1060 1061 #ifdef __ANDROID__ 1062 std::vector<ElfScanner> ElfScannerMgr::getAllELFs(EScanElfType type, EScanElfFilter filter) 1063 #else 1064 std::vector<ElfScanner> ElfScannerMgr::getAllELFs() 1065 #endif 1066 { 1067 std::vector<ElfScanner> elfs; 1068 1069 if (!_pMem) 1070 return elfs; 1071 1072 #ifdef __ANDROID__ 1073 const auto progMachine = getProgramElf().header().e_machine; 1074 static auto eMachineCheck = [](EScanElfType type, int a, int b) -> bool { 1075 return a == 0 || b == 0 || type == EScanElfType::Any || (type == EScanElfType::Native && a == b) || 1076 (type == EScanElfType::Emulated && a != b); 1077 }; 1078 1079 const bool isAppFilter = filter == EScanElfFilter::App; 1080 const bool isSysFilter = filter == EScanElfFilter::System; 1081 #endif 1082 1083 auto maps = KittyMemoryEx::getAllMaps(_pMem->processID()); 1084 if (maps.empty()) 1085 { 1086 KITTY_LOGD("GetAllELFs: Failed to get process maps."); 1087 return elfs; 1088 } 1089 1090 unsigned long lastElfNode = 0; 1091 1092 for (auto &it : maps) 1093 { 1094 #ifdef __LP64__ 1095 if (it.startAddress >= (0x7fffffffffff - 0x1000)) 1096 continue; 1097 #else 1098 if (it.startAddress >= (0xffffffff - 0x1000)) 1099 continue; 1100 #endif 1101 1102 if (!it.isValid() || !it.readable || it.writeable || it.is_shared || (it.inode != 0 && it.inode == lastElfNode)) 1103 continue; 1104 1105 #ifdef __ANDROID__ 1106 if (isAppFilter) 1107 { 1108 if (it.inode == 0 || (!KittyUtils::String::startsWith(it.pathname, "/data/") && 1109 !KittyUtils::String::startsWith(it.pathname, "/proc/") && 1110 !KittyUtils::String::startsWith(it.pathname, "/memfd:"))) 1111 continue; 1112 } 1113 else if (isSysFilter) 1114 { 1115 if ((it.inode == 0 && it.pathname != "[vdso]") || 1116 (!KittyUtils::String::startsWith(it.pathname, "/system/") && 1117 !KittyUtils::String::startsWith(it.pathname, "/apex/"))) 1118 continue; 1119 } 1120 #endif 1121 1122 if (_cached_elfs.size() && _cached_elfs.count(it.startAddress) > 0) 1123 { 1124 auto elf = _cached_elfs[it.startAddress]; 1125 if (elf.filePath() == it.pathname) 1126 { 1127 #ifdef __ANDROID__ 1128 if (eMachineCheck(type, progMachine, elf.header().e_machine)) 1129 #endif 1130 { 1131 elfs.push_back(elf); 1132 } 1133 lastElfNode = elf.baseSegment().inode; 1134 continue; 1135 } 1136 else 1137 { 1138 _cached_elfs.erase(it.startAddress); 1139 } 1140 } 1141 1142 #ifdef __ANDROID__ 1143 bool isFile = (!it.pathname.empty() && it.inode != 0); 1144 if (!isFile && it.pathname != "[vdso]" && !KittyUtils::String::startsWith(it.pathname, "/memfd:")) 1145 continue; 1146 1147 if (it.pathname == "cfi shadow") 1148 continue; 1149 1150 if (KittyUtils::String::startsWith(it.pathname, "/dev/") || 1151 KittyUtils::String::startsWith(it.pathname, "/system/fonts/") || 1152 KittyUtils::String::startsWith(it.pathname, "/data/priv-downloads/") || 1153 KittyUtils::String::startsWith(it.pathname, "/data/misc/")) 1154 continue; 1155 1156 if (KittyUtils::String::startsWith(it.pathname, "/system/etc/") && 1157 !KittyUtils::String::endsWith(it.pathname, ".so")) 1158 continue; 1159 1160 if (KittyUtils::String::startsWith(it.pathname, "/data/dalvik-cache/") || 1161 KittyUtils::String::startsWith(it.pathname, "/system/") || 1162 KittyUtils::String::startsWith(it.pathname, "/apex/com.android.") || 1163 (KittyUtils::String::startsWith(it.pathname, "/data/app/") && 1164 KittyUtils::String::contains(it.pathname, "/oat/"))) 1165 { 1166 if (KittyUtils::String::endsWith(it.pathname, ".jar") || 1167 KittyUtils::String::endsWith(it.pathname, ".art") || 1168 KittyUtils::String::endsWith(it.pathname, ".oat") || 1169 KittyUtils::String::endsWith(it.pathname, ".odex") || KittyUtils::String::endsWith(it.pathname, ".dex")) 1170 continue; 1171 } 1172 #endif 1173 1174 auto elf = ElfScanner(_pMem, it.startAddress, maps); 1175 if (elf.isValid()) 1176 { 1177 #ifdef __ANDROID__ 1178 if (eMachineCheck(type, progMachine, elf.header().e_machine)) 1179 #endif 1180 { 1181 elfs.push_back(elf); 1182 } 1183 lastElfNode = elf.baseSegment().inode; 1184 _cached_elfs[it.startAddress] = elf; 1185 } 1186 } 1187 1188 std::vector<uintptr_t> invalid_keys; 1189 for (auto &it : _cached_elfs) 1190 { 1191 if (it.first && !KittyMemoryEx::getAddressMap(_pMem->processID(), it.first, maps).readable) 1192 { 1193 invalid_keys.push_back(it.first); 1194 } 1195 } 1196 1197 for (auto &it : invalid_keys) 1198 { 1199 _cached_elfs.erase(it); 1200 } 1201 1202 return elfs; 1203 } 1204 1205 #ifdef __ANDROID__ 1206 ElfScanner ElfScannerMgr::findElf(const std::string &path, EScanElfType type, EScanElfFilter filter) 1207 #else 1208 ElfScanner ElfScannerMgr::findElf(const std::string &path) 1209 #endif 1210 { 1211 ElfScanner ret{}; 1212 1213 if (!_pMem || path.empty()) 1214 return ret; 1215 1216 std::vector<ElfScanner> elfs; 1217 std::vector<ElfScanner> dyn_elfs; 1218 1219 #ifdef __ANDROID__ 1220 const auto allElfs = getAllELFs(type, filter); 1221 #else 1222 const auto allElfs = getAllELFs(); 1223 #endif 1224 for (const auto &it : allElfs) 1225 { 1226 if (it.isValid() && KittyUtils::String::endsWith(it.realPath(), path)) 1227 { 1228 if (it.dynamic() && it.dynamics().size() > 0) 1229 dyn_elfs.push_back(it); 1230 else 1231 elfs.push_back(it); 1232 } 1233 } 1234 1235 if (elfs.empty() && dyn_elfs.empty()) 1236 return ret; 1237 1238 if (dyn_elfs.size() > 0) 1239 { 1240 if (dyn_elfs.size() == 1) 1241 return dyn_elfs[0]; 1242 1243 int nMostSegments = 0; 1244 for (auto &it : dyn_elfs) 1245 { 1246 int numSegments = it.segments().size(); 1247 // >= to get latest 1248 if (numSegments >= nMostSegments) 1249 { 1250 ret = it; 1251 nMostSegments = numSegments; 1252 } 1253 } 1254 } 1255 else if (elfs.size() > 0) 1256 { 1257 if (elfs.size() == 1) 1258 return elfs[0]; 1259 1260 int nMostSegments = 0; 1261 for (auto &it : elfs) 1262 { 1263 int numSegments = it.segments().size(); 1264 // >= to get latest 1265 if (numSegments >= nMostSegments) 1266 { 1267 ret = it; 1268 nMostSegments = numSegments; 1269 } 1270 } 1271 } 1272 1273 return ret; 1274 } 1275 1276 #ifdef __ANDROID__ 1277 std::vector<std::pair<uintptr_t, ElfScanner>> ElfScannerMgr::findSymbolAll(const std::string &symbolName, 1278 EScanElfType type, 1279 EScanElfFilter filter) 1280 #else 1281 std::vector<std::pair<uintptr_t, ElfScanner>> ElfScannerMgr::findSymbolAll(const std::string &symbolName) 1282 #endif 1283 { 1284 std::vector<std::pair<uintptr_t, ElfScanner>> ret{}; 1285 1286 #ifdef __ANDROID__ 1287 auto elfs = getAllELFs(type, filter); 1288 #else 1289 auto elfs = getAllELFs(); 1290 #endif 1291 for (auto &it : elfs) 1292 { 1293 uintptr_t sym = it.findSymbol(symbolName); 1294 if (sym != 0) 1295 { 1296 ret.emplace_back(sym, it); 1297 } 1298 } 1299 1300 return ret; 1301 } 1302 1303 uintptr_t ElfScannerMgr::findRemoteSymbol(const std::string &local_sym_name, uintptr_t local_sym_addr) 1304 { 1305 if (!_pMem || local_sym_name.empty() || !local_sym_addr) 1306 return 0; 1307 1308 ElfScanner r_lib{}; 1309 KittyMemoryEx::ProcMap l_lib{}; 1310 1311 l_lib = KittyMemoryEx::getAddressMap(getpid(), local_sym_addr); 1312 if (l_lib.isValid()) 1313 r_lib = findElf(l_lib.pathname); 1314 1315 if (!r_lib.isValid()) 1316 { 1317 KITTY_LOGD("KittyInjector: Failed to find %s, remote lib not found.", local_sym_name.c_str()); 1318 return 0; 1319 } 1320 1321 uintptr_t remote_address = r_lib.findSymbol(local_sym_name); 1322 1323 // fallback 1324 if (!remote_address) 1325 remote_address = local_sym_addr - l_lib.startAddress + r_lib.base(); 1326 1327 return remote_address; 1328 } 1329 1330 #ifdef __ANDROID__ 1331 LinkerScannerMgr::LinkerScannerMgr(IKittyMemOp *pMem, uintptr_t linkerBase) : ElfScanner(pMem, linkerBase) 1332 { 1333 memset(&_linker_syms, 0, sizeof(_linker_syms)); 1334 memset(&_soinfo_offsets, 0, sizeof(_soinfo_offsets)); 1335 _init = false; 1336 1337 if (!pMem || !isValid()) 1338 return; 1339 1340 _pMem = pMem; 1341 init(); 1342 } 1343 1344 LinkerScannerMgr::LinkerScannerMgr(IKittyMemOp *pMem, const ElfScanner &linkerElf) : ElfScanner(linkerElf) 1345 { 1346 memset(&_linker_syms, 0, sizeof(_linker_syms)); 1347 memset(&_soinfo_offsets, 0, sizeof(_soinfo_offsets)); 1348 _init = false; 1349 1350 if (!pMem || !isValid()) 1351 return; 1352 1353 _pMem = pMem; 1354 init(); 1355 } 1356 1357 bool LinkerScannerMgr::init() 1358 { 1359 if (!_pMem || !isValid()) 1360 return false; 1361 1362 if (_init) 1363 return true; 1364 1365 for (const auto &sym : dsymbols()) 1366 { 1367 if (KittyUtils::String::startsWith(sym.first, "__dl__ZL11solist_head") || 1368 KittyUtils::String::startsWith(sym.first, "__dl__ZL6solist")) 1369 { 1370 _linker_syms.solist = sym.second; 1371 continue; 1372 } 1373 if (KittyUtils::String::startsWith(sym.first, "__dl__ZL6somain")) 1374 { 1375 _linker_syms.somain = sym.second; 1376 continue; 1377 } 1378 if (KittyUtils::String::startsWith(sym.first, "__dl__ZL11solist_tail") || 1379 KittyUtils::String::startsWith(sym.first, "__dl__ZL6sonext")) 1380 { 1381 _linker_syms.sonext = sym.second; 1382 continue; 1383 } 1384 if (_linker_syms.solist && _linker_syms.somain && _linker_syms.sonext) 1385 break; 1386 } 1387 1388 if (!(_linker_syms.solist && _linker_syms.somain && _linker_syms.sonext)) 1389 { 1390 return false; 1391 } 1392 1393 KITTY_LOGD("solist(%zx) | somain(%zx) | sonext(%zx)", solist(), somain(), sonext()); 1394 1395 std::vector<char> solist_buf(KT_SOINFO_BUFFER_SZ, 0); 1396 _pMem->Read(solist(), solist_buf.data(), KT_SOINFO_BUFFER_SZ); 1397 1398 std::vector<char> si_buf(KT_SOINFO_BUFFER_SZ, 0); 1399 uintptr_t somain_ptr = somain(); 1400 _pMem->Read(somain_ptr ? somain_ptr : sonext(), si_buf.data(), KT_SOINFO_BUFFER_SZ); 1401 1402 auto allMaps = KittyMemoryEx::getAllMaps(_pMem->processID()); 1403 1404 ElfScanner si_elf{}; 1405 for (size_t i = 0; i < si_buf.size(); i += sizeof(uintptr_t)) 1406 { 1407 uintptr_t possible_base = *(uintptr_t *)&si_buf[i]; 1408 1409 auto tmp_map = KittyMemoryEx::getAddressMap(_pMem->processID(), possible_base, allMaps); 1410 if (!tmp_map.isValid() || !tmp_map.readable || tmp_map.writeable || tmp_map.is_shared) 1411 continue; 1412 1413 si_elf = ElfScanner(_pMem, possible_base, allMaps); 1414 if (si_elf.isValid()) 1415 { 1416 _soinfo_offsets.base = i; 1417 break; 1418 } 1419 } 1420 1421 KITTY_LOGD("soinfo_base(%zx)", _soinfo_offsets.base); 1422 1423 if (_soinfo_offsets.base == 0) 1424 return false; 1425 1426 for (size_t i = 0; i < si_buf.size(); i += sizeof(uintptr_t)) 1427 { 1428 uintptr_t value = *(uintptr_t *)&si_buf[i]; 1429 1430 if (!_soinfo_offsets.phdr && value == si_elf.phdr()) 1431 { 1432 _soinfo_offsets.phdr = i; 1433 continue; 1434 } 1435 if (!_soinfo_offsets.phnum && value == si_elf.header().e_phnum) 1436 { 1437 _soinfo_offsets.phnum = i; 1438 continue; 1439 } 1440 if (!_soinfo_offsets.size && 1441 (value == si_elf.loadSize() || 1442 value == 1443 (si_elf.loadSize() + KittyMemoryEx::getAddressMap(_pMem->processID(), si_elf.end(), allMaps).length))) 1444 { 1445 _soinfo_offsets.size = i; 1446 continue; 1447 } 1448 if (!_soinfo_offsets.dyn && value == si_elf.dynamic()) 1449 { 1450 _soinfo_offsets.dyn = i; 1451 continue; 1452 } 1453 if (!_soinfo_offsets.strtab && value == si_elf.stringTable()) 1454 { 1455 _soinfo_offsets.strtab = i; 1456 continue; 1457 } 1458 if (!_soinfo_offsets.symtab && value == si_elf.symbolTable()) 1459 { 1460 _soinfo_offsets.symtab = i; 1461 continue; 1462 } 1463 if (!_soinfo_offsets.bias && value == si_elf.loadBias() && i != _soinfo_offsets.base) 1464 { 1465 _soinfo_offsets.bias = i; 1466 continue; 1467 } 1468 if (!_soinfo_offsets.strsz && value == si_elf.stringTableSize()) 1469 { 1470 _soinfo_offsets.strsz = i; 1471 continue; 1472 } 1473 } 1474 1475 KITTY_LOGD("soinfo_bias(%zx) | soinfo_size(%zx)", _soinfo_offsets.bias, _soinfo_offsets.size); 1476 KITTY_LOGD("soinfo_phdr(%zx, %zx) | soinfo_dyn(%zx)", 1477 _soinfo_offsets.phdr, 1478 _soinfo_offsets.phnum, 1479 _soinfo_offsets.dyn); 1480 KITTY_LOGD("soinfo_strtab(%zx, %zx) | soinfo_symtab(%zx)", 1481 _soinfo_offsets.strtab, 1482 _soinfo_offsets.strsz, 1483 _soinfo_offsets.symtab); 1484 1485 if (!(_soinfo_offsets.size && _soinfo_offsets.bias && _soinfo_offsets.dyn && _soinfo_offsets.symtab && 1486 _soinfo_offsets.strtab)) 1487 { 1488 return false; 1489 } 1490 1491 for (size_t i = 0; i < solist_buf.size(); i += sizeof(uintptr_t)) 1492 { 1493 uintptr_t possible_next = *(uintptr_t *)&solist_buf[i]; 1494 1495 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), possible_next + _soinfo_offsets.base, allMaps).readable) 1496 continue; 1497 1498 uintptr_t possible_base = 0; 1499 _pMem->Read(possible_next + _soinfo_offsets.base, &possible_base, sizeof(uintptr_t)); 1500 1501 auto tmp_map = KittyMemoryEx::getAddressMap(_pMem->processID(), possible_base, allMaps); 1502 if (!tmp_map.isValid() || !tmp_map.readable || tmp_map.writeable || tmp_map.is_shared) 1503 continue; 1504 1505 auto tmp_elf = ElfScanner(_pMem, possible_base, allMaps); 1506 if (tmp_elf.isValid()) 1507 { 1508 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), possible_next + _soinfo_offsets.size, allMaps) 1509 .readable) 1510 continue; 1511 1512 uintptr_t possible_size = 0; 1513 _pMem->Read(possible_next + _soinfo_offsets.size, &possible_size, sizeof(uintptr_t)); 1514 if (possible_size == tmp_elf.loadSize() || 1515 possible_size == (tmp_elf.loadSize() + 1516 KittyMemoryEx::getAddressMap(_pMem->processID(), tmp_elf.end(), allMaps).length)) 1517 { 1518 _soinfo_offsets.next = i; 1519 break; 1520 } 1521 } 1522 } 1523 1524 KITTY_LOGD("soinfo_sonext(%zx)", _soinfo_offsets.next); 1525 1526 _init = _soinfo_offsets.next != 0; 1527 return _init; 1528 } 1529 1530 std::vector<kitty_soinfo_t> LinkerScannerMgr::allSoInfo() const 1531 { 1532 std::vector<kitty_soinfo_t> infos{}; 1533 1534 if (!_pMem || !isValid() || !_init) 1535 return infos; 1536 1537 auto maps = KittyMemoryEx::getAllMaps(_pMem->processID()); 1538 uintptr_t si = solist(), prev = 0; 1539 while (si && KittyMemoryEx::getAddressMap(_pMem->processID(), si, maps).readable) 1540 { 1541 kitty_soinfo_t info = infoFromSoInfo_(si, maps); 1542 infos.push_back(info); 1543 1544 prev = si; 1545 1546 if (_pMem->Read(si + _soinfo_offsets.next, &si, sizeof(uintptr_t)) != sizeof(uintptr_t)) 1547 break; 1548 1549 if (si == prev) 1550 break; 1551 } 1552 return infos; 1553 } 1554 1555 kitty_soinfo_t LinkerScannerMgr::findSoInfo(const std::string &name) const 1556 { 1557 const auto list = allSoInfo(); 1558 for (const auto &it : list) 1559 { 1560 if (KittyUtils::String::endsWith(it.realpath, name)) 1561 { 1562 return it; 1563 } 1564 } 1565 return {}; 1566 } 1567 1568 kitty_soinfo_t LinkerScannerMgr::infoFromSoInfo_(uintptr_t si, const std::vector<KittyMemoryEx::ProcMap> &maps) const 1569 { 1570 kitty_soinfo_t info{}; 1571 1572 if (!_pMem || !isValid() || !_init) 1573 return info; 1574 1575 std::vector<char> si_buf(KT_SOINFO_BUFFER_SZ, 0); 1576 if (!_pMem->Read(si, si_buf.data(), KT_SOINFO_BUFFER_SZ)) 1577 return info; 1578 1579 info.ptr = si; 1580 info.base = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.base); 1581 info.size = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.size); 1582 info.phdr = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.phdr); 1583 info.phnum = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.phnum); 1584 info.dyn = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.dyn); 1585 info.strtab = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.strtab); 1586 info.symtab = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.symtab); 1587 info.strsz = _soinfo_offsets.strsz ? *(uintptr_t *)(si_buf.data() + _soinfo_offsets.strsz) : 0; 1588 info.bias = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.bias); 1589 info.next = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.next); 1590 info.e_machine = header().e_machine; 1591 1592 uintptr_t start_map_addr = info.base; 1593 if (start_map_addr == 0) 1594 start_map_addr = info.base; 1595 if (start_map_addr == 0) 1596 start_map_addr = info.bias; 1597 if (start_map_addr == 0) 1598 start_map_addr = info.phdr; 1599 if (start_map_addr == 0) 1600 start_map_addr = info.dyn; 1601 if (start_map_addr == 0) 1602 start_map_addr = info.strtab; 1603 if (start_map_addr == 0) 1604 start_map_addr = info.symtab; 1605 1606 auto si_map = KittyMemoryEx::getAddressMap(_pMem->processID(), start_map_addr, maps); 1607 if (si_map.isValid()) 1608 { 1609 info.path = si_map.pathname; 1610 info.realpath = si_map.pathname; 1611 if (si_map.offset != 0) 1612 { 1613 KittyUtils::Zip::ZipEntryInfo ent{}; 1614 if (KittyUtils::Zip::findEntryInfoByDataOffset(si_map.pathname, si_map.offset, &ent) && 1615 !ent.fileName.empty()) 1616 { 1617 info.realpath += '!'; 1618 info.realpath += ent.fileName; 1619 } 1620 } 1621 } 1622 1623 return info; 1624 } 1625 1626 NativeBridgeScannerMgr::NativeBridgeScannerMgr(IKittyMemOp *pMem, 1627 KittyScannerMgr *memScanner, 1628 ElfScannerMgr *elfScanner) 1629 { 1630 _pMem = pMem; 1631 _memScanner = memScanner; 1632 _elfScanner = elfScanner; 1633 1634 _sohead = 0; 1635 1636 _nbItf = 0; 1637 _nbItf_data_size = 0; 1638 _isHoudini = false; 1639 1640 fnNativeBridgeInitialized = nullptr; 1641 1642 memset(&_nbItf_data, 0, sizeof(_nbItf_data)); 1643 memset(&_soinfo_offsets, 0, sizeof(_soinfo_offsets)); 1644 1645 _init = false; 1646 1647 if (!_pMem || !_memScanner || !_elfScanner) 1648 return; 1649 1650 init(); 1651 } 1652 1653 bool NativeBridgeScannerMgr::init() 1654 { 1655 if (!_pMem || !_memScanner || !_elfScanner) 1656 return false; 1657 1658 if (_init) 1659 return true; 1660 1661 _nbElf = _elfScanner->findElf("/libnativebridge.so", EScanElfType::Native, EScanElfFilter::System); 1662 if (!_nbElf.isValid()) 1663 { 1664 KITTY_LOGD("NativeBridgeScanner: Failed to find libnativebrdge.so"); 1665 return false; 1666 } 1667 1668 *(uintptr_t *)&fnNativeBridgeInitialized = _nbElf.findSymbol("NativeBridgeInitialized"); 1669 if (fnNativeBridgeInitialized == nullptr) 1670 *(uintptr_t *)&fnNativeBridgeInitialized = _nbElf.findSymbol("_ZN7android23NativeBridgeInitializedEv"); 1671 1672 _nbImplElf = _elfScanner->findElf("/libhoudini.so", EScanElfType::Native, EScanElfFilter::System); 1673 if (_nbImplElf.isValid()) 1674 _isHoudini = true; 1675 else 1676 _nbImplElf = _elfScanner->findElf("/libndk_translation.so", EScanElfType::Native, EScanElfFilter::System); 1677 1678 if (!_nbImplElf.isValid()) 1679 { 1680 KITTY_LOGD("NativeBridgeScanner: Failed to find nativebridge implementation"); 1681 return false; 1682 } 1683 1684 _nbItf = _nbImplElf.findSymbol("NativeBridgeItf"); 1685 if (_nbItf == 0) 1686 { 1687 KITTY_LOGD("NativeBridgeScanner: Failed to find export NativeBridgeItf"); 1688 return false; 1689 } 1690 1691 if (_pMem->Read(_nbItf, &_nbItf_data.version, sizeof(int)) != sizeof(int)) 1692 { 1693 KITTY_LOGD("NativeBridgeScanner: Failed to read nativebridge version"); 1694 return false; 1695 } 1696 1697 _nbItf_data_size = nbItf_data_t::GetStructSize(_nbItf_data.version); 1698 if (_nbItf_data_size == 0) 1699 { 1700 KITTY_LOGD("NativeBridgeScanner: Unsupported nativebridge version (%d)", _nbItf_data.version); 1701 return false; 1702 } 1703 1704 KITTY_LOGD("NativeBridgeScanner: Using nativebridge version (%d), data size (%p)", 1705 _nbItf_data.version, 1706 (void *)_nbItf_data_size); 1707 1708 if (_pMem->Read(_nbItf, &_nbItf_data, _nbItf_data_size) != _nbItf_data_size) 1709 { 1710 KITTY_LOGD("NativeBridgeScanner: Failed to read NativeBridgeItf data"); 1711 return false; 1712 } 1713 1714 // replace for nb v2 1715 if (_nbItf_data.version < KT_NB_NAMESPACE_VERSION) 1716 { 1717 uintptr_t pLoadLibrary = _nbElf.findSymbol("NativeBridgeLoadLibrary"); 1718 if (pLoadLibrary == 0) 1719 pLoadLibrary = _nbElf.findSymbol("_ZN7android23NativeBridgeLoadLibraryEPKci"); 1720 1721 uintptr_t pGetTrampoline = _nbElf.findSymbol("NativeBridgeGetTrampoline"); 1722 if (pGetTrampoline == 0) 1723 pGetTrampoline = _nbElf.findSymbol("_ZN7android25NativeBridgeGetTrampolineEPvPKcS2_j"); 1724 1725 if (pLoadLibrary != 0) 1726 *(uintptr_t *)&_nbItf_data.loadLibrary = pLoadLibrary; 1727 1728 if (pGetTrampoline != 0) 1729 *(uintptr_t *)&_nbItf_data.getTrampoline = pGetTrampoline; 1730 } 1731 1732 // emulated linker for google emulators 1733 #ifdef __LP64__ 1734 LinkerScannerMgr emulinker = LinkerScannerMgr(_pMem, 1735 _elfScanner->findElf("/linker64", 1736 EScanElfType::Emulated, 1737 EScanElfFilter::System)); 1738 #else 1739 LinkerScannerMgr emulinker = LinkerScannerMgr(_pMem, 1740 _elfScanner->findElf("/linker", 1741 EScanElfType::Emulated, 1742 EScanElfFilter::System)); 1743 #endif 1744 1745 if (!_isHoudini && emulinker.init()) 1746 { 1747 _sohead = emulinker.solist(); 1748 _soheadElf = *emulinker.asELF(); 1749 _soinfo_offsets = emulinker.soinfo_offsets(); 1750 1751 KITTY_LOGD("NativeBridgeScanner: Using Emulated Linker for solist."); 1752 } 1753 else // Houdini 1754 { 1755 uintptr_t emudlAddress = 0; 1756 for (auto &it : _elfScanner->getAllELFs(EScanElfType::Emulated, EScanElfFilter::System)) 1757 { 1758 if (KittyUtils::String::endsWith(it.realPath(), "/libdl.so")) 1759 { 1760 emudlAddress = it.base(); 1761 break; 1762 } 1763 } 1764 1765 if (emudlAddress == 0) 1766 { 1767 KITTY_LOGD("NativeBridgeScanner: Failed to find emulated libdl.so"); 1768 return false; 1769 } 1770 1771 auto emuElfs = _elfScanner->getAllELFs(EScanElfType::Emulated); 1772 if (emuElfs.empty()) 1773 { 1774 KITTY_LOGD("NativeBridgeScanner: Failed to find any loaded emulated so"); 1775 return false; 1776 } 1777 1778 struct kt_so_data_t 1779 { 1780 uintptr_t soinfo = 0; 1781 int soinfo_next_count = 0; 1782 ElfScanner elf{}; 1783 kitty_soinfo_offsets_t offsets{}; 1784 }; 1785 1786 std::vector<kt_so_data_t> soheads; 1787 static const char *heads[] = {"/app_process", "/app_process64", "/libdl.so"}; 1788 for (size_t i = 0; i < emuElfs.size(); i++) 1789 { 1790 if (emuElfs[i].base() < emudlAddress) 1791 { 1792 kt_so_data_t so{}; 1793 soheads.push_back({0, 0, emuElfs[i], {}}); 1794 continue; 1795 } 1796 1797 for (auto &name : heads) 1798 { 1799 if (KittyUtils::String::endsWith(emuElfs[i].realPath(), name)) 1800 { 1801 kt_so_data_t so{}; 1802 soheads.push_back({0, 0, emuElfs[i], {}}); 1803 } 1804 } 1805 } 1806 1807 auto maps = KittyMemoryEx::getAllMaps(_pMem->processID()); 1808 1809 for (auto &sohead : soheads) 1810 { 1811 struct 1812 { 1813 uintptr_t phdr = 0; 1814 size_t phnum = 0; 1815 } data; 1816 1817 data.phdr = sohead.elf.phdr(); 1818 data.phnum = sohead.elf.header().e_phnum; 1819 1820 KITTY_LOGD("NativeBridgeScanner: sohead phdr { %p, %zu }", (void *)(data.phdr), data.phnum); 1821 1822 // search in bss first 1823 for (auto &it : _nbImplElf.segments()) 1824 { 1825 if (it.is_rw) 1826 { 1827 sohead.soinfo = _memScanner->findDataFirst(it.startAddress, it.endAddress, &data, sizeof(data)); 1828 if (sohead.soinfo) 1829 { 1830 KITTY_LOGD("NativeBridgeScanner: Found sohead->phdr ref (%p) at %s", 1831 (void *)sohead.soinfo, 1832 it.toString().c_str()); 1833 break; 1834 } 1835 } 1836 } 1837 1838 if (sohead.soinfo == 0) 1839 { 1840 // search in read-only "[anon:Mem_" or "[anon:linker_alloc]" 1841 for (auto &it : maps) 1842 { 1843 if (!it.is_ro || it.executable || !it.is_private) 1844 continue; 1845 1846 bool check1 = (KittyUtils::String::startsWith(it.pathname, "[anon:Mem_")); 1847 bool check2 = (it.pathname == "[anon:linker_alloc]"); 1848 if (!check1 && !check2) 1849 continue; 1850 1851 sohead.soinfo = _memScanner->findDataFirst(it.startAddress, it.endAddress, &data, sizeof(data)); 1852 if (sohead.soinfo) 1853 { 1854 KITTY_LOGD("NativeBridgeScanner: Found sohead->phdr ref (%p) at %s", 1855 (void *)sohead.soinfo, 1856 it.toString().c_str()); 1857 break; 1858 } 1859 } 1860 } 1861 1862 if (sohead.soinfo == 0) 1863 { 1864 // search in read-write "[anon:Mem_" or "[anon:linker_alloc]" 1865 for (auto &it : maps) 1866 { 1867 if (!it.is_rw || it.executable || !it.is_private) 1868 continue; 1869 1870 bool check1 = (KittyUtils::String::startsWith(it.pathname, "[anon:Mem_")); 1871 bool check2 = (it.pathname == "[anon:linker_alloc]"); 1872 if (!check1 && !check2) 1873 continue; 1874 1875 sohead.soinfo = _memScanner->findDataFirst(it.startAddress, it.endAddress, &data, sizeof(data)); 1876 if (sohead.soinfo) 1877 { 1878 KITTY_LOGD("NativeBridgeScanner: Found sohead->phdr ref (%p) at %s", 1879 (void *)sohead.soinfo, 1880 it.toString().c_str()); 1881 break; 1882 } 1883 } 1884 } 1885 1886 if (sohead.soinfo == 0) 1887 continue; 1888 1889 std::vector<char> si_buf(KT_SOINFO_BUFFER_SZ, 0); 1890 _pMem->Read(sohead.soinfo, si_buf.data(), KT_SOINFO_BUFFER_SZ); 1891 1892 for (size_t i = 0; i < si_buf.size(); i += sizeof(uintptr_t)) 1893 { 1894 uintptr_t possible_next = *(uintptr_t *)&si_buf[i]; 1895 if (!KittyMemoryEx::getAddressMap(_pMem->processID(), possible_next, maps).readable) 1896 continue; 1897 1898 std::vector<char> si_buf_inner(KT_SOINFO_BUFFER_SZ, 0); 1899 _pMem->Read(possible_next, si_buf_inner.data(), KT_SOINFO_BUFFER_SZ); 1900 1901 ElfScanner si_elf{}; 1902 for (size_t j = 0; j < si_buf_inner.size(); j += sizeof(uintptr_t)) 1903 { 1904 uintptr_t possible_base = *(uintptr_t *)&si_buf_inner[j]; 1905 1906 auto tmp_map = KittyMemoryEx::getAddressMap(_pMem->processID(), possible_base, maps); 1907 if (possible_base != tmp_map.startAddress || !tmp_map.isValid() || !tmp_map.readable || 1908 tmp_map.writeable || tmp_map.is_shared) 1909 continue; 1910 1911 si_elf = ElfScanner(_pMem, possible_base, maps); 1912 if (si_elf.isValid()) 1913 { 1914 sohead.offsets.base = j; 1915 break; 1916 } 1917 } 1918 1919 if (sohead.offsets.base == 0) 1920 continue; 1921 1922 for (size_t j = 0; j < si_buf_inner.size(); j += sizeof(uintptr_t)) 1923 { 1924 uintptr_t value = *(uintptr_t *)&si_buf_inner[j]; 1925 1926 if (!sohead.offsets.phdr && value == si_elf.phdr()) 1927 { 1928 sohead.offsets.phdr = j; 1929 continue; 1930 } 1931 if (!sohead.offsets.phnum && value == si_elf.header().e_phnum) 1932 { 1933 sohead.offsets.phnum = j; 1934 continue; 1935 } 1936 if (!sohead.offsets.size && 1937 (value == si_elf.loadSize() || 1938 value == (si_elf.loadSize() + 1939 KittyMemoryEx::getAddressMap(_pMem->processID(), si_elf.end(), maps).length))) 1940 { 1941 sohead.offsets.size = j; 1942 continue; 1943 } 1944 if (!sohead.offsets.dyn && value == si_elf.dynamic()) 1945 { 1946 sohead.offsets.dyn = j; 1947 continue; 1948 } 1949 if (!sohead.offsets.strtab && value == si_elf.stringTable()) 1950 { 1951 sohead.offsets.strtab = j; 1952 continue; 1953 } 1954 if (!sohead.offsets.symtab && value == si_elf.symbolTable()) 1955 { 1956 sohead.offsets.symtab = j; 1957 continue; 1958 } 1959 if (!sohead.offsets.bias && value == si_elf.loadBias() && j != sohead.offsets.base) 1960 { 1961 sohead.offsets.bias = j; 1962 continue; 1963 } 1964 if (!sohead.offsets.strsz && value == si_elf.stringTableSize()) 1965 { 1966 sohead.offsets.strsz = j; 1967 continue; 1968 } 1969 } 1970 1971 if (sohead.offsets.size && sohead.offsets.bias && sohead.offsets.dyn && sohead.offsets.symtab && 1972 sohead.offsets.strtab) 1973 { 1974 // phdr offset might not be 0 1975 sohead.soinfo -= sohead.offsets.phdr; 1976 sohead.offsets.next = sohead.offsets.phdr + i; 1977 1978 uintptr_t si = sohead.soinfo, prev = 0; 1979 while (si && KittyMemoryEx::getAddressMap(_pMem->processID(), si, maps).readable) 1980 { 1981 sohead.soinfo_next_count++; 1982 1983 prev = si; 1984 1985 if (_pMem->Read(si + sohead.offsets.next, &si, sizeof(uintptr_t)) != sizeof(uintptr_t)) 1986 break; 1987 1988 if (si == prev) 1989 break; 1990 } 1991 1992 break; 1993 } 1994 } 1995 } 1996 1997 int nmost = 0; 1998 for (auto &sohead : soheads) 1999 { 2000 if (sohead.soinfo_next_count > nmost) 2001 { 2002 nmost = sohead.soinfo_next_count; 2003 2004 _sohead = sohead.soinfo; 2005 _soheadElf = sohead.elf; 2006 _soinfo_offsets = sohead.offsets; 2007 2008 KITTY_LOGD("NativeBridgeScanner: sohead (%d) %p -> %s", 2009 sohead.soinfo_next_count, 2010 (void *)_sohead, 2011 _soheadElf.realPath().c_str()); 2012 } 2013 } 2014 } 2015 2016 if (!_sohead || !_soheadElf.isValid()) 2017 { 2018 KITTY_LOGD("NativeBridgeScanner: Failed to find emulated solist head."); 2019 return false; 2020 } 2021 2022 KITTY_LOGD("nb_soinfo_base(%zx) | nb_soinfo_size(%zx) | nb_soinfo_bias(%zx)", 2023 _soinfo_offsets.base, 2024 _soinfo_offsets.size, 2025 _soinfo_offsets.bias); 2026 KITTY_LOGD("nb_soinfo_phdr(%zx, %zx) | nb_soinfo_dyn(%zx)", 2027 _soinfo_offsets.phdr, 2028 _soinfo_offsets.phnum, 2029 _soinfo_offsets.dyn); 2030 KITTY_LOGD("nb_soinfo_strtab(%zx, %zx) | nb_soinfo_symtab(%zx)", 2031 _soinfo_offsets.strtab, 2032 _soinfo_offsets.strsz, 2033 _soinfo_offsets.symtab); 2034 2035 KITTY_LOGD("nb_soinfo_next(%zx)", _soinfo_offsets.next); 2036 2037 _init = _soinfo_offsets.next != 0; 2038 return _init; 2039 } 2040 2041 std::vector<kitty_soinfo_t> NativeBridgeScannerMgr::allSoInfo() const 2042 { 2043 std::vector<kitty_soinfo_t> infos{}; 2044 2045 if (!_pMem || !_init) 2046 return infos; 2047 2048 auto maps = KittyMemoryEx::getAllMaps(_pMem->processID()); 2049 uintptr_t si = _sohead, prev = 0; 2050 while (si && KittyMemoryEx::getAddressMap(_pMem->processID(), si, maps).readable) 2051 { 2052 kitty_soinfo_t info = infoFromSoInfo_(si, maps); 2053 infos.push_back(info); 2054 2055 prev = si; 2056 2057 if (_pMem->Read(si + _soinfo_offsets.next, &si, sizeof(uintptr_t)) != sizeof(uintptr_t)) 2058 break; 2059 2060 if (si == prev) 2061 break; 2062 } 2063 return infos; 2064 } 2065 2066 kitty_soinfo_t NativeBridgeScannerMgr::findSoInfo(const std::string &name) const 2067 { 2068 const auto list = allSoInfo(); 2069 for (const auto &it : list) 2070 { 2071 if (KittyUtils::String::endsWith(it.realpath, name)) 2072 { 2073 return it; 2074 } 2075 } 2076 return {}; 2077 } 2078 2079 kitty_soinfo_t NativeBridgeScannerMgr::infoFromSoInfo_(uintptr_t si, 2080 const std::vector<KittyMemoryEx::ProcMap> &maps) const 2081 { 2082 kitty_soinfo_t info{}; 2083 2084 if (!_pMem || !_init) 2085 return info; 2086 2087 std::vector<char> si_buf(KT_SOINFO_BUFFER_SZ, 0); 2088 if (!_pMem->Read(si, si_buf.data(), KT_SOINFO_BUFFER_SZ)) 2089 return info; 2090 2091 info.ptr = si; 2092 info.base = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.base); 2093 info.size = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.size); 2094 info.phdr = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.phdr); 2095 info.phnum = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.phnum); 2096 info.dyn = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.dyn); 2097 info.strtab = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.strtab); 2098 info.symtab = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.symtab); 2099 info.strsz = _soinfo_offsets.strsz ? *(uintptr_t *)(si_buf.data() + _soinfo_offsets.strsz) : 0; 2100 info.bias = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.bias); 2101 info.next = *(uintptr_t *)(si_buf.data() + _soinfo_offsets.next); 2102 info.e_machine = _soheadElf.header().e_machine; 2103 2104 uintptr_t start_map_addr = info.base; 2105 if (start_map_addr == 0) 2106 start_map_addr = info.base; 2107 if (start_map_addr == 0) 2108 start_map_addr = info.bias; 2109 if (start_map_addr == 0) 2110 start_map_addr = info.phdr; 2111 if (start_map_addr == 0) 2112 start_map_addr = info.dyn; 2113 if (start_map_addr == 0) 2114 start_map_addr = info.strtab; 2115 if (start_map_addr == 0) 2116 start_map_addr = info.symtab; 2117 2118 auto si_map = KittyMemoryEx::getAddressMap(_pMem->processID(), start_map_addr, maps); 2119 if (si_map.isValid()) 2120 { 2121 info.path = si_map.pathname; 2122 info.realpath = si_map.pathname; 2123 if (si_map.offset != 0) 2124 { 2125 KittyUtils::Zip::ZipEntryInfo ent{}; 2126 if (KittyUtils::Zip::findEntryInfoByDataOffset(si_map.pathname, si_map.offset, &ent) && 2127 !ent.fileName.empty()) 2128 { 2129 info.realpath += '!'; 2130 info.realpath += ent.fileName; 2131 } 2132 } 2133 } 2134 2135 return info; 2136 } 2137 2138 #endif // __ANDROID__