【UEFI实战】BIOS中的openssl

news2024/11/16 9:20:43

BIOS中的openssl

openssl是一个密码库或者密码工具,在密码学基础_hex string is too short, padding with zero bytes t-CSDN博客介绍了基本的密码学概念已经openssl工具的使用,而这里将介绍BIOS下如何使用openssl。

在开源的BIOS代码库EDK中包含一个CryptoPkg,其中包含了BIOS需要使用到的密码库接口。通过包含openssl密码库代码,就可以在BIOS下使用密码学中的各种算法和工具。需要注意,EDK代码并不会直接包含openssl代码,而是通过外部链接的方式来实现的,如下图所示:

在这里插入图片描述

点击红框会跳转到对应的代码库,其中@之后的数字是对应的版本,这是因为无论是EDK还是openssl代码都一直在更新,所以存在兼容性的问题,通过制定版本信息,可以保证EDK可以正常编译和使用openssl。

这样当我们直接下载到EDK代码时,并不会包含openssl代码,需要额外的下载,这可以通过git的submodule子命令来下载。后续使用的测试代码https://gitee.com/jiangwei0512/edk2-beni.git已经提供了一键式的编译方式,在第一次编译的时候就会下载对应的openssl版本。

代码处理

当下载了openssl代码之后,EDK利用已有的库OpensslLib来包含代码并进行编译,这样的库有多个,差别在于包含的openssl功能,不如如果需要支持HTTPS中的TLS功能,在需要包含OpensslLib.inf,否则包含OpensslLibCrypto.inf即可:

!if $(NETWORK_TLS_ENABLE) == TRUE
  OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
!else
  OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf
!endif

其它的还有OpensslLibAccel.infOpensslLibFull.infOpensslLibFullAccel.inf等,本质没有差异,只是包含功能的多寡。

需要注意的是,这个OpensslLib库并不会直接被其它的EDK代码使用,中间还有包装了一层EDK通用的库,这些库会对应到BIOS的不同阶段或功能:

# SEC
[Components]
  #
  # SEC Phase modules
  #
  OvmfPkg/Sec/SecMain.inf {
    <LibraryClasses>
      NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
      NULL|OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf
      BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf
  }

# 通用
[LibraryClasses.common]
  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf

# Runtime
[LibraryClasses.common.DXE_RUNTIME_DRIVER]
  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf

# SMM
[LibraryClasses.common.DXE_SMM_DRIVER]
  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
  
# TLS
!if $(NETWORK_TLS_ENABLE) == TRUE
  TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf
!endif

因此当需要在BIOS下使用openssl,需要包含的是BaseCryptLib等库,并在代码中引入BaseCryptLib.h头文件。

此外,还需要注意几个点。

首先是为了开源的openssl能够正常的在EDK源码中正常编译,需要对其底层的一些基本函数进行包含,比如openssl代码中非常常用的memset()函数,如果是在Linux下编译,直接包含C标准库即可,但是EDK源码中是没有C标准库的,所以为了支持该命令,就需要对这些基础函数进行包装,这又引入了另外的一个EDK下的CrtLib(C RunTime Library),这可以通过edk2\CryptoPkg\Library\Include\CrtLibSupport.h看出来:

#ifndef __CRT_LIB_SUPPORT_H__
#define __CRT_LIB_SUPPORT_H__

#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PrintLib.h>

#define OPENSSLDIR  ""
#define ENGINESDIR  ""
#define MODULESDIR  ""

#define MAX_STRING_SIZE  0x1000

// 中间略

//
// Macros that directly map functions to BaseLib, BaseMemoryLib, and DebugLib functions
//
#define memcpy(dest, source, count)         CopyMem(dest,source,(UINTN)(count))
#define memset(dest, ch, count)             SetMem(dest,(UINTN)(count),(UINT8)(ch))
#define memchr(buf, ch, count)              ScanMem8(buf,(UINTN)(count),(UINT8)ch)
#define memcmp(buf1, buf2, count)           (int)(CompareMem(buf1,buf2,(UINTN)(count)))
#define memmove(dest, source, count)        CopyMem(dest,source,(UINTN)(count))
#define strlen(str)                         (size_t)(AsciiStrnLenS(str,MAX_STRING_SIZE))
#define strncpy(strDest, strSource, count)  AsciiStrnCpyS(strDest,MAX_STRING_SIZE,strSource,(UINTN)count)
#define strcat(strDest, strSource)          AsciiStrCatS(strDest,MAX_STRING_SIZE,strSource)
#define strncmp(string1, string2, count)    (int)(AsciiStrnCmp(string1,string2,(UINTN)(count)))
#define strcasecmp(str1, str2)              (int)AsciiStriCmp(str1,str2)
#define strstr(s1, s2)                      AsciiStrStr(s1,s2)
#define sprintf(buf, ...)                   AsciiSPrint(buf,MAX_STRING_SIZE,__VA_ARGS__)
#define localtime(timer)                    NULL
#define assert(expression)
#define offsetof(type, member)  OFFSET_OF(type,member)
#define atoi(nptr)              AsciiStrDecimalToUintn(nptr)
#define gettimeofday(tvp, tz)   do { (tvp)->tv_sec = time(NULL); (tvp)->tv_usec = 0; } while (0)

#endif

通过EDK下的另外一些库(比如IntrinsicLib库)就可以实现C标准库中的函数。而在openssl中包含的stdlib.h等C标注库头函数,其内部的实现就是包含CrtLibSupport.h这个头文件即可:

/** @file
  Include file to support building the third-party cryptographic library.

Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <CrtLibSupport.h>

这就构成了如下的样式:

+================================+
| EDK II Firmware Module/Library |
+================================+
     ^                 ^ 
     |                 |
     v                 v
+========+  +====================+
| TlsLib |  |    BaseCryptLib    |
+========+  +====================+
     ^                ^
     |                |
     v                v
+================================+
|     OpensslLib (Private)       |
+================================+
               ^
               |
               v
+================================+
|     IntrinsicLib (Private)     |
+================================+

其次,EDK包含openssl的方式是库的形式,但是这个库的实现却有不同的方式,可以是真正的库,也可以在库中包含Protocol或PPI。前者在速度上应该会快一点点,而后者可以降低openssl包含到EDK中的占用空间。

+===================+    +===================+     +===================+
|    EDK II PEI     |    |  EDK II DXE/UEFI  |     |     EDK II SMM    |
|   Module/Library  |    |   Module/Library  |     |   Module/Library  |
+===================+    +===================+     +===================+
  ^            ^           ^            ^            ^            ^
  |            |           |            |            |            |
  v            v           v            v            v            v
+===================+    +===================+     +===================+
|TlsLib|BaseCryptLib|    |TlsLib|BaseCryptLib|     |TlsLib|BaseCryptLib|
+-------------------+    +-------------------+     +-------------------+
|   BaseCryptLib    |    |   BaseCryptLib    |     |   BaseCryptLib    |
|   OnPpiProtocol/  |    |   OnPpiProtocol/  |     |   OnPpiProtocol/  |
|  PeiCryptLib.inf  |    |   DxeCryptLib.inf |     |  SmmCryptLib.inf  |
+===================+    +===================+     +===================+
           ^                      ^                         ^
          ||| (Dynamic)          ||| (Dynamic)             ||| (Dynamic)
           v                      v                         v
+===================+    +===================+    +=====================+
|     Crypto PPI    |    |  Crypto Protocol  |    | Crypto SMM Protocol |
+-------------------|    |-------------------|    |---------------------|
|     CryptoPei     |    |     CryptoDxe     |    |      CryptoSmm      |
+===================+    +===================+    +=====================+
     ^       ^                ^       ^                 ^       ^
     |       |                |       |                 |       |
     v       |                v       |                 v       |
+========+   |           +========+   |            +========+   |
| TlsLib |   |           | TlsLib |   |            | TlsLib |   |
+========+   v           +========+   v            +========+   v
  ^  +==============+      ^  +==============+       ^  +==============+
  |  | BaseCryptLib |      |  | BaseCryptLib |       |  | BaseCryptLib |
  |  +==============+      |  +==============+       |  +==============+
  |          ^             |          ^              |          ^
  |          |             |          |              |          |
  v          v             v          v              v          v
+===================+    +===================+     +===================+
|    OpensslLib     |    |    OpensslLib     |     |    OpensslLib     |
+===================+    +===================+     +===================+
          ^                        ^                         ^
          |                        |                         |
          v                        v                         v
+===================+    +===================+     +===================+
|    IntrinsicLib   |    |    IntrinsicLib   |     |    IntrinsicLib   |
+===================+    +===================+     +===================+

根据使用的BIOS二进制的大小,可以选择不同的方式。

代码示例

BIOS启动过程中会执行BootLoader来加载系统,最常用的就是GRUB,它可能是一个名为bootx64.efi的UEFI应用。BIOS启动的最后会将控制权交给这个bootx64.efi,并由后者来启动系统。但是这里存在一个问题,如何保证这个应用真的是我们需要的呢?如果该应用被修改甚至替换了,导致执行一些我们不希望其执行的代码,则是一个非常严重的安全漏洞。

在看过密码学基础_hex string is too short, padding with zero bytes t-CSDN博客之后就可以知道,可以使用数字签名的方式来解决bootx64.efi被修改的问题,其原理如下图所示:

在这里插入图片描述

实际使用的流程是这样的:

  1. 使用私钥对bootx64.efi进行加密,私钥由bootx64.efi的提供者保留,不能泄露。
  2. 将公钥放到BIOS代码中,启动时使用这个公钥校验bootx64.efi,成功的话再加载这个程序,否则就不加载。

通过这个操作,如果bootx64.efi被修改了,这个程序就不会被执行,这样可以防止执行异常的代码。下面将介绍这两部分的内容。

私钥加密

首先是私钥的创建,这通过openssl工具就可以完成。

  1. 创建私钥:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>openssl.exe genrsa -out private.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
....................................................................+++++
.....+++++
e is 65537 (0x010001)
  1. 从私钥提取出公钥:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>openssl.exe rsa -in private.pem -pubout -out public.pem
writing RSA key
  1. 对bootx64.efi(该文件手上暂时没有,使用helloworld.efi代替)的SHA256散列值进行加密:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>openssl.exe dgst -sign private.pem -sha256 -out sign.bin helloworld.efi

private.pem是前面创建的私钥,helloworld.efi是被签名的文件(用来替代bootx64.efi做测试),sign.bin是输出文件,表示helloworld.efi的数字签名。

  1. 如果要验证签名,可以通过如下的命令:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>openssl.exe dgst -verify public.pem -sha256 -signature sign.bin helloworld.efi
Verified OK

可以看到“Verified OK”,表示验证成功了。这里的public.pem是对应的公钥。后续我们的代码就是要实现这个步骤。

  1. 最后将原始文件(这里就是helloworld.efi)和数字签名放在一起,得到最终的efi文件:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>copy /b helloworld.efi+sign.bin helloworld_signed.bin
helloworld.efi
sign.bin
已复制         1 个文件。

最终得到一个helloworld_signed.efi,它与原始的版本进行比较,其差异如下:

在这里插入图片描述

公钥解密

这一部分需要BIOS的代码来实现,这里使用一个名为exec的命令来进行测试。

首先看一下原始的代码,它位于beni/BeniPkg/DynamicCommand/ExecuteShellAppCommand/Exec.c · jiangwei/edk2-beni - 码云 - 开源中国 (gitee.com),其主要的实现:

VOID
Exec (
  IN  CONST CHAR16                  *AppName
  )
{
  EFI_STATUS                Status = EFI_ABORTED;
  EFI_DEVICE_PATH_PROTOCOL  *DevPath = NULL;
  CHAR16                    *Str = NULL;

  DevPath = gEfiShellProtocol->GetDevicePathFromFilePath (AppName);
  if (NULL == DevPath) {
    DEBUG ((EFI_D_ERROR, "Device path not found!\n"));
    return;
  } else {
    Str = ConvertDevicePathToText (DevPath, TRUE, FALSE);
    if (Str) {
      DEBUG ((EFI_D_ERROR, "DevPath: %s\n", Str));
      FreePool (Str);
    }
  }

  Status = gEfiShellProtocol->Execute (&gImageHandle, (CHAR16 *)AppName, NULL, NULL);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "Execute failed. - %r\n", Status));
  }

  return;
}

这是Shell下的命令,通过如下的命令来执行:

exec helloworld.efi

helloworld.efi是一个Shell应用(未加密),而该操作会执行这个命令。

但是当加入了安全元素,就有了helloworld_signed.efi,因此代码中也需要加入相关的处理,在Exec()函数中增加判断:

VOID
Exec (
  IN  CONST CHAR16                  *AppName
  )
{
  EFI_STATUS                Status = EFI_ABORTED;
  EFI_DEVICE_PATH_PROTOCOL  *DevPath = NULL;
  CHAR16                    *Str = NULL;

  if (!(SecureCheck (AppName))) {
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SECURE_ERROR), mExecHiiHandle);
    return;
  } else {
    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SECURE_SUCCESS), mExecHiiHandle);
  }

SecureCheck()就要用到openssl,其操作流程大致如下:

读取文件内容
对读取内容做SHA256散列计算
将散列值进行公钥验签
判断验签结果

下面分别说明上述的步骤:

  1. 读取文件不多做介绍,调用一般接口即可完成。
  2. 对读取内容进行散列计算,使用的是SHA256,因为私钥加密中做的就是SHA256,两者必须要对应,其代码如下(为了方便查看,只保留主干代码):
  HashContext = AllocateZeroPool (Sha256GetContextSize ());

  CryptoStatus = Sha256Init (HashContext);

  CryptoStatus = Sha256Update (HashContext, FileBuffer, (FileSize - RSA_LEN));

  CryptoStatus = Sha256Final (HashContext, Digest);

这里需要注意的是现在的应用包含了原始内容数字签名两个部分,而散列只针对前一个部分。

  1. 之后是验签。这里需要使用到公钥,这部分在私钥加密的介绍中已经生成,不过需要进行转化才能在代码中使用:
D:\Gitee\edk2-beni\beni\BeniPkg\Tools>openssl.exe rsa -in private.pem -text
RSA Private-Key: (2048 bit, 2 primes)
modulus:
    00:91:ad:ec:3f:4d:85:5f:c0:a7:95:14:92:6c:2f:
    0d:37:6e:58:2d:9a:06:0b:07:c0:15:90:1e:d9:70:
    25:a5:fe:87:68:c3:cd:a2:e5:d4:d7:3c:06:1f:30:
    a3:81:a7:6a:f0:27:aa:26:0c:cb:7d:cb:c2:2c:c6:
    67:b5:76:ef:30:4d:8d:12:6b:4d:20:11:2c:c4:69:
    a6:9b:db:0e:c8:ae:3e:cc:a8:e3:83:b9:80:5b:d2:
    97:3c:e2:e7:85:5a:db:53:23:8a:b4:a0:f8:02:f3:
    03:ec:41:37:97:d0:b5:35:f5:01:d9:3b:e8:24:24:
    ef:39:80:40:5e:c0:c6:b5:3d:32:3b:f1:4b:80:a9:
    2d:93:06:d4:8e:06:b6:b0:3e:ce:6a:17:75:28:32:
    50:a4:c1:86:4c:c0:46:bb:8d:83:6c:8e:53:96:72:
    7d:99:85:6f:19:b5:0c:33:1e:00:57:19:15:59:6b:
    58:30:dc:c5:00:0d:7c:cc:37:05:00:4f:17:a7:41:
    05:e0:d2:f7:67:67:f8:ce:77:a3:1b:9a:45:cf:04:
    14:04:9a:df:58:9d:2a:99:00:f7:16:94:ad:90:77:
    86:ff:6e:6b:03:d3:80:f3:f6:de:d9:cc:89:cc:bc:
    3b:f9:42:06:5d:ba:9b:93:96:b6:f3:e0:fd:98:a1:
    ff:9b
publicExponent: 65537 (0x10001)

这里的moduluspublicExponent是代码中需要使用到的值,最终在代码中:

///
/// Public modulus of RSA Key.
///
CONST UINT8 mPublicKey[] = {
  0x91, 0xad, 0xec, 0x3f, 0x4d, 0x85, 0x5f, 0xc0, 0xa7, 0x95, 0x14, 0x92, 0x6c, 0x2f, 0x0d, 0x37,
  0x6e, 0x58, 0x2d, 0x9a, 0x06, 0x0b, 0x07, 0xc0, 0x15, 0x90, 0x1e, 0xd9, 0x70, 0x25, 0xa5, 0xfe,
  0x87, 0x68, 0xc3, 0xcd, 0xa2, 0xe5, 0xd4, 0xd7, 0x3c, 0x06, 0x1f, 0x30, 0xa3, 0x81, 0xa7, 0x6a,
  0xf0, 0x27, 0xaa, 0x26, 0x0c, 0xcb, 0x7d, 0xcb, 0xc2, 0x2c, 0xc6, 0x67, 0xb5, 0x76, 0xef, 0x30,
  0x4d, 0x8d, 0x12, 0x6b, 0x4d, 0x20, 0x11, 0x2c, 0xc4, 0x69, 0xa6, 0x9b, 0xdb, 0x0e, 0xc8, 0xae,
  0x3e, 0xcc, 0xa8, 0xe3, 0x83, 0xb9, 0x80, 0x5b, 0xd2, 0x97, 0x3c, 0xe2, 0xe7, 0x85, 0x5a, 0xdb,
  0x53, 0x23, 0x8a, 0xb4, 0xa0, 0xf8, 0x02, 0xf3, 0x03, 0xec, 0x41, 0x37, 0x97, 0xd0, 0xb5, 0x35,
  0xf5, 0x01, 0xd9, 0x3b, 0xe8, 0x24, 0x24, 0xef, 0x39, 0x80, 0x40, 0x5e, 0xc0, 0xc6, 0xb5, 0x3d,
  0x32, 0x3b, 0xf1, 0x4b, 0x80, 0xa9, 0x2d, 0x93, 0x06, 0xd4, 0x8e, 0x06, 0xb6, 0xb0, 0x3e, 0xce,
  0x6a, 0x17, 0x75, 0x28, 0x32, 0x50, 0xa4, 0xc1, 0x86, 0x4c, 0xc0, 0x46, 0xbb, 0x8d, 0x83, 0x6c,
  0x8e, 0x53, 0x96, 0x72, 0x7d, 0x99, 0x85, 0x6f, 0x19, 0xb5, 0x0c, 0x33, 0x1e, 0x00, 0x57, 0x19,
  0x15, 0x59, 0x6b, 0x58, 0x30, 0xdc, 0xc5, 0x00, 0x0d, 0x7c, 0xcc, 0x37, 0x05, 0x00, 0x4f, 0x17,
  0xa7, 0x41, 0x05, 0xe0, 0xd2, 0xf7, 0x67, 0x67, 0xf8, 0xce, 0x77, 0xa3, 0x1b, 0x9a, 0x45, 0xcf,
  0x04, 0x14, 0x04, 0x9a, 0xdf, 0x58, 0x9d, 0x2a, 0x99, 0x00, 0xf7, 0x16, 0x94, 0xad, 0x90, 0x77,
  0x86, 0xff, 0x6e, 0x6b, 0x03, 0xd3, 0x80, 0xf3, 0xf6, 0xde, 0xd9, 0xcc, 0x89, 0xcc, 0xbc, 0x3b,
  0xf9, 0x42, 0x06, 0x5d, 0xba, 0x9b, 0x93, 0x96, 0xb6, 0xf3, 0xe0, 0xfd, 0x98, 0xa1, 0xff, 0x9b,
};

///
/// Public exponent of RSA Key.
///
CONST UINT8 mRsaE[] = {
  0x01, 0x00, 0x01
  };

有了公钥之后就可以进行验签,其代码处理也比较简单:

![exec_helloworld_signed](BIOS.assets/exec_helloworld_signed.png)  Rsa = RsaNew ();

  CryptoStatus = RsaSetKey (Rsa, RsaKeyN, mPublicKey, sizeof (mPublicKey));

  CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));

  CryptoStatus = RsaPkcs1Verify (
                  Rsa,
                  Digest,
                  SHA256_DIGEST_SIZE,
                  FileBuffer + (FileSize - RSA_LEN),
                  RSA_LEN
                  );

RsaPkcs1Verify()接受的参数:

  • Rsa:RSA上下文。
  • DigestSHA256_DIGEST_SIZE:SHA256散列值及其大小。
  • FileBuffer + (FileSize - RSA_LEN)RSA_LEN:数字签名及其大小,因为使用了2046比特的签名,所以这个值是256。

FileBuffer + (FileSize - RSA_LEN)对应的就是应用程序最后的256个字节。

测试结果

以上的二进制和代码都已经包含在edk2-beni: 用于学习和验证UEFI BIOS。 (gitee.com),将helloworld_signed.efi包含在代码中,最终进入到Shell之后会被放到fs0:中,执行该程序可以成功,但是当修改helloworld_signed.efi中的任意一个字节,则会报错:

在这里插入图片描述

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

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

相关文章

数据结构作业复盘1:字符串疑难杂症小汇总(字符串赋值,指针数组...)

学校里开始上数据结构了&#xff0c;一开始是从C语言一些相关的基础开始讲起。第一次作业主要是字符串相关的基础知识以及编程题目。先做了一部分&#xff0c;整理了一下一些字符串隐含的知识和一些易误易混的概念&#xff0c;算是给自己的一个复盘和归纳。 strcpy函数相关 首…

Linux系统编程之多线程

目录 1、进程与线程 2、线程的优势与使用理由 3、多线程的使用 3.1 线程的使用 1.线程创建函数 2.线程退出函数 3.线程的等待 4.线程脱离 5. 线程ID获取及比较 6.示例 3.2 互斥锁的应用 1.互斥锁相关API 2.示例 3.3 条件变量的使用 1. 创建及销毁条件变量 2. 等待…

数字化转型导师坚鹏:证券公司数字化领导力提升之道

证券公司数字化领导力提升之道 ——融合中西智慧&#xff0c;践行知行合一思想&#xff0c;实现知行果合一 课程背景&#xff1a; 很多证券公司存在以下问题&#xff1a; 不知道证券公司数字化思维如何提升&#xff1f; 不清楚证券公司数字化领导力模型内涵&#xff1f;…

加密与安全_探索数字证书

文章目录 Pre概述使用keytool生成证书使用Openssl生成证书 &#xff08;推荐&#xff09;证书的吊销小结 Pre PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证 PKI - 04 证书授权颁发机构&#xff08;CA&#xff09; & 数字证书 PKI - 数字签名与数字证…

土壤侵蚀量化评估

根据之前的文章,已经算出了R、K、LS、C、P 现在计算土壤侵蚀,将几个前期制作好的因子的TIFF文件,用栅格计算器相乘 发现局部地区存在轻度侵蚀,大部分区域是微度侵蚀 然后对比了一下范围 其中的几个因子都在文献范围内,说明计算结果并未出错,可能就是研究区正常范围和结…

《数字图像处理(MATLAB版)》相关算法代码及其分析(1)

目录 1 自适应中值滤波算法 1.1 函数定义 1.2 输入参数检查 1.3 初始化 1.4 自适应中值滤波过程 1.5 处理剩余未处理的像素 1.6 总结 2 计算输入数组的平均值 2.1 函数定义 2.2 注释 2.3 输入验证 2.4 计算平均值 2.5 总结 3 基于高斯模型的贝叶斯分类器 3.1 函…

【搭建 Hbase 集群】

搭建 Hbase 集群 一、准备工作二、三台服务器之间的 SSH 免密登录1.修改hosts文件添加DNS映射2.在每台服务器上生成 SSH 密钥对3.将公共密钥&#xff08;通常为 ~/.ssh/id_rsa.pub&#xff09;复制到目标服务器上4.从本地使用 SSH 命令无需密码连接到目标服务器 二、安装JDK1.执…

Linux/Docker 修改系统时区

目录 1. Linux 系统1.1 通过 timedatectl 命令操作1.2 直接修改 /etc/localtime 文件 2. Docker 容器中的 Linux 操作环境&#xff1a; CentOS / AlmaOSMySQL Docker 镜像 1. Linux 系统 1.1 通过 timedatectl 命令操作 使用 timedatectl list-timezones 命令列出可用的时区…

Learning from Unlabeled 3D Environments forVision-and-Language Navigation

这篇论文是关于高级指令的 摘要 在视觉和语言导航 (VLN) 中&#xff0c;实体代理需要按照自然语言指令在真实的 3D 环境中进行导航。现有 VLN 方法的一个主要瓶颈是缺乏足够的训练数据&#xff0c;导致对未见过的环境的泛化效果不理想。虽然 VLN 数据通常是手动收集的&#x…

2024年 前端JavaScript Web APIs 第一天 笔记

1.1 -声明变量const优先 1.2 -DOM树和DOM对象 1.3 -获取DOIM元素 1.4 -DOM修改元素内容以及年会抽奖 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content&quo…

初识面相对象深入理解、构造方法--学习JavaEE的day12

day12 一、初识面相对象深入理解 需求&#xff1a; 创建人类的对象&#xff0c;并操作对象 分析&#xff1a; 人类 - Person 属性&#xff1a;name、sex、age 方法&#xff1a;eat、sleep 场景&#xff1a;创建多个对象&#xff0c;去操作对象 public class Person {//成员变…

9、taocms代码审计

一、XSS 1、DOM型xss 限制 无复现 payload: aa)alert(1)( 触发的参数&#xff1a;name代码 根据路由找到对应的文件&#xff0c;在api.php里接受全局变量action&#xff0c;最终赋值给$m,判断 如果$m不在数组就结束&#xff0c;新建方法复制给$model。检查类的方法是否存…

2024 年广东省职业院校技能大赛(高职组)“云计算应用”赛项样题 2

#需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; 某企业根据自身业务需求&#…

【全局异常处理记录】⭐️通过自定义全局处理器有效统一各种异常并记录

目录 前言 方案 示例 测试 总结 前言 朋友们大家好啊&#xff0c;随着项目的进行&#xff0c;接口也是越来越多了&#xff0c;每个接口无论调用成功与否&#xff0c;都要有相应的应对措施&#xff0c;总不能出错的时候返回一堆异常信息给调用者&#xff0c;所以每个接口都…

Python算法100例-3.2 水仙花数

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序6.问题拓展7.巧用字符串技巧 1&#xff0e;问题描述 输出所有的“水仙花数”。所谓的“水仙花数”是指一个三位数&#xff0c;其各位数字的立方和等于该…

【机器学习】有监督学习算法之:支持向量机

支持向量机 1、引言2、决策树2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;泡澡啊。 小鱼&#xff1a;不去 小屌丝&#xff1a;… 此话当真&#xff1f; 小鱼&#xff1a;此话不假 小屌丝&#xff1a;到底去还是…

奔跑吧,前端er!前端五大方向技能罗列,webGL、AI、桌面、游戏

经常看到头条上前端们争论各种框架的优劣&#xff0c;然后相互争吵不休&#xff0c;其实技术也好&#xff0c;框架也好&#xff0c;都是服务于项目需求的&#xff0c;争论的铁子们都站在自己的项目角度来品评工具&#xff0c;肯定是公说公有理婆说婆有理啦。 技术和框架是中性的…

ArrayBlockingQueue 数组阻塞队列 源码阅读

1. 概述 数组阻塞队列 有界的阻塞数组, 容量一旦创建, 无法修改阻塞队列, 队列满的时候, 往队列put数据会被阻塞, 队列空, 取数据也会被阻塞并发安全 2. 数据结构 /** 存储队列元素的数组 */ /** 存储队列元素的数组 */ final Object[] items;/** 队首位置&#xff0c;下一…

【王道操作系统】ch1计算机系统概述-06虚拟机

文章目录 【王道操作系统】ch1计算机系统概述-06虚拟机01传统计算机02虚拟机的基本概念&#xff08;1&#xff09;第一类虚拟机管理程序&#xff08;2&#xff09; 第二类虚拟机管理程序&#xff08;3&#xff09; 两类虚拟机管理程序的对比 【王道操作系统】ch1计算机系统概述…

【Linux系统化学习】线程概念

目录 线程的概念 线程的引出 什么是线程 理解线程比进程更加的轻量化 线程的优点 现成的缺点 线程异常 线程用途 Linux进程VS线程 线程的简单现象 线程的概念 有关操作系统的书籍或者课本都会这样描述线程&#xff1a; 线程是比进程轻量化的一种执行流线程是进程内部…