当前位置: 首页 > news >正文

frida_hook_libart(简单解释)

一:直接取代码


//frida -U -f com.xingin.xhs -l hook_art.js -o xhsart.log
//frida -U -f com.tencent.mobileqq -l hook_art.js -o qqart.logconst STD_STRING_SIZE = 3 * Process.pointerSize;
class StdString {constructor() {this.handle = Memory.alloc(STD_STRING_SIZE);}dispose() {const [data, isTiny] = this._getData();if (!isTiny) {Java.api.$delete(data);}}disposeToString() {const result = this.toString();this.dispose();return result;}toString() {const [data] = this._getData();return data.readUtf8String();}_getData() {const str = this.handle;const isTiny = (str.readU8() & 1) === 0;const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer();return [data, isTiny];}
}function prettyMethod(method_id, withSignature) {const result = new StdString();Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0);return result.disposeToString();
}/*
GetFieldID is at  0xe39b87c5 _ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_
GetMethodID is at  0xe39a1a19 _ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_
NewStringUTF is at  0xe39cff25 _ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc
RegisterNatives is at  0xe39e08fd _ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
GetStaticFieldID is at  0xe39c9635 _ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_
GetStaticMethodID is at  0xe39be0ed _ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_
GetStringUTFChars is at  0xe39d06e5 _ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh
FindClass is at  0xe399ae5d _ZN3art3JNI9FindClassEP7_JNIEnvPKc
*/function hook_libart() {var symbols = Module.enumerateSymbolsSync("libart.so");var addrGetStringUTFChars = null;var addrNewStringUTF = null;var addrFindClass = null;var addrGetMethodID = null;var addrGetStaticMethodID = null;var addrGetFieldID = null;var addrGetStaticFieldID = null;var addrRegisterNatives = null;var so_name = "lib";      //TODO 这里写需要过滤的sofor (var i = 0; i < symbols.length; i++) {var symbol = symbols[i];if (symbol.name.indexOf("art") >= 0 &&symbol.name.indexOf("JNI") >= 0 &&symbol.name.indexOf("CheckJNI") < 0 &&symbol.name.indexOf("_ZN3art3JNIILb0") >= 0) {if (symbol.name.indexOf("GetStringUTFChars") >= 0) {addrGetStringUTFChars = symbol.address;console.log("GetStringUTFChars is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("NewStringUTF") >= 0) {addrNewStringUTF = symbol.address;console.log("NewStringUTF is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("FindClass") >= 0) {addrFindClass = symbol.address;console.log("FindClass is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("GetMethodID") >= 0) {addrGetMethodID = symbol.address;console.log("GetMethodID is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("GetStaticMethodID") >= 0) {addrGetStaticMethodID = symbol.address;console.log("GetStaticMethodID is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("GetFieldID") >= 0) {addrGetFieldID = symbol.address;console.log("GetFieldID is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("GetStaticFieldID") >= 0) {addrGetStaticFieldID = symbol.address;console.log("GetStaticFieldID is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("RegisterNatives") >= 0) {addrRegisterNatives = symbol.address;console.log("RegisterNatives is at ", symbol.address, symbol.name);} else if (symbol.name.indexOf("CallStatic") >= 0) {console.log("CallStatic is at ", symbol.address, symbol.name);Interceptor.attach(symbol.address, {onEnter: function (args) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var java_class = args[1];var mid = args[2];var class_name = Java.vm.tryGetEnv().getClassName(java_class);if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) {var method_name = prettyMethod(mid, 1);console.log("<>CallStatic:", DebugSymbol.fromAddress(this.returnAddress), class_name, method_name);}}},onLeave: function (retval) { }});} else if (symbol.name.indexOf("CallNonvirtual") >= 0) {console.log("CallNonvirtual is at ", symbol.address, symbol.name);Interceptor.attach(symbol.address, {onEnter: function (args) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var jobject = args[1];var jclass = args[2];var jmethodID = args[3];var obj_class_name = Java.vm.tryGetEnv().getObjectClassName(jobject);var class_name = Java.vm.tryGetEnv().getClassName(jclass);if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) {var method_name = prettyMethod(jmethodID, 1);console.log("<>CallNonvirtual:", DebugSymbol.fromAddress(this.returnAddress), class_name, obj_class_name, method_name);}}},onLeave: function (retval) { }});} else if (symbol.name.indexOf("Call") >= 0 && symbol.name.indexOf("Method") >= 0) {console.log("Call<>Method is at ", symbol.address, symbol.name);Interceptor.attach(symbol.address, {onEnter: function (args) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var java_class = args[1];var mid = args[2];var class_name = Java.vm.tryGetEnv().getObjectClassName(java_class);if (class_name.indexOf("java.") == -1 && class_name.indexOf("android.") == -1) {var method_name = prettyMethod(mid, 1);console.log("<>Call<>Method:", DebugSymbol.fromAddress(this.returnAddress), class_name, method_name);}}},onLeave: function (retval) { }});}}}if (addrGetStringUTFChars != null) {Interceptor.attach(addrGetStringUTFChars, {onEnter: function (args) {},onLeave: function (retval) {if (retval != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var bytes = Memory.readCString(retval);console.log("[GetStringUTFChars] result:" + bytes, DebugSymbol.fromAddress(this.returnAddress));}}}});}if (addrNewStringUTF != null) {Interceptor.attach(addrNewStringUTF, {onEnter: function (args) {if (args[1] != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var string = Memory.readCString(args[1]);console.log("[NewStringUTF] bytes:" + string, DebugSymbol.fromAddress(this.returnAddress));}}},onLeave: function (retval) { }});}if (addrFindClass != null) {Interceptor.attach(addrFindClass, {onEnter: function (args) {if (args[1] != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var name = Memory.readCString(args[1]);console.log("[FindClass] name:" + name, DebugSymbol.fromAddress(this.returnAddress));}}},onLeave: function (retval) { }});}if (addrGetMethodID != null) {Interceptor.attach(addrGetMethodID, {onEnter: function (args) {if (args[2] != null) {var clazz = args[1];var class_name = Java.vm.tryGetEnv().getClassName(clazz);var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var name = Memory.readCString(args[2]);if (args[3] != null) {var sig = Memory.readCString(args[3]);console.log("[GetMethodID] class_name:" + class_name + " name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress));} else {console.log("[GetMethodID] class_name:" + class_name + " name:" + name, DebugSymbol.fromAddress(this.returnAddress));}}}},onLeave: function (retval) { }});}if (addrGetStaticMethodID != null) {Interceptor.attach(addrGetStaticMethodID, {onEnter: function (args) {if (args[2] != null) {var clazz = args[1];var class_name = Java.vm.tryGetEnv().getClassName(clazz);var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var name = Memory.readCString(args[2]);if (args[3] != null) {var sig = Memory.readCString(args[3]);console.log("[GetStaticMethodID] class_name:" + class_name + " name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress));} else {console.log("[GetStaticMethodID] class_name:" + class_name + " name:" + name, DebugSymbol.fromAddress(this.returnAddress));}}}},onLeave: function (retval) { }});}if (addrGetFieldID != null) {Interceptor.attach(addrGetFieldID, {onEnter: function (args) {if (args[2] != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var name = Memory.readCString(args[2]);if (args[3] != null) {var sig = Memory.readCString(args[3]);console.log("[GetFieldID] name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress));} else {console.log("[GetFieldID] name:" + name, DebugSymbol.fromAddress(this.returnAddress));}}}},onLeave: function (retval) { }});}if (addrGetStaticFieldID != null) {Interceptor.attach(addrGetStaticFieldID, {onEnter: function (args) {if (args[2] != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var name = Memory.readCString(args[2]);if (args[3] != null) {var sig = Memory.readCString(args[3]);console.log("[GetStaticFieldID] name:" + name + ", sig:" + sig, DebugSymbol.fromAddress(this.returnAddress));} else {console.log("[GetStaticFieldID] name:" + name, DebugSymbol.fromAddress(this.returnAddress));}}}},onLeave: function (retval) { }});}if (addrRegisterNatives != null) {Interceptor.attach(addrRegisterNatives, {onEnter: function (args) {console.log("[RegisterNatives] method_count:", args[3], DebugSymbol.fromAddress(this.returnAddress));var env = args[0];var java_class = args[1];var class_name = Java.vm.tryGetEnv().getClassName(java_class);var methods_ptr = ptr(args[2]);var method_count = parseInt(args[3]);for (var i = 0; i < method_count; i++) {var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));var name = Memory.readCString(name_ptr);var sig = Memory.readCString(sig_ptr);var find_module = Process.findModuleByAddress(fnPtr_ptr);console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));}},onLeave: function (retval) { }});}
}setImmediate(hook_libart);

二:代码解释

Frida 脚本旨在监控 Android 应用程序中 libart.so 库的 Java Native Interface (JNI) 调用。这个脚本通过拦截特定的 JNI 方法,捕获和记录它们的调用信息,帮助我们分析应用程序的行为。

1. 脚本结构

该脚本主要分为几个部分:

  • 常量和类定义: 定义了一些常量和 StdString 类,用于处理 C++ 字符串。
  • 辅助函数: prettyMethod 函数用于获取方法的可读名称。
  • hook_libart 函数: 该函数负责查找和拦截 libart.so 中的 JNI 方法。
  • 设置和执行: 最后调用 setImmediate 执行 hook_libart 函数。

2. 关键功能

2.1 StdString
class StdString {constructor() {this.handle = Memory.alloc(STD_STRING_SIZE);}dispose() {const [data, isTiny] = this._getData();if (!isTiny) {Java.api.$delete(data);}}disposeToString() {const result = this.toString();this.dispose();return result;}toString() {const [data] = this._getData();return data.readUtf8String();}_getData() {const str = this.handle;const isTiny = (str.readU8() & 1) === 0;const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer();return [data, isTiny];}
}
  • 功能: 这个类用于处理 C++ 中的 std::string 对象,提供了字符串的读取和释放方法。
  • 内存管理: dispose 方法负责释放非小字符串的内存。
2.2 prettyMethod 函数
function prettyMethod(method_id, withSignature) {const result = new StdString();Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0);return result.disposeToString();
}
  • 功能: 该函数调用 art::ArtMethod::PrettyMethod 获取方法的可读名称,便于后续的日志记录。
2.3 hook_libart 函数

这是脚本的核心部分,负责查找和拦截多个 JNI 方法:

  • 符号查找: 使用 Module.enumerateSymbolsSync 获取 libart.so 中的符号,并根据名称过滤出相关的 JNI 方法。

  • 拦截 JNI 方法: 对于每个找到的 JNI 方法,通过 Interceptor.attach 进行拦截,记录方法调用的详细信息。

例如,拦截 GetStringUTFChars 方法:

if (addrGetStringUTFChars != null) {Interceptor.attach(addrGetStringUTFChars, {onEnter: function (args) {},onLeave: function (retval) {if (retval != null) {var module = Process.findModuleByAddress(this.returnAddress);if (module != null && module.name.indexOf(so_name) == 0) {var bytes = Memory.readCString(retval);console.log("[GetStringUTFChars] result:" + bytes, DebugSymbol.fromAddress(this.returnAddress));}}}});
}
  • 参数和返回值处理: 在 onEnteronLeave 中处理方法的参数和返回值,记录相关信息。

3. 监控的 JNI 方法

该脚本监控了多个 JNI 方法,包括:

  • GetFieldID
  • GetMethodID
  • GetStaticFieldID
  • GetStaticMethodID
  • RegisterNatives
  • NewStringUTF
  • GetStringUTFChars
  • FindClass
  • CallStatic
  • CallNonvirtual

这些方法的调用通常涉及 Java 和 C/C++ 之间的交互,监控这些方法可以帮助分析应用程序的行为,尤其是在涉及 JNI 的部分。

4. 使用方法

要使用这个脚本,需要:

  1. 安装 Frida: 确保您已经在设备上安装了 Frida Server,并且在我们的计算机上安装了 Frida 工具。

  2. 运行命令: 使用如下命令运行脚本:

    frida -U -f com.xingin.xhs -l hook_art.js -o xhsart.log
    frida -U -f com.tencent.mobileqq -l hook_art.js -o qqart.log
    

    这里 -U 表示连接到 USB 设备,-f 指定要启动的应用程序,-l 指定要加载的脚本,-o 指定输出日志文件。

5. 总结

这个 Frida 脚本是一个强大的工具,用于监控 Android 应用程序中的 JNI 调用。通过拦截 libart.so 中的关键方法,可以深入了解 Java 和本地代码之间的交互,帮助进行调试、分析和安全研究。脚本的灵活性和可扩展性使其能够适应多种分析需求。

相关文章:

frida_hook_libart(简单解释)

一&#xff1a;直接取代码 //frida -U -f com.xingin.xhs -l hook_art.js -o xhsart.log //frida -U -f com.tencent.mobileqq -l hook_art.js -o qqart.logconst STD_STRING_SIZE 3 * Process.pointerSize; class StdString {constructor() {this.handle Memory.alloc(STD_S…...

计算机网络八股整理(二)

计算机网络八股整理&#xff08;二&#xff09; 应用层 1&#xff1a;dns的全称了解过吗&#xff1f; dns全称domain-name-system&#xff0c;翻译过来就是域名系统&#xff0c;是在计算机网络中将域名转换成ip地址的分布式数据库系统&#xff1b; 域名服务器的层级类似一个树…...

强化学习off-policy进化之路(PPO->DPO->KTO->ODPO->ORPO->simPO)

需要LLM在训练过程中做生成的方法是 On Policy&#xff0c;其余的为Off Policy。 On Policy是包含了反馈机制&#xff0c;Off Policy不包含反馈机制。 若进行环境交互的模型与被更新的模型是相同的模型&#xff0c;通常这种更新策略被称为on-policy的策略。on-policy的方法会有…...

Linux 如何创建逻辑卷并使用

一、逻辑卷的介绍 生成环境中逻辑卷使用率很高 逻辑卷的诞生&#xff1a;如果对磁盘直接使用fdisk分区&#xff0c;那么这中分区&#xff0c;我们叫做Linux的标准分区&#xff0c;Linux的标准分区格式化成文件系统之后&#xff0c;挂载使用&#xff0c;那么一旦文件系统的空间…...

java实现将图片插入word文档

插入图片所用依赖 private static void insertImage(XWPFDocument document, String path) {List<XWPFParagraph> paragraphs document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {CTP ctp paragraph.getCTP();for (int dwI 0; dwI < ctp.sizeO…...

初识java(3)

大家好&#xff0c;今天我们来讲讲我们的老伙计-变量&#xff0c;在哪一门编程语言中&#xff0c;变量的作用都是不可或缺的&#xff0c;那么下面我们就来详细了解一下java中的变量。 一.变量概念 在程序中&#xff0c;除了有始终不变的常量外&#xff0c;有些内容可能会经常…...

coqui-ai TTS 初步使用

项目地址&#xff1a;https://github.com/coqui-ai/TTS 1. 创建一个新的conda环境&#xff0c;如果自己会管理python环境也可以用其他方法 克隆项目下来 pip install -r requirements.txt # 安装依赖 pip install coqui-tts # 只要命令行工具的话 下载自己想要的模型 …...

matlab代码--卷积神经网络的手写数字识别

1.cnn介绍 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种深度学习的算法&#xff0c;在图像和视频识别、图像分类、自然语言处理等领域有着广泛的应用。CNN的基本结构包括输入层、卷积层、池化层&#xff08;Pooling Layer&#xff09;、全连…...

Scala—Map用法详解

Scala—Map用法详解 在 Scala 中&#xff0c;Map 是一种键值对的集合&#xff0c;其中每个键都是唯一的。Scala 提供了两种类型的 Map&#xff1a;不可变 Map 和可变 Map。 1. 不可变集合&#xff08;Map&#xff09; 不可变 Map 是默认的 Map 实现&#xff0c;位于 scala.co…...

极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【六】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…...

ES6 、ESNext 规范、编译工具babel

ES6 、ESNext 规范、编译工具简介 ES6ES&#xff08;ECMAScript&#xff09; vs JS常量进一步探讨 obj对象的扩展面试&#xff1a;使对象属性也不能更改——Object.freeze(obj) 解构deconstruction变量的解构赋值&#xff1a;数组解构赋值&#xff1a;对象解构赋值&#xff1a;…...

DeepSpeed 配置文件(DeepSpeed Configuration Files)详解:中英文解释

中文版 本文详细介绍 DeepSpeed 配置文件&#xff0c;结合 4 卡 3090 的实际使用场景&#xff0c;重点解释各个参数的含义&#xff0c;并提供应对爆显存的方案。 DeepSpeed 配置文件详解&#xff1a;从基础到实战 DeepSpeed 是用于加速大规模分布式训练的重要工具&#xff0c…...

前端JavaScript(一)---基本介绍

Javascript是一种由Netscape(网景)的LiveScript发展而来的原型化继承的面向对象的动态类型的区分大小写的客户端脚本语言&#xff0c;主要目的是为了解决服务器端语言&#xff0c;比如Perl&#xff0c;遗留的速度问题&#xff0c;为客户提供更流畅的浏览效果。当时服务端需要对…...

文本处理之sed

1、概述 sed是文本编辑器&#xff0c;作用是对文本的内容进行增删改查。 和vim不一样&#xff0c;sed是按行进行处理。 sed一次处理一行内容&#xff0c;处理完一行之后紧接着处理下一行&#xff0c;一直到文件的末尾 模式空间&#xff1a;临时储存&#xff0c;修改的结果临…...

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…...

计算机网络 实验七 NAT配置实验

一、实验目的 通过本实验理解网络地址转换的原理和技术&#xff0c;掌握扩展NAT/NAPT设计、配置和测试。 二、实验原理 NAT配置实验的原理主要基于网络地址转换&#xff08;NAT&#xff09;技术&#xff0c;该技术用于将内部私有网络地址转换为外部公有网络地址&#xff0c;从…...

数据结构——排序算法第二幕(交换排序:冒泡排序、快速排序(三种版本) 归并排序:归并排序(分治))超详细!!!!

文章目录 前言一、交换排序1.1 冒泡排序1.2 快速排序1.2.1 hoare版本 快排1.2.2 挖坑法 快排1.2.3 lomuto前后指针 快排 二、归并排序总结 前言 继上篇学习了排序的前面两个部分:直接插入排序和选择排序 今天我们来学习排序中常用的交换排序以及非常稳定的归并排序 快排可是有多…...

【kafka04】消息队列与微服务之Kafka 图形工具

Kafka 在 ZooKeeper 里面的存储结构 topic 结构 /brokers/topics/[topic] partition结构 /brokers/topics/[topic]/partitions/[partitionId]/state broker信息 /brokers/ids/[o...N] 控制器 /controller 存储center controller中央控制器所在kafka broker的信息 消费者 /c…...

剖析前后端 API 接口参数设计:JSON 数据结构化全攻略

在当今软件开发领域&#xff0c;前后端分离架构已成为主流趋势。而 API 接口作为前后端之间数据交互的桥梁&#xff0c;其设计的合理性对系统的可维护性和扩展性起着至关重要的作用。JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&…...

vue3 多种方式接受props,定义ref,reactive

定义props 1 第一种 interface AddType { dialogStudyVisible: boolean; } const props defineProps<AddType>(); 第二种 // const props defineProps({ // dialogStudyVisible:{ // type:Boolean, // default:false // } // }) 第三种 // const …...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...