iOS 逆向入门 - TikTok 调试

一、MonkeyDev 1、简介 MonkeyDev 是一个工具集合,基于 iOSOpenDev 进行升级并集成到 Xcode 里面,可以用来开发越狱机器的插件,可以很方便地注入动态库并重签名安装到非越狱机器,堪称神器。 2、安装 参考官方文档进行安装:https://github.com/AloneMonkey/MonkeyDev/wiki 3、开始使用 新建 MonkeyApp 项目。 拖入 已砸壳 的 ipa 包到指定文件夹 配置开发证书。 如无意外即可运行到手机上。 4、其它运行问题 1. 链接错误 ld: file not found: /usr/lib/libstdc++.dylib 这是由于 Xcode 10 开始就不再集成 libstdc++ 库,需要把相关的库文件重新添加到对应的路径。 使用 GitHub 上的这个库 https://github.com/devdawei/libstdc- 可以比较方便地添加 libstdc++ 库。 2. Bundle ID TikTok 对 Bundle ID 应该有校验,用其它 Bundle ID 会导致无法联网,这时候可以在 Build Settings 里面,找到 MONKEYDEV_DEFAULT_BUNDLEID 设为 YES,这时候重新编辑安装到手机即可。 3. 需要国外手机卡 TikTok 对地区有限制,手机需要插上国外手机卡才能进行开播,这样对调试不太友好。 CTCarrier 是iOS上获取运营商信息的系统框架,我们可以对其进行 Hook,使其返回指定运营商信息。 得益于 MonkeyDev 维护了非越狱插件 CocoaPods 私有仓库(https://github.com/AloneMonkey/MonkeyDevSpecs),我们可以直接使用别人提供的插件,使用方法跟我们平时使用 CocoaPods 完全一致,添加对应的源地址即可: ...

2021年9月3日 · Darren Ou

C 语言中利用单引号表示整数

背景 在进行与竟品的性能对比中,需要知道竟品的部分参数,与竟品对齐参数后再进行性能测试。 在 hook TikTok 的摄像头输出参数时发现,PixelFormatType 的值是整数 875704422,这样的一串整数很难知道其含义。 分析 从 key PixelFormatType 可以猜出是 kCVPixelFormatType 枚举中的一个,kCVPixelFormatType 枚举中大部分的值是以 '420f' 这样的单引号形式来表示,通过逐一对比知道,原来 875704422 对应的就是 kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 的值,也就是 '420f'。 那么,为什么 875704422 == '420f' ? 原来,可以通过 ascii 编码进行转换,以 '420f' 为例: 4/2/0/f 的 ascii 编码分别为 52/50/48/102 ,转换为二进制分别为 00110100/00110010/00110000/01100110,合并起来 00110100001100100011000001100110 转换为十进制,刚好就是 875704422。 为方便看出对应的字符串,写了以下转换算法: 转换算法 NSString * changeToTypeStr(int value) { char *str = malloc(10); int count = 0; while (value > 0) { char ch = (char)(value & 0xFF); str[count] = ch; value = value >> 8; count ++; } if (count > 1) { int left = 0, right = count - 1; while (left < right) { char tmp = str[left]; str[left] = str[right]; str[right] = tmp; left ++; right --; } } str[count] = '\0'; NSString *res = [[NSString alloc] initWithUTF8String:str]; free(str); return res; }

2021年9月1日 · Darren Ou

iOS 逆向入门 - 砸壳

一、背景 iOS 手机通过 App Store 安装的应用都经过加密,无法直接进行逆向分析。我们需要对应用进行解密,称为“砸壳”。 我手上的设备是 iPhone 6s,系统是 iOS 13.5.1 二、手机越狱 安装爱思助手,一键越狱的工具里面有很多个工具(不一定需要安装爱思助手,可以直接从官网下载越狱工具)。 这里主要推荐两个:一个是通过硬件漏洞进行越狱的 checkra1n;一个是通过软件漏洞进行越狱的 Unc0ver。 相对来说通过硬件漏洞进行越狱的 checkra1n 会比较稳定,我使用的是 checkra1n。 按照提示进行操作,手机重启后会出现 checkra1n 应用,打开应用安装 Cydia (这个过程手机需要连接代理)。 注意:不同的越狱工具,对手机跟系统都有要求,太新的设备或者太新的系统都有可能不支持,需要仔细阅读官网的文档。另外,保证手机的重要资料都已经备份。 三、通过 SSH 连接手机 1. Wi-Fi 手机安装 Cydia 后,默认安装了 OpenSSH,可以直接通过 Wi-Fi 或者 USB 连接手机。 ssh root@your_device_ip_address // 密码默认为 alpine 2. USB // 安装 usbmuxd brew install usbmuxd // 建立端口映射(把 2222 映射到 22) iproxy 2222 22 // 建立 ssh 连接 ssh -p 2222 root@localhost 建立端口映射时,终端会一直显示 “waiting for connection”,这是正常的,新建一个终端窗口进行其它操作即可。 ...

2021年8月30日 · Darren Ou

iOS 逆向入门 - 工具

iOS 越狱 https://checkra.in/ (基于硬件漏洞,较稳定) https://unc0ver.dev/ (基于软件漏洞,每次重启手机后都要再越狱) App文件系统结构 https://www.i-funbox.com/zh-cn/index.html https://macroplant.com/iexplorer App UI调试工具 https://revealapp.com/ https://lookin.work/ (免费) 反编译工具 https://hex-rays.com/ida-pro/ https://www.hopperapp.com/ MachO https://github.com/gdbinit/MachOView 越狱开发框架 https://github.com/theos/theos ipa砸壳工具 https://github.com/stefanesser/dumpdecrypted https://github.com/KJCracks/Clutch https://github.com/AloneMonkey/frida-ios-dump class-dump http://stevenygard.com/projects/class-dump/ 动态库注入 https://github.com/alexzielenski/optool 获取keychain信息 https://github.com/ptoomey3/Keychain-Dumper 工具集 https://github.com/kokoabim/iOSOpenDev https://github.com/AloneMonkey/MonkeyDev (基于iOSOpenDev开发,可开发非越狱插件) 持续更新。。。

2021年8月29日 · Darren Ou

OpenGL + Xcode 开发环境搭建

一、OpenGL 相关库的下载与安装 GLFW GLFW 是配合 OpenGL 使用的轻量级工具程序库,缩写自 Graphics Library Framework(图形库框架)。GLFW 的主要功能是创建并管理窗口和 OpenGL 上下文,同时还提供了处理手柄、键盘、鼠标输入的功能。 就是用来创建窗口界面。 // 使用 Homebrew 安装: brew install glfw3 // 头文件路径 /usr/local/Cellar/glfw/3.3.4/include/GLFW // 库路径 /usr/local/Cellar/glfw/3.3.4/lib GLEW OpenGL Extension Wrangler Library (GLEW), a cross-platform C/C++ library that helps in querying and loading OpenGL extensions. 实现对底层OpenGL接口封装。 // 使用 Homebrew 安装: brew install glew // 头文件路径 /usr/local/Cellar/glew/2.2.0_1/include/GL // 库路径 /usr/local/Cellar/glew/2.2.0_1/lib Glad 作用与 GLEW 类似。 下载地址:https://glad.dav1d.de/ Language: C/C++ Specification: OpenGL API: Version 3.3 Profile: Core 选中 Generate a loader 并点击 GENERATE 按钮,下载 glad.zip 文件,解压后复制到 /usr/local/Cellar/glad/。 ...

2021年8月4日 · Darren Ou

macOS 解决 App Nap 导致 Timer 回调变慢问题

背景 在开发 macOS 上的窗口共享过程中,发现 demo 被其它应用覆盖后,在25s左右,观众收到的窗口画面开始变得卡顿。 经过排查发现问题出在主播端的采集逻辑处。在我的上一篇文章 macOS 屏幕共享开发 提到,窗口共享的实现跟屏幕共享不一样,窗口共享没有现有的系统接口,需要启动一个 Timer 去定时对窗口截图,再对截图进行处理。 通过打印日志发现,demo 进入后台后,Timer 在25s左右,回调开始变慢,大约2s才回调一次,问题的原因就出在这里。 排查原因 为了避免其它逻辑影响了结果,新建一个干净的 demo。 我在窗口共享中用的是 GCD Timer,一开始猜测是 GCD Timer 的某些参数没有设置,查看文档后没找到相关的参数;然后猜测 GCD Timer 的问题,但是换成 NSTimer 后,发现也有一样的问题,这时候我开始猜测是系统导致的问题了。 开始查阅资料,发现了 一篇文章 里面提到: App Nap 是 OS X 10.9 Mavericks 的一项新功能。它能帮你在同时运行多个应用程序时节省电能。 这时候有了切入点,查询关键字 App Nap 就可以发现相关资料。 App Nap 附上苹果官方说明文档:Extend App Nap If an app isn’t performing user-initiated work such as updating content on screen, playing music, or downloading a file, the system may put the app in App Nap. App Nap conserves battery life by regulating the app’s CPU usage and by reducing the frequency with which its timers are fired. ...

2021年7月5日 · Darren Ou

macOS 屏幕共享开发

一、屏幕录制权限 应用首次创建屏幕截图或者窗口截图时(以下任一接口都可以),就会显示系统的权限申请弹窗,通过选中Screen Recording里面的相关应用,重启应用后即可开启权限。 CGDisplayCreateImage() CGDisplayCreateImageForRect() CGWindowListCreateImage() CGWindowListCreateImageFromArray() 二、获取screenId 通过AppKit的NSScreen.screens或者通过CoreGraphics的CGGetActiveDisplayList()都可以获取当前的所有显示器信息,下面用NSScreen.screens举例子: [NSScreen.screens enumerateObjectsUsingBlock:^(NSScreen * _Nonnull screen, NSUInteger idx, BOOL * _Nonnull stop) { NSNumber *screenNumber = screen.deviceDescription[@"NSScreenNumber"]; if (screenNumber) { CGDirectDisplayID displayId = screenNumber.unsignedIntValue; NSLog(@"displayId: %d", displayId); } }]; 注意:如果是镜像显示,则只会打印一个显示器信息。 三、获取windowId 1、获取windowId列表 通过接口CGWindowListCopyWindowInfo()可以获取windowId列表。 其中kCGWindowListExcludeDesktopElements参数表示从列表中排除所有属于桌面元素的窗口。 CGWindowListCopyWindowInfo()返回的是一个CFArrayRef,使用完后需要主动release。 这里有一个技巧,利用CFBridgingRelease()函数,可以把CFArrayRef桥接到NSArray,并且会把内存管理转移到ARC,就是说我们不需要再去主动release了。 NSArray *windowDictArr = CFBridgingRelease(CGWindowListCopyWindowInfo(kCGWindowListOptionAll | kCGWindowListExcludeDesktopElements, 0)); 2、过滤无用windowId 通过以上接口获取到的windowId列表可能会包含很多我们不关心的windowId: 1. 没显示出来的window 通过kCGWindowLayer跟kCGWindowAlpha两个key,可以获取到当前window是否有layer以及是否透明,我们需要过滤掉不可见的window。 2. 过滤信息不全的window kCGWindowNumberkey可以从字典里获取到windowId,需要过滤没有windowId的字典信息。 3. 过滤无法获取截图的window 通过CGWindowListCreateImage()接口,传入对应windowId,可获取到window的截图,如果无法获取到截图,可能没有录屏权限、不是window主体、window不可见。 3、获取window frame 通过CGRectMakeWithDictionaryRepresentation()可获取窗口的frame,某些业务可能需要用到frame。 四、屏幕共享 屏幕共享的视频输入总体来说跟摄像头的视频输入相当类似,可以理解成视频流从摄像头改成了屏幕输入(AVCaptureDeviceInput->AVCaptureScreenInput),视频输出的处理则跟摄像头的输出处理完全一样。 1、关键代码: - (void)startCapture { self.captureSession = [[AVCaptureSession alloc] init]; self.captureSession.sessionPreset = AVCaptureSessionPresetMedium; // input AVCaptureScreenInput *input = [[AVCaptureScreenInput alloc] initWithDisplayID:kCGDirectMainDisplay]; [self.captureSession addInput:input]; // output [self.captureSession beginConfiguration]; dispatch_queue_t queue = dispatch_queue_create("smaple_buffer", DISPATCH_QUEUE_SERIAL); AVCaptureVideoDataOutput *videoDataOutput = [[AVCaptureVideoDataOutput alloc] init]; videoDataOutput.videoSettings = @{(NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)}; [videoDataOutput setSampleBufferDelegate:self queue:queue]; AVCaptureConnection *videoConnection = [videoDataOutput connectionWithMediaType:AVMediaTypeVideo]; videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait; [self.captureSession addOutput:videoDataOutput]; [self.captureSession commitConfiguration]; [self.captureSession startRunning]; } 2、视频输出分辨率设置 我们的编码分辨率最大为720p,一个是避免捕获到的图片过大造成性能浪费,一个是避免难以适配太多的屏幕分辨率,我们需要指定输出的分辨率。 ...

2021年5月18日 · Darren Ou

群晖 NAS - 购置篇

为什么想要购买NAS 我的理解NAS无非就两个作用,一个是作为资料存储容器,一个是作为个人服务器 作为资料存储容器 这个很容易理解,NAS就是一块很大的磁盘(空间大),足够我接下来三年的资料存储需要。两块磁盘以上组raid(安全)。 作为个人服务器 这个就很好玩了,可以说是只有想不到,没有做不到。 举几个例子: 文件共享服务器,可以在任意地方访问我的NAS里面的文件(局域网或公网); Homebridge服务器,把Homebridge部署到NAS里面,可以轻松桥接小米智能家居; Gitlab服务器,把仓库放在自己家,放心; 资料备份,Mac可以直接通过Time Machine备份到NAS,手机也有相应的工具备份; 下载工具、邮件服务器、娱乐中心…… 选购 明确需求 我选购前就明确了几方面的需求,优先级由高到低排序: 数据安全优于一切; 系统成熟稳定,考虑到家人也会使用,需要足够易用; 双盘位以上,用于组raid保障数据安全; 作为第一个NAS,有一定的性价比; 系统选择 对比了几个系统: 群晖,各大博主推荐; 威联通,很多人把威联通比作安卓,群晖比作iOS; TrueNAS,开源的NAS系统,前身是FreeNAS,功能非常强大,但对硬件有一定门槛,且操作也不足够易用; Linux或Windows自组系统,需要有一定运维能力,使用不太友好。 综上,最终选择群晖系统。 品牌选择 确认需要群晖系统后,有两种选择,一个是选择群晖官方的机器,一个是购买其它的机器刷入黑群晖系统。 考虑到其它机器不一定能很好地兼容群晖系统,而且黑群晖系统没有官方的技术支持与QuickConnect功能(黑群晖洗白后可支持),作为第一台NAS,我还是买群晖官方的机器会更有安全感。 型号选择 明确了需求已经很好选择了,最终选择了群晖DS220+。 硬盘 NAS是7x24运行,而且数据安全非常重要,所以选择硬盘需要相当谨慎。 酷狼是希捷主推的NAS专用硬盘,大部分店家都是推荐酷狼,在没有了解过硬盘信息的情况下,闭着眼睛选酷狼就可以了。 于是我买了两块酷狼8T硬盘。不过我后悔了。 因为希捷还有一个银河系列,专为企业用户打造。对比酷狼转速跟缓存都更高,意味着读写速度更快,官方宣称的无故障时长比酷狼多出两倍,而且质保是5年,比酷狼多出两年,价格还比酷狼便宜(2021.3)。 所以我是首推希捷银河系列,其次是酷狼系列。 至于西数,我还没用过西数的产品,我后面估计会换一个西数的硬盘,毕竟鸡蛋不能放在一个篮子里。 UPS UPS 即不间断电源 (Uninterruptible Power Supply) 虽说酷狼硬盘是专为NAS打造,但是突然断电对硬盘的伤害非常大,非常容易造成数据的丢失,非常多的博主都建议买一个UPS,避免突然断电造成数据丢失。 UPS我选择的是施耐德BK650M2,原因是它跟群晖有很好的兼容性,可以实现断电后UPS备用电将要耗尽时通知群晖关机。 路由器 我原来在用的路由器是小米路由器mini,说是千兆路由器,但实际上远远没有千兆(这个我还排查了很久,珍惜生命远离小米路由器),这肯定会影响NAS的使用体验。趁着这次,顺便把路由器也换了。 需要有WiFi6、链路聚合功能,主要在考虑华硕路由器的两个型号:AX82U、AX86U 我最终选择了AX82U,价钱是AX86U的一半,我觉得最大的不足就是没有2.5G网口。 其它 内存 群晖DS220+是2G内存,考虑到会使用docker,2G内存可能不太够,我添加了根三星4G内存条。 机柜 我喜欢整洁,还买了个家用机柜收纳上面的设备。 总支出(2021年3月购买) 群晖DS220+(2250) + 希捷酷狼8T * 2(2360) + 施耐德UPS(420) + 三星4G内存条(140) + 华硕路由器AX82U(770) + 机柜(130) = 6070 ...

2021年3月20日 · Darren Ou

iOS UI 自动化测试简介

前言 发布内测版的时候,每次在提交代码前、上传ipa包前、发布前都需要手动地跑一下主流程,比如在视频详情页划几页,在直播页划几个直播间等。都是比较重复且有规律的操作,可以利用自动化测试来代替手工操作。 我们在Jenkins上面打包时,会有一个UI自动化测试的选项,是架构组自己弄的一套自动化测试环境,想要自己搭建估计不太方便。所以需要有一套轻量级切足够易用的UI自动化测试框架。 XCUITest 简介 XCUITest是苹果在iOS9.3提供的自动化测试框架(iOS9.3之前提供的是UI Automation),Xcode自带的框架,不需要搭建其它环境,由于是苹果提供的框架,运行稳定。使用Swift或者OC编写测试用例(可能对于测试不是很友好)。 使用 func testExample() throws { // UI tests must launch the application that they test. let app = XCUIApplication(bundleIdentifier: "appium.test") app.launch() // 启动应用 for _ in 1 ..< 5 { app.swipeUp() // 上划 } for _ in 1 ... 3 { app.swipeRight() // 右划 } app.swipeDown() // 下划刷新 sleep(5) // 等待5s再执行下一步 app.cells.firstMatch.tap() // 点击当前的第一个cell for _ in 1 ... 5 { app.swipeUp() // 上划 sleep(2) // 等待2s再执行下一步 } app.buttons["live_room_quit_btn"].tap() // 点击标志btn } 通过id获取UI元素,需要先在代码设置accessibilityIdentifier: _quitButton.accessibilityIdentifier = @"live_room_quit_btn"; ...

2020年11月28日 · Darren Ou

在树莓派上搭建 Homebridge,实现 HomeKit 控制智能家居

一、什么是Homebridge Homebridge is a lightweight NodeJS server you can run on your home network that emulates the iOS HomeKit API. It supports Plugins, which are community-contributed modules that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of “smart home” devices. HomeKit是苹果的智能家居平台,是iOS系统层面支持的平台,拥有其它平台无法比拟用户体验。可惜大部分米家设备及其它平台的设备都不支持HomeKit,但是可以通过Homebridge作为桥接,实现HomeKit控制其它平台的设备。 二、如何在树莓派上搭建Homebridge https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Raspbian 三、安装插件 在这个网址https://www.npmjs.com/search?q=keywords%3Ahomebridge-plugin上可以通过关键字搜索插件, 常用插件: 1.Aqara套装:homebridge-mi-aqara 2.米家空调伴侣:homebridge-mi-acpartner 3.米家yeelight台灯:homebridge_yeelight 4.小米风扇:homebridge-mi-fan 5.米家智能摄像机:homebridge-mi-camera 6.米家智能排插:homebridge-mi-outlet 7.米家空气净化器:homebridge-mi-airpurifier 8.飞利浦灯泡:homebridge-mi-philips-light 9.智能插座:homebridge-mi-outlet ... 四、配置设备 在Homebridge上,插件利用设备的IP地址及设备的token即可以实现控制某个设备,IP地址我们可以登录路由器查看已连接的设备获取,获取token有以下几种方法: 1、使用安卓手机下载旧版本的米家app,导出里面的数据库找到设备token 2、使用miio discover命令获取(米家新的设备基本都隐藏了token,这种方法基本失效) 3、利用Charles抓包 ...

2020年10月11日 · Darren Ou