首页
社区
课程
招聘
[原创]初探android crc检测及绕过
发表于: 2025-2-28 20:30 53406

[原创]初探android crc检测及绕过

2025-2-28 20:30
53406

在开始之前先说下什么是crc检测,通俗点讲就是,把本地文件中的数据和内存中的数据进行crc计算得到的结果进行比较,来校验结果是否一致,不一致则判定数据被篡改。

举个例子:以libc.so为目标so,当我们第一次用frida以spwan的方式注入hook 时,未对libc.so的函数进行hook的话,app未退出,一旦我们对libc.so中的函数或指令进行了修改注入(不考虑inline hoook的因素影响),app便直接崩溃退出,这种情况基本就是检测到了数据被篡改,也就是crc检测。

基本的介绍到这里,下面开始对crc相关途径的检测进行分析,以及如何去绕过。

本次分析以libc.so为目标,以下的绕过都是用frida去处理。

app是我总结的一部分crc检测,会把链接放置在结尾。

frida版本: 16.5.9
目标app: LinkerDemo
分析so: libc.so
ELF工具:010Editor
arm平台: arm64

目前crc的检测大的方向分两种:
1.本地文件与所属app的/proc/{id}/maps文件中so的内存范围作比较
2.本地文件与linker中获取到的so的内存范围作比较

先说一下此校验方法的相关逻辑
描述:提取本地文件/apex/com.android.runtime/lib64/bionic/libc.so的可执行段数据和app在/proc/{id}/maps下映射的libc.so可执行段内存进行crc校验


获取可执行段表中的 p_offset(在文件中的偏移)和 p_filesz(在文件中的大小)。后续都是以这个为参照物与内存进行crc校验

图片描述
(正常来说只有一行r-xp段,因为我使用了frida,所以会出现这种内存布局)
提取出里面带有x的内存段数据。

最后通过相关算法计算出两种途径获取到的内存结果进行比较。
算法一般都是crc32,当然个例可能会使用其他的算法,比如md5,aes等等,很少见的。

打开app,点击libc maps crc,可以在控制台看到如下输出:
图片描述
此时我们的环境是正常的。接着我们用frida注入,对libc.so中的pthread_create方法进行hook,得到以下输出:
图片描述
可以很明显的看出内存中可执行段的crc值与文件中可执行的不一致,并且检测出了环境是hook的。

针对上述的检测,我们可以在maps中模拟一段可执行段数据,并把libc.so原本的可执行段名称给抹去,变为匿名内存。最后app获取到的maps内存范围就是我们模拟的一段数据

图片描述
注入上述代码后再次点击按钮看控制台输出:
图片描述
可以看到两种方式获取到的值一致了,环境也是安全的了。

这里面主要使用到了mmap在maps中映射一段名称为libc.so的数据,用mremap把原本的可执行段数据给设置为匿名内存
图片描述
图片描述
这里就可以看到maps中libc.so的可执行段已设置为匿名内存,并且map中也有我们模拟的可执行段内存。

本地文件获取的方式不再赘述了,直接看如何从Linker中获取内存。

linker作为so加载器,里面存放了所有已经加载的so,并把这些已经加载的so会依次存放进solist变量中,solist存储了所有so的soinfo结构体,它是一个soinfo结构体数组,我们可以从solist中获取到自己想要的so。

那么如何获取到libc.so的结构体呢?
带着这个疑问我们先了解下soinfo的相关结构组成。

这里我已经标注了相关变量在内存中的指针索引。里面描述了so的基址和一些节表和大量的方法。当然这些不是我们这里的关注重点,我们只需要多关注以下的变量:

检测逻辑:
lib base mem crc:获取本地文件的可执行段的偏移地址,计算soinfo结构体中的base与可执行段偏移地址的和,得到内存中的可执行段地址,再取内存中可执行段数据和本地文件可执行段数据作比较。
lib func mem crc: 通过dl_iterate_phdr方法获取到linker map,取linker map中的dlpi_addr获取到so的基址,获取本地文件的可执行段的偏移地址,计算基址和偏移的和,通过再取内存中可执行段数据和本地文件可执行段数据作比较。

分别点击libc base mem crc按钮和libc func mem crc按钮,控制台输出如下
图片描述

针对上述的检测,我们可以把soinfo结构体中的base,和link_map_head指针指向我们在maps中映射的地址,达到绕过检测的目的。

图片描述
注入上述代码后,再次点击这两个按钮查看控制台输出:
图片描述
此时环境也正常了
注:对base和load_bias进行修改,会有app崩溃的风险

4.libc section mem crc的绕过
这个我就简单说下检测及绕过思路:

获取到soinfo结构体中的节表地址(这里以strtab_变量作检测),再与本地文件或取到的节表偏移相见得到so的基地址,计算基地址与可执行段的偏移得到可执行段的地址,最后提取内存中可执行段数据和本地文件可执行段数据作比较。

把soinfo结构体中的节表指针指向我们在maps中映射的地址,达到绕过检测的目的。

图片描述
图片描述
注入代码后再次点击按钮:
图片描述

此次分享主要是提供个思路,仅供参考,包括libart.so也可以这样去弄,总之crc的大方向就是上述的两个,其次小方向的检测手段就是有很多细节去相互嵌套了。

function hiddenSoExecSegmentInMaps(so_path) {
    //      /apex/com.android.runtime/lib64/bionic/libc.so
    let mmap_addr = Module.findExportByName("libc.so", "mmap");
    let mmapFunc = new NativeFunction(mmap_addr, 'pointer', ['pointer', 'int', 'int', 'int', 'int', 'int'])
 
    let munmap_addr = Module.findExportByName("libc.so", "munmap");
    let munmapFunc = new NativeFunction(munmap_addr, 'int', ['pointer', 'int'])
 
    let mremap_addr = Module.findExportByName("libc.so", "mremap");
    let mremapFunc = new NativeFunction(mremap_addr, 'pointer', ['pointer', 'int64', 'int64', 'int64', 'pointer'])
 
    let open_addr = Module.findExportByName("libc.so", "open");
    var openFunc = new NativeFunction(open_addr, 'int', ['pointer', 'int']);
 
    let memset_addr = Module.findExportByName("libc.so", "memset");
    var memsetFunc = new NativeFunction(memset_addr, 'pointer', ['pointer', 'int', 'int'])
 
    let close_addr = Module.findExportByName("libc.so", "close");
    var closeFunc = new NativeFunction(close_addr, 'int', ['int'])
 
    const parts = so_path.split('/');
    const so_name = parts.pop();
    let soExecSegmentRangeFromMaps = findSoExecSegmentRangeFromMaps(so_name);
    let startAddress = soExecSegmentRangeFromMaps.base;
    let size = soExecSegmentRangeFromMaps.size;
 
    if (startAddress === 0 || size === 0) {
        console.log("可执行段未找到:", startAddress, size)
        return;
    }
 
    let soExecSegmentFromFile = findSoExecSegmentFromFile(so_path);
 
    //创建匿名内存,临时存储so可执行段内存
    let new_addr = mmapFunc(ptr(-1), size, 7, 0x20 | 2, -1, 0);//0x20:匿名内存标识符(MAP_ANONYMOUS), 2:私有(MAP_PRIVATE)
    console.log("创建的可执行段匿名内存起始地址:" + new_addr);
 
    //把so可执行段内存复制到创建的匿名内存中去
    Memory.copy(new_addr, startAddress, size);
    console.log("复制完毕")
 
    //调整so,使传入的so可执行段内存变成匿名内存
    let ret = mremapFunc(new_addr, size, size, 1 | 2, startAddress);
    if (ret === -1) {
        console.log("mremap  调整失败")
        return;
    }
    console.log("匿名目标so可执行段完成 ret:" + ret)
 
    // 打开需要模拟的文件路径,用于后续在maps中生成指定名称的内存区域
    let moniter_path = so_path;
    let moniter_path_addr = Memory.allocUtf8String(moniter_path);
    var fd = openFunc(moniter_path_addr, 0);
    if (fd === -1) {
        console.log("open " + moniter_path + " is error")
        return -1;
    }
 
    //在maps中创建传入so路径名称的内存区域
    let target_addr = mmapFunc(ptr(-1), size, 7, 2, fd, 0);
    console.log("模拟的可执行段内存起始地址:" + target_addr);
 
    closeFunc(fd)
 
    //给创建的so内存区域全部置0
    memsetFunc(target_addr, 0, size);
 
    //把so文件中获取的可执行段内存复制到创建的so名称的内存区域中
    Memory.copy(target_addr, soExecSegmentFromFile.start, soExecSegmentFromFile.size)
    Memory.protect(target_addr, size, "r-x");
 
    //卸载映射的匿名内存
    // munmapFunc(new_addr, size);
    console.log("maps中隐藏可执行段完成")
 
}
function hiddenSoExecSegmentInMaps(so_path) {
    //      /apex/com.android.runtime/lib64/bionic/libc.so
    let mmap_addr = Module.findExportByName("libc.so", "mmap");
    let mmapFunc = new NativeFunction(mmap_addr, 'pointer', ['pointer', 'int', 'int', 'int', 'int', 'int'])
 
    let munmap_addr = Module.findExportByName("libc.so", "munmap");
    let munmapFunc = new NativeFunction(munmap_addr, 'int', ['pointer', 'int'])
 
    let mremap_addr = Module.findExportByName("libc.so", "mremap");
    let mremapFunc = new NativeFunction(mremap_addr, 'pointer', ['pointer', 'int64', 'int64', 'int64', 'pointer'])
 
    let open_addr = Module.findExportByName("libc.so", "open");
    var openFunc = new NativeFunction(open_addr, 'int', ['pointer', 'int']);
 
    let memset_addr = Module.findExportByName("libc.so", "memset");
    var memsetFunc = new NativeFunction(memset_addr, 'pointer', ['pointer', 'int', 'int'])
 
    let close_addr = Module.findExportByName("libc.so", "close");
    var closeFunc = new NativeFunction(close_addr, 'int', ['int'])
 
    const parts = so_path.split('/');
    const so_name = parts.pop();
    let soExecSegmentRangeFromMaps = findSoExecSegmentRangeFromMaps(so_name);
    let startAddress = soExecSegmentRangeFromMaps.base;
    let size = soExecSegmentRangeFromMaps.size;
 
    if (startAddress === 0 || size === 0) {
        console.log("可执行段未找到:", startAddress, size)
        return;
    }
 
    let soExecSegmentFromFile = findSoExecSegmentFromFile(so_path);
 
    //创建匿名内存,临时存储so可执行段内存
    let new_addr = mmapFunc(ptr(-1), size, 7, 0x20 | 2, -1, 0);//0x20:匿名内存标识符(MAP_ANONYMOUS), 2:私有(MAP_PRIVATE)
    console.log("创建的可执行段匿名内存起始地址:" + new_addr);
 
    //把so可执行段内存复制到创建的匿名内存中去
    Memory.copy(new_addr, startAddress, size);
    console.log("复制完毕")
 
    //调整so,使传入的so可执行段内存变成匿名内存
    let ret = mremapFunc(new_addr, size, size, 1 | 2, startAddress);
    if (ret === -1) {
        console.log("mremap  调整失败")
        return;
    }
    console.log("匿名目标so可执行段完成 ret:" + ret)
 
    // 打开需要模拟的文件路径,用于后续在maps中生成指定名称的内存区域
    let moniter_path = so_path;
    let moniter_path_addr = Memory.allocUtf8String(moniter_path);
    var fd = openFunc(moniter_path_addr, 0);
    if (fd === -1) {
        console.log("open " + moniter_path + " is error")
        return -1;
    }
 
    //在maps中创建传入so路径名称的内存区域
    let target_addr = mmapFunc(ptr(-1), size, 7, 2, fd, 0);
    console.log("模拟的可执行段内存起始地址:" + target_addr);
 
    closeFunc(fd)
 
    //给创建的so内存区域全部置0
    memsetFunc(target_addr, 0, size);
 
    //把so文件中获取的可执行段内存复制到创建的so名称的内存区域中
    Memory.copy(target_addr, soExecSegmentFromFile.start, soExecSegmentFromFile.size)
    Memory.protect(target_addr, size, "r-x");
 
    //卸载映射的匿名内存
    // munmapFunc(new_addr, size);
    console.log("maps中隐藏可执行段完成")
 
}
struct soinfo {
 #if defined(__work_around_b_24465209__)
  private:
   char old_name_[SOINFO_NAME_LEN];
 #endif
  public:
   const ElfW(Phdr)* phdr; //0
   size_t phnum;   //1
 #if defined(__work_around_b_24465209__)
   ElfW(Addr) unused0; // DO NOT USE, maintained for compatibility.
 #endif
   ElfW(Addr) base;    //2
   size_t size;    //3
  
 #if defined(__work_around_b_24465209__)
   uint32_t unused1;  // DO NOT USE, maintained for compatibility.
 #endif
  
   ElfW(Dyn)* dynamic; //4
  
 #if defined(__work_around_b_24465209__)
   uint32_t unused2; // DO NOT USE, maintained for compatibility
   uint32_t unused3; // DO NOT USE, maintained for compatibility
 #endif
  
   soinfo* next;   //5
  private:
   uint32_t flags_;    //6
  
   const char* strtab_;    //7 .dynstr
   ElfW(Sym)* symtab_; //8     .dynsym
  
   size_t nbucket_;
   size_t nchain_;
   uint32_t* bucket_; //11
   uint32_t* chain_; //12
  
 #if defined(__mips__) || !defined(__LP64__)
   // This is only used by mips and mips64, but needs to be here for
   // all 32-bit architectures to preserve binary compatibility.
   ElfW(Addr)** plt_got_;  //arm64未被使用
 #endif
  
 #if defined(USE_RELA)
   ElfW(Rela)* plt_rela_; //.real.plt  13
   size_t plt_rela_count_;
  
   ElfW(Rela)* rela_;  //15 //real.dyn
   size_t rela_count_;             //16
 #else
   ElfW(Rel)* plt_rel_;   
   size_t plt_rel_count_;
  
   ElfW(Rel)* rel_;       
   size_t rel_count_;     
 #endif
  
   linker_ctor_function_t* preinit_array_;//17
   size_t preinit_array_count_;//18
  
   linker_ctor_function_t* init_array_;
   size_t init_array_count_;
   linker_dtor_function_t* fini_array_;
   size_t fini_array_count_;
  
   linker_ctor_function_t init_func_; //23
   linker_dtor_function_t fini_func_;//    24
  
 #if defined(__arm__)  //arm64不进入
  public:
   // ARM EABI section used for stack unwinding.
   uint32_t* ARM_exidx;
   size_t ARM_exidx_count;
  private:
 #elif defined(__mips__)//arm64不进入
   uint32_t mips_symtabno_;
   uint32_t mips_local_gotno_;
   uint32_t mips_gotsym_;
   bool mips_relocate_got(const VersionTracker& version_tracker,
                          const soinfo_list_t& global_group,
                          const soinfo_list_t& local_group);
 #if !defined(__LP64__)//arm64不进入
   bool mips_check_and_adjust_fp_modes();
 #endif
 #endif
   size_t ref_count_;  //25
  public:
   link_map link_map_head; //26 27 28 29 30
     // struct link_map {
           //     ElfW(Addr) l_addr;
           //     char* l_name;
           //     ElfW(Dyn)* l_ld;
           //     struct link_map* l_next;
           //     struct link_map* l_prev;
           // };
   bool constructors_called;
  
   // When you read a virtual address from the ELF file, add this
   // value to get the corresponding address in the process' address space.
   ElfW(Addr) load_bias; //32
  
 #if !defined(__LP64__)
   bool has_text_relocations;
 #endif
   bool has_DT_SYMBOLIC;
  
  public:
   soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
          off64_t file_offset, int rtld_flags);
   ~soinfo();
  
   void call_constructors();
   void call_destructors();
   void call_pre_init_constructors();
   bool prelink_image();
   bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
                   const android_dlextinfo* extinfo, size_t* relro_fd_offset);
   bool protect_relro();
  
   void add_child(soinfo* child);
   void remove_all_links();
  
   ino_t get_st_ino() const;
   dev_t get_st_dev() const;
   off64_t get_file_offset() const;
  
   uint32_t get_rtld_flags() const;
   uint32_t get_dt_flags_1() const;
   void set_dt_flags_1(uint32_t dt_flags_1);
  
   soinfo_list_t& get_children();
   const soinfo_list_t& get_children() const;
  
   soinfo_list_t& get_parents();
  
   bool find_symbol_by_name(SymbolName& symbol_name,
                            const version_info* vi,
                            const ElfW(Sym)** symbol) const;
  
   ElfW(Sym)* find_symbol_by_address(const void* addr);
   ElfW(Addr) resolve_symbol_address(const ElfW(Sym)* s) const;
  
   const char* get_string(ElfW(Word) index) const;
   bool can_unload() const;
   bool is_gnu_hash() const;
  
   bool inline has_min_version(uint32_t min_version __unused) const {
 #if defined(__work_around_b_24465209__)
     return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
 #else
     return true;
 #endif
   }
  
   bool is_linked() const;
   bool is_linker() const;
   bool is_main_executable() const;
  
   void set_linked();
   void set_linker_flag();
   void set_main_executable();
   void set_nodelete();
  
   size_t increment_ref_count();
   size_t decrement_ref_count();
   size_t get_ref_count() const;
  
   soinfo* get_local_group_root() const;
  
   void set_soname(const char* soname);
   const char* get_soname() const;
   const char* get_realpath() const;
   const ElfW(Versym)* get_versym(size_t n) const;
   ElfW(Addr) get_verneed_ptr() const;
   size_t get_verneed_cnt() const;
   ElfW(Addr) get_verdef_ptr() const;
   size_t get_verdef_cnt() const;
  
   int get_target_sdk_version() const;
  
   void set_dt_runpath(const char *);
   const std::vector<std::string>& get_dt_runpath() const;
   android_namespace_t* get_primary_namespace();
   void add_secondary_namespace(android_namespace_t* secondary_ns);
   android_namespace_list_t& get_secondary_namespaces();
  
   soinfo_tls* get_tls() const;
  
   void set_mapped_by_caller(bool reserved_map);
   bool is_mapped_by_caller() const;
  
   uintptr_t get_handle() const;
   void generate_handle();
   void* to_handle();
  
  private:
   bool is_image_linked() const;
   void set_image_linked();
  
   bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* elf_addr_lookup(const void* addr);
   bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
   ElfW(Sym)* gnu_addr_lookup(const void* addr);
  
   bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
                            const char* sym_name, const version_info** vi);
  
   template<typename ElfRelIteratorT>
   bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
                 const soinfo_list_t& global_group, const soinfo_list_t& local_group);
   bool relocate_relr();
   void apply_relr_reloc(ElfW(Addr) offset);
  
  private:
   // This part of the structure is only available
   // when FLAG_NEW_SOINFO is set in this->flags.
   uint32_t version_;
  
   // version >= 0
   dev_t st_dev_;
   ino_t st_ino_;
  
   // dependency graph
   soinfo_list_t children_;
   soinfo_list_t parents_;
  
   // version >= 1
   off64_t file_offset_;
   uint32_t rtld_flags_;
   uint32_t dt_flags_1_;
   size_t strtab_size_;
  
   // version >= 2
  
   size_t gnu_nbucket_;
   uint32_t* gnu_bucket_;
   uint32_t* gnu_chain_;
   uint32_t gnu_maskwords_;
   uint32_t gnu_shift2_;
   ElfW(Addr)* gnu_bloom_filter_;
  
   soinfo* local_group_root_;
  
   uint8_t* android_relocs_;
   size_t android_relocs_size_;
  
   const char* soname_;
   std::string realpath_;
  
   const ElfW(Versym)* versym_;
  
   ElfW(Addr) verdef_ptr_;
   size_t verdef_cnt_;
  
   ElfW(Addr) verneed_ptr_;
   size_t verneed_cnt_;
  
   int target_sdk_version_;
  
   // version >= 3
   std::vector<std::string> dt_runpath_;
   android_namespace_t* primary_namespace_;
   android_namespace_list_t secondary_namespaces_;
   uintptr_t handle_;
  
   friend soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si);
  
   // version >= 4
   ElfW(Relr)* relr_;
   size_t relr_count_;
  
   // version >= 5
   std::unique_ptr<soinfo_tls> tls_;
   std::vector<TlsDynamicResolverArg> tlsdesc_args_;
 }
struct soinfo {
 #if defined(__work_around_b_24465209__)
  private:
   char old_name_[SOINFO_NAME_LEN];
 #endif
  public:
   const ElfW(Phdr)* phdr; //0
   size_t phnum;   //1
 #if defined(__work_around_b_24465209__)
   ElfW(Addr) unused0; // DO NOT USE, maintained for compatibility.
 #endif
   ElfW(Addr) base;    //2
   size_t size;    //3
  
 #if defined(__work_around_b_24465209__)
   uint32_t unused1;  // DO NOT USE, maintained for compatibility.
 #endif
  
   ElfW(Dyn)* dynamic; //4
  
 #if defined(__work_around_b_24465209__)
   uint32_t unused2; // DO NOT USE, maintained for compatibility
   uint32_t unused3; // DO NOT USE, maintained for compatibility
 #endif
  
   soinfo* next;   //5
  private:
   uint32_t flags_;    //6
  
   const char* strtab_;    //7 .dynstr
   ElfW(Sym)* symtab_; //8     .dynsym
  
   size_t nbucket_;
   size_t nchain_;
   uint32_t* bucket_; //11
   uint32_t* chain_; //12
  
 #if defined(__mips__) || !defined(__LP64__)
   // This is only used by mips and mips64, but needs to be here for
   // all 32-bit architectures to preserve binary compatibility.
   ElfW(Addr)** plt_got_;  //arm64未被使用
 #endif
  
 #if defined(USE_RELA)
   ElfW(Rela)* plt_rela_; //.real.plt  13
   size_t plt_rela_count_;
  
   ElfW(Rela)* rela_;  //15 //real.dyn
   size_t rela_count_;             //16
 #else
   ElfW(Rel)* plt_rel_;   
   size_t plt_rel_count_;
  
   ElfW(Rel)* rel_;       
   size_t rel_count_;     
 #endif
  
   linker_ctor_function_t* preinit_array_;//17
   size_t preinit_array_count_;//18
  
   linker_ctor_function_t* init_array_;
   size_t init_array_count_;
   linker_dtor_function_t* fini_array_;
   size_t fini_array_count_;
  
   linker_ctor_function_t init_func_; //23
   linker_dtor_function_t fini_func_;//    24
  
 #if defined(__arm__)  //arm64不进入
  public:
   // ARM EABI section used for stack unwinding.
   uint32_t* ARM_exidx;
   size_t ARM_exidx_count;
  private:
 #elif defined(__mips__)//arm64不进入
   uint32_t mips_symtabno_;
   uint32_t mips_local_gotno_;
   uint32_t mips_gotsym_;
   bool mips_relocate_got(const VersionTracker& version_tracker,
                          const soinfo_list_t& global_group,
                          const soinfo_list_t& local_group);
 #if !defined(__LP64__)//arm64不进入
   bool mips_check_and_adjust_fp_modes();
 #endif
 #endif
   size_t ref_count_;  //25
  public:
   link_map link_map_head; //26 27 28 29 30
     // struct link_map {
           //     ElfW(Addr) l_addr;
           //     char* l_name;
           //     ElfW(Dyn)* l_ld;
           //     struct link_map* l_next;
           //     struct link_map* l_prev;
           // };
   bool constructors_called;
  
   // When you read a virtual address from the ELF file, add this
   // value to get the corresponding address in the process' address space.
   ElfW(Addr) load_bias; //32
  
 #if !defined(__LP64__)
   bool has_text_relocations;
 #endif
   bool has_DT_SYMBOLIC;
  
  public:
   soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
          off64_t file_offset, int rtld_flags);
   ~soinfo();
  
   void call_constructors();
   void call_destructors();
   void call_pre_init_constructors();
   bool prelink_image();
   bool link_image(const soinfo_list_t& global_group, const soinfo_list_t& local_group,
                   const android_dlextinfo* extinfo, size_t* relro_fd_offset);
   bool protect_relro();
  
   void add_child(soinfo* child);
   void remove_all_links();
  

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 299
支持
分享
最新回复 (259)
雪    币: 6
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-2-28 20:46
1
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
11
2025-2-28 20:47
0
雪    币: 2522
活跃值: (2280)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2025-2-28 20:51
0
雪    币: 18
活跃值: (745)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好东西
2025-2-28 20:54
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
2025-2-28 21:00
0
雪    币: 163
活跃值: (2778)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2025-2-28 21:02
0
雪    币: 102
活跃值: (2785)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
好东西。
2025-2-28 21:05
0
雪    币: 439
活跃值: (1903)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
看看
2025-2-28 21:14
0
雪    币: 352
活跃值: (136)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
6666666
2025-2-28 21:18
1
雪    币: 224
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
感谢分享
2025-2-28 21:23
0
雪    币: 78
活跃值: (1416)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2025-2-28 21:29
0
雪    币: 90
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
6666
2025-2-28 22:05
0
雪    币: 3203
活跃值: (3937)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
14

我有个想法  对libc 的路径 进行 重定向 拿 错误的libc 去内存中对比 ,openat 进行 io 重定向  到 临时重内存dump 修复的so

最后于 2025-2-28 22:34 被逆天而行编辑 ,原因:
2025-2-28 22:33
1
雪    币: 529
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
学习了
2025-2-28 22:53
0
雪    币: 235
活跃值: (740)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
学习下
2025-2-28 22:59
0
雪    币: 1472
活跃值: (808)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17
逆天而行 我有个想法&nbsp;&nbsp;对libc 的路径 进行 重定向 拿 错误的libc 去内存中对比 ,openat&nbsp;进行&nbsp;io&nbsp; ...
可以的,只要是两边的校验值相等就行
2025-2-28 23:10
0
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
太强了大佬
2025-2-28 23:20
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
撒大苏打
2025-2-28 23:52
0
雪    币: 100
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
太强了大佬
2025-3-1 03:11
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
Mark
2025-3-1 04:36
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
666
2025-3-1 09:44
0
雪    币: 4522
活跃值: (4334)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
6666
2025-3-1 11:58
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
666
2025-3-1 15:28
0
雪    币: 252
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
666666
2025-3-1 15:39
1
游客
登录 | 注册 方可回帖
返回