CrackProof iOS版分析(二)补充

2026-04-11 14:301阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

0x0

最近又研究了一下,仅作简单的补充

0x1 dyld

iOS加载Mach-O的时候会由dyld调用目标Mach-O全部的mod_init_func来完成初始化,和安卓的.init_proc段是一个作用
hook一下全局的pthread再配合trace日志,可以知道mod_init_func_0调用了pthread来创建线程进行越狱检测,触发pthread的调用点为0xa03050c,创建的函数为0xa07ce90

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10b8e0e90!0xa07ce90 0x10b8e0e90 !0xa07ce90 (0xa07ce90) arg: 0x10ccf5118 pthread_t*: 0x16fb10650 -> 0x16fffb000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10bab1668!0xa24d668 0x10bab1668 !0xa24d668 (0xa24d668) #3 dyld:0x10059842c!0x2842c 0x10059842c dyld!invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const #4 dyld:0x1005c76ec!0x576ec 0x1005c76ec dyld!invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const #5 dyld:0x1005752d0!0x52d0 0x1005752d0 dyld!invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const #6 dyld:0x100574788!0x4788 0x100574788 dyld!dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const #7 dyld:0x100573d78!0x3d78 0x100573d78 dyld!dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const #8 dyld:0x1005c1160!0x51160 0x1005c1160 dyld!dyld3::MachOFile::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, bool&) block_pointer) const #9 dyld:0x10057ed94!0xed94 0x10057ed94 dyld!dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const #10 dyld:0x10057b97c!0xb97c 0x10057b97c dyld!dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const #11 dyld:0x100578444!0x8444 0x100578444 dyld!dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const #12 dyld:0x1005984b4!0x284b4 0x1005984b4 dyld!dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_1::operator()() const #13 dyld:0x10057d4d4!0xd4d4 0x10057d4d4 dyld!dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const #14 dyld:0x100577c1c!0x7c1c 0x100577c1c dyld!dyld4::APIs::dlopen_from(char const*, int, void*) #15 CoreFoundation:0x1a2166f58!0x122f58 0x1a2166f58 CoreFoundation!_CFBundleDlfcnLoadFramework

然后0xa07ce90又会继续创建两个线程进行越狱检测

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10b938704!0xa0d4704 0x10b938704 !0xa0d4704 (0xa0d4704) arg: 0x16fffae58 pthread_t*: 0x16fffa5c0 -> 0x170087000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10b9ea704!0xa186704 0x10b9ea704 !0xa186704 (0xa186704) #3 UnityFramework:0x10b8af47c!0xa04b47c 0x10b8af47c !0xa04b47c (0xa04b47c) #4 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #5 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #6 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #7 UnityFramework:0x10b8f6c80!0xa092c80 0x10b8f6c80 !0xa092c80 (0xa092c80) #8 UnityFramework:0x10b9ca288!0xa166288 0x10b9ca288 !0xa166288 (0xa166288) #9 UnityFramework:0x10b8e1134!0xa07d134 0x10b8e1134 !0xa07d134 (0xa07d134) #10 libsystem_pthread.dylib:0x1ecdf40ec!0x30ec 0x1ecdf40ec libsystem_pthread.dylib!_pthread_start

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10ba2f23c!0xa1cb23c 0x10ba2f23c !0xa1cb23c (0xa1cb23c) arg: 0x170086f10 pthread_t*: 0x16fff9310 -> 0x170113000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10b9d929c!0xa17529c 0x10b9d929c !0xa17529c (0xa17529c) #3 UnityFramework:0x10b8af47c!0xa04b47c 0x10b8af47c !0xa04b47c (0xa04b47c) #4 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #5 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #6 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #7 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #8 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #9 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #10 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #11 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #12 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #13 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #14 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #15 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18)

0x2 魔改ollvm

入口点长这样
PixPin_2026-03-29_11-06-341825×1300 267 KB
初始化分发器
PixPin_2026-03-29_11-07-321597×763 151 KB
分发器核心,整体如下
PixPin_2026-03-29_11-08-051920×1044 139 KB
分发器最具特色的应该就是这个opcode生成了
PixPin_2026-03-29_11-09-061920×1044 325 KB
通过一系列计算来获取初步的opcode
PixPin_2026-03-29_11-09-521492×327 67.4 KB
然后会进入如下两个switch case,二次解密opcode以后再选择函数执行
PixPin_2026-03-29_11-11-541006×934 134 KB
PixPin_2026-03-29_11-13-361193×1855 473 KB
每个case对应的函数又是一个分发器,分发器里面还有crackproof::state_compute0,反正塞了致死量的魔改ollvm

不过通过trace可以得知,整个trace.log前面全是垃圾计算,目的是掩盖真实的调用函数,这下就很容易找到检测函数了
PixPin_2026-03-29_11-17-371385×2077 421 KB
这里发现了一个上次没分析出来的检测,这玩意会检测__objd段是否有修改,有任何修改也会通过OS_dispatch_queue_main压入exit(0)杀掉进程(这玩意还会sleep几秒,阴完了)

环境检测倒是和上次的分析一致,下面是字符串的解密算法:

  • 先把立即数拷到缓冲区里面,直到遇到0为止
  • s[i] = (~ROL8(s[i], 3) - (i & 3)) & 0xff; 字节左转3位,然后取反,再减掉i&3

0xF

得从VMProtect里面学学垃圾代码生成了,然后又可以出CTF题目折磨逆向的了

网友解答:
--【壹】--:

这个保护器全平台都是高强度防御的(
只不过windows能通过ring0直接注入dll来改内存,安卓和iOS这边就不好搞了(


--【贰】--:

为啥一个iOS上的游戏会塞这么多检查
感觉macOS上很少见到这么强的保护


--【叁】--:

佬友太强了

问题描述:

0x0

最近又研究了一下,仅作简单的补充

0x1 dyld

iOS加载Mach-O的时候会由dyld调用目标Mach-O全部的mod_init_func来完成初始化,和安卓的.init_proc段是一个作用
hook一下全局的pthread再配合trace日志,可以知道mod_init_func_0调用了pthread来创建线程进行越狱检测,触发pthread的调用点为0xa03050c,创建的函数为0xa07ce90

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10b8e0e90!0xa07ce90 0x10b8e0e90 !0xa07ce90 (0xa07ce90) arg: 0x10ccf5118 pthread_t*: 0x16fb10650 -> 0x16fffb000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10bab1668!0xa24d668 0x10bab1668 !0xa24d668 (0xa24d668) #3 dyld:0x10059842c!0x2842c 0x10059842c dyld!invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const #4 dyld:0x1005c76ec!0x576ec 0x1005c76ec dyld!invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const #5 dyld:0x1005752d0!0x52d0 0x1005752d0 dyld!invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const #6 dyld:0x100574788!0x4788 0x100574788 dyld!dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const #7 dyld:0x100573d78!0x3d78 0x100573d78 dyld!dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const #8 dyld:0x1005c1160!0x51160 0x1005c1160 dyld!dyld3::MachOFile::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, bool&) block_pointer) const #9 dyld:0x10057ed94!0xed94 0x10057ed94 dyld!dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const #10 dyld:0x10057b97c!0xb97c 0x10057b97c dyld!dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const #11 dyld:0x100578444!0x8444 0x100578444 dyld!dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const #12 dyld:0x1005984b4!0x284b4 0x1005984b4 dyld!dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_1::operator()() const #13 dyld:0x10057d4d4!0xd4d4 0x10057d4d4 dyld!dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const #14 dyld:0x100577c1c!0x7c1c 0x100577c1c dyld!dyld4::APIs::dlopen_from(char const*, int, void*) #15 CoreFoundation:0x1a2166f58!0x122f58 0x1a2166f58 CoreFoundation!_CFBundleDlfcnLoadFramework

然后0xa07ce90又会继续创建两个线程进行越狱检测

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10b938704!0xa0d4704 0x10b938704 !0xa0d4704 (0xa0d4704) arg: 0x16fffae58 pthread_t*: 0x16fffa5c0 -> 0x170087000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10b9ea704!0xa186704 0x10b9ea704 !0xa186704 (0xa186704) #3 UnityFramework:0x10b8af47c!0xa04b47c 0x10b8af47c !0xa04b47c (0xa04b47c) #4 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #5 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #6 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #7 UnityFramework:0x10b8f6c80!0xa092c80 0x10b8f6c80 !0xa092c80 (0xa092c80) #8 UnityFramework:0x10b9ca288!0xa166288 0x10b9ca288 !0xa166288 (0xa166288) #9 UnityFramework:0x10b8e1134!0xa07d134 0x10b8e1134 !0xa07d134 (0xa07d134) #10 libsystem_pthread.dylib:0x1ecdf40ec!0x30ec 0x1ecdf40ec libsystem_pthread.dylib!_pthread_start

creator: UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) start_routine: UnityFramework:0x10ba2f23c!0xa1cb23c 0x10ba2f23c !0xa1cb23c (0xa1cb23c) arg: 0x170086f10 pthread_t*: 0x16fff9310 -> 0x170113000 attr: default backtrace: #0 UnityFramework:0x10b89450c!0xa03050c 0x10b89450c !0xa03050c (0xa03050c) #1 UnityFramework:0x10b896cbc!0xa032cbc 0x10b896cbc !0xa032cbc (0xa032cbc) #2 UnityFramework:0x10b9d929c!0xa17529c 0x10b9d929c !0xa17529c (0xa17529c) #3 UnityFramework:0x10b8af47c!0xa04b47c 0x10b8af47c !0xa04b47c (0xa04b47c) #4 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #5 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #6 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #7 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #8 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #9 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #10 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #11 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #12 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #13 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #14 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18) #15 UnityFramework:0x10b8afb18!0xa04bb18 0x10b8afb18 !0xa04bb18 (0xa04bb18)

0x2 魔改ollvm

入口点长这样
PixPin_2026-03-29_11-06-341825×1300 267 KB
初始化分发器
PixPin_2026-03-29_11-07-321597×763 151 KB
分发器核心,整体如下
PixPin_2026-03-29_11-08-051920×1044 139 KB
分发器最具特色的应该就是这个opcode生成了
PixPin_2026-03-29_11-09-061920×1044 325 KB
通过一系列计算来获取初步的opcode
PixPin_2026-03-29_11-09-521492×327 67.4 KB
然后会进入如下两个switch case,二次解密opcode以后再选择函数执行
PixPin_2026-03-29_11-11-541006×934 134 KB
PixPin_2026-03-29_11-13-361193×1855 473 KB
每个case对应的函数又是一个分发器,分发器里面还有crackproof::state_compute0,反正塞了致死量的魔改ollvm

不过通过trace可以得知,整个trace.log前面全是垃圾计算,目的是掩盖真实的调用函数,这下就很容易找到检测函数了
PixPin_2026-03-29_11-17-371385×2077 421 KB
这里发现了一个上次没分析出来的检测,这玩意会检测__objd段是否有修改,有任何修改也会通过OS_dispatch_queue_main压入exit(0)杀掉进程(这玩意还会sleep几秒,阴完了)

环境检测倒是和上次的分析一致,下面是字符串的解密算法:

  • 先把立即数拷到缓冲区里面,直到遇到0为止
  • s[i] = (~ROL8(s[i], 3) - (i & 3)) & 0xff; 字节左转3位,然后取反,再减掉i&3

0xF

得从VMProtect里面学学垃圾代码生成了,然后又可以出CTF题目折磨逆向的了

网友解答:
--【壹】--:

这个保护器全平台都是高强度防御的(
只不过windows能通过ring0直接注入dll来改内存,安卓和iOS这边就不好搞了(


--【贰】--:

为啥一个iOS上的游戏会塞这么多检查
感觉macOS上很少见到这么强的保护


--【叁】--:

佬友太强了