iOS逆向工程可谓喜忧参半。一方面,用Objective-C和Swift编程的应用程序可以......
iOS逆向工程喜忧参半。一方面,用Objective-C和Swift编程的应用程序可以很好地反汇编。在Objective-C中,对象方法通过称为"选择器"的动态函数指针调用,这些指针在运行时通过名称解析。运行时名称解析的优势在于,这些名称需要在最终二进制文件中保持不变,从而使反汇编更具可读性。遗憾的是,这也意味着反汇编器中无法提供方法间的直接交叉引用,因此构建流程图具有挑战性。
在iOS上,所有应用程序代码(包括Swift和Objective-C)都编译为机器代码(如ARM)。因此,分析iOS应用程序需要反汇编器。
如果您有IDAPro的许可证,也可以使用IDAPro分析应用程序二进制文件。
不幸的是,免费版IDA不支持ARM处理器类型。
要开始分析,只需在IDAPro中打开应用程序二进制文件即可。
普通的IDAPro许可证默认情况下不包含反编译器,而且还需要额外的Hex-Rays反编译器许可证,价格昂贵。相比之下,Ghidra内置的免费反编译器功能强大,是逆向工程的理想选择。
静态分析iOS应用程序的首选方法是使用原始Xcode项目文件。理想情况下,您可以编译和调试应用程序,以快速识别源代码中的任何潜在问题。
在无法访问原始源代码的情况下对iOS应用程序进行黑盒分析需要逆向工程。例如,iOS应用程序没有反编译器(尽管大多数商业和开放源代码反汇编器可以提供二进制文件的伪源代码视图),因此深入检查需要读取汇编代码。
在本节中,我们将了解一些使用静态分析收集给定应用程序基本信息的方法和工具。
unzipDamnVulnerableiOSApp.ipacdPayload/DamnVulnerableIOSApp.appotool-hvDamnVulnerableIOSApp输出结果如下
DamnVulnerableIOSApp(architecturearmv7):MachheadermagiccputypecpusubtypecapsfiletypencmdssizeofcmdsflagsMH_MAGICARMV70x00EXECUTE333684NOUNDEFSDYLDLINKTWOLEVELPIEDamnVulnerableIOSApp(architecturearm64):MachheadermagiccputypecpusubtypecapsfiletypencmdssizeofcmdsflagsMH_MAGIC_64ARM64ALL0x00EXECUTE334192NOUNDEFSDYLDLINKTWOLEVELPIE注意架构:armv7"(32位)和"arm64"(64位)。胖二进制文件的这种设计允许在不同架构上部署应用程序。要使用class-dump分析应用程序,我们必须创建一个所谓的瘦二进制文件,其中只包含一种架构:
lipo-thinarmv7DamnVulnerableIOSApp-outputDVIA32然后我们就可以继续执行类转储了:
iOS8-jailbreak:~root#class-dumpDVIA32@interfaceFlurryUtil:./DVIA/DVIA/DamnVulnerableIOSApp/DamnVulnerableIOSApp/YapDatabase/Extensions/Views/Internal/{}+(BOOL)appIsCracked;+(BOOL)deviceIsJailbroken;注意加号,它表示这是一个返回BOOL类型的类方法。减号表示这是一个实例方法。请参阅后面的章节,了解它们之间的实际区别。
下面的命令正在列出共享库:
Ghidra可用于分析iOS二进制文件,并通过右键单击所需函数并选择ShowReferencesto获取交叉引用。
iOS平台为应用程序中的常用功能提供了许多内置库,例如加密、蓝牙、NFC、网络和定位库。确定应用程序中是否存在这些库可以为我们提供有关其底层工作的宝贵信息。
你可能会遇到的大多数应用程序都会连接到远程端点。即使在执行任何动态分析(如流量捕获和分析)之前,也可以通过枚举应用程序应与之通信的域来获取一些初始输入或入口点。
通常情况下,这些域会以字符串的形式存在于应用程序的二进制文件中。我们可以通过检索字符串(如上所述)或使用Ghidra等工具检查字符串来提取域。后一种方法有一个明显的优势:它可以为你提供上下文信息,因为通过检查交叉引用,你可以看到每个域是在哪种上下文中使用的。
从这里开始,您就可以利用这些信息获得更多有用的信息,例如,您可以将域名与固定证书进行匹配,或对域名进行进一步侦查,以了解更多目标环境信息。
安全连接的实施和验证是一个复杂的过程,需要考虑很多方面。例如,许多应用程序使用HTTP以外的其他协议,如XMPP或纯TCP数据包,或执行证书锁定以阻止MITM攻击。
在本节中,我们将手动探索iOS应用程序的二进制代码,并对其执行静态分析。手动分析是一个缓慢的过程,需要极大的耐心。良好的手动分析可以使动态分析更加成功。
执行静态分析没有硬性规定,但有一些经验法则可用于系统地进行手动分析:
本节讨论的技术是通用的,适用于任何分析工具。
当用户输入错误字符串时,应用程序会弹出"验证失败"的消息。
您可以记下弹出窗口中显示的字符串,因为这可能有助于搜索处理输入并做出决定的代码。幸运的是,该应用程序的复杂性和交互都很简单,这对我们的逆转工作是个好兆头。
本节的静态分析将使用Ghidra9.0.4。Ghidra9.1_beta自动分析有一个错误,无法显示Objective-C类。
如果我们继续仔细分析,就会发现"VerificationFailed(验证失败)"字符串,它用于在输入错误时弹出。如果跟踪该字符串的交叉引用(Xrefs),就会找到ViewController类的buttonClick函数。我们将在本节的稍后部分研究buttonClick函数。在进一步检查应用程序中的其他字符串时,只有少数几个字符串看起来可能是hiddenflag的候选字符串。您也可以尝试验证一下。
接下来,我们有两条路可走。我们可以开始分析上述步骤中确定的buttonClick函数,或者从各个入口点开始分析应用程序。在现实世界中,大多数情况下你会选择第一种途径,但从学习的角度来看,本节我们将选择后一种途径。
许多应用程序都会在这些部分执行关键代码,因此它们通常是系统跟踪代码的良好起点。
如果我们对该函数进行反编译,会发现一些有趣的现象。例如,第31行调用了一个本地函数,第27-29行初始化了一个标签,并将"setHidden"标志设置为1。你可以记下这些观察结果,并继续探索该类中的其他函数。为简洁起见,探索函数的其他部分留作读者练习。
在第一步中,我们观察到应用程序只有在按下用户界面按钮时才会验证输入字符串。因此,分析buttonClick函数是一个显而易见的目标。如前所述,该函数也包含我们在弹出窗口中看到的字符串。在第29行,我们根据isEqualString(第23行保存在uVar1中的输出)的结果做出了决定。比较的输入来自文本输入框(来自用户)和label的值。因此,我们可以假定隐藏标记存储在该标签中。
如上所述,Objective-C代码也可以编译成本地二进制代码,但分析C/C++本地代码可能更具挑战性。在Objective-C中存在各种符号(尤其是函数名),这有助于理解代码。在上一节中,我们已经了解到,"setText"、"isEqualStrings"等函数名可以帮助我们快速理解代码的语义。在C/C++本地代码中,如果所有二进制文件都被剥离,那么可以帮助我们分析代码的符号就会非常少甚至没有。
反编译器可以帮助我们分析本地代码,但应谨慎使用。现代反编译器非常复杂,在它们用来反编译代码的许多技术中,有几种是基于启发式的。基于启发式的技术不一定总能给出正确的结果,确定给定本地函数的输入参数数就是一个例子。在反编译器的辅助下,掌握分析反汇编代码的知识可以减少分析本地代码时出错的几率。
我们将分析上一节中在viewDidLoad函数中确定的本地函数。该函数位于偏移量0x1000080d4。该函数的返回值用于setText标签的函数调用。该文本用于与用户输入进行比较。因此,我们可以确定该函数将返回一个字符串或等价文本。
在反汇编函数时,我们首先可以看到函数没有输入。整个函数都没有读取寄存器X0-X7。此外,该函数还多次调用其他函数,如0x100008158、0x10000dbf0等。
与这些函数调用相对应的指令如下。分支指令bl用于调用位于0x100008158的函数。
1000080f01a000094blFUN_1000081581000080f460020039strbw0,[x19]=>DAT_10000dbf0函数的返回值(在W0中找到)被存储到寄存器X19中的地址(strb将一个字节存储到寄存器中的地址)。我们可以看到其他函数调用的相同模式,返回值存储在X19寄存器中,每次偏移量都比前一次函数调用多一个。这种行为与每次填充字符串数组的每个索引有关。每次返回值都被写入该字符串数组的一个索引。这样的调用共有11次,根据目前的证据,我们可以推测隐藏标志的长度为11。在反汇编即将结束时,函数返回了该字符串数组的地址。
100008148E00313aamovx0=>DAT_10000dbf0,x19要确定隐藏标志的值,我们需要知道上面确定的每个后续函数调用的返回值。在分析函数0x100006fb4时,我们可以发现这个函数比我们之前分析的函数要大得多、复杂得多。函数图对分析复杂函数非常有帮助,因为它有助于更好地理解函数的控制流。在Ghidra中,点击子菜单中的显示函数图图标即可获得函数图。
不要回避使用自动扫描仪进行分析--它们可以帮助你挑选低垂的果实,让你专注于更有趣的分析方面,如业务逻辑。请记住,静态分析仪可能会产生假阳性和假阴性;请务必仔细查看分析结果。
越狱设备的生活很轻松:您不仅可以轻松获得对设备的访问权限,由于没有代码签名,您还可以使用更强大的动态分析技术。在iOS上,大多数动态分析工具都基于CydiaSubstrate(一个用于开发运行时补丁的框架)或Frida(一个动态自省工具)。对于基本的API监控,你可以不了解Substrate或Frida工作原理的所有细节,只需使用现有的API监控工具即可。
由于Apple的配置和代码签名系统令人困惑,因此重新签名应用程序比想象中更具挑战性。除非配置文件和代码签名头完全正确,否则iOS不会运行应用程序。这需要学习许多概念--证书类型、捆绑ID、应用程序ID、团队标识符,以及Apple的构建工具如何将它们连接起来。让操作系统运行未通过默认方法(Xcode)构建的二进制文件是一个令人生畏的过程。
请注意,以下步骤仅适用于macOS,因为Xcode仅适用于macOS。
供应配置文件是一个由Apple签名的plist文件,它将你的代码签名证书添加到一个或多个设备上可接受的证书列表中。换句话说,这代表苹果明确允许你的应用程序因某些原因运行,例如在选定设备上调试(开发配置文件)。供应配置文件还包括授予应用程序的entitlements。certificate包含你用来签名的私钥。
根据你是否注册为iOS开发者,你可以通过以下方式之一获得证书和供应配置文件:
使用iOS开发者账户:
使用常规AppleID:
在iOS上,收集有关运行中进程或应用程序的基本信息可能比Android稍具挑战性。在Android(或任何基于Linux的操作系统)上,进程信息是通过procfs以可读取文本文件的形式公开的。因此,在root设备上可以通过解析这些文本文件获得目标进程的任何信息。相比之下,iOS上没有与procfs相对应的文件。此外,在iOS上,许多用于探索进程信息的标准UNIX命令行工具(如lsof和vmmap)都被移除,以减少固件的大小。
在运行PID为2828的iOS应用程序中使用lsof,可以列出各种打开的文件,如下所示。
LLDB等iOS调试器使用它来附加、步进或继续进程,但却不能使用它来读取或写入内存(缺少所有PT_READ_*和PT_WRITE*请求)。相反,它们必须获得所谓的马赫任务端口(通过调用带有目标进程ID的task_for_pid),然后使用马赫IPC接口API函数来执行暂停目标进程、读/写寄存器状态(thread_get_state/thread_set_state)和虚拟内存(mach_vm_read/mach_vm_write)等操作。
要获取可执行文件,请加载以下DMG镜像:
codesign-s---entitlementsentitlements.plist-fdebugserver将修改后的二进制文件复制到测试设备上的任意目录。以下示例使用usbmuxd通过USB转发本地端口。
iproxy222222scp-P2222debugserverroot@localhost:/tmp/注:在iOS12及更高版本中,使用以下步骤签署从XCode镜像中获取的debugserver二进制文件。
VP-iPhone-18:/tmproot#./debugserver*:1234-a2670debugserver-@(#)PROGRAM:debugserverPROJECT:debugserver-320.2.89forarmv7.Attachingtoprocess2670...使用以下命令,您可以通过运行在目标设备上的debugserver启动应用程序:
debugserver-xbackboard\*:1234/Applications/MobileSMS.app/MobileSMS附加到已运行的应用程序:
debugserver\*:1234-a"MobileSMS"现在您可以从主机连接到iOS设备:
与调试构建不同,为发布构建编译的代码经过优化,以实现最高性能和最小二进制构建大小。作为一般的最佳做法,发布版编译会去掉大部分调试符号,这就增加了逆向工程和调试二进制文件的复杂性。
由于调试符号的缺失,反向跟踪输出中缺少了符号名,因此无法通过函数名来设置断点。幸运的是,调试器也支持直接在内存地址上设置断点。在本节中,我们将进一步学习如何设置断点,最终解决crackme的难题。
在使用内存地址设置断点之前,我们需要做一些基础工作。这需要确定两个偏移量:
iOS是一个现代操作系统,采用了多种技术来减少代码执行攻击,其中一种技术就是地址空间随机化布局(ASLR)。每次执行新的应用程序时,系统都会生成一个随机的ASLR移位偏移量,不同进程的数据结构都会根据该偏移量进行移位。
调试器最终使用的断点地址是上述两个地址的总和(断点偏移+ASLR移位偏移)。这种方法假定反汇编器和iOS使用的映像基址(稍后讨论)是相同的,这在大多数情况下是正确的。
当二进制文件在Ghidra等反汇编器中打开时,它会通过模拟相应操作系统的加载器来加载二进制文件。加载二进制文件的地址称为_imagebaseaddress_。二进制文件中的所有代码和符号都可以使用从该映像基址偏移的常量地址来寻址。在Ghidra中,可以通过确定Mach-O文件的起始地址来获得映像基地址。在本例中,它是0x100000000。
对于第二个地址,我们需要确定给定进程的ASLR移位偏移量。可以使用LLDB命令"imagelist-o-f"来确定ASLR偏移量。输出结果如下面的截图所示。
在输出中,第一列包含图像的序列号([X]),第二列包含随机生成的ASLR偏移量,第三列包含图像的完整路径,最后,括号中的内容显示了将ASLR偏移量添加到原始图像基地址后的图像基地址(0x100000000+0x70000=0x100070000)。您会发现图像基地址0x100000000与Ghidra中的相同。现在,要获得代码位置的有效内存地址,我们只需在Ghidra中确定的地址上加上ASLR偏移量即可。设置断点的有效地址将是0x100004520+0x70000=0x100074520。可以使用命令b0x100074520设置断点。
在上述输出中,你可能还会注意到许多列为图像的路径并不指向iOS设备上的文件系统。相反,它们指向运行LLDB的主机上的某个位置。这些图像是系统库,其调试符号可在主机上使用,以帮助应用程序开发和调试(作为XcodeiOSSDK的一部分)。因此,您可以直接使用函数名对这些库设置断点。
设置断点并运行应用程序后,一旦断点被击中,执行就会停止。现在,您可以访问并探索进程的当前状态。在本例中,通过之前的静态分析,我们知道寄存器X0中包含隐藏的字符串,因此让我们来探索它。在LLDB中,您可以使用po(printobject)命令打印Objective-C对象。
跟踪涉及记录程序的执行信息。与Android不同的是,可用于跟踪iOS应用程序各个方面的选项非常有限。在本节中,我们将主要依赖Frida等工具来执行跟踪。
拦截Objective-C方法是一种有用的iOS安全测试技术。例如,您可能会对数据存储操作或网络请求感兴趣。在下面的示例中,我们将编写一个简单的跟踪器,用于记录通过iOS标准HTTPAPI发出的HTTP(S)请求。我们还将向你展示如何将跟踪器注入Safari网页浏览器。
Frida附带一个函数跟踪工具frida-trace。frida-trace通过-m标志接受Objective-C方法。你也可以向它传递通配符,例如,如果给定了-[NSURL*],frida-trace就会自动在所有NSURL类选择器上安装钩子。我们将用它来大致了解用户打开URL时Safari调用了哪些库函数。
在设备上运行Safari,并确保设备已通过USB连接。然后启动frida-trace如下:
$frida-trace-U-m"-[NSURL*]"SafariInstrumentingfunctions...-[NSURLisMusicStoreURL]:Loadedhandlerat"/Users/berndt/Desktop/__handlers__/__NSURL_isMusicStoreURL_.js"-[NSURLisAppStoreURL]:Loadedhandlerat"/Users/berndt/Desktop/__handlers__/__NSURL_isAppStoreURL_.js"(...)Startedtracing248functions.PressCtrl+Ctostop.接下来,在Safari中导航到一个新网站。你应该会在frida-trace控制台上看到跟踪到的函数调用。请注意,调用initWithURL:方法是为了初始化一个新的URL请求对象。
遗憾的是,目前还没有诸如strace或ftrace等工具可用于跟踪iOS应用程序的系统调用或函数调用。只有DTrace是一款功能强大、用途广泛的跟踪工具,但它只适用于MacOS,不适用于iOS。
在开发和调试应用程序时,Xcode工具链会生成x86代码,这些代码可以在iOS模拟器中执行。但是,在发布版本时,只会生成ARM代码(与iOS模拟器不兼容)。这就是为什么从AppleAppStore下载的应用程序无法在iOS模拟器上进行任何应用程序分析的原因。
Corellium是一款商业工具,可提供运行实际iOS固件的虚拟iOS设备,是有史以来唯一公开的iOS模拟器。由于它是一款专有产品,因此有关其实现的信息并不多。Corellium没有社区许可证,因此我们不会详细介绍其使用方法。
Corellium允许你启动一个设备(无论是否越狱)的多个实例,这些实例可以作为本地设备访问(通过简单的VPN配置)。它还能拍摄和恢复设备状态快照,并为设备提供方便的网络外壳。最后,也是最重要的一点,由于它的"模拟器"性质,你可以执行从苹果应用商店下载的应用程序,从而可以对真正的iOS(越狱)设备进行任何类型的应用程序分析。
如果我们分析一下该函数和随后的函数调用,就会发现它并不依赖于任何外部库,也不执行任何系统调用。对函数的唯一外部访问发生在地址0x1000080f4处,其中一个值被存储到地址0x10000dbf0,该地址映射到"__data"部分。
因此,为了正确模拟这部分代码,除了__text部分(包含指令)外,我们还需要加载__data部分。
要使用Unicorn解决这一难题,我们将执行以下步骤:
从上表中,我们将使用__text和__data部分的基地址分别为0x10000432c和0x10000d3e8将它们加载到内存中。
为Unicorn分配内存时,内存地址应为4k页面对齐,分配的大小应为1024的倍数。
下面的脚本模拟了位于0x1000080d4的函数,并转储了秘密字符串:
总之,使用Unicorn确实需要在执行二进制文件前进行一些额外设置,但一旦完成,该工具就能帮助深入了解二进制文件。它提供了执行完整二进制文件或有限部分二进制文件的灵活性。Unicorn还提供了应用程序接口,可将钩子附加到执行过程中。使用这些钩子,你可以在执行过程中的任何时刻观察程序的状态,甚至可以操作寄存器或变量值,强行探索程序中的其他执行分支。在Unicorn中运行二进制程序的另一个好处是,你不必担心各种检查,如root/jailbreak检测或调试器检测等。
Angr中的Mach-O后端并不完善,但在我们的案例中却运行得很好。
如果我们重新查看该函数,就会发现它涉及多个子函数调用,有趣的是,这些函数都不依赖于其他库调用或系统调用。这是使用Angr具体执行引擎的完美案例。请按照以下步骤解决这一难题:
importangrimportclaripydefsolve():#Loadthebinarybycreatingangrproject.project=angr.Project('uncrackable.arm64')#Passtheaddressofthefunctiontothecallablefunc=project.factory.callable(0x1000080d4)#Getthereturnvalueofthefunctionptr_secret_string=claripy.backends.concrete.convert(func()).valueprint("Addressofthepointertothesecretstring:"+hex(ptr_secret_string))#Extractthevaluefromthepointertothesecretstringsecret_string=func.result_state.mem[ptr_secret_string].string.concreteprint(f"SecretString:{secret_string}")solve()上面,Angr在其具体执行引擎提供的执行环境中执行了ARM64代码。从内存中访问结果就像在真实设备上执行程序一样。这个案例就是一个很好的例子,二进制分析框架使我们能够对二进制文件进行全面分析,即使没有运行该文件所需的专用设备。
是时候认真对待了!如你所知,IPA文件实际上是ZIP压缩包,因此你可以使用任何ZIP工具来解压压缩包。
因此,要调试从AppStore获取的iOS应用程序,需要使用带有"get-task-allow"权限的开发供应配置文件对其重新签名。下一节将讨论如何重新签名应用程序。
当然,篡改应用程序会使主可执行文件的代码签名失效,因此无法在非越狱设备上运行。你需要替换供应配置文件,并用配置文件中列出的证书签署主可执行文件和你所包含的文件(如FridaGadget.dylib)。
首先,将我们自己的配置文件添加到软件包中:
cpAwesomeRepackaging.mobileprovisionPayload/UnCrackable\Level\1.app/embedded.mobileprovision接下来,我们需要确保Info.plist中的绑定ID与配置文件中指定的一致,因为在签名过程中,代码设计工具将从Info.plist中读取绑定ID;错误的值将导致签名无效。
/usr/libexec/PlistBuddy-c"Set:CFBundleIdentifiersg.vantagepoint.repackage"Payload/UnCrackable\Level\1.app/Info.plist最后,我们使用代码设计工具重新签署两个二进制文件。你需要使用_你自己_的签名身份(在本例中为8004380F331DCA22CC1B47FB1A805890AE41C938),你可以通过执行命令securityfind-identity-v输出该身份。
$rm-rfPayload/UnCrackable\Level\1.app/_CodeSignature$/usr/bin/codesign--force--sign8004380F331DCA22CC1B47FB1A805890AE41C938Payload/UnCrackable\Level\1.app/FridaGadget.dylibPayload/UnCrackableLevel1.app/FridaGadget.dylib:replacingexistingsignatureentitlements.plist是你为空iOS项目创建的文件。
ios-deploy--debug--bundlePayload/UnCrackable\Level\1.app/如果一切顺利,应用程序应在调试模式下启动并附加LLDB。然后,Frida也应能连接到应用程序。您可以通过frida-ps命令来验证:
从iOS10开始,应用程序压缩包会在安装时解压到"/private/var/containers/Bundle/Application/[GUID]/[APP].app"文件夹中,因此可以在此位置修改JavaScript应用程序主文件。
使用以下方法修补JavaScript文件:
在本节中,我们将学习如何使用Frida获取运行中应用程序的信息。
在FridaREPLObjective-C运行时中,"ObjC"命令可用于访问运行应用程序中的信息。在ObjC命令中,函数enumerateLoadedClasses列出了给定应用程序已加载的类。
Process.enumerateThreads()[{"context":{...},"id":1287,"state":"waiting"},...进程"命令提供了多个函数,可根据需要加以利用。一些有用的函数包括findModuleByAddress,findModuleByName和enumerateRanges等。
-(instancetype)initWithURL:(NSURL*)url;利用这些信息,我们可以编写一个Frida脚本,拦截initWithURL:方法并打印传递给该方法的URL。完整脚本如下。请务必阅读代码和内联注释,以了解其中的内容。
测试应用程序时,进程探索可让测试人员深入了解应用程序的进程内存。它可通过运行时仪器实现,并允许执行以下任务:
正如你所看到的,这些任务都是辅助性的和/或被动的,它们会帮助我们收集数据和信息,为其他技术提供支持。因此,它们通常与方法挂钩等其他技术结合使用。
如果你只对应用程序加载的模块(二进制文件和库)感兴趣,可以使用命令\il列出所有模块:
你也可以使用objection来显示相同的信息。
请参阅r2frida的搜索命令帮助(\/),了解搜索命令并获取选项列表。下面显示的只是其中的一部分:
[0x00000000]>\//search/jsearchjson/wsearchwide/wjsearchwidejson/xsearchhex/xjsearchhexjson...你可以使用搜索设置\e~search来调整搜索。例如,\esearch.quiet=true;将只打印结果并隐藏搜索进度:
[0x00000000]>\e~searchesearch.in=perm:r--esearch.quiet=false现在,我们继续使用默认设置,专注于字符串搜索。在第一个例子中,你可以从搜索你知道应该位于应用程序主二进制文件中的东西开始:
\[0x00000000]>/iGoat搜索5个字节:69476f6174在\[0x0000000100b7c000-0x0000000100de0000]中搜索5个字节...命中5090x100d7d332hit2\_0iGoat\_Swift24StringAnalysisExerciseVCC0x100d7d3b2hit2\_1iGoat\_Swift28BrokenCryptographyExerciseVCC0x100d7d442hit2\_2iGoat\_Swift23BackgroundingExerciseVCC0x100d7d4b2hit2\_3iGoat\_Swift9AboutCellC0x100d7d522hit2\_4iGoat\_Swift12FadeAnimatorV现在点击第一下,找到它并检查你在内存地图中的当前位置:
[0x00000000]>\/owasp-mstghits:10x1c06619c0hit3_0owasp-mstg事实上,可以在地址0x1c06619c0找到字符串。查找s到那里,然后用\dm.获取当前内存区域。
[0x100d7d332]>s0x1c06619c0[0x1c06619c0]>\dm.0x00000001c0000000-0x00000001c8000000rw-现在你知道字符串位于内存映射的rw-(读写)区域。
这一次,我们运行\dm.命令,搜索与globhit5_*匹配的所有@@命中。
[0x00000000]>/wowasp-mstgSearching20bytes:6f0077006100730070002d006d00730074006700Searching20bytesin[0x0000000100708000-0x000000010096c000]...hits:20x1020d1280hit5_06f0077006100730070002d006d007300740067000x1030c9c85hit5_16f0077006100730070002d006d00730074006700[0x00000000]>\dm.@@hit5_*0x0000000102000000-0x0000000102100000rw-0x0000000103084000-0x00000001030cc000rw-它们处于不同的rw-区域。请注意,搜索字符串的宽版本有时是找到它们的唯一方法,这在下一节中将会看到。
有了反对意见,就可以使用"memorydumpall"命令转储设备上运行进程的所有内存。
$objectionexploreiPhoneon(iPhone:10.3.1)[usb]#memorydumpall/Users/foo/memory_iOS/memoryDumping768.0KiBfrombase:0x1ad200000[####################################]100%Memorydumpedtofile:/Users/foo/memory_iOS/memory或者,你也可以使用Fridump。首先,你需要输入要转储的应用程序的名称,可以使用frida-ps获取。
$frida-ps-UPIDName----------1026Gadget然后,在Fridump中指定应用程序名称。
$python3fridump.py-uGadget-sCurrentDirectory:/Users/foo/PentestTools/iOS/fridumpOutputdirectoryissetto:/Users/foo/PentestTools/iOS/fridump/dumpCreatingdirectory...StartingMemorydump...Progress:[##################################################]100.0%CompleteRunningstringsonallfiles:Progress:[##################################################]100.0%CompleteFinished!PressCtrl+C添加-s标志后,所有字符串都会从转储的原始内存文件中提取出来,并添加到文件strings.txt中,该文件保存在Fridump的转储目录中。
$r2memory_ios[0x00000000]>/owasp-mstgSearching10bytesin[0x0-0x628c000]hits:0[0x00000000]>/wowasp-mstgSearching20bytesin[0x0-0x628c000]hits:10x0036f800hit4_06f0077006100730070002d006d00730074006700接下来,我们可以使用s0x0036f800或shit4_0查找它的地址,然后使用psw(代表printstringwide)或使用px打印它的原始十六进制值:
[0x0036f800]>pswowasp-mstg[0x0036f800]>px48-offset-0123456789ABCDEF0123456789ABCDEF0x0036f8006f0077006100730070002d006d007300o.w.a.s.p.-.m.s.0x0036f81074006700000000000000000000000000t.g.............0x0036f82000000000000000000000000000000000................注意,要使用strings命令找到这个字符串,必须使用-e标志指定编码,本例中的l表示16位little-endian字符。
下面的命令对包含"aes"(~+aes)的符号进行不区分大小写的搜索(grep)。
[0x00000000]>\islibboringssl.dylib~+aes0x1863d6ed8sEVP_aes_128_cbc0x1863d6ee4sEVP_aes_192_cbc0x1863d6ef0sEVP_aes_256_cbc0x1863d6f14sEVP_has_aes_hardware0x1863d6f1csaes_init_key0x1863d728csaes_cipher0x0uccaes_cbc_decrypt_mode0x0uccaes_cbc_encrypt_mode...或者你也可以查看导入/导出。例如
对于大的二进制文件,建议通过添加~..将输出导入内部less程序,即\iiiGoat-Swift~...(如果不这样做,对于这个二进制文件,你会得到近5000行打印到你的终端)。
接下来你可能要看的是类:
[0x00000000]>\ic~+passcodePSPasscodeField_UITextFieldPasscodeCutoutBackgroundUIPasscodeFieldPasscodeFieldCell...列表类字段:
[0x19687256c]>\icUIPasscodeField0x000000018eec6680-becomeFirstResponder0x000000018eec5d78-appendString:0x000000018eec6650-canBecomeFirstResponder0x000000018eec6700-isFirstResponder0x000000018eec6a60-hitTest:forEvent:0x000000018eec5384-setKeyboardType:0x000000018eec5c8c-setStringValue:0x000000018eec5c64-stringValue...假设您对0x000000018eec5c8c-setStringValue:感兴趣。您可以使用s0x000000018eec5c8c查找该地址,分析函数af并打印10行反汇编内容pd10: