GPS 校验和 代码_Linux recovery 移除签名校验

fb81371d1b7e4fca5963fda81ef75f3e.gif

原创作者:王锐,多年 Linux 系统、龙芯平台移植与优化研发经验,Linux Contributor、Mozillian。

背景

某个设备配套的刷机程序是个 Linux recovery kernel,刷机过程会先从U盘加载刷机脚本,仅在签名校验通过后才执行脚本。本文记录了分析和移除签名校验的方法。

分析

刷机程序是一个 bzImage 文件,从启动的输出来看,内部包含了一个 initrd,在 initrd 中实现了读取U盘中的脚本和签名校验过程。

查看initrd内容

通过增加启动参数(cmdline)rdinit=/bin/sh,可以使 Kernel 启动后执行 /bin/sh,而不是默认的 /init 程序,有了命令行接口后,就可以查看 initrd 的内容。

# busybox find /
# cat /init

从 initrd 的内容来看,由 /init 调用 gpg2 对 U 盘中的刷机脚本执行签名校验,只有公钥集成在 initrd 中,没有私钥。

到这一步,我们已经清楚了签名校验的实现方法,并且也能使启动过程进入受控的命令行交互状态,其实已经可以手工操作跳过签名过程来刷机。

修改

每次手工操作的确太麻烦,那就来移除 initrd 中的签名校验过程吧。

b4d55cecde841cfa0c29fc113e2fdaf3.png

从 bzImage 的结构来看,要想修改 initrd,先要从 bzImage 中提取出 vmlinux,再从 vmlinux 中提取出 initrd。

1. 提取 vmlinux

从 bzImage 中提取 vmlinux 比较简单,有现成的工具,位于 Linux 源代码中 scripts/extract-vmlinux

./scripts/extract-vmlinux bzImage > vmlinux

2. 提取 initrd

initrd 的格式可以是 cpio archive,也可以是 gzip、bzip2、lzma、xz 或 lzo 压缩的,先用 binwalk 扫描一遍。

binwalk vmlinux
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 32-bit LSB executable, Intel 80386, version 1 (SYSV)
3641536       0x3790C0        Linux kernel version "2.6.39 (ubuntu@ubuntu) (gcc version 4.9.3 20150311 (prerelease) (crosstool-NG 1.20.0) ) #24 SMP Fri Jun 7 14:32:37 CST 2019"
3922304       0x3BD980        CRC32 polynomial table, little endian
4318976       0x41E700        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/desc.h
4321256       0x41EFE8        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/i387.h
4322244       0x41F3C4        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/processor.h
4323964       0x41FA7C        Unix path: /x86/kernel/cpu/perf_event_intel.c
4324152       0x41FB38        Unix path: /x86/kernel/cpu/perf_event_intel_ds.c
4325960       0x420248        Unix path: /x86/kernel/cpu/mcheck/mce.c
4326820       0x4205A4        Unix path: /x86/kernel/cpu/mcheck/mce_intel.c
4327124       0x4206D4        Unix path: /x86/kernel/cpu/mcheck/therm_throt.c
4328480       0x420C20        Unix path: /x86/kernel/cpu/mtrr/generic.c
4329752       0x421118        Unix path: /x86/kernel/cpu/mtrr/cleanup.c
4329832       0x421168        Unix path: /x86/kernel/cpu/perfctr-watchdog.c
4336148       0x422A14        Unix path: /x86/kernel/apic/apic_noop.c
4336572       0x422BBC        Unix path: /x86/kernel/apic/io_apic.c
4343276       0x4245EC        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/fixmap.h
4347540       0x425694        Unix path: /x86/kernel/cpu/common.c
4347663       0x42570F        Unix path: /x86/kernel/cpu/vmware.c
4347911       0x425807        Unix path: /x86/kernel/cpu/intel.c
4350475       0x42620B        Unix path: /x86/kernel/acpi/boot.c
4352464       0x4269D0        Unix path: /x86/kernel/apic/apic.c
4352799       0x426B1F        Unix path: /x86/kernel/apic/ipi.c
4367224       0x42A378        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/mmu_context.h
4374285       0x42BF0D        Unix path: /sys/kernel/debug/tracing/trace_clock
4383716       0x42E3E4        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/pgalloc.h
4384752       0x42E7F0        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/dma-mapping.h
4513864       0x44E048        xz compressed data
4514016       0x44E0E0        Unix path: /home/ubuntu/ce5300/barcelona_kernel/arch/x86/include/asm/syscall.h
4533558       0x452D36        Unix path: /Buffer/String/Package/Ref/Ddb], found [%s] %p
4612622       0x46620E        Unix path: /sys/kernel/debug/dri
4614914       0x466B02        Unix path: /sys/kernel/debug/dri.
4618302       0x46783E        Unix path: /sys/kernel/debug/dri/%s/%s
4618366       0x46787E        Unix path: /sys/kernel/debug/dri/%s
4618509       0x46790D        Unix path: /sys/kernel/debug/dri.
4661219       0x471FE3        Unix path: /S70/S75/505V/F505/F707/F717/P8
4665828       0x4731E4        Unix path: /usr/include/asm/ioctls.h
4678778       0x47647A        Copyright string: "Copyright(c) Pierre Ossman"
4690408       0x4791E8        Unix path: /x86/oprofile/../../../drivers/oprofile/event_buffer.c
5242204       0x4FFD5C        ELF, 32-bit LSB shared object, Intel 80386, version 1 (SYSV)
5243884       0x5003EC        ELF, 32-bit LSB shared object, Intel 80386, version 1 (SYSV)

在 vmlinux 文件偏移 0x44E048 处,有一个疑似 xz 压缩文档,提取出来尝试解压。

if=vmlinux 

唯一的疑似压缩文档解压出错了,这个方法行不通,那就换另外一个方法吧。:)

2.1. 分析启动过程中的 initrd 加载

从 bzImage 中提取出的 vmlinux 是 strip 掉 symbols 的,不便于反汇编后定位函数,我们先提取该内核的 /proc/kallsyms,直接在 rdinit=/bin/sh 启动的命令行中 cat /proc/kallsyms 就可以了。

有了 symbols 后,首先我们要找 populate_rootfs 函数,从汇编代码中获得__initramfs_start 和 __initramfs_size。

c14d03b1 t populate_rootfs
c14d0129 t unpack_to_rootfs
c14d03b1:    55                      push   %ebp
c14d03b2:    b8 6c 59 51 c1          mov    $0xc151596c,%eax
c14d03b7:    57                      push   %edi
c14d03b8:    56                      push   %esi
c14d03b9:    53                      push   %ebx
c14d03ba:    8d 64 24 b8             lea    -0x48(%esp),%esp
c14d03be:    8b 15 70 6f 8e c1       mov    0xc18e6f70,%edx
c14d03c4:    e8 60 fd ff ff          call   0xc14d0129

在 0xc14d03c4 处调用了0xc14d0129 这个函数,也就是 unpack_to_rootfs,传递了两个参数,%eax 就是 __initramfs_start,值是 0xc151596c,%edx 就是 __initramfs_size,%edx 的值是存储在地址 0xc18e6f70 处的。

有了 __initramfs_start 的程序地址后,只需要转换为 vmlinux 文件的偏移地址后,就可以提取出 initrd 的内容了。映射关系可以通过 readelf 获得。

readelf 

程序地址 0xc151596c 和 0xc18e6f70 都隶属于 .init.data section,文件偏移计算:

Offset = Addr - Section Base Addr + Section Base Offset

0xc151596c: 0xc151596c - 0xc14f3b40 + 0x4f4b40 = 0x51696c
0xc18e6f70: 0xc18e6f70 - 0xc14f3b40 + 0x4f4b40 = 0x8e7f70
2.2. 提取 initrd

提取 initrd,首先需要知道 __initramfs_size,该值位于 vmlinux 文件的 0x8e7f70 偏移处,类型是 unsigned long。

08e7f70 
if=vmlinux 
2.3. 分析 initrd 格式

虽然提取出了 initrd,但不是已知的格式,内核支持的格式都有确定的 magic number:

static 
hexdump initrd

0000000 6fde 40fe 2ee2 5fbf 27e3 e8fe fb88 6a72
0000010 b649 904e 378a 49f4 057f 69b4 f9d9 4d43
0000020 7a8a fe5b 1ba5 2442 3ea5 365e 7945 fd49
0000030 9afb fca6 143c b30d eff8 a715 0982 424c
...

既然这个内核能执行,说明它有一种未知的加载方法,那就看看它是怎么做的吧,我们需要找到 unpack_to_rootfs 函数。

c14d0129 t unpack_to_rootfs
c1001410 T aes_key_schedule_128
c10017c0 T aes_decrypt_128
c14d0129:    55                      push   %ebp
c14d012a:    b9 11 00 00 00          mov    $0x11,%ecx
c14d012f:    89 d5                   mov    %edx,%ebp
c14d0131:    57                      push   %edi
c14d0132:    56                      push   %esi
c14d0133:    be ce c6 41 c1          mov    $0xc141c6ce,%esi
c14d0138:    53                      push   %ebx
c14d0139:    89 c3                   mov    %eax,%ebx
c14d013b:    8d a4 24 30 ff ff ff    lea    -0xd0(%esp),%esp
c14d0142:    8d 7c 24 0f             lea    0xf(%esp),%edi
c14d0146:    8d 54 24 20             lea    0x20(%esp),%edx
c14d014a:    8d 44 24 0f             lea    0xf(%esp),%eax
c14d014e:    f3 a4                   rep movsb %ds:(%esi),%es:(%edi)
c14d0150:    e8 bb 12 b3 ff          call   0xc1001410 // aes_key_schedule_128
c14d0155:    31 f6                   xor    %esi,%esi
c14d0157:    39 ee                   cmp    %ebp,%esi
c14d0159:    73 13                   jae    0xc14d016e
c14d015b:    8d 14 33                lea    (%ebx,%esi,1),%edx
c14d015e:    8d 44 24 20             lea    0x20(%esp),%eax
c14d0162:    89 d1                   mov    %edx,%ecx
c14d0164:    83 c6 10                add    $0x10,%esi
c14d0167:    e8 54 16 b3 ff          call   0xc10017c0 // aes_decrypt_128
c14d016c:    eb e9                   jmp    0xc14d0157
c14d016e:    a1 7c 74 93 c1          mov    0xc193747c,%eax

果然是 unpack_to_rootfs 被修改了,里面调用了 aes_key_schedule_128 和 aes_decrypt_128 两个函数,加入了 AES128 解密过程,这说明我们提取出来的 initrd 是被加密的。
AES128 是对称加密,如果没有使用加硬件密钥不管,极有可能是硬编码在程序中的,试试提出它。从汇编代码中看,在栈上构建了一个 crypto 上下文,部分内容是从地址 0xc141c6ce 复制过来的,这会不会就是密钥呢?

041d6b2 

一个 16 字节的数据,与字符串混编在一起,极有可能是 128 位的密钥。

2.4. 解密 initrd
-128-ecb -

经常一些尝试,使用 AES-128-ECB 解密成功,还原出了 initrd.img,实际为 cpio 格式。

2.5. 修改 initrd
cd rootfs
2.6. 写回 initrd

从 unpack_to_rootfs 汇编代码可以看出,aes_decrypt 将明文写到了对应密文的相同内存空间,我们可以修改代码来跳过解密过程,这样就可以直接把 initrd-noverify.img 写回到 vmlinux 中,而不需要再加密来找麻烦了。

55                      

程序地址 0xc14d0155 处的代码修改为 jmp 0xc14d016e,这样就可以直接跳过 aes_decrypt 过程了。如果不懂 x86 的 instruction encoding 方法,有个简单的方法可以产生正确的 jmp 0xc14d016e 编码。

    .text
    .globl _start
_start:
    jmp    0xc14d016e
gcc -m32 -o jmp -nostdlib -Wl,-Ttext=0xc14d0155 jmp.S
objdump -d jmp
c14d0155 <_start>:c14d0155:    e9 14 00 00 00          jmp    c14d016e <_start>

现在可以写回 initrd-noverify.img 了

if=initrd-noverify.img 

还需要编辑 vmlinux 文件 0x8e7f70 偏移处的 __initramfs_size,改为 initrd-noverify.img 的长度。

2.7. 写回 vmlinux

extract-vmlinux 脚本也是通过搜索 magic number 和尝试解压来提取 vmlinux 的,以此就可以获得 vmlinux 在 bzImage 中的偏移,参考写回 initrd 类似的方法,可以将 vmlinux 写回至 bzImage 原来的偏移位置。

不幸的是,修改后的 bzImage 无法启动,启动参数加入 earlyprintk=ttyS0,115200 后,可以看到 LZMA data is corrupt 的错误。

59efc5f243628aca5bc8f1dd43fea30c.png

bzImage 的解压缩过程是从 input addr 读取压缩数据,解压后写到 output addr,而 output addr 与 input addr 之间的空间是不够完整存放解压后的数据的,之所以没有问题是因为这个 input addr 与 output addr 之间的差值是经过精心计算的,能够保证覆盖发生时,被覆盖的数据已完成解压。

正是因为这个原因,我们修改后的 vmlinux 由于内容变化,压缩比也发现了变化,已不能适应之前的比例计算出的差值,有两种方法解决这个问题:1. 将 output addr 向低地址方向移动。2. 将 input addr 向高地址方向移动。

从反汇编 bzImage 的代码来看,output addr 在之后还有校验,相对修改 input addr更为复杂。

objdump -D -b binary -mi386 bzImage
...
  5d91d8:    8d ab 00 10 bf ff       lea    -0x337000(%ebx),%ebp
  5d91de:    55                      push   %ebp                // output address
  5d91df:    68 f5 d1 4f 00          push   $0x5d5747           // input length
  5d91e4:    8d 83 62 00 00 00       lea    0x62(%ebx),%eax     // input address
  5d91ea:    50                      push   %eax
  5d91eb:    8d 83 40 7b 5d 00       lea    0x5d7b40(%ebx),%eax // heap
  5d91f1:    50                      push   %eax
  5d91f2:    56                      push   %esi                // rmode
  5d91f3:    e8 14 04 00 00          call   0x5d960c
  5d91f8:    83 c4 14                add    $0x14,%esp
  5d91fb:    31 db                   xor    %ebx,%ebx
  5d91fd:    ff e5                   jmp    *%ebp
...

本文转载自作者的博客,欢迎移步本文文末左下方点击 “”。

0b985985b4a121af37bf5fbd36d7f29b.png

扫 码 关 注 我 们   

再 + 好 友 tinylab

进 泰 晓 技 术 群

泰  晓  科  技

d9d63d5e9083ebfd1065977496e83a0a.png

d9c3abd92601b9c079adaceaf851f657.png关注“泰晓科技”!点“在看”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/507861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

shell su 密码_[SU模型] 59个公共卫生间

介绍 - Introduce名称&#xff5c;59个公共卫生间格式&#xff5c;skp大小&#xff5c;127 MB获取方式&#xff5c;免费获取嗨&#xff0c;大家好~今天给大家分享的是59个公共卫生间模型。文末获取素材- 部分素材内容的预览图如下 -A | ZD有一个计划&#xff1a;前期在公众平台…

mysql触发器的要素_MySQL触发器

触发器是一类特殊的事务&#xff0c;可以监视某种数据操作(insert&#xff0c;update&#xff0c;delete)&#xff0c;并触发相关操作(insert&#xff0c;update&#xff0c;delete)触发器创建之四要素&#xff1a;监视地点(table)监视事件(insert&#xff0c;update&#xff0…

您与此网站建立的连接不安全_dede网站密码忘记找回服务为先

dede网站密码忘记找回服务为先网站安全是现在一个非常重要的课题。基本上&#xff0c;互联网上的所有用户群都对自己的隐私信息和企业相关信息更感兴趣。因此&#xff0c;无论是搭建网站还是做一些平台&#xff0c;用户对网站服务器和网站空间安全都有很高的要求。对于网站服务…

通达信手机版指标源码大全_通达信指标公式源码短炒买卖指标

做价值的传播者&#xff0c;一路同行&#xff0c;一起成长问题&#xff1a;怎样才能每天都收到这类文章&#xff01;答案&#xff1a;只需点击上方《通达信指标公式软件》VAR1:((CLOSE-MA(CLOSE,6))/MA(CLOSE,6)*100(CLOSE-MA(CLOSE,24))/MA(CLOSE,24)*100(CLOSE-MA(CLOSE,32))…

c++ curl 超时_cc++写网络爬虫,curl+gumbo配合使用

是的&#xff0c;你没有听错。就是用c或者说c语言写爬虫。其实不难&#xff0c;虽然没有Python写起来那么简单。但是也不是那么复杂啦&#xff0c;毕竟好多大佬都写了那么多库&#xff0c;我们只要会用大佬写的库就行。网址&#xff1a;https://acm.sjtu.edu.cn/OnlineJudge/st…

S如何边缘控制_强夯法效果如何?来看看这个检测结果

强夯法指的是为提高软弱地基的承载力&#xff0c;用重锤自一定高度下落夯击土层使地基迅速固结的方法。强夯法适用于处理碎石土、砂土、低饱和度的粉土与黏性土、湿陷性黄土、杂填土和素填土等地基。对高饱和度的粉土与黏性土等地基&#xff0c;当采用在夯坑内回填块石、碎石或…

metinfo mysql_Metinfo 5.3.17 前台SQL注入漏洞

Metinfo 8月1日升级了版本&#xff0c;修复了一个影响小于等于5.3.17版本(几乎可以追溯到所有5.x版本)的SQL注入漏洞。这个SQL注入漏洞不受软WAF影响&#xff0c;可以直接获取数据&#xff0c;影响较广。### 0x01. 漏洞原理分析漏洞出现在 /include/global.func.php 文件的 jum…

冒泡和快速排序的时间复杂度_三分钟快速记住冒泡排序算法

冒泡排序名字由来&#xff1a;是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列)&#xff0c;就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样&#xff0c;故名“冒泡排序”。冒泡排序原理&#xff1a;①、比较相邻的元素。如果第一个比第二个大&#xf…

js二维数组arr中表示读取第i行第j列的是:_c++ c语言 数组与字符串

c语法7 - 数组与字符串概述定义&#xff1a;把具有相同类型的若干变量按有序形式组织起来称为数组。C语言数组属于构造数据类型。一个数组可以分解为多个数组元素&#xff0c;这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同&#xff0c;数组又可分为数…

eprime经典程序案例_小程序经典案例!写字楼里的小店铺如何利用小程序增加人流量!...

大家好&#xff0c;我是柳州木子科技&#xff0c;当前短视频营销如火如荼&#xff0c;相比之下小程序不温不火&#xff0c;我还是那句话&#xff0c;是因为小程序没有把成功案例挖掘出来&#xff0c;通过小程序卖货赚钱的大有人在。前几篇分享了小程序玩赚的文章案例&#xff0…

怎么看电脑配置高不高_电脑店学徒写的电脑配置单处处都是“亮点”,能“气死”师傅...

无论选择哪种类型的电脑都要把重点放在电脑硬件配置上面&#xff0c;电脑的性能完全依靠硬件配置的组合情况&#xff0c;电脑的价格高低标准依据同样是看电脑硬件配置组合情况&#xff0c;对于组装电脑来说&#xff0c;那硬件组合情况就格外重要了&#xff0c;因为组装电脑的硬…

hao123电脑版主页_百度浏览器停更没关系,hao123才令人唏嘘!

月初&#xff0c;百度浏览器官网发布公告&#xff0c;“由于部门业务调整&#xff0c;官方将于2019年4月30日对产品部分功能停止服务。相关的产品包括桌面百度、百度工具栏、百度地址栏、百度极速浏览器、hao123浏览器&#xff0c;产品将不再更新&#xff0c;基本功能本地仍可使…

笔记本电脑摄像头不能用_电脑没有摄像头怎么办

现在大多数家庭电脑都没有配备摄像头&#xff0c;或者大多数普通笔记本电脑的摄像头又非常模糊&#xff0c;如果突然要用摄像头的话又不能马上买。但是手机上的摄像头又那么清楚&#xff0c;有没有办法把手机上的摄像头装到电脑上面呢&#xff1f;今天我要推荐的一款软件是Droi…

excel取消隐藏_猴哥讲述:对excel工作表进行隐藏和取消隐藏的操作行为

有的时候因为工作需要&#xff0c;我们会在一个工作簿中创建插入多个excel工作表&#xff0c;如果工作表越来越多&#xff0c;我们在选择操作工作表的时候很不方便&#xff0c;我们这时候就可以对excel工作表进行隐藏&#xff0c;excel工作表隐藏和取消隐藏的操作方法如下&…

mysql大量数据合并_mysql中将多行数据合并成一行数据

一个字段可能对应多条数据&#xff0c;用mysql实现将多行数据合并成一行数据例如&#xff1a;一个活动id(activeId)对应多个模块名(modelName),按照一般的sql语句&#xff1a;1 SELECT am.activeId,m.modelName2 FROM activemodel am3 JOIN model m4 ON am.modelId m.modelId5…

不同图像锐化算子提取的图像信息有哪些不同_传统图像处理

传统图像处理一、边缘检测算子①Sobel算子该算子中引入了类似局部平均的运算&#xff0c;因此对噪声具有平滑作用&#xff0c;能很好的消除噪声的影响。与Prewitt算子相比&#xff0c;Sobel算子对于像素的位置的影响做了加权&#xff0c;可以降低边缘模糊程度&#xff0c;因此效…

文本聚类分析算法_聚类分析算法综述

前 言聚类是人类认识未知世界的一种重要的认知手段。在生产和生活中,人们往往面对非常复杂的事和物,如果能够把相似的东西归为一类,有明显区别的事物分属在不同的类别中,处理起来就大为简便。所谓“物以类聚,人以群分”,说的就是这个道理。譬如人们将生物分为动物和植物,又根据…

按照标题排序mysql_Oracle EBS Form中实现点击列标题进行排序

在做EBS表单开发时&#xff0c;虽然使用folder功能提供了排序功能&#xff0c;对多行数据块可以对前三列进行指定排序&#xff0c;也可以单击前三列的列标题进行排27.1 问题描述在做EBS表单开发时&#xff0c;虽然使用folder功能提供了排序功能&#xff0c;对多行数据块可以对前…

vscode导入本地jar包_go导入本地包踩坑(已解决!)

当我想要仿照C语言的大程序结构&#xff0c;来写go语言的程序&#xff0c;出现下面的报错&#xff08;ps&#xff1a;系统是windows&#xff0c;文本编辑器&#xff08;或称IDE&#xff09;是vscode&#xff09;然后vscode还会时不时地在右下角出现这样地提示信息对于go语言新手…

java super用法_Java基础面试题汇总

blog.csdn.net/ThinkWon/article/details/104390612Java概述何为编程编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码&#xff0c;并最终得到结果的过程。为了使计算机能够理解人的意图&#xff0c;人类就必须要将需解决的问题的思路、方法、和手段通过计算…