记录Fastboot OEM命令

2020-09-27 17:34:07

打印机很酷,因为它们很酷,但我有朋友至少每周提醒我黑客攻击打印机是没有用的。每一次几乎都是同样的事情,找一个1990年的类型错误,写一个愚蠢的脚本,完成。几个月前,我开始了一个新的项目,在谷歌庞大的代码库中疯狂地骑行。虽然谷歌的大部分代码,特别是Android,都是开源的,但有些部分不是开源的。我将试着谈谈一个这样的案例,Pixel3手机的引导加载程序。

您将要阅读的内容主要适用于Android 10及更高版本。很多事情都改变了,但令我们兴奋的是,现在Fast boot可以在用户空间模式下运行了。

恢复分区和快速引导分区现在是一回事。一个更少的分区,更多的代码重用。好的。

启动恢复或快速启动的机制现在略有不同,但这是由引导加载程序处理的。

因为Userspace fast boot不能发出OEM命令,所以我们必须深入研究引导加载器代码。

一看到这一点,我就开始想知道手机是什么时候开始使用UEFI的。UEFI和EDK2很酷,但它们是什么时候开始在手机上使用的呢?

这里有一些关于QC为什么使用UEFI的历史记录。如果我理解正确的话,那是因为他们想在ARM上支持Windows。

既然我们知道了它是UEFI,并且我们满足了我们对为什么它是UEFI的好奇心,我们就可以开始研究它了。

引导加载器映像上的Binwalk将恰好生成零。UEFI图像非常结构化,支持压缩,并允许嵌套卷。以太,你知道你在看什么,否则你走不远的。

UEFI-Firmware-Parser它更像是一个框架,可以在脚本中使用。幸运的是,它们提供了一个非常好用的包装器。该脚本可以强制-b任何未知的图像类型,搜索已知的UEFI幻数。

➜uefi-固件-解析器-b引导加载器-sargo-b4s4-0.2-6066691.img在0x885a8固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x000cfeff,修订版2,校验和0xc520,大小0x270000(2555904字节)固件卷块:(4992,0x200)文件0:FFFFFF-FFF-FFFFFF类型0xf0,attr 0x00,状态0x07,大小0xfa0(4,000字节),(填充)文件1:8af09f13-44c5-96ec-1437-899cbee5d类型0x03,attr 0x28,0x200)文件0:FFFFFF-FFF-FFFF类型0xF0,状态0x07,大小0xfa0(4,000字节),(填充)文件1:8af09f13-44c5-96EC-1437-899cbee5d类型0x03,Atr 0x28,0x200)文件0:FFFFFF-FFF-FFFFF类型0xF0,状态0x07,大小0xfa0(163864字节),大小0xF0。(安全核心)第0节:类型0x19,大小0xf34(3,892字节)(原始节)第1节:类型0x12,大小0x270cc(159948字节)(简明可执行(TE)节)文件2:dde58710-41cd-4306-dbfb-3fa90bb1d2dd类型0x02,attr 0x00,状态0x07,大小0x261e(9758字节),(自由格式)第0节:类型0x15,大小0x1e(30字节)(用户接口名节)名称:uefiplat.cfg 1:类型0x19,大小0x25e6(9702)(原始节)文件3:9e21fd93-9c72-4c15-8cb-7e77e7db7d2type 0x0b,(自由格式)第0节:类型0x15,大小0x1e(30字节)(用户接口名节)名称:uefiplat.cfg 1:类型0x19,大小0x25e6(9702)(原始节)。属性0x00,状态0x07,大小0x19938a(1676170字节),(固件卷映像)第0节:类型0x02,大小0x199372(1676146字节)(GUID定义的部分)GUID定义的:1d301fe9-be79-4353-91c2-d23bc959ae0c偏移=0x18属性=0x1(Processing_Required)在0x7125e8固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003feff,rev 2,cksum 0x1cd9,大小0x000)文件0:9e21f93-9c3e8固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003feff,rev 2,cksum 0x1cd9,大小0x200)文件0:9e21f93-9c3e8固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003feff,rev 2,cksum 0x1cd9,大小0x000。(固件卷映像)第0节:类型0x02,大小0x40185(262533字节)(GUID定义节)GUID定义的:ee4e5898-3914-4259-9d6e-dc7bd79403cf偏移量=0x18属性=0x1(正在处理_必需)节0:类型0x19,大小0x4(4字节)(原始节)第1节:类型0x17,大小0x14ea04(1370628字节)(固件卷映像节)固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003fev 2,0xb874,大小0x14e00(1370624字节)(原始节)第1节:类型0x17,大小0x14ea04(1370628字节)(固件卷映像节)固件卷:8c8ce578-8a3d-4f1c-9935-896185c32dd3 attr 0x0003fev 2,0xb874。0x40)文件0:FFFFFFF-FFFF-FFFFFFFF类型0xf0,属性0x00,状态0x07,大小0x2c(44字节),(ff填充)文件1:8d40eae1-aebd-4c76-8929-62d04d3e0882类型0x09,属性0x00,状态0x07,大小0x5e038(385080字节),(应用程序)第0节:类型0x15,大小0x1c(28字节)(用户界面名称部分)名称:LinuxLoader第1节:类型0x10,大小0x5e004(PE32图像)文件2:ff725d98-21d5-479-80bc-82c71deec81类型0x07,大小0x7c(28字节)(用户界面名称部分)名称:LinuxLoader第1部分:类型0x10,大小0x5e004(PE32图像)文件2:ff725d98-21d5-479-80bc-82c71deec81类型0x07,大小0x7c(28字节)(用户界面名称部分)名称:LinuxLoader 1:类型0x10,大小0x5e004(PE32图像)。大小0x13050(77904字节),(驱动程序)第0节:类型0x10,大小0x13004(77828字节)(PE32映像节)第1节:类型0x15,大小0x34(52字节)(用户界面名节)名称:FastbootTransportUsbDxe文件3:61f96920-c022-4b2b-aa80-1c364a4f64b1类型0x09,属性0x00,状态0x07,大小0x7e040(516160字节),(应用程序)节0:类型0x15,大小0x24(36字节)(用户界面名节)名称:B1c1Fastboot节1:类型0x10,状态0x07,大小0x7e040(516160字节),(应用程序)节0:类型0x15,大小0x24(36字节)(用户接口名节)名称:B1c1Fastboot节1:类型0x10,状态0x07。大小0x7e004(516100字节)(pe32图像节)文件4:d9b2d43d-e02f-4a86-a445-bd1474b33671类型0x02,属性0x00,状态0x07,大小0x32be(12990字节),(自由格式)节0:类型0x15,大小0x2a(42字节)(用户界面名称节)名称:红色警告1440.bmp节1:类型0x19,大小0x327a(12922字节)(原始节)。

请注意,第二个卷上有更多文件。为了简明扼要,我省略了它们。在使用-e选项解压文件之后,我们可以开始反转。好的。

(我后来发现Anestis BechtSoudis已经写了一个图像解包器。我知道这个工具可以解压第一卷中的文件3,这是主要的引导加载程序代码。这很好,但对于本文的范围来说,这不是必需的。)。

超级简单。找到吉德拉,装上PE,仔细看一看,当你最终弄清楚的时候,大喊“是”。

Fastboot DXE驱动程序。这个驱动程序至少有一部分是开源的,您可以在EDK2GitHub库中找到。查看代码很有用,但理解此模块的功能并不重要。

快速启动应用程序处理程序。封闭的源代码,很可能是由Google实现的。B1c1FastbootApp处理来自FastbootTransportUsbDxe的命令。

二进制文件被剥离,但是有很好的字符串可以理解正在发生的事情。

2K字符串。好的。我们想了解OEM命令是如何工作的。我知道,如果我使用不存在的OEM命令,我会收到此错误:

如果我们是正确的,并且这是处理快速启动的二进制文件,我们应该能找到那个字符串。你瞧:

此字符串用于一个大函数中。我们希望通过命令列表进行一些循环。从屏幕截图可以明显看出,While循环正在对36个元素执行一些操作。

COMMAND_HANDLER使用指向BSS中某些内容的指针进行初始化。如果我们去那里,一开始是很难看的:

通过查看内存访问,如下图所示,很容易猜测前两个成员是8字节指针。正如您在红色框中看到的,一个指针被加载到R23中,随后在R23中加载另一个指针,上一个指针的值减去8字节(反汇编视图中的绿色框)。虽然Ghidra反编译器的输出可能不是最大的(它试图将操作显示为数组访问,但最终使用了负索引),但是程序集非常简单。

我们找到了OEM命令!定义此结构后,使用一个简单的Ghidra脚本,就可以获得一个很好的列表:

已成功编译:ListBootloaderCommands.javaListBootloaderCommands.java>;正在运行...ListBootloaderCommands.java>;0";setbrightness";ListBootloaderCommands.java>;1";get_config";ListBootloaderCommands.java>;2";set_config";ListBootloaderCommands.java>;3";rm_config";ListBootloaderCommands.java>;4";get_platform_info";ListBootloaderCommands.java>;5";set_platform_info";ListBootloaderCommands.java>;6";select-display-panel";ListBootloaderCommands.java>;7";esim_erase";ListBootloaderCommands.java>;8";esim_atp";ListBootloaderCommands.java>;9";esim_eid";ListBootloaderCommands.java>;10";psim_info";ListBootloaderCommands.java>;11";ListBootloaderCommands.java&>12";off-mode-charge";ListBootloaderCommands.java>;13";sha1sum";ListBootloaderCommands.java>;14";ramdump";ListBootloaderCommands.java>;15";ramdump_sahara";ListBootloaderCommands.java>;16";rma&34;ListBootloaderCommands.java&>;17";dump-chipid";ListBootloaderCommands.java>;18";check-hw-security";ListBootloaderCommands.java>;19&34;HALT";ListBootloaderCommands.java&>20";Set_display_power_mode";ListBootloaderCommands.java>;21";citadel";ListBootloaderCommands.java>;22";enable-factory-lock";ListBootloaderCommands.java>;23";factory-lock";ListBootloaderCommands.java>;24";ddrtest";ListBootloaderCommands.java>;25";continue-factory";ListBootloaderCommands.java>;26";dmesg";ListBootloaderCommands.java>;27";Pmic-dump";ListBootloaderCommands.java>;28";pmic-write";ListBootloaderCommands.java>;29";check-dp";ListBootloaderCommands.java>;30";allow-flash-super";ListBootloaderCommands.java>;31";silentota";ListBootloaderCommands.java>;32";barcode";ListBootloaderCommands.java>;33";display_color";ListBootloaderCommands.java>;34&34;enter-ship mode";ListBootloaderCommands.java>;35";verify-erased";ListBootloaderCommands.java>;完成!

没有关于OEM命令的文档,但是在考虑使用它们的上下文时,理解需要哪些参数是相当琐碎的。例如,PMIC-DUMP转储电源管理器IC的配置,条形码在屏幕上以条形码的形式显示每个设备标识号。起初很容易混淆,但它只是代号和特定于领域的语言。请注意,某些命令依赖于其他UEFI驱动程序才能工作。UEFI驱动程序是在固定地址加载的,因此映射内存中的每个驱动程序处理程序并查看它是如何使用的并不是一件非常棘手的事情。

我在网上的任何地方都找不到这些信息,我不得不承认,深入研究Android引导加载程序是如何操作的,这是相当不错的。