iOS 逆向入门 - 常用反逆向手段

在「iOS 逆向入门 - 绕过抖音反调试」中提到常用反调试手段,这里写下具体实现。 一、常用反逆向手段 1、反调试:ptrace ptrace 被常用于防止 lldb 依附,原理是一个进程只能被 ptrace 只能被一次,先于别人调用 ptrace 则可以防止别人依附。 ptrace 有几种方式进行调用: 1)直接调用 #import <sys/ptrace.h> ptrace(PT_DENY_ATTACH,0,0,0); iOS SDK 中不包含 ptrace.h 头文件,无法使用此方法调用,可使用以下方法。 2)通过 dlopen + dlsym 调用 #import <dlfcn.h> #import <sys/types.h> typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data); #if !defined(PT_DENY_ATTACH) #define PT_DENY_ATTACH 31 #endif void disable_attach() { void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW); ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace"); ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0); dlclose(handle); } 3)通过 syscall 调用 #import <sys/syscall.h> #if !defined(PT_DENY_ATTACH) #define PT_DENY_ATTACH 31 #endif void disable_attach() { syscall(SYS_ptrace, PT_DENY_ATTACH, 0, 0, 0); // #define SYS_ptrace 26 } 4)通过汇编调用 内联 svc + ptrace 实现,相当于直接调用 ptrace(PT_DENY_ATTACH,0,0,0); ...

December 9, 2021 · Darren Ou

iOS dSYM 文件 & 符号化

一、dSYM 文件生成 1、Xcode 自动生成,配置: Xcode -> Build Settings -> Code Generation -> Generate Debug Symbols -> Yes Xcode -> Build Settings -> Build Option -> Debug Information Format -> DWARF with dSYM File 2、手动生成: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil /Users/oudushu/Library/Developer/Xcode/DerivedData/YourApp-cqvijavqbptjyhbwewgpdmzbmwzk/Build/Products/Debug-iphonesimulator/YourApp.app/YourApp -o YourApp.dSYM 二、如何找到对应的 dSYM 文件: 从发布的归档包里面找: Xcode -> Window -> Organizer -> 找到打包好的文件(Show in Finder)-> 选中文件(右键显示包内容)-> dSYMs文件夹下就是了 从iTunes Connect里面找 mdfind工具:mdfind “com_apple_xcode_dsym_uuids == E30FC309-DF7B-3C9F-8AC5-7F0F6047D65F” 三、symbolicatecrash 1、查找 find /Applications/Xcode.app -name symbolicatecrash -type f /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash 2、使用 export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer ./symbolicatecrash ./appName.crash ./appName.app.dSYM > customName.log 四、atos 1、使用 atos -o yourAppName.app.dSYM/Contents/Resources/DWARF/yourAppName -arch arm64/armv7 -l <load-address> <address> 或 atos -o yourAppName.app.dSYM/Contents/Resources/DWARF/yourAppName -arch arm64/armv7 <address> // 崩溃地址对应的符号表地址 二、实践 ...

December 8, 2021 · Darren Ou

阿 B 出生记

这是一篇流水账,记录老婆怀胎十月到阿B出生的历程。 怀孕 2021年3月,有一天试纸出现两条杠,去到医院再次确认,确实是怀孕了。 把医生的化验单给老爸老妈看,他们也非常开心,老妈说道:明年过年我们家可就热闹了。 老婆说小孩子很小气,过了3个月才跟身边的朋友说这件事。 怀孕期间 多亏了外企的“福利”,老婆大部分时间都是在家办公,这就避免了上下班的麻烦,缺点是独自在家少人交流。 这里感慨一下外企对于孕妇的政策确实要比国内企业人性化,比如产假更多、补贴更多、还能在家办公。 得知怀孕前,老婆已经拿到SHEIN、小鹏等公司的offer,得知怀孕后,把offer都拒了。 冲刺 11月7日,把丈母娘接到广州,有丈母娘照顾老婆,我放心得多。 期间丈母娘煮饭做家务陪老婆散步陪老婆产检,真是辛苦。 计划 基于我老婆的情况,一家人讨论了一个星期,决定了剖腹产。计划阿B跟我老婆同一天生日,这该是多么美好的场景。 于是11月20日去医院让医生开了住院单,21日办理了入院手续,22日经过医生的确认,确定了23日早上七点的剖腹产手术 一切都按照计划去推进。 出生 2021年11月23日星期二,距离阿B的预产期只剩下两天,这天是我老婆的生日。 前一天医生安排了早上七点第一床手术。 3:36 老婆给我打电话,跟我说破羊水了,医生正在给她做检查。心里一惊,难道阿B想提前出生? 4:08 老婆宫口开得比较快,我赶紧起床。 4:16 跟丈母娘一起出发去医院。 5:03 到了医院,老婆已被推进分娩中心。 6:13 老婆已开5指,经医生讨论,决定尝试顺产,取消了手术。 8:55 阿B出生! 9:16 老婆给我打电话阿B顺利出生。我给家人朋友报喜。 阿B顺产出生,真是计划外的惊喜。 新生儿科 阿B出生后在分娩中心观察了两个小时,护士采取了各种措施,阿B体温还未恢复正常水平,医生决定让阿B在新生儿科住院观察几天。 护士推着阿B出来,我见了一面,拍了几张照片,就被送到新生儿科了。 第一次见到阿B,第一次听到听到阿B的声音,简直心都化了。 老婆出院 11月25日下午,去到医院给老婆办理出院手续。 看到老婆的状态挺好,心里不由感慨阿B醒目,真会挑时间出生,晚一个小时发动,可能就按照计划进行剖腹产了。 阿B回家 11月26日下午,医生给我打电话,阿B的各项指标都正常,符合出院的条件了。 11月27日上午,去到医院办理阿B的出院手续。 接到阿B的时候,让老婆去抱他下楼,老婆不会抱,折腾了几分钟。 月嫂说阿B身体素质好,哭声响亮,眼仔碌碌,压根不需要住新生儿科。 阿B美照

November 28, 2021 · Darren Ou

iOS 逆向入门 - 实现 TikTok 自动播放下一个视频

一、背景 经过之前对 iOS 逆向的初步了解,想了个实现 TikTok 自动播放下一个视频的小需求实践一下。 二、实现过程 1、使用 class-dump 工具获取类信息 class-dump 工具通过解析 MachO 文件生成类信息,包括 OC 方法、属性、成员变量等。 有几个点需要留意: C 语言函数无法 dump; OC 方法的参数如果是对象类型,则只会显示 id; dump 出来的 OC 方法包含了 .h .m 文件里面的。 2、通过视图堆栈找出对应文件 从视图堆栈里面可以很方便找出播放器相关的文件,从 class-dump 出来的文件中找到相关文件,在文件中找出相关方法。 比如我需要实现自动播放下一个视频的话,分为两个步骤:1.监听播放完一个视频的事件;2.播放下一个视频。 找到“播放下一个视频”的方法: 我从视图堆栈里定位到 AWEFeedTableViewController 类; 从 class-dump 出来的文件中打开 AWEFeedTableViewController.h; 在文件中搜索 NextVideo,很容易可以找到 - (void)scrollToNextVideo; 方法。 类似的方法找出“播放完一个视频的事件”。 3、快速验证 从上一步找到的类还有对应方法是否真的可以实现“播放下一个视频”呢?我们可以在代码中 Hook 对应方法验证,但是这样验证的方法比较低效。 使用 Cycript 可以动态调试 App,这里简单介绍如何通过 Cycript 快速验证: 越狱手机上通过 Cydia 安装 Cycript; 通过 SSH 连接手机; 找到进程:root# ps -e | grep 'TikTok'; 依附到进程:cycript -p 进程号; 打印视图堆栈,输入命令:UIApp.keyWindow.recursiveDescription() ; 找到 AWEFeedTableViewController 内存地址并执行 [#0x1118da200 scrollToNextVideo](内存地址前需要加 # 号) 此时发现 App 真的切换到了下一个视频,证明这个方法就是我们需要找的方法。 ...

September 18, 2021 · Darren Ou

iOS 逆向入门 - 绕过抖音反调试

一、背景 在「iOS 逆向入门 - TikTok 调试」文章中介绍了使用 MonkeyDev 工具对 TikTok 进行调试。使用同样的方法对抖音进行调试的过程中遇到了几个问题,在这里记录一下。 二、动态库注入失败 按照 TikTok 的方式运行后,发现控制台没有打印 insert dylib success 的信息,猜测动态库注入失败了,果然在编译信息的输出中找到相关错误打印: 在 MonkeyDev 的 change.log 中找到信息,尝试恢复使用 optool 工具注入动态库。 下载 optool 的二进制文件并复制到相应位置,然后修改以下代码: # 注释原来的 MONKEYPARSER # "$MONKEYPARSER" install -c load -p "@executable_path/Frameworks/lib""${TARGET_NAME}""Dylib.dylib" -t "${BUILD_APP_PATH}/${APP_BINARY}" # 修改为 optool OPTOOL="${MONKEYDEV_PATH}/bin/optool" "$OPTOOL" install -c load -p "@executable_path/Frameworks/lib""${TARGET_NAME}""Dylib.dylib" -t "${BUILD_APP_PATH}/${APP_BINARY}" 重新编译运行后可发现控制台中出现 insert dylib success 信息,证明动态库已经注入成功。 三、绕过反调试 动态库注入成功后,发现控制台没有了任何输出,且 lldb 已经断开,证明抖音使用了某种反调试手段。 1、反调试常规手段 1)ptrace ptrace 被常用于防止 lldb 依附,原理是一个进程只能被 ptrace 只能被一次,先于别人调用 ptrace 则可以防止别人依附。 ...

September 15, 2021 · Darren Ou

iOS 上的 adb 工具 - libimobiledevice

一、简介 libimobiledevice 是一个与iOS设备通信的工具集,类似于安卓上的 adb 工具,像爱思助手、PP助手等底层都是用的这个工具。 A library to communicate with services on iOS devices using native protocols. ideviceinstaller 依赖于 libimobiledevice,主要用于操作 App,如获取应用列表、安装卸载应用等。 A command-line application to manage apps and app archives on iOS devices. 二、安装 Mac 上可以直接利用 Homebrew 安装: // 安装 libimobiledevice brew install libimobiledevice // 安装 ideviceinstaller brew install ideviceinstaller 三、使用 下面介绍常用的命令: 1. idevice_id 打印连接的设备的 UUID ➜ ~ idevice_id -l 0e68ed5333802b17d5ac62bfa708619de597eef2 2. idevicecrashreport 把设备上的崩溃报告移到指定文件夹。 ➜ ~ idevicecrashreport -u 0e68ed5333802b17d5ac62bfa708619de597eef2 crash Move: /com.apple.appstored/appstored.log Move: /Retired/rtcreportingd_2021-09-02-17-17-59_messageLog.ips Move: /Retired/liveshow-2021-08-31-165309.ips Move: /Retired/log-aggregated-2021-08-31-080228.ips ... 3. idevicedate 获取或者设置设备时间。 ...

September 6, 2021 · Darren Ou

iOS 沙盒挂载工具 - ifuse

一、ifuse ifuse 是一个文件系统工具,在未越狱的设备上可以挂载 App 的文件夹,在已越狱的设备上可以挂载根文件夹 This project allows mounting various directories of an iOS device locally using the FUSE file system interface. 二、安装 利用 Homebrew 进行安装: // 期间可能需要输入电脑密码 brew install macfuse brew install ifuse 安装时可能出现错误: // 编辑 ifuse 的安装配置 vim `brew formula ifuse` // 注释或删除以下几行 # on_macos do # disable! date: "2021-04-08", because: "requires closed-source macFUSE" # end // 重新安装 brew install ifuse 三、使用 1. 挂载 // 新建挂载点文件夹 mkdir ~/Sandbox // 设置挂载点 ifuse --container ifuse.test ~/Sandbox 此时 ifuse.test 的沙盒被成功挂载到 Sandbox 文件夹: ...

September 5, 2021 · Darren Ou

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,使其返回指定运营商信息。 ...

September 3, 2021 · 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; }

September 1, 2021 · 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 ...

August 30, 2021 · 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开发,可开发非越狱插件) 持续更新。。。

August 29, 2021 · 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/。 ...

August 4, 2021 · 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. ...

July 5, 2021 · 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,一个是避免捕获到的图片过大造成性能浪费,一个是避免难以适配太多的屏幕分辨率,我们需要指定输出的分辨率。 ...

May 18, 2021 · 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 ...

March 20, 2021 · Darren Ou