当前位置: 首页 > 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 …...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

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

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

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...