/ deps / KittyMemoryEx / KittyScanner.cpp
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__