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__