安卓逆向之脱壳-认识一下动态加载 双亲委派(一)
安卓逆向和脱壳是安全研究、漏洞挖掘、恶意软件分析等领域的重要环节。脱壳(unpacking)指的是去除应用程序中加固或保护措施的过程,使得可以访问应用程序的原始代码或者数据。脱壳的重要性:
- 分析恶意软件:很多恶意软件采用加壳技术来隐藏其真实行为。脱壳后,安全研究人员可以更容易地理解恶意代码的实现方式、传播途径及其攻击目标,帮助开发有效的防御策略。
- 漏洞分析:应用程序可能存在各种漏洞,比如远程代码执行、信息泄露等。通过脱壳,可以查看原始代码,分析潜在漏洞,进而发现可能的攻击面。
- 破解保护机制:很多安卓应用为了保护自己的知识产权或防止被修改,会采用加壳技术或其他防篡改机制。逆向工程和脱壳可以帮助研究者绕过这些保护,获取应用的原始功能或源代码。
- 提升安全性:通过脱壳并分析应用的源代码,可以发现其安全缺陷并加以修复。这对安卓开发者来说,能够提升自己的应用在面对恶意攻击时的安全性。
- 反作弊:一些游戏或者应用采用加壳和加密技术来防止被作弊或修改。脱壳能够帮助研究者或者开发者对抗这些作弊行为,确保应用的公平性和安全性。
脱壳技术一般涉及到一些技巧,比如使用动态调试工具(如Frida, Xposed等)、静态分析工具(如IDA Pro, Ghidra等)以及一些专用的脱壳工具(如UnpackMe, Apktool等)。掌握这些工具和技巧对安卓逆向工程师来说非常重要。
1.讲述Android开发中dex文件加载的class loader机制,特别是pass class loader在加载未加壳类中的作用
在 Android 开发中,Dex
(Dalvik Executable)文件是应用程序的核心,它包含了字节码,供 Android 的虚拟机(Dalvik VM 或 ART)执行。Android 系统中的 ClassLoader
是加载这些字节码并将其转换为 Java 类的关键组件。理解 ClassLoader
的工作机制,尤其是 Pass ClassLoader
,对于深入理解 Android 逆向与脱壳过程具有重要意义。
1. Android 的 ClassLoader 机制概述
Android 使用多种 ClassLoader
来加载不同类型的类。默认情况下,Android 使用的是 PathClassLoader
来加载应用程序的 dex
文件。它通过以下几个步骤工作:
- 系统 ClassLoader (
BootClassLoader
):它负责加载 Android 系统核心库(如android.*
和java.*
等)。 - 应用 ClassLoader (
PathClassLoader
):负责加载应用程序的主dex
文件。 - 用户 ClassLoader (
DexClassLoader
):在一些高级应用中,允许动态加载外部的dex
文件(例如插件化框架)。
每个 ClassLoader
都有自己的类加载路径,它们通过层层委托的方式来加载类。委托模式意味着一个 ClassLoader
会请求父 ClassLoader
加载类,直到找到该类为止。如果父 ClassLoader
不能加载该类,它才会尝试自行加载。
2. Pass ClassLoader 的作用
Pass ClassLoader
是一个特殊的类加载器,它主要用于 加载未经过加壳或加密保护的类,特别是在进行逆向分析或破解时。为了更好地理解 Pass ClassLoader
,我们需要先了解一些加壳和加密的基本概念。
在一些保护措施中,开发者可能会对应用程序的 dex
文件进行加壳或加密。加壳后,dex
文件中的字节码被封装在某种保护的形式中,需要特定的脱壳工具或机制才能提取和加载原始的类。
Pass ClassLoader 的作用:
- 绕过壳层:对于加壳的
dex
文件,Pass ClassLoader 可以直接加载那些未经过加密保护的类,避免常规的ClassLoader
在加载时受壳层的干扰。 - 绕过保护:在一些反调试、反篡改或者加密的情况下,Pass ClassLoader 可以让逆向人员加载未加密的类代码,帮助分析原始逻辑。
- 实现代码注入:在 Android 逆向过程中,有时会通过 Pass ClassLoader 动态地注入新的类或修改已有类,尤其是做插件化开发时。它能够动态加载外部的
dex
文件,支持模块化的加载机制。
3. Pass ClassLoader 在脱壳过程中的作用
在一些典型的脱壳和逆向过程中,Pass ClassLoader
是必不可少的工具。具体来说,它在脱壳中的作用体现在以下几个方面:
- 动态加载未加壳类:在很多情况下,应用的某些类(尤其是加壳的
dex
文件)会被包装或加密,不能直接用常规的ClassLoader
加载。这时,使用Pass ClassLoader
就能绕过加密保护,直接加载未加壳的类。 - 绕过防篡改机制:有些应用在加载过程中会使用复杂的防篡改机制,比如校验
dex
文件的完整性或签名。Pass ClassLoader 通过绕过这些机制,能够加载原始类,供分析和修改。 - 支持动态调试与注入:逆向分析人员可以利用
Pass ClassLoader
动态注入自己的类或修改已有类,实现代码修改和调试。这对于破解和动态分析非常有用。
4. 实际应用中的 Pass ClassLoader
在实际的 Android 逆向过程中,Pass ClassLoader
主要应用于以下场景:
- 加壳应用的逆向分析:对于通过加壳或加密保护的应用,通过脱壳可以恢复其原始的
dex
文件。而在一些加壳的应用中,Pass ClassLoader
用于加载脱壳后的类,使得它们可以被执行和分析。 - 恶意软件分析:恶意软件分析时,攻击者常通过加壳技术隐藏真实的攻击代码。研究人员使用
Pass ClassLoader
绕过壳层,将恶意代码加载到内存中,以便分析其行为。 - 插件化框架的实现:一些 Android 插件化框架(例如
RePlugin
,Xposed
)使用Pass ClassLoader
来动态加载外部dex
文件和插件,支持运行时动态扩展和模块化。
5. 小结
在 Android 开发与逆向过程中,ClassLoader
是管理 dex
文件加载的核心组件,而 Pass ClassLoader
则是绕过加壳和加密保护、加载原始类的重要工具。在逆向分析、恶意软件分析、漏洞挖掘等场景中,理解并灵活应用 Pass ClassLoader
,可以帮助研究人员突破保护措施,更加高效地进行代码审计和漏洞分析。
相关学习链接:
https://segmentfault.com/a/1190000008491597
https://blog.csdn.net/u014634338/article/details/81434327
https://segmentfault.com/a/1190000013469223
2.class loader的加载流程、脱壳点及pass list对象的重要性,展示了如何验证class loader类型及获取其加载的dex文件信息
1. ClassLoader 的加载流程
在 Android 中,ClassLoader
主要负责将字节码(即 .dex
文件中的内容)转换成类,并将其加载到 JVM 或 ART 中。类加载器的加载过程遵循以下的流程:
1.1 类加载的步骤
- 查找类:当程序请求加载一个类时,
ClassLoader
会首先查找其缓存中是否已有该类。如果存在,就直接返回该类。如果没有,它会进入加载过程。 - 委托给父类加载器:按照 委托机制(父类优先),如果当前
ClassLoader
没有加载该类,它会将加载请求委托给父加载器处理。父类加载器会继续递归地查找该类。 - 加载类:如果父加载器无法加载该类,当前加载器才会尝试从指定的路径(通常是
.dex
文件或.jar
包)中加载类。 - 字节码解析:在
ClassLoader
找到类的字节码之后,它会将字节码解析为Class
对象,放到内存中。此时类加载完成,可以通过反射等方式进行访问。
1.2 ClassLoader的层次结构
Android 中的类加载器是按照父子关系来进行层次化管理的:
- 系统 ClassLoader(BootClassLoader):负责加载 Java 核心类库(如
java.lang.*
和android.*
等)。 - 应用 ClassLoader(PathClassLoader):负责加载应用程序的主
.dex
文件。 - 插件类加载器(DexClassLoader):在一些动态加载的场景下(如插件化框架),会用
DexClassLoader
来加载外部的dex
文件。
2. 脱壳点与 Pass ClassLoader 的重要性
2.1 脱壳点
在 Android 应用的逆向工程过程中,很多开发者会使用一些加壳工具(如 ProGuard、DexGuard、AndResGuard 等)来对 .dex
文件进行加密或加壳,防止代码被轻易反编译或篡改。脱壳的目的是恢复加密或加壳后的真实 .dex
文件,以便进一步分析。
脱壳的常见手段:
- 静态脱壳:使用反编译工具(如 IDA、Ghidra)静态地分析壳层和加密算法,直接恢复
dex
文件。 - 动态脱壳:通过动态调试工具(如 Frida、Xposed)分析程序的运行时行为,提取真实的
dex
文件。
脱壳点:
- 解密算法:很多加密的
dex
文件会包含一段加密或解密的逻辑。脱壳点一般会在该解密算法的关键步骤或函数中。 - 类加载器修改:一些加壳工具通过修改类加载器的行为来保护
dex
文件,逆向人员需要在加载类的过程中发现解密或还原dex
文件的点。
2.2 Pass ClassLoader 的作用
Pass ClassLoader
是一个特殊的类加载器,用于在加载未加壳类时绕过一些防护机制。它的作用在于:
- 绕过加壳保护:当
dex
文件经过加壳加密时,Pass ClassLoader
可以帮助绕过壳层,直接加载未加壳的类。 - 动态分析:通过
Pass ClassLoader
可以帮助分析应用的实际行为,尤其是用于绕过反篡改机制,进行恶意软件分析。
3. 如何验证 ClassLoader 类型及获取加载的 Dex 文件信息
在 Android 逆向工程过程中,验证 ClassLoader
类型并获取其加载的 .dex
文件信息是一个关键步骤。以下是一些实用的技巧和方法。
3.1 验证 ClassLoader 类型
要验证当前类是通过哪个 ClassLoader
加载的,通常可以利用 Java 的反射机制来获取当前类的加载器。
ClassLoader classLoader = MyClass.class.getClassLoader();
Log.d("ClassLoader", "ClassLoader: " + classLoader);
这将返回一个 ClassLoader
对象,表示当前类的加载器。通过判断其类型,可以知道是否为 PathClassLoader
、DexClassLoader
或者 BaseDexClassLoader
(Android 中的父类)。
3.2 获取加载的 Dex 文件信息
要获取当前 ClassLoader
加载的 .dex
文件信息,可以通过以下步骤:
- PathClassLoader:对于应用的主
dex
文件,可以通过反射或直接访问PathClassLoader
的构造函数来获取它的加载路径。
PathClassLoader pathClassLoader = (PathClassLoader) MyClass.class.getClassLoader();
Field pathListField = PathClassLoader.class.getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathList = pathListField.get(pathClassLoader);Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
dexElementsField.setAccessible(true);
Object[] dexElements = (Object[]) dexElementsField.get(pathList);for (Object dexElement : dexElements) {Field dexFileField = dexElement.getClass().getDeclaredField("dexFile");dexFileField.setAccessible(true);Object dexFile = dexFileField.get(dexElement);Log.d("DexFile", "Loaded dex: " + dexFile);
}
这段代码会获取并打印出通过 PathClassLoader
加载的 .dex
文件的信息。
- DexClassLoader:如果是使用
DexClassLoader
加载的dex
文件,可以直接获取其dex
路径信息。一般来说,DexClassLoader
加载的dex
文件路径会通过构造函数传入。
DexClassLoader dexClassLoader = (DexClassLoader) MyClass.class.getClassLoader();
String dexPath = dexClassLoader.getDexPath();
Log.d("DexClassLoader", "Dex path: " + dexPath);
这将打印出 DexClassLoader
加载的 .dex
文件的路径。
3.3 动态加载 Dex 文件
在一些动态分析的场景下,可以利用 DexClassLoader
动态加载一个外部的 dex
文件:
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, optimizedDirectory, null, context.getClassLoader());
Class<?> loadedClass = dexClassLoader.loadClass("com.example.DynamicClass");
通过这种方式,加载一个外部 dex
文件,可以动态地加载并执行其中的类。
4. 总结
- ClassLoader 流程:类加载器通过查找和委托机制加载类,分为系统加载器、应用加载器、插件加载器等。
- 脱壳点和 Pass ClassLoader:在加壳应用中,Pass ClassLoader 用于绕过加壳保护,直接加载未加壳类,尤其在动态调试与恶意软件分析中非常重要。
- 验证 ClassLoader 和加载的 Dex 信息:通过反射和直接访问类加载器内部字段,能够验证当前类加载器的类型并获取加载的
dex
文件信息。
这些方法对于 Android 逆向工程、漏洞分析以及动态调试和脱壳过程非常有帮助。
3.提及自定义class loader和found class在加载过程中的作用,深入具体实现细节
1. 自定义 ClassLoader
在 Android 或 Java 中,我们可以创建自定义的 ClassLoader
来修改或扩展默认的类加载行为。自定义 ClassLoader
通常用于以下几种场景:
- 动态加载外部
.dex
文件:用于插件化框架或动态加载模块。 - 绕过安全性措施:比如绕过加壳保护、篡改默认的类加载机制等。
- 动态代码注入与修改:通过修改
ClassLoader
的行为,注入自己的类或者修改已有类。
自定义 ClassLoader
的关键在于重写 findClass()
和 loadClass()
方法。这里是 Java 中 ClassLoader
加载类的基本原理和我们如何自定义加载过程。
2. ClassLoader
的默认加载流程
loadClass()
:每个ClassLoader
都会重写loadClass()
方法。loadClass()
方法会首先检查类是否已经加载,如果已加载,则直接返回该类。如果没有加载,它会调用findClass()
来查找并加载类。findClass()
:findClass()
是ClassLoader
类的一个抽象方法,我们可以在自定义的ClassLoader
中实现该方法。findClass()
负责实际的类加载工作,它通过byte[]
数据来创建Class
对象。- 委托机制:
ClassLoader
是基于父类委托的机制来加载类的。也就是说,当一个ClassLoader
请求加载类时,它会首先委托给父ClassLoader
来加载类。如果父ClassLoader
无法加载类,它才会自行加载。
3. 自定义 ClassLoader 的实现
下面是一个简单的自定义 ClassLoader
的例子,用于加载外部 dex
文件中的类:
public class MyClassLoader extends ClassLoader {private String dexPath;public MyClassLoader(String dexPath, ClassLoader parent) {super(parent); // 使用系统的默认类加载器作为父加载器this.dexPath = dexPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// 获取 dex 文件中的字节码数据byte[] classData = loadClassData(name);if (classData == null) {throw new ClassNotFoundException("Class " + name + " not found in dex file.");}// 将字节码数据转换成 Class 对象return defineClass(name, classData, 0, classData.length);}private byte[] loadClassData(String className) {// 将类名转换为对应的文件路径String filePath = dexPath + "/" + className.replace('.', '/') + ".dex";try (InputStream inputStream = new FileInputStream(filePath)) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();int data;while ((data = inputStream.read()) != -1) {byteArrayOutputStream.write(data);}return byteArrayOutputStream.toByteArray();} catch (IOException e) {e.printStackTrace();return null;}}
}
在这个例子中,我们重写了 findClass()
方法来加载指定路径下的 .dex
文件中的类,并通过 defineClass()
方法将字节码转换成 Class
对象。
4. findClass()
和 defineClass()
-
findClass()
:该方法是自定义ClassLoader
中最重要的部分,它负责查找并加载字节码。它的输入是类名,通过特定的逻辑获取字节码后,调用defineClass()
来完成类的加载。 -
defineClass()
:该方法将字节码(byte[]
)转换为Class
对象。它的签名如下:protected Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError
name
:类的全名(包括包名)。b
:字节码数组。off
:字节码数组的起始偏移。len
:字节码的长度。
defineClass()
会创建一个新的Class
对象,并加载到 JVM 中,之后可以通过该类对象进行反射操作。
5. foundClass
在加载过程中的作用
foundClass
并不是 ClassLoader
中的标准方法,但它的概念通常用于描述在加载类的过程中,ClassLoader
查找到了目标类,并将其作为 Class
对象返回。
在自定义 ClassLoader
中,findClass()
方法返回的就是 “found class”。而在 loadClass()
方法中,如果父类 ClassLoader
能够找到并加载目标类,就直接返回该类,否则会委托给 findClass()
方法。
以下是一个简化的过程说明:
- 请求加载类:如果请求加载的类尚未加载,
loadClass()
会调用findClass()
。 findClass()
查找类:findClass()
会尝试根据类名找到该类的字节码数据。- 返回找到的类(found class):如果成功找到并加载字节码,就通过
defineClass()
返回一个Class
对象。这时,类被认为是“已找到”(found)并成功加载。
6. 验证 ClassLoader 类型及加载的 Dex 信息
验证当前类是由哪个 ClassLoader
加载,可以使用 getClassLoader()
方法。例如:
ClassLoader classLoader = MyClass.class.getClassLoader();
Log.d("ClassLoader", "ClassLoader: " + classLoader);
这会输出当前类加载器的类型(如 PathClassLoader
、DexClassLoader
或自定义的 ClassLoader
)。如果你想进一步分析加载的 .dex
文件或验证具体的路径,可以使用反射来获取更详细的信息,如:
Field pathListField = PathClassLoader.class.getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathList = pathListField.get(classLoader);Field dexElementsField = pathList.getClass().getDeclaredField("dexElements");
dexElementsField.setAccessible(true);
Object[] dexElements = (Object[]) dexElementsField.get(pathList);for (Object dexElement : dexElements) {Field dexFileField = dexElement.getClass().getDeclaredField("dexFile");dexFileField.setAccessible(true);Object dexFile = dexFileField.get(dexElement);Log.d("DexFile", "Loaded dex: " + dexFile);
}
7. 总结
- 自定义
ClassLoader
:通过重写findClass()
和loadClass()
方法,我们可以控制类加载的具体过程,包括加载外部dex
文件,或修改加载机制。 findClass()
的角色:findClass()
是自定义ClassLoader
中查找类并返回字节码的关键方法,它将字节码数据转换为Class
对象。foundClass
:指的是ClassLoader
成功加载并返回的类。在加载过程中,类可能会经过多次查找,直到找到并返回给请求者。- 验证类加载器类型和加载的
dex
文件:可以通过反射获取当前ClassLoader
和它加载的dex
文件路径,帮助进行调试和分析。
通过自定义 ClassLoader
,我们可以更灵活地控制类的加载过程,尤其是在插件化框架、动态代码注入和逆向分析等领域,这些技巧非常有用。
相关文章:

安卓逆向之脱壳-认识一下动态加载 双亲委派(一)
安卓逆向和脱壳是安全研究、漏洞挖掘、恶意软件分析等领域的重要环节。脱壳(unpacking)指的是去除应用程序中加固或保护措施的过程,使得可以访问应用程序的原始代码或者数据。脱壳的重要性: 分析恶意软件:很多恶意软件…...

Nuxt:利用public-ip这个npm包来获取公网IP
目录 一、安装public-ip包1.在Vue组件中使用2.在Nuxt.js插件中使用public-ip 一、安装public-ip包 npm install public-ip1.在Vue组件中使用 你可以在Nuxt.js的任意组件或者插件中使用public-ip来获取公网IP。下面是在一个Vue组件中如何使用它的例子: <template…...

babylon.js-3:了解STL网格模型
网格模型上色 本篇文章主要介绍如何在 BabylonJS 中实现STL网格模型上色。 文章目录 网格模型上色运用场景概要延申正文加载器库的支持认识 OBJ 和 STL 文件GUI 色板选择器网格模型异步加载加载动画网格模型上色官方即将弃用 ImportMesh 而推荐使用 ImportMeshAsync 说明OBJ …...

基于SpringBoot的假期周边游平台的设计与实现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...

【MySQL】初始MySQL、库与表的操作
目录 基本使用 使用案例 SQL分类 存储引擎 库的操作 字符集和校验规则 查看系统默认字符集和校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 指定编码常见数据库 校验规则对数据库的影响 操纵数据库 库的备份与恢复 表的操作 创建表 查看表 …...

将DeepSeek接入Word,打造AI办公助手
最近,DeepSeek热度一路高涨,成为AI领域的焦点。通过开放的API,我们可以将DeepSeek接入Word,直接进行AI对话。更进一步,还能利用DeepSeek辅助修改文档,甚至提出一些排版建议。 Word报告工具已经新增“DeepS…...
Coze,Dify,FastGPT,对比
在当今 AI 技术迅速发展的背景下,AI Agent 智能体成为了关键领域,Coze、Dify 和 FastGPT 作为其中的佼佼者,各有千秋。 平台介绍 - FastGPT:由环界云计算公司发起,是基于大语言模型(LLM)的开源…...

Kafka 日志存储 — 磁盘存储
Kafka 依赖与磁盘来存储和缓存消息,采用文件追加的方式来写入消息。顺序写盘的速度快于随机写内存。 1 磁盘存储 除顺序写入外,Kafka中大量使用了页缓存、零拷贝等技术来进一步提升吞吐性能。 1.1 页缓存 页缓存是操作系统实现的一种磁盘缓存&#x…...

996引擎 - NPC-添加NPC引擎自带形象
996引擎 - NPC-添加NPC引擎自带形象 截图参考添加NPC参考资料截图参考 添加NPC 编辑NPC表:Envir\DATA\cfg_npclist.xls 1.1. 需要临时隐藏NPC时可以在id前加 // 1.2. 如果NPC朝向不对,可以调整dir 列。(按8方向,上是0顺时针数。我这里给的4) 1.3. 形象代码:NPC代码、怪物…...
GL C++显示相机YUV视频数据使用帧缓冲FBO后期处理,实现滤镜功能。
一.前言: GitHub地址:GitHub - wangyongyao1989/WyFFmpeg: 音视频相关基础实现 系列文章: 1. OpenGL Texture C 预览Camera视频; 2. OpenGL Texture C Camera Filter滤镜; 3. OpenGL 自定义SurfaceView Texture C预览Camera视…...

【hot100】刷题记录(7)-除自身数组以外的乘积
题目描述: 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#x…...
解决.NET程序通过网盘传到Linux和macOS不能运行的问题
问题描述:.net程序用U盘传到虚拟机macOS和Linux可以正常运行,但是网盘传过去就不行。 解决方法: 这是文件权限的问题。当你通过U盘将文件传输到虚拟机的macOS和Linux系统时,文件的权限和所有权可能得到了保留或正确设置。但如果…...

练习(复习)
大家好,今天我们来做几道简单的选择题目来巩固一下最近学习的知识,以便我们接下来更好的学习。 这道题比较简单,我们前面学过,在Java中,一个类只能继承一个父类,但是一个父类可以有多个子类,一个…...
Class2(2020):Shell基础(二)——Shell脚本设计基础
本系列博客为MIT的《Missing in CS Class》的课程笔记。 Class2(2020):Shell基础(二)——Shell脚本设计基础 注:若无特殊说明,本文中带有[]的部分均为可选参数。 脚本文件 脚本语言为解释执行,其运行需有解释器,如Python。Shel…...
HBase-2.5.10 伪分布式环境搭建【Mac】
文章目录 前言一、搭建单节点Zookeeper1. 解压zookeeper2. 配置环境变量3. 修改配置文件4. 启动zk 二、搭建伪分布式Hbase1. 解压hbase2. 配置环境变量3. 修改配置4. 启动HBase 前言 搭建hbase伪分布式环境 提示:以下是本篇文章正文内容,下面案例仅供参…...

计算机毕业设计Python+CNN卷积神经网络高考推荐系统 高考分数线预测 高考爬虫 协同过滤推荐算法 Vue.js Django Hadoop 大数据毕设
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

macos的图标过大,这是因为有自己的设计规范
苹果官方链接:App 图标 | Apple Developer Documentation 这个在官方文档里有说明,并且提供了sketch 和 ps 的模板。 figma还提供了模板: Figma...

2025_1_29 C语言学习中关于指针
1. 指针 指针就是存储的变量的地址,指针变量就是指针的变量。 1.1 空指针 当定义一个指针没有明确指向内容时,就可以将他设置为空指针 int* p NULL;这样对空指针的操作就会使程序崩溃而不会导致出现未定义行为,因为程序崩溃是宏观的&…...
解决ImportError: cannot import name ‘notf‘
解决ImportError: cannot import name ‘notf‘ 报错: 报错代码: from torch.utils.tensorboard import SummaryWriter cannot import name notf from tensorboard.compat 解决方法: pip install numpy1.26.0 测试代码: py…...

HTML<label>标签
例子 三个带标签的单选按钮: <form action"/action_page.php"> <input type"radio" id"html" name"fav_language" value"HTML"> <label for"html">HTML</label><br&…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...

GraphRAG优化新思路-开源的ROGRAG框架
目前的如微软开源的GraphRAG的工作流程都较为复杂,难以孤立地评估各个组件的贡献,传统的检索方法在处理复杂推理任务时可能不够有效,特别是在需要理解实体间关系或多跳知识的情况下。先说结论,看完后感觉这个框架性能上不会比Grap…...