NB!小哥竟然绕过了安全启动,Dump了SoC的BootROM。

news2024/9/25 3:21:29
  • 原文:Amlogic S905 SoC: bypassing the (not so) Secure Boot to dump the BootROM
  • 译者:TrustZone

推荐语:

这是一篇关于如何绕过安全启动,然后实现破解BootRom的文章。通过这篇文章,可以让你对于ATF、安全启动等有个更深刻的影响哦。

往期经典:

  • 万字长文带你搞懂安全启动及ATF
  • 硬核!大佬通过Intel CPU的JTAG接口,DUMP微软原始Xbox的加密BootROM。
  • 硬的不行来软的,我还破解不了你?看老哥如何使用软件Dump你的BootRom。
  • 牛掰!这老哥用显微镜摄取芯片ROM,还原了芯片的二进制固件。

Amlogic S905 系统级芯片是一款专为视频应用设计的 ARM 处理器。

它广泛用于 Android/Kodi 媒体盒子中。该 SoC 实现了 TrustZone 安全扩展,以运行一个可信执行环境(TEE),该环境支持数字版权管理(DRM)和其他安全功能:

Amlogic S905 System Block Diagram

该 SoC 包含一个安全启动机制,用于在将受信执行环境(TEE)映像加载到 TrustZone 之前对其进行身份验证。安全启动链的第一个环节是 BootROM 代码,该代码直接存储在芯片中。

本文介绍了如何从基于 Android 的 Inphic Spot i7 设备中的此 SoC 提取 BootROM 代码。

技术文档

Amlogic 在 Hardkernel 的帮助下发布了 S905 数据手册的公开版本。然而,该版本被大量删减,其中大部分关于安全启动或 TrustZone 的内容已被移除。

但我们仍然可以在 Amlogic 和原始设备制造商(OEM)发布的 GPL 源代码包中找到大量技术信息。

例如,我们可以找到 BootROM 代码的一个潜在地址:

#define ROMBOOT_START   0xD9040000
#define ROM_SIZE        (64 * 1024)
#define ROMBOOT_END     (ROMBOOT_START + ROM_SIZE)

通过 UART 获取 root 访问权限

我们首先从连接串口(或 UART)开始,因为这个接口可以快速轻松地访问引导程序和 Linux 内核上的调试消息和串行控制台。

由于板上有一个带有引脚布局标签的端口接头,因此识别该板上的串口相当简单:

UART on Inphic Spot i7 board

我们将 USB 到 UART 适配器连接到这个端口。一旦 Linux 内核启动过程完成,我们就可以直接访问 root shell。

我们可以开始探索系统(的非安全侧)。例如,我们可以转储分区:

root@p200:/# ls -l /dev/block/platform/d0074000.emmc/
lrwxrwxrwx root     root              2015-01-01 00:00 boot -> /dev/block/boot
lrwxrwxrwx root     root              2015-01-01 00:00 bootloader -> /dev/block/bootloader
drwxr-xr-x root     root              2015-01-01 00:00 by-num
lrwxrwxrwx root     root              2015-01-01 00:00 cache -> /dev/block/cache
lrwxrwxrwx root     root              2015-01-01 00:00 crypt -> /dev/block/crypt
lrwxrwxrwx root     root              2015-01-01 00:00 data -> /dev/block/data
lrwxrwxrwx root     root              2015-01-01 00:00 env -> /dev/block/env
lrwxrwxrwx root     root              2015-01-01 00:00 instaboot -> /dev/block/instaboot
lrwxrwxrwx root     root              2015-01-01 00:00 logo -> /dev/block/logo
lrwxrwxrwx root     root              2015-01-01 00:00 misc -> /dev/block/misc
lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0 -> /dev/block/mmcblk0
lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0boot0 -> /dev/block/mmcblk0boot0
lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0boot1 -> /dev/block/mmcblk0boot1
lrwxrwxrwx root     root              2015-01-01 00:00 mmcblk0rpmb -> /dev/block/mmcblk0rpmb
lrwxrwxrwx root     root              2015-01-01 00:00 recovery -> /dev/block/recovery
lrwxrwxrwx root     root              2015-01-01 00:00 reserved -> /dev/block/reserved
lrwxrwxrwx root     root              2015-01-01 00:00 rsv -> /dev/block/rsv
lrwxrwxrwx root     root              2015-01-01 00:00 system -> /dev/block/system
lrwxrwxrwx root     root              2015-01-01 00:00 tee -> /dev/block/tee

虽然 tee 分区(Trusted Execution Environment,受信执行环境)为空,但引导程序分区包含多个引导程序。

但 BootROM 不在其中,因为它存储在 SoC 中,而不是闪存中。

(尝试失败)读取 BootROM

由于我们拥有 root 权限和 BootROM 的潜在内存地址,我们可以尝试直接读取它。

提供的 Android ROM 包含一个方便的 debugfs 接口,用于从用户空间窥探和访问物理内存:

root@p200:/# echo "d0070000" >/sys/kernel/debug/aml_reg/paddr               
root@p200:/# cat /sys/kernel/debug/aml_reg/paddr                             
[0xd0070000] = 0x1000254

这个 aml_reg 驱动程序使用 ioremap 内核函数来为请求的地址设置适当的内核页表映射。

但是,如果我们尝试读取假定的 BootROM 区域:

root@p200:/# echo "d9040000" >/sys/kernel/debug/aml_reg/paddr
root@p200:/# cat /sys/kernel/debug/aml_reg/paddr
[  376.546491@0] Unhandled fault: synchronous external abort (0x96000010) at 0xffffff80001aa000
[  376.549396@0] Internal error: : 96000010 [#1] PREEMPT SMP
[  376.554712@0] Modules linked in: dwc_otg dhd(O) aml_thermal(O) mali(O) aml_nftl_dev(PO)

内核崩溃了。所以要么是 BootROM 地址错误,要么是这个内存区域被设置为安全的。

由于我们没有 BootROM 地址的其他候选者,我们可以说从非安全世界无法访问 BootROM 区域。

进入安全世界

理论上,安全启动链会阻止在安全世界中加载未授权的代码。

在启动的早期阶段,通过 UART 快速检查调试日志表明,这些引导程序基于 ARM Trusted Firmware(ATF)参考实现。

ARM Trusted Firmware Design

现在我们将探索一些进入安全世界的方法。

U-Boot 引导程序

通过 UART 连接到控制台,我们可以中断 U-Boot 的启动序列以访问提示符。从这里,我们可以运行任意的 U-Boot 命令:

Hit any key to stop autoboot: 0
gxb_p200_v1#help
?       - alias for 'help'
aml_sysrecovery- Burning with amlogic format package from partition sysrecovery
amlmmc  - AMLMMC sub system
amlnf   - aml nand sub-system
amlnf_test- AMLPHYNAND sub-system
autoping- do auto ping test
autoscr - run script from memory

然而,U-Boot 引导程序(在 ATF 设计中称为 BL33)在非安全模式下运行,这可以从 UART 控制台的启动日志中看出:

INFO:    BL3-1: Preparing for EL3 exit to normal world
INFO:    BL3-1: Next image address = 0x1000000
INFO:    BL3-1: Next image spsr = 0x3c9

U-Boot 2015.01-ga9e9562-dirty (May 06 2016 - 03:36:02)

所以在这个点上,我们已经被安全世界锁定在外了。接下来我们尝试其他方法。

SMC 接口

安全世界和非安全世界可以通过 ARM 安全监视器调用(SMC)进行通信。当核心执行 SMC 指令时,它会切换到安全监视器模式(异常级别 EL3)。

在 ATF 设计中,在 EL3 下运行的代码被称为引导程序阶段 3-1(BL31)。我们可以在之前转储的引导程序分区中找到这个映像。此代码对 TrustZone 安全至关重要,因此我们应该对其进行研究。

BL31 映像中的开源 ATF 代码库通过逆向工程促进了分析,因为我们可以快速恢复 ATF 代码结构。

以下是处理来自正常世界的 SMC 中断的已注册服务列表:

Registered services in BL31 image

sip_svc 服务很有趣,因为它包含 Amlogic 开发的一些自定义函数:

List of handlers in the SIP service

乍一看,hdcp22_sec_read_reg 和 hdcp22_sec_write_reg 函数很有希望,因为它们是用于安全内存的读写原语。但是,它们严格限制了对特定内存范围的访问:

Function hdcp22_sec_read_reg decompiled

对其他函数的快速(不完整)分析并未在参数清理(任意读写漏洞)方面发现任何明显的缺陷。其中一些函数相当复杂,特别是加密函数,因此我们尚未对其进行任何检查。

如果我们发现这些函数中的某个存在漏洞,我们可能能够从正常世界触发安全世界内存损坏,从而实现特权提升到安全世界。然而,这需要一些专业技能来实际利用这些漏洞。因此,让我们探索另一种攻击向量。

绕过安全启动链

访问安全世界的另一种解决方案是在安全启动链的某个阶段打破/绕过/欺骗/请求安全启动链。安全启动链的一个常见攻击面是下一阶段的加载、解析和认证步骤。

由于BL1代码存储在SoC中,因此我们(目前)无法访问它。但我们拥有之前转储的引导程序分区中的BL2映像。因此,我们将分析BL2用于解析和认证BL31映像的机制,希望能找到有趣的漏洞。

现在,我们将开始一个漫长的逆向工程过程,这个二进制文件没有任何系统调用,只有极少量的字符串来指导我们的工作。幸运的是,BL2映像相当小,只有约40KB。而且我们有一些节省时间的方法:

与BL31一样,BL2映像遵循ATF(Arm Trusted Firmware)代码逻辑,因此逆向工程工作得到了一定程度的简化:我们可以快速找到ATF代码库中定义的主要函数和结构。

另一个逆向工程技巧是通过识别函数访问的内存映射设备来推断它们的作用。这些内存区域的几个地址范围可以在SoC数据手册和GPL源代码中找到。例如,我们可以预期加密函数会访问专用于硬件加密引擎的内存寄存器。

最后,我们不想花时间去逆向开源代码,尤其是加密代码,因为这项任务相当艰巨。而且从开发者的角度来看,这也很复杂,所以我们可以推测他们使用了一个可能是开源的库。因此,我们在BL2代码和几个潜在的开源软件(OSS)库之间寻找函数原型、调用序列和上下文结构初始化的相似性。在我们的案例中,我们很快发现加密代码来自OSS PolarSSL/mbed TLS项目。

分析BL2认证例程

一旦BL2从NAND加载了BL3映像,就会解析其头部。我们目前还没有关于头部结构的任何信息(ATF代码中不存在),但我们可以注意到它以一个常量魔术值"@AML"开头。这有助于我们在BL2二进制文件中快速定位解析代码。

我们结合“猜测”(即在十六进制编辑器中查看BL31头部)和对BL2解析代码的逆向工程,来找出头部结构的一些成员:

struct aml_img_header {
  unsigned char magic[4];// "@AML"
  uint32_t total_len;
  uint8_t header_len;
  uint8_t unk_x9;
  uint8_t unk_xA;
  uint8_t unk_xB;
  uint32_t unk_xC;
  uint32_t sig_type;
  uint32_t sig_offset;
  uint32_t sig_size;
  uint32_t data_offset;
  uint32_t unk_x20;
  uint32_t cert_offset;
  uint32_t cert_size;
  uint32_t data_len;
  uint32_t unk_x30;
  uint32_t code_offset;
  uint32_t code_len;
  uint32_t unk_x3C;
} aml_img_header_t;

头部表明映像被分为4个部分:

  • 头部:始终为64字节
  • 签名:RSA-1024、RSA-2048、RSA-4096或SHA-256
  • 证书:x509证书
  • 代码:有效载荷

在我们的目标设备上,BL31映像的签名类型(头部中的sig_type)是SHA-256。这很有趣,因为仅SHA-256哈希本身并不足以提供认证。

以下是BL2中认证例程的简化算法伪代码:

int auth_image(aml_img_header_t *img){
  validate_header(img); // checks on magic value & header length
  hash = hash_sha256(img);// hash whole image except signature
  if(img->sig_type == RSA) {
    return check_rsa_signature(img, hash)
  }else{
    return memcmp(hash, (char*)img + (img->sig_offset));
  }
}

我们可以确认,SHA-256选项仅会对加载的映像进行哈希处理,并将结果与同一映像中预计算的哈希值进行比较。我们本可以设想一个更复杂的解决方案,如HMAC,但实际上在这种情况下,仅检查了完整性,而没有进行认证。

即使加载的映像使用RSA签名,我们仍然可以将签名类型更改为SHA-256并重新生成正确的哈希值。

如果签名类型由eFuse强制执行,则可以避免此问题。

这意味着我们可以轻松地修改BL31映像,这是TrustZone中最具特权的代码。

自定义BL31映像

在前面的部分中,我们描述了SMC函数hdcp22_sec_read_reg,该函数可以从普通世界读取安全内存的受限范围。

现在是时候练习我们的NOP技术(NOP是一种汇编语言指令,代表“无操作”,用于填充代码空间或延迟执行),以摆脱这些限制,从而完全访问安全内存。

Modified hdcp22_sec_read_reg function
我们还需要扩展页表,因为BootROM内存区域没有映射。MMU(内存管理单元)初始化是在ATF代码库中实现的,因此再次在BL31二进制文件中很容易找到并分析。

默认情况下,以下内存区域被映射:

Original list of memory regions mapped in BL31

我们将其中一个的大小扩展以覆盖BootROM区域:
Modified list of memory regions mapped in BL31

映射区域0xD9000000的新大小为0x80000,因此它包括了BootROM区域0xD9040000-0xD9050000。

我们几乎完成了对BL31的修改:我们还需要更新SHA-256哈希值。

aml_bootloader_tool:解析并重新计算Amlogic引导加载程序的SHA-256

此工具可以解析并重新生成引导加载程序分区中包含的引导加载程序的SHA-256。源代码在GitHub上。

每个引导加载程序都通过UUID进行标识,这些UUID在ATF源代码中定义。在我们的案例中,BL31映像是第2个条目:

$ ./aml_bootloader_tool ./dump/bootloader.img H 2
fip_toc_header.name:        aa640001
fip_toc_header.serial_number:        12345678
fip_toc_header.flags:        0
TOC ENTRY #2
fip_toc_entry.uuid:        47D4086D4CFE98469B952950CBBD5A00
fip_toc_entry.offset_address:    14000 (absolute: 0x20000)
fip_toc_entry.size:        0x11130
fip_toc_entry.flags:        0x0
magic[@0x0]:        @AML
total_len[@0x4]:    0x11130
header_len[@0x8]:    0x40
unk_xC[@0xC]:        0x5eec9094
sig_type[@0x10]:    0x0
sig_offset[@0x14]:    0x40
sig_len[@0x18]:        0x20
data_offset[@0x1c]:    0x60
unk_x20[@0x20]:        0x0
cert_offset[@0x24]:    0x60
cert_len:        0x0
data_len:        0x110d0
unk_x30[@0x30]:        0x0
code_offset[@0x34]:    0x60
code_len[@0x38]:    0x110d0
unk_x3C[@0x3C]:        0x0
signature:        263BEFAFC5A051C550D31791EC1212576BE65DB8AD365074560F0BABC076D3CA
computed_sha256:    35AD6B284EE2D6B5672DD0958592028D5BF455A6DCD1EB086D8336FB86533853

BL31映像的哈希值已更新,我们现在可以在设备上重新刷新转储:

$ dd if=./bootloader.img of=/dev/block/bootloader

最后,我们重启设备以在TrustZone中加载我们自定义的BL31映像。

转储BootROM

SMC系统调用只能从EL1(执行级别1)及以上级别调用。因此,我们创建了一个简单的内核模块,该模块将在EL3级别执行SMC调用到我们修改后的函数hdcp22_sec_read_reg。

这个快速而“肮脏”的hack是基于Amlogic的debugfs驱动程序reg_access。源代码在GitHub上。

一旦加载,为了启动SMC调用,我们将参数写入文件/sys/kernel/debug/aml_smc/smc。第一个参数是被调用的SMC函数的ID(在hdcp22_sec_read_reg的情况下为0x82000018)。第二个参数(对于这个特定的SMC ID)是读取的内存地址。结果DWORD(双字)直接打印在内核日志中(我们说它“肮脏”)。

$ insmod ./smc_access.ko
$ echo 82000018 D9040000 > /sys/kernel/debug/aml_smc/smc
[  219.092948@0] smc_access: SMC call 82000018 returns: aa1f03e0

结果aa1f03e0很有希望,它对应于ARM指令:MOV X0, XZR

为了自动提取整个BootROM内存区域,我们创建了一个简单的脚本:

$ seq -f %1.f 0xD9040000 0x4 0xD9050000 | xargs printf "echo \"82000018 %x\" > /sys/kernel/debug/aml_smc/smc\n"
echo "82000018 d9040000" > /sys/kernel/debug/aml_smc/smc
echo "82000018 d9040004" > /sys/kernel/debug/aml_smc/smc
echo "82000018 d9040008" > /sys/kernel/debug/aml_smc/smc
[...]
echo "82000018 d904fff8" > /sys/kernel/debug/aml_smc/smc
echo "82000018 d904fffc" > /sys/kernel/debug/aml_smc/smc

最后,我们将所有这些DWORD(双字)合并到一个名为bootrom.bin的文件中。

$ ls -l ./bootrom.bin
-rw-r--r-- 1 user user 65537 juil.  8 12:43 ./bootrom.bin
$ sha1sum bootrom.bin
bff0c7fb88b4f03e732dc7a4ce504d748d0d47dd  bootrom.bin
$ strings bootrom.bin |tail -22
BL1:
FEAT
READ
EMMC
NAND
LOOP
auth failed, reboot...
08dafda0fd31778
glacier.amlogic
qian
04/14/15_14:23:08
gcc version 4.8
08dafda0fd31778
boot@USB
boot@SDC
BAD PASSWORD
!!!!
vRQ>
8STs
LwH'
Err:sha
0!0

结论

S905 SoC提供了支持安全启动的硬件特性,但OEM(原始设备制造商)仍然可以选择是否启用它。但即使在强制执行安全启动的情况下,Amlogic当前版本的BL2中的一个缺陷仍然可以绕过它。因此,可信执行环境(TEE)并不可信。好消息是,与BootROM不同,BL2可以进行修补。

我要感谢@Karnalzi的帮助!

披露时间表

  • 2016-08-08:发现漏洞

  • 2016-08-08:通过电子邮件联系Amlogic和一些受影响的OEM以查找安全证明概念(PoC)

  • 2016-08-10:OEM #1回复说“Amlogic不提供任何直接联系”

  • 2016-08-20:第二次尝试通过电子邮件联系Amlogic

  • 2016-09-05:与Amlogic共享漏洞报告

  • 2016-09-13:请求状态更新

  • 2016-09-25:请求状态更新

  • 2016-10-05:公开披露

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

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

相关文章

什么牌子的灯具性价比高?五款必入的灯具品牌推荐

随着科技的发展,生活质量水平的不断提升,大家对于生活的要求也在不断拔高。护眼台灯进入众多家庭里面,成为不可或缺的产品。然而,灯具在市面上,种类颇多,其质量也是参差不齐。那么,我们该如何选…

4.1 操作系统

大纲 进程管理重点,占本章历年考试一半分数, 前趋图、信号量和PV操作、死锁和银行家算法 出计算题 作业管理历年考试从来没有考过 操作系统概述 进程管理 进程的组成和状态 前趋图 进程资源图 真题 1

【概念介绍】Signed Distance Function(SDF)

三维空间的表示形式可以分为显式和隐式 显式: 体素Voxel,点云Point Cloud,三角面片Mesh隐式:符号距离函数Signed Distance Funciton(SDF),占用场Occupancy Field,神经辐射场Neural Radiance Field&#xff…

简单仿写MVC

代码地址(需要自取):mvc_Imitation: 简单仿写实现MVC (gitee.com) 项目目录 先把架子搭好 Controller注解 Documented Retention(RetentionPolicy.RUNTIME) Target(ElementType.TYPE) public interface Controller { }RequestMapping Do…

走拼箱货必看海运拼箱的实用技巧

在国际海运运输中,海运拼箱适用于货物数量较少或体积不足以填满整个集装箱的情况。 海运拼箱货物通常由物流公司或货代进行组织和管理。多个货主的货物通过合理拼装,使集装箱空间得到充分利用。 那么,在海运拼箱和整柜有哪些不同&#xff0c…

Xilinx Vitis 2020工程源目录修改

目录 1 背景2 分析3 解决4 使用4.1 修改路径4.2 编译工程4.2.1 清理工程4.2.2 编译工程 1 背景 Xilinx Vitis可以做standalone程序开发,不过其工程中使用的路径为绝对路径。工程更换位置后编译将会显示错误。例如:源目录为D:/work,复制到同事电脑上放到C:/work(同事…

无忧易售:在线刊登配备定价计算器,精准定价赢市场

在跨境电商的浩瀚宇宙里,精准定价是通往成功的关键钥匙。无忧易售,推出在线产品刊登页面的定价计算器功能,精准定价,轻松管理,让您的商品在海外市场脱颖而出,让每一次销售都精准高效,利润满满。…

Selenium 的基本操作你知道哪些?

1. 前言 今天的推文,我们就来说说看,怎么实现模拟真人去打开微信读书网站。 2.需求分析和准备 整体的需求大致可以分为以下步骤: 打开chrome浏览器 打开百度网页 搜索“微信读书” 点击进入“微信读书”官网 搜索关键词“长安的荔枝” 点…

浮动刹车盘和固定刹车盘有什么区别

在讨论刹车系统的设计理念时,浮动和固定刹车盘无疑是两个重要的分支。 它们各自拥有独特的设计哲学、工作原理以及适用场景,这些差异直接影响到了制动系统的性能和耐久性。 浮动刹车盘和固定刹车盘在设计和工作原理上有显著的区别,主要体现在…

现代化木工装备建设新颖校园木工创客室

校园木工创客室是一个集木工制作、创意设计、科技融合与教育实践于一体的多功能空间。它为学生提供了一个动手实践、创新创造的平台,旨在培养学生的动手能力、创新思维、解决问题的能力以及团队协作能力。 木工创客室的设备选择应综合考虑需求、预算、品牌、质量、安…

【源码下载】瓦房店农村电商大数据平台模板

技术详细实现可在评论区留言。 概述 用 echarts 和 jquery 实现的大屏模板效果。 部分代码展示,访问 dt.sim3d.cn 获取源码: (function($){$.extend({initMapChartPath : function(options){var defs {domId : ,mapName:china,mapCenter:["5…

saas lims系统:适合中小检测机构的实验室管理系统

目前市面上的LIMS系统分为两种:一种是传统的LIMS系统,一次性买断,配置服务器,成本相对来说是比较高的。还有一种就是以白码LIMS云平台为代表的,基于SaaS模式的LIMS系统。白码LIMS系统提供saas模式购买,帮助…

网络安全设备——探针

网络安全设备探针是一种专门用于网络安全领域的工具,它通过对网络流量进行监控和分析,帮助发现和防止网络攻击。以下是对网络安全设备探针的详细解释: 定义与功能 定义:网络安全设备探针是一种设备或软件,它通过捕获…

第58期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

短信群发精准营销策略全解析

短信群发作为传统而高效的营销手段,其效果却常因缺乏精准性而大打折扣。要实现短信群发的精准营销,关键在于两大核心要素与选择合适的平台。 一、精准营销的两大核心 1.数据细分,精准定位 在启动短信群发前,企业需…

基于JAVA+SpringBoot+Vue的社区普法平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 社区普法平台旨在为社…

【结构性型模式-适配器模式】

定义 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 适配器模式分为类适配器模式和对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结…

道达尔远景首个光储项目圆满收官,助力纺织业绿色转型

近日,由道达尔远景(TEESS)开发、设计、建设并运营的德州夏仁津和纺织分布式光储项目顺利并网发电。通过光伏发电与储能系统的有机结合,不仅满足了纺织厂的用电需求,也为纺织业的绿色转型注入了新动力。 我国是全球最大…

如何使用ParaView可视化工具来绘制点云数据的3D点云图像(亲测好用)

如何使用ParaView来绘制点云数据。以下是如何将你的数据导入ParaView并进行可视化的步骤 一、准备数据 首先,你需要将你的数据转换为ParaView可以读取的格式。ParaView支持多种文件格式,其中最常见的是.vtk和.csv格式。为了简单起见,这里我…

【Gradle】(三)详细聊聊依赖管理:坐标、依赖配置、依赖传递、依赖冲突

文章目录 1.概述2.依赖管理2.1.坐标2.2.依赖的基本概念2.3.依赖配置(Dependency configurations)2.3.1.依赖路径2.3.2.依赖配置与依赖路径的关联 2.4.依赖传递2.4.1.准备工作2.4.2.运行时依赖传递jar包生成与依赖配置依赖树打印使用 Dependency Analyzer…