/ deps / KittyMemoryEx / KittyScanner.hpp
KittyScanner.hpp
   1  #pragma once
   2  
   3  #include <link.h>
   4  
   5  #include "KittyUtils.hpp"
   6  #include "KittyMemoryEx.hpp"
   7  #include "KittyMemOp.hpp"
   8  
   9  #include <cstddef>
  10  #include <cstdint>
  11  #include <mutex>
  12  #include <unordered_map>
  13  #include <functional>
  14  #include <utility>
  15  
  16  /**
  17   * @brief Manager class for pattern scanning operations.
  18   */
  19  class KittyScannerMgr
  20  {
  21  private:
  22      IKittyMemOp *_pMem;
  23  
  24  public:
  25      KittyScannerMgr() : _pMem(nullptr)
  26      {
  27      }
  28  
  29      /**
  30       * @brief Constructor for KittyScannerMgr.
  31       *
  32       * @param pMem Pointer to the memory operation interface.
  33       */
  34      KittyScannerMgr(IKittyMemOp *pMem) : _pMem(pMem)
  35      {
  36      }
  37  
  38      /**
  39       * @brief Searches for bytes within a remote memory range and returns all results.
  40       *
  41       * @param start: The starting address to search.
  42       * @param end: The ending address to search.
  43       * @param bytes: The bytes to search for.
  44       * @param mask: The bytes mask using 'x' and '?' wildcards.
  45       *
  46       * @return A vector containing all addresses where the bytes were found.
  47       */
  48      std::vector<uintptr_t> findBytesAll(const uintptr_t start,
  49                                          const uintptr_t end,
  50                                          const char *bytes,
  51                                          const std::string &mask) const;
  52  
  53      /**
  54       * @brief Searches for bytes within a remote memory range and returns the first result.
  55       *
  56       * @param start: The starting address to search.
  57       * @param end: The ending address to search.
  58       * @param bytes: The bytes to search for.
  59       * @param mask: The bytes mask using 'x' and '?' wildcards.
  60       *
  61       * @return The first address where the bytes were found, or `0` if not found.
  62       */
  63      uintptr_t findBytesFirst(const uintptr_t start,
  64                               const uintptr_t end,
  65                               const char *bytes,
  66                               const std::string &mask) const;
  67  
  68      /**
  69       * @brief Searches for hex within a remote memory range and returns all results.
  70       *
  71       * @param start: The starting address to search.
  72       * @param end: The ending address to search.
  73       * @param hex: The hex bytes to search for.
  74       * @param mask: The hex mask using 'x' and '?' wildcards.
  75       *
  76       * @return A vector containing all addresses where the hex was found.
  77       */
  78      std::vector<uintptr_t> findHexAll(const uintptr_t start,
  79                                        const uintptr_t end,
  80                                        std::string hex,
  81                                        const std::string &mask) const;
  82  
  83      /**
  84       * @brief Searches for hex within a remote memory range and returns the first result.
  85       *
  86       * @param start: The starting address to search.
  87       * @param end: The ending address to search.
  88       * @param hex: The hex bytes to search for.
  89       * @param mask: The hex mask using 'x' and '?' wildcards.
  90       *
  91       * @return The first address where the hex was found, or `0` if not found.
  92       */
  93      uintptr_t findHexFirst(const uintptr_t start, const uintptr_t end, std::string hex, const std::string &mask) const;
  94  
  95      /**
  96       * @brief Searches for a pattern within a remote memory range using the IDA pattern syntax and returns all results.
  97       *
  98       * @param start: The starting address to search.
  99       * @param end: The ending address to search.
 100       * @param pattern: The IDA pattern string (e.g., "FF DD ? 99 CC ? 00").
 101       *
 102       * @return A vector containing all addresses where the pattern was found.
 103       */
 104      std::vector<uintptr_t> findIdaPatternAll(const uintptr_t start, const uintptr_t end, const std::string &pattern);
 105  
 106      /**
 107       * @brief Searches for a pattern within a remote memory range using the IDA pattern syntax and returns the first result.
 108       *
 109       * @param start: The starting address to search.
 110       * @param end: The ending address to search.
 111       * @param pattern: The IDA pattern string (e.g., "FF DD ? 99 CC ? 00").
 112       *
 113       * @return The first address where the pattern was found, or `0` if not found.
 114       */
 115      uintptr_t findIdaPatternFirst(const uintptr_t start, const uintptr_t end, const std::string &pattern);
 116  
 117      /**
 118       * @brief Searches for data within a remote memory range and returns all results.
 119       *
 120       * @param start: The starting address to search.
 121       * @param end: The ending address to search.
 122       * @param data: A pointer to the data to search for.
 123       * @param size: The size of the data to search for.
 124       *
 125       * @return A vector containing all addresses where the data was found.
 126       */
 127      std::vector<uintptr_t> findDataAll(const uintptr_t start, const uintptr_t end, const void *data, size_t size) const;
 128  
 129      /**
 130       * @brief Searches for data within a remote memory range and returns the first result.
 131       *
 132       * @param start: The starting address to search.
 133       * @param end: The ending address to search.
 134       * @param data: A pointer to the data to search for.
 135       * @param size: The size of the data to search for.
 136       *
 137       * @return The first address where the data was found, or `0` if not found.
 138       */
 139      uintptr_t findDataFirst(const uintptr_t start, const uintptr_t end, const void *data, size_t size) const;
 140  };
 141  
 142  #ifdef __ANDROID__
 143  
 144  #define KT_SOINFO_BUFFER_SZ 0x250
 145  
 146  /**
 147   * @brief Structure to hold info of linker soinfo
 148   */
 149  struct kitty_soinfo_t
 150  {
 151      uintptr_t ptr = 0;
 152      uintptr_t base = 0;
 153      size_t size = 0;
 154      uintptr_t phdr = 0;
 155      size_t phnum = 0;
 156      uintptr_t dyn = 0;
 157      uintptr_t strtab = 0;
 158      uintptr_t symtab = 0;
 159      size_t strsz = 0;
 160      uintptr_t bias = 0;
 161      uintptr_t next = 0;
 162      uint16_t e_machine = 0;
 163      std::string path;
 164      std::string realpath;
 165  };
 166  
 167  /**
 168   * @brief Enum class representing the type of ELF file to scan for.
 169   */
 170  enum class EScanElfType : uint32_t
 171  {
 172      Any,
 173      Native,
 174      Emulated,
 175  };
 176  
 177  /**
 178   * @brief Enum class representing the filter criteria for ELF files to scan.
 179   */
 180  enum class EScanElfFilter : uint32_t
 181  {
 182      Any,
 183      System,
 184      App,
 185  };
 186  
 187  #endif
 188  
 189  /**
 190   * @brief Represents a scanner for memory ELF files.
 191   * This class is used to scan ELF files from memory and extract information about their contents.
 192   */
 193  class ElfScanner
 194  {
 195      friend class ElfScannerMgr;
 196      friend class LinkerScannerMgr;
 197      friend class NativeBeidgeScannerMgr;
 198  
 199  protected:
 200      IKittyMemOp *_pMem;
 201      uintptr_t _elfBase;
 202      KT_ElfW(Ehdr) _ehdr;
 203      uintptr_t _phdr;
 204      std::vector<KT_ElfW(Phdr)> _phdrs;
 205      int _loads;
 206      uintptr_t _loadBias, _loadSize;
 207      uintptr_t _dynamic;
 208      std::vector<KT_ElfW(Dyn)> _dynamics;
 209      uintptr_t _stringTable, _symbolTable;
 210      size_t _strsz, _syment;
 211      bool _fixedBySoInfo;
 212      KittyMemoryEx::ProcMap _baseSegment;
 213      std::vector<KittyMemoryEx::ProcMap> _segments;
 214      std::vector<KittyMemoryEx::ProcMap> _bssSegments;
 215      std::string _filepath;
 216      std::string _realpath;
 217      bool _symbols_init;
 218      bool _dsymbols_init;
 219      std::unordered_map<std::string, uintptr_t> _symbolsMap;
 220      std::unordered_map<std::string, uintptr_t> _dsymbolsMap;
 221  
 222  public:
 223      ElfScanner()
 224          : _pMem(nullptr), _elfBase(0), _phdr(0), _loads(0), _loadBias(0), _loadSize(0), _dynamic(0), _stringTable(0),
 225            _symbolTable(0), _strsz(0), _syment(0), _fixedBySoInfo(false), _symbols_init(false), _dsymbols_init(false)
 226      {
 227      }
 228  
 229      /**
 230       * @brief Constructor for ElfScanner class.
 231       * This constructor initializes the ElfScanner class with the given ELF base address.
 232       *
 233       * @param pMem Pointer to the memory operation interface.
 234       * @param elfBase The base address of the ELF file.
 235       * @param maps The vector of cached process memory maps.
 236       */
 237      ElfScanner(IKittyMemOp *pMem, uintptr_t elfBase, const std::vector<KittyMemoryEx::ProcMap> &maps);
 238  
 239      /**
 240       * @brief Constructor for ElfScanner class.
 241       * This constructor initializes the ElfScanner class with the given ELF base address.
 242       *
 243       * @param pMem Pointer to the memory operation interface.
 244       * @param elfBase The base address of the ELF file.
 245       * @param maps The vector of cached process memory maps (optional).
 246       */
 247      ElfScanner(IKittyMemOp *pMem, uintptr_t elfBase)
 248          : ElfScanner(pMem,
 249                       elfBase,
 250                       (pMem ? KittyMemoryEx::getAllMaps(pMem->processID()) : std::vector<KittyMemoryEx::ProcMap>()))
 251      {
 252      }
 253  
 254  #ifdef __ANDROID__
 255      /**
 256       * @brief Constructor for ElfScanner class.
 257       * This constructor initializes the ElfScanner class with the given soinfo.
 258       *
 259       * @param pMem Pointer to the memory operation interface.
 260       * @param soinfo The soinfo of the ELF file.
 261       * @param maps The vector of cached process memory maps.
 262       */
 263      ElfScanner(IKittyMemOp *pMem, const kitty_soinfo_t &soinfo, const std::vector<KittyMemoryEx::ProcMap> &maps);
 264  
 265      /**
 266       * @brief Constructor for ElfScanner class.
 267       * This constructor initializes the ElfScanner class with the given soinfo.
 268       *
 269       * @param pMem Pointer to the memory operation interface.
 270       * @param soinfo The soinfo of the ELF file.
 271       * @param maps The vector of cached process memory maps (optional).
 272       */
 273      ElfScanner(IKittyMemOp *pMem, const kitty_soinfo_t &soinfo)
 274          : ElfScanner(pMem,
 275                       soinfo,
 276                       (pMem ? KittyMemoryEx::getAllMaps(pMem->processID()) : std::vector<KittyMemoryEx::ProcMap>()))
 277      {
 278      }
 279  #endif
 280  
 281      /**
 282       * @brief Checks if the ElfScanner class is valid.
 283       */
 284      inline bool isValid() const
 285      {
 286          return _elfBase && _loadSize && _phdr && _loadBias;
 287      }
 288  
 289      /**
 290       * @brief Checks if the ELF file is fixed by soinfo.
 291       * Some Elf headers are obfuscated or removed,
 292       * \ref createWithSoInfo(const kitty_soinfo_t&, const std::vector<KittyMemory::ProcMap>&) may fix header.
 293       */
 294      inline bool isFixedBySoInfo() const
 295      {
 296          return _fixedBySoInfo;
 297      }
 298  
 299      /**
 300       * @brief Elf's Base address in memory.
 301       */
 302      inline uintptr_t base() const
 303      {
 304          return _elfBase;
 305      }
 306  
 307      /**
 308       * @brief Elf's end address in memory.
 309       */
 310      inline uintptr_t end() const
 311      {
 312          return _elfBase + _loadSize;
 313      }
 314  
 315      /**
 316       * @brief Elf's header.
 317       */
 318      inline KT_ElfW(Ehdr) header() const
 319      {
 320          return _ehdr;
 321      }
 322  
 323      /**
 324       * @brief Elf's program header address in memory.
 325       */
 326      inline uintptr_t phdr() const
 327      {
 328          return _phdr;
 329      }
 330  
 331      /**
 332       * @brief Vector of Elf's program headers.
 333       */
 334      inline std::vector<KT_ElfW(Phdr)> programHeaders() const
 335      {
 336          return _phdrs;
 337      }
 338  
 339      /**
 340       * @brief Elf's number of loads.
 341       */
 342      inline int loads() const
 343      {
 344          return _loads;
 345      }
 346  
 347      /**
 348       * @brief Elf's load bias address in memory.
 349       */
 350      inline uintptr_t loadBias() const
 351      {
 352          return _loadBias;
 353      }
 354  
 355      /**
 356       * @brief Elf's load size.
 357       */
 358      inline uintptr_t loadSize() const
 359      {
 360          return _loadSize;
 361      }
 362  
 363      /**
 364       * @brief Elf's dynamic section address in memory.
 365       */
 366      inline uintptr_t dynamic() const
 367      {
 368          return _dynamic;
 369      }
 370  
 371      /**
 372       * @brief Vector of Elf's dynamic sections.
 373       */
 374      inline std::vector<KT_ElfW(Dyn)> dynamics() const
 375      {
 376          return _dynamics;
 377      }
 378  
 379      /**
 380       * @brief Elf's dynamic string table address in memory.
 381       */
 382      inline uintptr_t stringTable() const
 383      {
 384          return _stringTable;
 385      }
 386  
 387      /**
 388       * @brief Elf's dynamic symbol table address in memory.
 389       */
 390      inline uintptr_t symbolTable() const
 391      {
 392          return _symbolTable;
 393      }
 394  
 395      /**
 396       * @brief Elf's dynamic string table size.
 397       */
 398      inline size_t stringTableSize() const
 399      {
 400          return _strsz;
 401      }
 402  
 403      /**
 404       * @brief Elf's symbol entry size.
 405       */
 406      inline size_t symbolEntrySize() const
 407      {
 408          return _syment;
 409      }
 410  
 411      /**
 412       * @brief Returns a map of symbols from the dynamic symbol table (DT_SYMTAB).
 413       * @return A map where keys are symbol names and values are their corresponding memory addresses.
 414       */
 415      std::unordered_map<std::string, uintptr_t> symbols();
 416  
 417      /**
 418       * @brief Returns a map of symbols from the symbol table (SHT_SYMTAB) on disk.
 419       * @return A map where keys are symbol names and values are their corresponding memory addresses.
 420       */
 421      std::unordered_map<std::string, uintptr_t> dsymbols();
 422  
 423      /**
 424       * @brief Finds a symbol from the dynamic symbol table by name.
 425       *
 426       * @param symbolName The name of the symbol to find.
 427       * @return The memory address of the symbol if found, otherwise zero.
 428       */
 429      uintptr_t findSymbol(const std::string &symbolName);
 430  
 431      /**
 432       * @brief Finds a symbol from the symbol table (SHT_SYMTAB) on disk by name.
 433       *
 434       * @param symbolName The name of the symbol to find.
 435       * @return The memory address of the symbol if found, otherwise zero.
 436       */
 437      uintptr_t findDebugSymbol(const std::string &symbolName);
 438  
 439      /**
 440       * @brief Elf's base memory map info.
 441       */
 442      KittyMemoryEx::ProcMap baseSegment() const
 443      {
 444          return _baseSegment;
 445      }
 446  
 447      /**
 448       * @brief Returns all of Elf's memory maps info.
 449       */
 450      std::vector<KittyMemoryEx::ProcMap> segments() const
 451      {
 452          return _segments;
 453      }
 454  
 455      /**
 456       * @brief Returns all of Elf's BSS memory maps.
 457       */
 458      std::vector<KittyMemoryEx::ProcMap> bssSegments() const
 459      {
 460          return _bssSegments;
 461      }
 462  
 463      /**
 464       * @brief Returns the file path of the memory mapped Elf file.
 465       */
 466      inline std::string filePath() const
 467      {
 468          return _filepath;
 469      }
 470  
 471      /**
 472       * @brief Returns the real path of the memory mapped Elf file
 473       * (e.g, incase if it's inside a zip, it will return full path to zip entry).
 474       */
 475      inline std::string realPath() const
 476      {
 477          return _realpath;
 478      }
 479  
 480      /**
 481       * @brief Returns if the memory mapped Elf file was loaded from zip file.
 482       */
 483      inline bool isZipped() const
 484      {
 485          return _baseSegment.offset != 0;
 486      }
 487  
 488      /**
 489       * @brief Finds the r_debug structure in the process.
 490       * @param out Pointer to store the r_debug structure.
 491       * @return True if the r_debug structure is found, false otherwise.
 492       */
 493      inline bool find_r_debug(r_debug *out) const
 494      {
 495          for (auto &it : _dynamics)
 496          {
 497              if (it.d_tag == DT_DEBUG && it.d_un.d_val)
 498              {
 499                  if (out)
 500                      _pMem->Read(it.d_un.d_val, out, sizeof(r_debug));
 501  
 502                  return true;
 503              }
 504          }
 505          return false;
 506      }
 507  };
 508  
 509  /**
 510   * @brief Manager class for ELF scanners.
 511   */
 512  class ElfScannerMgr
 513  {
 514      friend class NativeBeidgeScannerMgr;
 515  
 516  protected:
 517      IKittyMemOp *_pMem;
 518      ElfScanner _programElf;
 519      std::unordered_map<uintptr_t, ElfScanner> _cached_elfs;
 520  
 521  public:
 522      ElfScannerMgr() : _pMem(nullptr)
 523      {
 524      }
 525  
 526      /**
 527       * @brief Constructor for ElfScannerMgr.
 528       * @param pMem Pointer to the memory operation interface.
 529       */
 530      ElfScannerMgr(IKittyMemOp *pMem) : _pMem(pMem)
 531      {
 532      }
 533  
 534      /**
 535       * @brief Constructs ElfScanner class with the given ELF base address.
 536       *
 537       * @param elfBase The base address of the ELF file in memory.
 538       */
 539      inline ElfScanner createWithBase(uintptr_t elfBase) const
 540      {
 541          return !_pMem ? ElfScanner() : ElfScanner(_pMem, elfBase);
 542      }
 543  
 544      /**
 545       * @brief Constructs ElfScanner class with the given process memory map info.
 546       *
 547       * @param elfMap The base process memory map of the ELF file.
 548       */
 549      inline ElfScanner createWithMap(const KittyMemoryEx::ProcMap &map) const
 550      {
 551          return !_pMem ? ElfScanner() : ElfScanner(_pMem, map.startAddress);
 552      }
 553  #ifdef __ANDROID__
 554      /**
 555       * @brief Constructs ElfScanner class with the given soinfo.
 556       *
 557       * @param soinfo The soinfo of the ELF file.
 558       */
 559      inline ElfScanner createWithSoInfo(const kitty_soinfo_t &soinfo) const
 560      {
 561          return !_pMem ? ElfScanner() : ElfScanner(_pMem, soinfo);
 562      }
 563  #endif
 564  
 565      /**
 566       * @brief Checks if provided base address is an Elf
 567       * @param elfBase: ELF base address
 568       */
 569      bool isValidELF(uintptr_t elfBase) const;
 570  
 571      /**
 572       * @brief Checks if the memory-mapped ELF file is native to the Android device.
 573       * @param elf The ELF scanner object.
 574       * @return True if the ELF is native, false otherwise.
 575       */
 576      inline bool isElfNative(const ElfScanner &elf)
 577      {
 578          int a = getProgramElf().header().e_machine, b = elf.header().e_machine;
 579          return a != 0 && b != 0 && a == b;
 580      }
 581  
 582      /**
 583       * @brief Checks if the memory-mapped ELF file is emulated to the Android device.
 584       * @param elf The ELF scanner object.
 585       * @return True if the ELF is emulated, false otherwise.
 586       */
 587      inline bool isElfEmulated(const ElfScanner &elf)
 588      {
 589          int a = getProgramElf().header().e_machine, b = elf.header().e_machine;
 590          return a != 0 && b != 0 && a != b;
 591      }
 592  
 593      /**
 594       * @brief Returns the program ELF.
 595       */
 596      ElfScanner &getProgramElf();
 597  
 598  #ifdef __ANDROID__
 599      /**
 600       * @brief Fetches all memory mapped ELFs.
 601       * @param type (optional) The type of ELF file to find (e.g., Any, Native, Emulated).
 602       * @param filter (optional) The filter to apply when searching for ELF files (e.g., Any, System, App).
 603       * @return A vector of all memory mapped ELFs.
 604       */
 605      std::vector<ElfScanner> getAllELFs(EScanElfType type = EScanElfType::Any,
 606                                         EScanElfFilter filter = EScanElfFilter::Any);
 607  
 608      /**
 609       * @brief Searches for a memory mapped ELF file based on the given path, type, and filter.
 610       * @note If multiple ELFs found, it will prioritize ELFs with dynamic and return the latest mapped one with the
 611       * most segments. This function can extract full path to loaded zipped Elf files.
 612       *
 613       * @param path The path to the ELF file to find.
 614       * @param type (optional) The type of ELF file to find (e.g., Any, Native, Emulated).
 615       * @param filter (optional) The filter to apply when searching for ELF files. (e.g., Any, System, App).
 616       * @return An ElfScanner object representing the found ELF file, or an empty ElfScanner object if not found.
 617       */
 618      ElfScanner findElf(const std::string &path,
 619                         EScanElfType type = EScanElfType::Any,
 620                         EScanElfFilter filter = EScanElfFilter::Any);
 621  
 622      /**
 623       * @brief Lookup dynamic symbol name in all loaded ELFs
 624       * @param symbolName The name of the symbol to lookup.
 625       * @param type (optional) The type of ELF file to find (e.g., Any, Native, Emulated).
 626       * @param filter (optional) The filter to apply when searching for ELF files. (e.g., Any, System, App).
 627       * @return A vector of pairs containing the symbol's absolute address and the ELF where the symbol was found.
 628       */
 629      std::vector<std::pair<uintptr_t, ElfScanner>> findSymbolAll(const std::string &symbolName,
 630                                                                  EScanElfType type = EScanElfType::Any,
 631                                                                  EScanElfFilter filter = EScanElfFilter::Any);
 632  #else
 633      /**
 634       * @brief Fetches all memory mapped ELFs.
 635       * @return A vector of all memory mapped ELFs.
 636       */
 637      std::vector<ElfScanner> getAllELFs();
 638  
 639      /**
 640       * @brief Searches for a memory mapped ELF file based on the given path, type, and filter.
 641       * @note If multiple ELFs found, it will prioritize ELFs with dynamic and return the latest mapped one with the
 642       * most segments. This function can extract full path to loaded zipped Elf files.
 643       *
 644       * @param path The path to the ELF file to find.
 645       * @return An ElfScanner object representing the found ELF file, or an empty ElfScanner object if not found.
 646       */
 647      ElfScanner findElf(const std::string &path);
 648  
 649      /**
 650       * @brief Lookup dynamic symbol name in all loaded ELFs
 651       * @param symbolName The name of the symbol to lookup.
 652       * @return A vector of pairs containing the symbol's absolute address and the ELF where the symbol was found.
 653       */
 654      std::vector<std::pair<uintptr_t, ElfScanner>> findSymbolAll(const std::string &symbolName);
 655  #endif
 656  
 657      /**
 658       * @brief Finds the remote address of a local symbol.
 659       *
 660       * This function searches for the remote address of a local symbol based on its name and address.
 661       *
 662       * @param local_sym_name The name of the local symbol.
 663       * @param local_sym_addr The address of the local symbol.
 664       * @return The remote address of the symbol, or 0 if not found.
 665       */
 666      uintptr_t findRemoteSymbol(const std::string &local_sym_name, uintptr_t local_sym_addr);
 667  };
 668  
 669  #ifdef __ANDROID__
 670  
 671  /**
 672   * @brief Structure to hold info of linker symbols
 673   */
 674  struct kitty_linker_syms_t
 675  {
 676      uintptr_t solist = 0;
 677      uintptr_t somain = 0;
 678      uintptr_t sonext = 0;
 679  };
 680  
 681  /**
 682   * @brief Structure to hold info of linker soinfo offsets
 683   */
 684  struct kitty_soinfo_offsets_t
 685  {
 686      uintptr_t base = 0;
 687      uintptr_t size = 0;
 688      uintptr_t phdr = 0;
 689      uintptr_t phnum = 0;
 690      uintptr_t dyn = 0;
 691      uintptr_t strtab = 0;
 692      uintptr_t symtab = 0;
 693      uintptr_t strsz = 0;
 694      uintptr_t bias = 0;
 695      uintptr_t next = 0;
 696  };
 697  
 698  /**
 699   * @brief Manager class for linker Elf.
 700   *
 701   * This class inherits from ElfScanner and provides methods for linker Elf.
 702   */
 703  class LinkerScannerMgr : public ElfScanner
 704  {
 705  private:
 706      kitty_linker_syms_t _linker_syms;
 707      kitty_soinfo_offsets_t _soinfo_offsets;
 708      bool _init;
 709  
 710  public:
 711      LinkerScannerMgr() : ElfScanner(), _init(false)
 712      {
 713          memset(&_linker_syms, 0, sizeof(_linker_syms));
 714          memset(&_soinfo_offsets, 0, sizeof(_soinfo_offsets));
 715      }
 716  
 717      /**
 718       * @brief Constructor for LinkerScannerMgr with a linker base address.
 719       * @param pMem Pointer to the memory operation interface.
 720       * @param linkerBase The base address of the linker.
 721       */
 722      LinkerScannerMgr(IKittyMemOp *pMem, const ElfScanner &linkerElf);
 723  
 724      /**
 725       * @brief Constructor for LinkerScannerMgr with the linker ElfScanner object.
 726       * @param pMem Pointer to the memory operation interface.
 727       * @param linkerElf Linker ElfScanner object.
 728       */
 729      LinkerScannerMgr(IKittyMemOp *pMem, uintptr_t linkerBase);
 730  
 731      /**
 732       * @brief Initializes the linker scanner.
 733       * @return True if initialization is successful, false otherwise.
 734       */
 735      bool init();
 736  
 737      /**
 738       * @brief Returns true if initialized, false otherwise.
 739       */
 740      inline bool isInitialized() const
 741      {
 742          return isValid() && _init;
 743      }
 744  
 745      /**
 746       * @brief Converts the LinkerScannerMgr object to an ElfScanner pointer.
 747       * @return The ElfScanner pointer.
 748       */
 749      inline ElfScanner *asELF() const
 750      {
 751          return (ElfScanner *)this;
 752      }
 753  
 754      /**
 755       * @brief Returns the linker symbols offsets.
 756       */
 757      inline kitty_linker_syms_t linker_offsets() const
 758      {
 759          return _linker_syms;
 760      }
 761  
 762      /**
 763       * @brief Returns the soinfo offsets.
 764       */
 765      inline kitty_soinfo_offsets_t soinfo_offsets() const
 766      {
 767          return _soinfo_offsets;
 768      }
 769  
 770      /**
 771       * @brief Returns the linker solist head address.
 772       */
 773      inline uintptr_t solist() const
 774      {
 775          if (!isValid() || !_linker_syms.solist)
 776              return 0;
 777  
 778          uintptr_t value = 0;
 779          return _pMem->Read(_linker_syms.solist, &value, sizeof(uintptr_t)) == sizeof(uintptr_t) ? value : 0;
 780      }
 781  
 782      /**
 783       * @brief Returns the linker somain address.
 784       */
 785      inline uintptr_t somain() const
 786      {
 787          if (!isValid() || !_linker_syms.somain)
 788              return 0;
 789  
 790          uintptr_t value = 0;
 791          return _pMem->Read(_linker_syms.somain, &value, sizeof(uintptr_t)) == sizeof(uintptr_t) ? value : 0;
 792      }
 793  
 794      /**
 795       * @brief Returns the linker solist tail address.
 796       */
 797      inline uintptr_t sonext() const
 798      {
 799          if (!isValid() || !_linker_syms.sonext)
 800              return 0;
 801  
 802          uintptr_t value = 0;
 803          return _pMem->Read(_linker_syms.sonext, &value, sizeof(uintptr_t)) == sizeof(uintptr_t) ? value : 0;
 804      }
 805  
 806      /**
 807       * @brief Returns the linker somain info.
 808       */
 809      inline kitty_soinfo_t somainInfo() const
 810      {
 811          if (!isValid() || !_linker_syms.somain)
 812              return {};
 813  
 814          return infoFromSoInfo_(somain(), KittyMemoryEx::getAllMaps(_pMem->processID()));
 815      }
 816  
 817      /**
 818       * @brief Returns the linker solist tail info.
 819       */
 820      inline kitty_soinfo_t sonextInfo() const
 821      {
 822          if (!isValid())
 823              return {};
 824  
 825          return infoFromSoInfo_(sonext(), KittyMemoryEx::getAllMaps(_pMem->processID()));
 826      }
 827  
 828      /**
 829       * @brief Returns all linker's soinfo.
 830       */
 831      std::vector<kitty_soinfo_t> allSoInfo() const;
 832  
 833      /**
 834       * @brief Finds a soinfo by name.
 835       * @param name The name of the soinfo.
 836       * @return The soinfo if found or empty object.
 837       */
 838      kitty_soinfo_t findSoInfo(const std::string &name) const;
 839  
 840  private:
 841      kitty_soinfo_t infoFromSoInfo_(uintptr_t si, const std::vector<KittyMemoryEx::ProcMap> &maps) const;
 842  };
 843  
 844  enum KT_JNICallType
 845  {
 846      KT_JNICallTypeRegular = 1,
 847      KT_JNICallTypeCriticalNative = 2,
 848  };
 849  
 850  enum KT_NativeBridgeImplementationVersion
 851  {
 852      // first version, not used.
 853      KT_NB_DEFAULT_VERSION = 1,
 854      // The version which signal semantic is introduced.
 855      KT_NB_SIGNAL_VERSION = 2,
 856      // The version which namespace semantic is introduced.
 857      KT_NB_NAMESPACE_VERSION = 3,
 858      // The version with vendor namespaces
 859      KT_NB_VENDOR_NAMESPACE_VERSION = 4,
 860      // The version with runtime namespaces
 861      KT_NB_RUNTIME_NAMESPACE_VERSION = 5,
 862      // The version with pre-zygote-fork hook to support app-zygotes.
 863      KT_NB_PRE_ZYGOTE_FORK_VERSION = 6,
 864      // The version with critical_native support
 865      KT_NB_CRITICAL_NATIVE_SUPPORT_VERSION = 7,
 866      // The version with native bridge detection fallback for function pointers
 867      KT_NB_IDENTIFY_NATIVELY_BRIDGED_FUNCTION_POINTERS_VERSION = 8,
 868  };
 869  
 870  /**
 871   * @brief Structure to hold info of native bridge callbacks data.
 872   */
 873  struct nbItf_data_t
 874  {
 875      inline nbItf_data_t()
 876      {
 877          memset(this, 0, sizeof(nbItf_data_t));
 878      }
 879  
 880      int version;
 881  #ifdef __LP64__
 882      uint32_t pad1;
 883  #endif
 884      bool (*initialize)(const void *runtime_cbs, const char *private_dir, const char *instruction_set);
 885      void *(*loadLibrary)(const char *libpath, int flag);
 886      void *(*getTrampoline)(void *handle, const char *name, const char *shorty, uint32_t len);
 887      bool (*isSupported)(const char *libpath);
 888      const void *(*getAppEnv)(const char *instruction_set);
 889      bool (*isCompatibleWith)(uint32_t bridge_version);
 890      void *(*getSignalHandler)(int signal);
 891      int (*unloadLibrary)(void *handle);
 892      const char *(*getError)();
 893      bool (*isPathSupported)(const char *library_path);
 894      bool (*initAnonymousNamespace)(const char *public_ns_sonames, const char *anon_ns_library_path);
 895      void *(*createNamespace)(const char *name,
 896                               const char *ld_library_path,
 897                               const char *default_library_path,
 898                               uint64_t type,
 899                               const char *permitted_when_isolated_path,
 900                               void *parent_ns);
 901      bool (*linkNamespaces)(void *from, void *to, const char *shared_libs_sonames);
 902      void *(*loadLibraryExt)(const char *libpath, int flag, void *ns);
 903      void *(*getVendorNamespace)();
 904      void *(*getExportedNamespace)(const char *name);
 905      void (*preZygoteFork)();
 906      void *(*getTrampolineWithJNICallType)(void *handle,
 907                                            const char *name,
 908                                            const char *shorty,
 909                                            uint32_t len,
 910                                            enum KT_JNICallType jni_call_type);
 911      void *(*getTrampolineForFunctionPointer)(const void *method,
 912                                               const char *shorty,
 913                                               uint32_t len,
 914                                               enum KT_JNICallType jni_call_type);
 915      bool (*isNativeBridgeFunctionPointer)(const void *method);
 916  
 917      inline static size_t GetStructSize(int version)
 918      {
 919          switch (version)
 920          {
 921          case KT_NB_SIGNAL_VERSION:
 922              return sizeof(uintptr_t) * 8;
 923          case KT_NB_NAMESPACE_VERSION:
 924              return sizeof(uintptr_t) * 15;
 925          case KT_NB_VENDOR_NAMESPACE_VERSION:
 926              return sizeof(uintptr_t) * 16;
 927          case KT_NB_RUNTIME_NAMESPACE_VERSION:
 928              return sizeof(uintptr_t) * 17;
 929          case KT_NB_PRE_ZYGOTE_FORK_VERSION:
 930              return sizeof(uintptr_t) * 18;
 931          case KT_NB_CRITICAL_NATIVE_SUPPORT_VERSION:
 932              return sizeof(uintptr_t) * 19;
 933          case KT_NB_IDENTIFY_NATIVELY_BRIDGED_FUNCTION_POINTERS_VERSION:
 934              return sizeof(uintptr_t) * 21;
 935          }
 936          return 0;
 937      }
 938  };
 939  
 940  /**
 941   * @brief Manager class for scanning native bridge.
 942   */
 943  class NativeBridgeScannerMgr
 944  {
 945  private:
 946      IKittyMemOp *_pMem;
 947      KittyScannerMgr *_memScanner;
 948      ElfScannerMgr *_elfScanner;
 949      ElfScanner _nbElf, _nbImplElf, _soheadElf;
 950      uintptr_t _sohead;
 951      kitty_soinfo_offsets_t _soinfo_offsets;
 952      bool _init;
 953      bool _isHoudini;
 954  
 955      uintptr_t _nbItf;
 956      size_t _nbItf_data_size;
 957      nbItf_data_t _nbItf_data;
 958  
 959  public:
 960      bool (*fnNativeBridgeInitialized)();
 961  
 962      NativeBridgeScannerMgr()
 963          : _pMem(nullptr), _memScanner(nullptr), _elfScanner(nullptr), _sohead(0), _init(false), _isHoudini(false),
 964            _nbItf(0), _nbItf_data_size(0), fnNativeBridgeInitialized(nullptr)
 965      {
 966          memset(&_nbItf_data, 0, sizeof(_nbItf_data));
 967          memset(&_soinfo_offsets, 0, sizeof(_soinfo_offsets));
 968      }
 969  
 970      /**
 971       * @brief Constructor for NativeBridgeScannerMgr.
 972       * @param pMem Pointer to the memory operation interface.
 973       * @param memScanner A pointer to a `KittyScannerMgr` object.
 974       * @param elfScanner A pointer to an `ElfScannerMgr` object.
 975       */
 976      NativeBridgeScannerMgr(IKittyMemOp *pMem, KittyScannerMgr *memScanner, ElfScannerMgr *elfScanner);
 977  
 978      /**
 979       * @brief Initializes the native bridge scanner.
 980       * @return True if initialization is successful, false otherwise.
 981       */
 982      bool init();
 983  
 984      /**
 985       * @brief Returns true if initialized, false otherwise.
 986       */
 987      inline bool isValid() const
 988      {
 989          return _init;
 990      }
 991  
 992      /**
 993       * @brief Returns the soinfo offsets.
 994       */
 995      inline kitty_soinfo_offsets_t soinfo_offsets() const
 996      {
 997          return _soinfo_offsets;
 998      }
 999  
1000      /**
1001       * @brief Getter for 'libnativebridge.so' Elf.
1002       */
1003      inline ElfScanner &nbElf()
1004      {
1005          return _nbElf;
1006      }
1007  
1008      /**
1009       * @brief Getter for the native bridge implementaion Elf (e.g, 'libhoudini.so' or 'libndk_translation.so').
1010       */
1011      inline ElfScanner &nbImplElf()
1012      {
1013          return _nbImplElf;
1014      }
1015  
1016      /**
1017       * @brief Getter for the first loaded emulated so Elf.
1018       */
1019      inline ElfScanner &soheadElf()
1020      {
1021          return _soheadElf;
1022      }
1023  
1024      /**
1025       * @brief Check if the native bridge implementaion is Houdini.
1026       */
1027      inline bool isHoudini() const
1028      {
1029          return _isHoudini;
1030      }
1031  
1032      /**
1033       * @brief Returns the first loaded emulated so address.
1034       */
1035      inline uintptr_t sohead() const
1036      {
1037          return _sohead;
1038      }
1039  
1040      /**
1041       * @brief Returns the first loaded emulated soinfo.
1042       */
1043      inline kitty_soinfo_t soheadInfo() const
1044      {
1045          if (!_pMem || !_sohead)
1046              return {};
1047  
1048          return infoFromSoInfo_(_sohead, KittyMemoryEx::getAllMaps(_pMem->processID()));
1049      }
1050  
1051      /**
1052       * @brief Returns all emulated soinfo.
1053       */
1054      std::vector<kitty_soinfo_t> allSoInfo() const;
1055  
1056      /**
1057       * @brief Finds a soinfo by name.
1058       * @param name The name of the soinfo.
1059       * @return The soinfo if found or empty object.
1060       */
1061      kitty_soinfo_t findSoInfo(const std::string &name) const;
1062  
1063      /**
1064       * @brief Returns native bridge callbacks data size.
1065       */
1066      inline size_t nbItfDataSize() const
1067      {
1068          return _nbItf_data_size;
1069      }
1070  
1071      /**
1072       * @brief Returns native bridge callbacks data.
1073       */
1074      inline nbItf_data_t nbItfData() const
1075      {
1076          return _nbItf_data;
1077      }
1078  
1079  private:
1080      kitty_soinfo_t infoFromSoInfo_(uintptr_t si, const std::vector<KittyMemoryEx::ProcMap> &maps) const;
1081  };
1082  
1083  #endif // __ANDROID__