trivy os软件包扫描原理分析
具体可以基于之前的博客来做
基于trivy获取基础镜像
参数修改一下:
cliOpt.ListAllPkgs = true
结果中会带有如下格式的结果:
"Results":[{"Target":"192.168.1.94:443/test22/centos:7 (centos 7.9.2009)","Class":"os-pkgs","Type":"centos","Packages":[{"ID":"acl@2.2.51-15.el7.x86_64","Name":"acl","Version":"2.2.51","Release":"15.el7","Arch":"x86_64","SrcName":"acl","SrcVersion":"2.2.51","SrcRelease":"15.el7","Licenses":["GPLv2+"],"Maintainer":"CentOS","DependsOn":["glibc@2.17-317.el7.x86_64","libacl@2.2.51-15.el7.x86_64","libattr@2.4.46-13.el7.x86_64"],"Layer":{"DiffID":"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02"},"Type":"rpm"},{"ID":"audit-libs@2.8.5-4.el7.x86_64","Name":"audit-libs","Version":"2.8.5","Release":"4.el7","Arch":"x86_64","SrcName":"audit","SrcVersion":"2.8.5","SrcRelease":"4.el7","Licenses":["LGPLv2+"],"Maintainer":"CentOS","DependsOn":["glibc@2.17-317.el7.x86_64","libcap-ng@0.7.5-4.el7.x86_64"],"Layer":{"DiffID":"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02"},"Type":"rpm"},
......
其中的原理就是根据对应的软件包信息文件来读取。前面的调用路径与基于trivy获取基础镜像一致。都是通过analyzer.RegisterAnalyzer函数将自己注册进analyzers的map中。最后就可以去获取镜像的软件包列表。
os的软件包代码都在pkg/fanal/analyzer/pkg/中。这里面有三个目录apk、dpkg、rpm。它们分别对应于alpine、ubuntu(debian)、centos操作系统。
我们以ubuntu为例来分析。系统启动时,会将dpkg分析器注册进来。代码如下:
func init() {analyzer.RegisterAnalyzer(&dpkgAnalyzer{})
}
根据前面关于基础镜像的博客,我们知道,只有Required返回成功才会进行分析。所以我们先看这个函数的代码:
const (analyzerVersion = 3statusFile = "var/lib/dpkg/status"statusDir = "var/lib/dpkg/status.d/"infoDir = "var/lib/dpkg/info/"
)
......func (a dpkgAnalyzer) Required(filePath string, _ os.FileInfo) bool {dir, fileName := filepath.Split(filePath)if a.isListFile(dir, fileName) || filePath == statusFile {return true}if dir == statusDir {return true}return false
}
主要逻辑就是通过检查当前文件是否是var/lib/dpkg/status或者当前为目录的话,就判定是否是var/lib/dpkg/status.d。很明显,这里考虑了一个问题,镜像中的文件是占大多数的,所以先检查文件名是否相同,对性能会好点。匹配成功返回true。
如果成功,就会进入Analyze函数。源码如下:
func (a dpkgAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {scanner := bufio.NewScanner(input.Content)if a.isListFile(filepath.Split(input.FilePath)) {return a.parseDpkgInfoList(scanner)}return a.parseDpkgStatus(input.FilePath, scanner)
}
如果是文件,则调用parseDpkgInfoList函数去解析软件包,如果是目录,则调用parseDpkgStatus,具体代码我们往下看。
parseDpkgInfoList函数:
// parseDpkgStatus parses /var/lib/dpkg/info/*.list
func (a dpkgAnalyzer) parseDpkgInfoList(scanner *bufio.Scanner) (*analyzer.AnalysisResult, error) {var installedFiles []stringvar previous stringfor scanner.Scan() {//一行一行的读取current := scanner.Text()if current == "/." {continue}// Add the file if it is not directory.// e.g.// /usr/sbin// /usr/sbin/tarcat//// In the above case, we should take only /usr/sbin/tarcat since /usr/sbin is a directoryif !strings.HasPrefix(current, previous+"/") {//这里去除了目录信息,将所有文件都加入到切片中installedFiles = append(installedFiles, previous)}previous = current}// Add the last fileinstalledFiles = append(installedFiles, previous)if err := scanner.Err(); err != nil {return nil, xerrors.Errorf("scan error: %w", err)}return &analyzer.AnalysisResult{SystemInstalledFiles: installedFiles,}, nil
}
parseDpkgStatus函数:
// parseDpkgStatus parses /var/lib/dpkg/status or /var/lib/dpkg/status/*
//这里注释说明数据来源,我们以/var/lib/dpkg/status为例,来分析下面的代码,数据格式在下方有展示
func (a dpkgAnalyzer) parseDpkgStatus(filePath string, scanner *bufio.Scanner) (*analyzer.AnalysisResult, error) {var pkg *types.Packagepkgs := map[string]*types.Package{}//创建一个临时的package map,key为通过软件名和版本构成的IDpkgIDs := map[string]string{}//以软件名为key,ID为value的mapfor scanner.Scan() {line := strings.TrimSpace(scanner.Text())if line == "" {//软件包的信息以空行结束,如果遇到空行说明当前软件包的解析结束,跳过,为下一个解析做好准备continue}pkg = a.parseDpkgPkg(scanner)//重点在这个函数中,开始解析软件包if pkg != nil {pkgs[pkg.ID] = pkgpkgIDs[pkg.Name] = pkg.ID}}if err := scanner.Err(); err != nil {return nil, xerrors.Errorf("scan error: %w", err)}a.consolidateDependencies(pkgs, pkgIDs)//依赖处理return &analyzer.AnalysisResult{PackageInfos: []types.PackageInfo{{FilePath: filePath,Packages: lo.MapToSlice(pkgs, func(_ string, p *types.Package) types.Package {return *p}),//将结果格式化成切片返回},},}, nil
}
/var/lib/dpkg/status的部分内容
Package: accountsservice
Status: install ok installed
Priority: optional
Section: admin
Installed-Size: 452
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Version: 0.6.55-0ubuntu12~20.04.5
Depends: dbus, libaccountsservice0 (= 0.6.55-0ubuntu12~20.04.5), libc6 (>= 2.4), libglib2.0-0 (>= 2.44), libpolkit-gobject-1-0 (>= 0.99)
Suggests: gnome-control-center
Conffiles:/etc/dbus-1/system.d/org.freedesktop.Accounts.conf 06247d62052029ead7d9ec1ef9457f42
Description: query and manipulate user account informationThe AccountService project provides a set of D-Businterfaces for querying and manipulating user accountinformation and an implementation of these interfaces,based on the useradd, usermod and userdel commands.
Homepage: https://www.freedesktop.org/wiki/Software/AccountsService/
Original-Maintainer: Debian freedesktop.org maintainers <pkg-freedesktop-maintainers@lists.alioth.debian.org>Package: accountsservice-ubuntu-schemas
Status: install ok installed
Priority: optional
Section: gnome
Installed-Size: 44
Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com>
Architecture: all
Multi-Arch: foreign
Source: gsettings-ubuntu-touch-schemas
Version: 0.0.7+17.10.20170922-0ubuntu1
Replaces: accountsservice-ubuntu-touch-schemas (<= 0.0.1+14.04.20140130.1-0ubuntu1), ubuntu-system-settings (<= 0.1+14.04.20140130-0ubuntu1)
Depends: accountsservice
Breaks: accountsservice-ubuntu-touch-schemas (<= 0.0.1+14.04.20140130.1-0ubuntu1), ubuntu-system-settings (<= 0.1+14.04.20140130-0ubuntu1)
Description: AccountsService schemas for Ubuntuaccountsservice-ubuntu-schemas contains a collection of AccountsService vendorextension schemas used by various components of an Ubuntu environment.
Homepage: https://launchpad.net/gsettings-ubuntu-touch-schemasPackage: acl
Status: install ok installed
Priority: optional
Section: utils
Installed-Size: 192
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: foreign
Version: 2.2.53-6
Depends: libacl1 (= 2.2.53-6), libc6 (>= 2.14)
Description: access control list - utilitiesThis package contains the getfacl and setfacl utilities needed for
......
parseDpkgPkg函数:
func (a dpkgAnalyzer) parseDpkgPkg(scanner *bufio.Scanner) (pkg *types.Package) {var (name stringversion stringsourceName stringdependencies []stringisInstalled boolsourceVersion stringmaintainer string)isInstalled = truefor {line := strings.TrimSpace(scanner.Text())if line == "" {break}switch {case strings.HasPrefix(line, "Package: ")://对照上面的例子,这里就是软件名name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))case strings.HasPrefix(line, "Source: "):// Source line (Optional)// Gives the name of the source package// May also specifies a versionsrcCapture := dpkgSrcCaptureRegexp.FindAllStringSubmatch(line, -1)[0]md := map[string]string{}for i, n := range srcCapture {md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)}sourceName = md["name"]if md["version"] != "" {sourceVersion = md["version"]}case strings.HasPrefix(line, "Version: ")://版本version = strings.TrimPrefix(line, "Version: ")case strings.HasPrefix(line, "Status: "):isInstalled = a.parseStatus(line)case strings.HasPrefix(line, "Depends: ")://依赖dependencies = a.parseDepends(line)case strings.HasPrefix(line, "Maintainer: ")://维护者maintainer = strings.TrimSpace(strings.TrimPrefix(line, "Maintainer: "))}if !scanner.Scan() {break}}if name == "" || version == "" || !isInstalled {return nil} else if !debVersion.Valid(version) {log.Logger.Warnf("Invalid Version Found : OS %s, Package %s, Version %s", "debian", name, version)return nil}pkg = &types.Package{ID: a.pkgID(name, version),Name: name,Version: version,DependsOn: dependencies, // Will be consolidated laterMaintainer: maintainer,}//将解析结果保存到pkg中,// Source version and names are computed from binary package names and versions// in dpkg.// Source package name:// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n338// Source package version:// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n355if sourceName == "" {sourceName = name}if sourceVersion == "" {sourceVersion = version}if !debVersion.Valid(sourceVersion) {log.Logger.Warnf("Invalid Version Found : OS %s, Package %s, Version %s", "debian", sourceName, sourceVersion)return pkg}pkg.SrcName = sourceNamepkg.SrcVersion = sourceVersionreturn pkg
}
然后调用AnalysisResult的Merge函数将PackageInfos合并,继而调用其Sort函数进行排序。然后将结果保存在缓存中,这里是本地缓存。最后在Scanner的ScanArtifact中通过调用s.driver.Scan将结果格式化成types.Results,这里的driver会是local scanner,具体代码如下:
// Scan scans the artifact and return results.
func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys []string, options types.ScanOptions) (types.Results, ftypes.OS, error) {artifactDetail, err := s.applier.ApplyLayers(artifactKey, blobKeys)switch {case errors.Is(err, analyzer.ErrUnknownOS):log.Logger.Debug("OS is not detected.")// Packages may contain OS-independent binary information even though OS is not detected.if len(artifactDetail.Packages) != 0 {artifactDetail.OS = ftypes.OS{Family: "none"}}// If OS is not detected and repositories are detected, we'll try to use repositories as OS.if artifactDetail.Repository != nil {log.Logger.Debugf("Package repository: %s %s", artifactDetail.Repository.Family, artifactDetail.Repository.Release)log.Logger.Debugf("Assuming OS is %s %s.", artifactDetail.Repository.Family, artifactDetail.Repository.Release)artifactDetail.OS = ftypes.OS{Family: artifactDetail.Repository.Family,Name: artifactDetail.Repository.Release,}}case errors.Is(err, analyzer.ErrNoPkgsDetected):log.Logger.Warn("No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.")log.Logger.Warn(`e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"`)case err != nil:return nil, ftypes.OS{}, xerrors.Errorf("failed to apply layers: %w", err)}var eosl boolvar results, pkgResults types.Results// Fill OS packages and language-specific packagesif options.ListAllPackages {//这里就是我们刚开始说的那个标志,如果为true,进行整合if res := s.osPkgsToResult(target, artifactDetail, options); res != nil {pkgResults = append(pkgResults, *res)}pkgResults = append(pkgResults, s.langPkgsToResult(artifactDetail)...)}// Scan packages for vulnerabilitiesif options.Scanners.Enabled(types.VulnerabilityScanner) {var vulnResults types.ResultsvulnResults, eosl, err = s.scanVulnerabilities(target, artifactDetail, options)if err != nil {return nil, ftypes.OS{}, xerrors.Errorf("failed to detect vulnerabilities: %w", err)}artifactDetail.OS.Eosl = eosl// Merge package results into vulnerability resultsmergedResults := s.fillPkgsInVulns(pkgResults, vulnResults)results = append(results, mergedResults...)} else {// If vulnerability scanning is not enabled, it just adds package results.results = append(results, pkgResults...)}// Scan IaC config filesif ShouldScanMisconfigOrRbac(options.Scanners) {configResults := s.MisconfsToResults(artifactDetail.Misconfigurations)results = append(results, configResults...)}// Scan secretsif options.Scanners.Enabled(types.SecretScanner) {secretResults := s.secretsToResults(artifactDetail.Secrets)results = append(results, secretResults...)}// Scan licensesif options.Scanners.Enabled(types.LicenseScanner) {licenseResults := s.scanLicenses(artifactDetail, options.LicenseCategories)results = append(results, licenseResults...)}// Scan misconfigurations on container image configif options.ImageConfigScanners.Enabled(types.MisconfigScanner) {if im := artifactDetail.ImageConfig.Misconfiguration; im != nil {im.FilePath = target // Set the target name to the file path as container image config is not a real file.results = append(results, s.MisconfsToResults([]ftypes.Misconfiguration{*im})...)}}// Scan secrets on container image configif options.ImageConfigScanners.Enabled(types.SecretScanner) {if is := artifactDetail.ImageConfig.Secret; is != nil {is.FilePath = target // Set the target name to the file path as container image config is not a real file.results = append(results, s.secretsToResults([]ftypes.Secret{*is})...)}}// For WASM plugins and custom analyzersif len(artifactDetail.CustomResources) != 0 {results = append(results, types.Result{Class: types.ClassCustom,CustomResources: artifactDetail.CustomResources,})}for i := range results {// Fill vulnerability detailss.vulnClient.FillInfo(results[i].Vulnerabilities)}// Post scanningresults, err = post.Scan(ctx, results)if err != nil {return nil, ftypes.OS{}, xerrors.Errorf("post scan error: %w", err)}return results, artifactDetail.OS, nil
}
osPkgsToResult代码:
func (s Scanner) osPkgsToResult(target string, detail ftypes.ArtifactDetail, options types.ScanOptions) *types.Result {if len(detail.Packages) == 0 || !detail.OS.Detected() {return nil}pkgs := detail.Packagesif options.ScanRemovedPackages {pkgs = mergePkgs(pkgs, detail.ImageConfig.Packages)//主要是去重}sort.Sort(pkgs)return &types.Result{Target: fmt.Sprintf("%s (%s %s)", target, detail.OS.Family, detail.OS.Name),Class: types.ClassOSPkg,//标识为os的软件包Type: detail.OS.Family,//os namePackages: pkgs,}
}
至此,代码逻辑基本讲解完了。
相关文章:
trivy os软件包扫描原理分析
具体可以基于之前的博客来做 基于trivy获取基础镜像 参数修改一下: cliOpt.ListAllPkgs true 结果中会带有如下格式的结果: "Results":[{"Target":"192.168.1.94:443/test22/centos:7 (centos 7.9.2009)","Clas…...
算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ
算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ 完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物…...
Java 基础(1)—泛型简单使用
一、泛型定义及作用 泛型是一种编程机制,允许在编写代码时使用参数化类型,以在编译时实现类型安全。 以下是泛型作用: 增强代码可读性和可维护性:通过在代码中使用泛型参数,可以使代码更清晰、更具有可读性和可维护性…...
内存卡损坏了怎么恢复?
内存卡损坏了怎么恢复?现在我们身边有不少电子设备都是用存储卡来存储数据的。一旦需要方便我们直接导出使用。但这存储的数据也不是一定安全的,当我们将内存卡连接到电脑时,难免会碰到病毒、格式化等提示,在这些情况下,可能会导…...
Mysql使用规范(纯技术和实战建议)
1、事务隔级别: (强制):Repeatable-Read(重复读),且不能在会话操作时临时开启隔离级别。 注: Repeatable-Read(重复读)隔离级别解决不了幻读。 可用 show variables l…...
Netty源码解读-EventLoop(二)
一、简介 NioEventLoop的重要组成:Selector、线程、任务队列,他既会处理io事件,也会处理普通任务和定时任务. 1.下面是Selector,注意有两个哦后面会讲 2.下面的爷爷类提供的Thread变量,其实下面发excutor用的就是这个…...
OSI模型详解
今天,我们详解OSI(Open System Inter-connection Reference Model)模型,来看看工业物联网的网络互联和数据互通。 OSI模型 1984年,国际标准化组织(International Organization for Standardization&#…...
Share Creators完成500万美元融资,以工具化手段帮助企业从数字资产管理中解放
近日,总部位于旧金山湾区的初创公司Share Creators宣布完成了新一轮500万美元的融资,投资方为五源资本和福昕PDF。本轮融资主要用于扩大客户基础,并加速在美国、欧洲和亚洲的业务发展。近几年,企业内容及数字资产管理全球市场正在…...
几个Base64编码工具,也有蹊跷
起因 需求:对一段内容进行base64加密,然后通过url的get请求进行发送到后台,由于加密的内容比较少,base64串也不是很长,我认为此方案可行。 于是找了三个base64编码的在线工具,分别是: 平台1&…...
Python|每日一练|排序|递归|字符串|数组|动态规划|单选记录:以特殊格式处理连续增加的数字|正则表达式匹配|地下城游戏
1、以特殊格式处理连续增加的数字(排序) 贡献者:EricLao 给出一串数字, 程序要把数字按照这样的格式输出,把连续增加的数字用 [x-y] 的形式表示,只显示这一组顺序数字的首位两个数字,不连续增…...
Spring Cloud微服务网关Gateway组件
目录 网关简介 什么是Spring Cloud Gateway Spring Cloud Gateway 功能特征 核心概念 工作原理 Spring Cloud Gateway快速开始 环境搭建 集成Nacos 路由断言工厂(Route Predicate Factories)配置 自定义路由断言工厂 过滤器工厂( …...
cluster nodes(集群节点)
CLUSTER NODES 复制 自3.0.0起可用。 时间复杂度: O(N)其中N是 Cluster 节点的总数 Redis 集群中的每个节点都有其当前集群配置的视图,由已知节点的集合给出,我们与这些节点的连接状态,它们的标志&…...
【Android学习】下载jar慢和gradle慢的情况
目录 问题出现的原因 解决方法 解决Gradle下载问题:手动安装 解决jar包下载慢问题:更改下载源 问题出现的原因 国内访问谷歌被墙导致访问速度慢或者干脆无法下载 解决方法 解决Gradle下载问题:手动安装 访问官网Gradle | Release Candi…...
下一个排列-力扣31-java
一、题目描述整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。例如,arr [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&…...
前端面试题
1.HTTP request报文结构是怎样的 1.首行是Request-Line包括:请求方法,请求URI,协议版本,CRLF(换行符) 2.首行之后是若干行请求头,包括general-header,request-header或者entity-hea…...
jsp游戏门户网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 jsp 游戏门户网站系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,使…...
Git与IDEA强强联合(HTTPS协议连接)
最近在写项目的时候,在台式机和笔记本之间频繁切换,竟然还是用qq传压缩包,我自己都感觉无语,有git这样强大的版本管理工具,我竟然没想起来。然后也没有相关的博文就想来更新一篇。 那么如何使idea和git强强联合呢&…...
leetcode 第二题:两数相加-C语言实现
题目地址 备注: 不要忘记最后一个进位的可能。可以使用typedef,来简化struct的书写 代码实现: #include<stdio.h> #include<stdlib.h>struct listNode {int val;struct listNode* next; };// 使用typedef typedef struct lis…...
【人工智能】PTP网络时钟服务器在智能驾驶里的重要性
【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 一辆宣称具备L4/L5自动驾驶功能的车辆,如果多个激光雷达之间的时间同步不够精确?如果传感器感知数据通过以太网传输到智驾域控制器的延迟不可控…...
【蓝桥杯集训3】二分专题(3 / 5)
目录 二分模板 1460. 我在哪? - 二分答案 哈希表 1221. 四平方和 - 哈希表 / 二分 1、哈希表 2、二分 自定义排序 1227. 分巧克力 - 113. 特殊排序 - 二分模板 l r >> 1 —— 先 r mid 后 l mid1 —— 寻找左边界 —— 找大于某个数的最小值lr…...
Llama-3.2V-11B-cot企业级应用:双卡4090支撑的生产环境视觉推理服务搭建
Llama-3.2V-11B-cot企业级应用:双卡4090支撑的生产环境视觉推理服务搭建 1. 项目概述 Llama-3.2V-11B-cot是基于Meta最新多模态大模型开发的高性能视觉推理工具,专为企业级生产环境设计。该工具针对双卡NVIDIA RTX 4090环境进行了深度优化,…...
从CISC到RISC:指令寻址方式如何影响CPU设计?
从CISC到RISC:指令寻址方式如何重塑现代CPU设计? 在计算机体系结构的演进历程中,指令寻址方式始终是影响处理器性能的关键因素。当我们比较x86与ARM处理器的能效差异时,或是分析苹果M系列芯片为何能在低功耗下实现惊人性能时&…...
如何用掩码生成蒸馏(MGD)提升小模型性能?实战ResNet-18到ImageNet分类
掩码生成蒸馏实战:如何让ResNet-18在ImageNet上提升1.8%准确率 在模型轻量化的浪潮中,知识蒸馏技术正经历着从简单模仿到特征重构的范式转变。当我们用ResNet-50这样的"大模型"指导ResNet-18等"小模型"训练时,传统方法往…...
快马平台快速原型:十分钟用AI生成你的第一个龙虾养殖系统Docker部署方案
最近在研究如何用Docker快速搭建一个龙虾养殖模拟系统,发现用InsCode(快马)平台可以大大简化这个过程。作为一个快速原型验证工具,它让我在十分钟内就完成了从构思到部署的全流程。下面分享下我的实践心得: 项目构思阶段 这个模拟系统需要展示…...
虚拟光驱软件Daemon Tools Lite
链接:https://pan.quark.cn/s/ebc5b998a07bDaemon Tools Lite 是一款免费、稳定、方便、优秀的虚拟光驱软件。安装后会自动在资源管理器生成一个和真实光驱一样的盘符,让您像访问真正光驱一样来访问虚拟光驱。Daemon Tools Lite 还可以模拟备份并且合并保…...
万物皆含意识:基于 OFIRM 框架下“信息闭合与自动确认”机制的本体论重构(声明:这是一个理论假说)
万物皆含意识:基于 OFIRM 框架下“信息闭合与自动确认”机制的本体论重构——对德布罗意物质波假说的对称性扩展与量子测量问题的去玄学化解作者:Haiting Allen Chen对应理论:本源场直觉共振模型 (OFIRM)___________________________________…...
微信聊天记录永久保存与智能分析:WeChatMsg完全使用指南
微信聊天记录永久保存与智能分析:WeChatMsg完全使用指南 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeC…...
保姆级教程:在Windows 11上用VSCode和Conda搞定Depth-Anything-3(含常见报错修复)
Windows 11深度估计实战:VSCodeConda环境下的Depth-Anything-3全流程指南 深度估计作为计算机视觉领域的重要技术,正在自动驾驶、增强现实等场景中发挥关键作用。本文将带你在Windows 11系统上,使用VSCode和Conda搭建Depth-Anything-3开发环境…...
如何快速实现Font Awesome图标字体文件格式转换:终极在线工具指南
如何快速实现Font Awesome图标字体文件格式转换:终极在线工具指南 【免费下载链接】Font-Awesome The iconic SVG, font, and CSS toolkit 项目地址: https://gitcode.com/GitHub_Trending/fo/Font-Awesome Font Awesome作为一款标志性的SVG、字体和CSS工具包…...
Pixel Fashion Atelier实战教程:从零构建像素时装生成API服务
Pixel Fashion Atelier实战教程:从零构建像素时装生成API服务 1. 项目介绍与核心价值 Pixel Fashion Atelier(像素时装锻造坊)是一款专为时尚设计师和像素艺术爱好者打造的AI图像生成工具。它基于Stable Diffusion和Anything-v5模型&#x…...
