Native开发与逆向第二篇 - 动态注册函数逆向

news2024/9/28 5:34:44

ida静态分析

示例app是网上找的一个杀毒软件,做安全的app防护应该是OK的。
直接找到JNI_OnLoad
类名没处理,直接是明文。

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  jint v2; // w19
  __int64 v4; // [xsp+0h] [xbp-30h] BYREF

  qword_25148 = vm;
  if ( (*vm)->GetEnv(vm, &v4, 65540LL) )
    return -1;
  v2 = -1;
  if ( (sub_6454)(v4, "com/avl/engine/security/NativeUtils", off_24058, 13LL) )
  {
    sub_BABC();
    if ( (sub_6454)(v4, "com/avl/engine/security/AVLA", off_24190, 32LL) )
      return 65540;
    else
      return -1;
  }
  return v2;
}

sub_6454 里面可以看到RegisterNatives 实现动态注册

bool __fastcall sub_6454(JNIEnv *a1, const char *a2, const JNINativeMethod *a3, jint a4)
{
  void *v8; // x22
  jint v9; // w20

  v8 = ((*a1)->FindClass)(a1);
  if ( (*a1)->ExceptionOccurred(a1) )
  {
    (*a1)->ExceptionDescribe(a1);
    (*a1)->ExceptionClear(a1);
  }
  if ( v8 )
  {
    v9 = (*a1)->RegisterNatives(a1, v8, a3, a4);
    (*a1)->DeleteLocalRef(a1, v8);
    return v9 >= 0;
  }
  else
  {
    __android_log_print(6, "@AVLSDK Error", "class %s  not found!", a2);
    return 0LL;
  }
}

sub_6454 的三个参数就是函数的JNINativeMethod结构体,里面就是动态注册函数的方法名,方法签名和对应的实现的函数地址。

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

前面JNI_OnLoad里面调了两次sub_6454 ,第四个参数是注册的方法数量,也就是NativeUtils类注册了13个方法,AVLA类注册了32个方法。
分别是
(sub_6454)(v4, “com/avl/engine/security/NativeUtils”, off_24058, 13LL)
(sub_6454)(v4, “com/avl/engine/security/AVLA”, off_24190, 32LL)

看一下off_24058 ,这里就是13个动态注册的函数
在这里插入图片描述
同样的 off_24190 是32个动态注册的函数,这里截图只截取部分。
在这里插入图片描述
在方法名、方法签名等没有处理的情况下,通过静态分析也能很清楚的看到动态注册的对应函数。
如果方法名、方法签名做了处理,比如加密,ida静态就没办法清楚的呈现了。
这个时候就需要动态分析,上frida hook。

frida hook RegisterNatives

frida hook register的脚步网上很多,我这里用的这个
https://github.com/lasting-yang/frida_hook_libart
脚本如下:


function find_RegisterNatives(params) {
    let symbols = Module.enumerateSymbolsSync("libart.so");
    let addrRegisterNatives = null;
    for (let i = 0; i < symbols.length; i++) {
        let symbol = symbols[i];
        
        //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
        if (symbol.name.indexOf("art") >= 0 &&
                symbol.name.indexOf("JNI") >= 0 && 
                symbol.name.indexOf("RegisterNatives") >= 0 && 
                symbol.name.indexOf("CheckJNI") < 0) {
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);
            hook_RegisterNatives(addrRegisterNatives)
        }
    }

}

function hook_RegisterNatives(addrRegisterNatives) {

    if (addrRegisterNatives != null) {
        Interceptor.attach(addrRegisterNatives, {
            onEnter: function (args) {
                console.log("[RegisterNatives]");
                let java_class = args[1];
                let class_name = Java.vm.tryGetEnv().getClassName(java_class);
                console.log("java_class ===> " + class_name);
                console.log("method_count ===> " + args[3]);

                let methods_ptr = ptr(args[2]);

                let method_count = parseInt(args[3]);
                for (let i = 0; i < method_count; i++) {
                    let name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    let sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    let fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                    let name = Memory.readCString(name_ptr);
                    let sig = Memory.readCString(sig_ptr);
                    let symbol = DebugSymbol.fromAddress(fnPtr_ptr)
                    console.log("[RegisterNatives] ===>", "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr,  " fnOffset:", symbol, " callee:", DebugSymbol.fromAddress(this.returnAddress));
                }
            }
        });
    }
}

setImmediate(find_RegisterNatives);

运行打印效果:

[Pixel 3a::com.antiy.avl ]-> [RegisterNatives]
java_class ===> com.avl.engine.security.NativeUtils
method_count ===> 0xd
[RegisterNatives] ===> name: getLocalUID sig: ()Ljava/lang/String; fnPtr: 0x7c8be18fdc  fnOffset: 0x7c8be18fdc libavlasys.so!0xdfdc  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getCpuPlatform sig: ()Ljava/lang/String; fnPtr: 0x7c8be190f0  fnOffset: 0x7c8be190f0 libavlasys.so!0xe0f0  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: unzipAvllib sig: (Ljava/lang/String;Ljava/lang/String;)I fnPtr: 0x7c8be194a4  fnOffset: 0x7c8be194a4 libavlasys.so!0xe4a4  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getFileMD5 sig: (Ljava/lang/String;I)Ljava/lang/String; fnPtr: 0x7c8be1a1c8  fnOffset: 0x7c8be1a1c8 libavlasys.so!0xf1c8  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getStringMD5 sig: (Ljava/lang/String;I)Ljava/lang/String; fnPtr: 0x7c8be1a26c  fnOffset: 0x7c8be1a26c libavlasys.so!0xf26c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: unzipFile sig: (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)I fnPtr: 0x7c8be1994c  fnOffset: 0x7c8be1994c libavlasys.so!0xe94c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: unzipAssetsFile sig: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)I fnPtr: 0x7c8be195fc  fnOffset: 0x7c8be195fc libavlasys.so!0xe5fc  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: unzipAssetsFileEfficient sig: (Landroid/content/res/AssetManager;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)I fnPtr: 0x7c8be1972c  fnOffset: 0x7c8be1972c libavlasys.so!0xe72c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: readAssetsFile sig: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be19a34  fnOffset: 0x7c8be19a34 libavlasys.so!0xea34  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: readAssetsFileEfficient sig: (Landroid/content/res/AssetManager;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be19c0c  fnOffset: 0x7c8be19c0c libavlasys.so!0xec0c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: searchFile sig: (Ljava/lang/String;Lcom/avl/engine/security/FileSearcher;)I fnPtr: 0x7c8be1261c  fnOffset: 0x7c8be1261c libavlasys.so!0x761c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: searchFile sig: ([Ljava/lang/String;Lcom/avl/engine/security/FileSearcher;)I fnPtr: 0x7c8be126b0  fnOffset: 0x7c8be126b0 libavlasys.so!0x76b0  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getMetaInfEntryNames sig: (Ljava/lang/String;)[[B fnPtr: 0x7c8be14220  fnOffset: 0x7c8be14220 libavlasys.so!0x9220  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives]
java_class ===> com.avl.engine.security.AVLA
method_count ===> 0x20
[RegisterNatives] ===> name: checkKey sig: ()I fnPtr: 0x7c8be19104  fnOffset: 0x7c8be19104 libavlasys.so!0xe104  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setAVLSdkPath sig: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)I fnPtr: 0x7c8be19108  fnOffset: 0x7c8be19108 libavlasys.so!0xe108  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: installPackage sig: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)I fnPtr: 0x7c8be192e8  fnOffset: 0x7c8be192e8 libavlasys.so!0xe2e8  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: scanEx sig: (Ljava/lang/String;[IJ)[Ljava/lang/String; fnPtr: 0x7c8be18a5c  fnOffset: 0x7c8be18a5c libavlasys.so!0xda5c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: scan sig: (Ljava/lang/String;[I)Ljava/lang/String; fnPtr: 0x7c8be18900  fnOffset: 0x7c8be18900 libavlasys.so!0xd900  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: arbitrateVirusName sig: (Ljava/lang/String;)I fnPtr: 0x7c8be18b6c  fnOffset: 0x7c8be18b6c libavlasys.so!0xdb6c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getVirusDescription sig: (Ljava/lang/String;I)Ljava/lang/String; fnPtr: 0x7c8be18ba4  fnOffset: 0x7c8be18ba4 libavlasys.so!0xdba4  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getEngineVersion sig: ()Ljava/lang/String; fnPtr: 0x7c8be193ec  fnOffset: 0x7c8be193ec libavlasys.so!0xe3ec  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getSigLibVersion sig: ()Ljava/lang/String; fnPtr: 0x7c8be19448  fnOffset: 0x7c8be19448 libavlasys.so!0xe448  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getEngConfVersion sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be1a3e8  fnOffset: 0x7c8be1a3e8 libavlasys.so!0xf3e8  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getCertHash sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be19e40  fnOffset: 0x7c8be19e40 libavlasys.so!0xee40  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getCertFullHash sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be19ee4  fnOffset: 0x7c8be19ee4 libavlasys.so!0xeee4  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: getAPKInfo sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be19f88  fnOffset: 0x7c8be19f88 libavlasys.so!0xef88  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: computeToken sig: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I fnPtr: 0x7c8be1a0d8  fnOffset: 0x7c8be1a0d8 libavlasys.so!0xf0d8  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: initEngine sig: ()I fnPtr: 0x7c8be1a310  fnOffset: 0x7c8be1a310 libavlasys.so!0xf310  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: releaseEngine sig: ()I fnPtr: 0x7c8be1a314  fnOffset: 0x7c8be1a314 libavlasys.so!0xf314  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setScanLimit sig: (III)I fnPtr: 0x7c8be1a318  fnOffset: 0x7c8be1a318 libavlasys.so!0xf318  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setDEXScanLimit sig: (IIII)I fnPtr: 0x7c8be1a328  fnOffset: 0x7c8be1a328 libavlasys.so!0xf328  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setOpcDEXScanLimit sig: (II)I fnPtr: 0x7c8be1a33c  fnOffset: 0x7c8be1a33c libavlasys.so!0xf33c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setMapleScanLimit sig: (I)I fnPtr: 0x7c8be1a348  fnOffset: 0x7c8be1a348 libavlasys.so!0xf348  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setScanLimitEx sig: (III)I fnPtr: 0x7c8be1a350  fnOffset: 0x7c8be1a350 libavlasys.so!0xf350  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setAIES sig: (II)I fnPtr: 0x7c8be1a360  fnOffset: 0x7c8be1a360 libavlasys.so!0xf360  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: setAIER sig: (DDD)I fnPtr: 0x7c8be1a36c  fnOffset: 0x7c8be1a36c libavlasys.so!0xf36c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: gsi sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be16764  fnOffset: 0x7c8be16764 libavlasys.so!0xb764  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: icf sig: (Ljava/lang/String;I)I fnPtr: 0x7c8be18c50  fnOffset: 0x7c8be18c50 libavlasys.so!0xdc50  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: gcv sig: (Ljava/lang/String;I)Ljava/lang/String; fnPtr: 0x7c8be18d5c  fnOffset: 0x7c8be18d5c libavlasys.so!0xdd5c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: fcf sig: (I)V fnPtr: 0x7c8be18f44  fnOffset: 0x7c8be18f44 libavlasys.so!0xdf44  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: feedbackInit sig: (Ljava/lang/String;)I fnPtr: 0x7c8be1a370  fnOffset: 0x7c8be1a370 libavlasys.so!0xf370  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: feedbackRelease sig: ()V fnPtr: 0x7c8be1a3e4  fnOffset: 0x7c8be1a3e4 libavlasys.so!0xf3e4  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: signBlockHash sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be1a54c  fnOffset: 0x7c8be1a54c libavlasys.so!0xf54c  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: keySetHash sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be1a5f4  fnOffset: 0x7c8be1a5f4 libavlasys.so!0xf5f4  callee: 0x7c8be114dc libavlasys.so!0x64dc
[RegisterNatives] ===> name: signBlockAndKeySetHash sig: (Ljava/lang/String;)Ljava/lang/String; fnPtr: 0x7c8be1a6a8  fnOffset: 0x7c8be1a6a8 libavlasys.so!0xf6a8  callee: 0x7c8be114dc libavlasys.so!0x64dc

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

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

相关文章

全免费的数据恢复工具推荐!这几个不容错过!

不小心的数据丢失总会带来许多困扰&#xff0c;不过这些困扰也能通过一些全免费的数据恢复工具解决。接下来&#xff0c;就来给大家介绍几款好用的数据恢复工具&#xff01; 第一款&#xff1a;福昕数据恢复 直达链接&#xff1a;www.pdf365.cn/foxit-restore/ 福昕数据恢复…

6.2K star!推荐一款开源混沌工程测试平台:Chaos Mesh

1、Chaos Mesh 介绍 Chaos Mesh是一个开源的混沌工程平台&#xff0c;旨在帮助用户在生产环境中测试、验证和优化其应用程序的可靠性和稳定性。通过引入故障注入和混沌工程原则&#xff0c;Chaos Mesh可以模拟各种故障场景&#xff0c;如网络延迟、节点故障、磁盘故障等&#…

【spring】学习笔记1:starter和application

https://spring.io/toolsSpring Boot Extension Pack vs版本 使用Spring Tool Suite初始化Spring项目

如何将本地的hexo博客部署到云服务器

云服务器系统&#xff1a;centos 7 本地电脑 mac 第一步&#xff1a; 初始化Hexo博客 npm install hexo-cli -g hexo init HexoBlog 注意node版本需要16以上 cd HexoBlog hexo server访问地址localhost:4000 云服务器执行以下操作 配置的ssh访问用户 useradd git passw…

知网硕士论文稿酬领取方式

目录 知网硕士论文稿酬领取方式: 建议:版税制付酬 版税 知网 学位年度2008年(含2008年)以后的稿酬标准 知网硕士论文稿酬领取方式: 建议:版税制付酬 你怎么能把自己看死了,以后有大用。 中国知网是由清华大学、清华同方发起,始建于1999年6月,是以实现全社会知识…

一文300字从0到1使用Postman轻松搞定文件上传测试!

postman经常用于接口测试&#xff0c;但是上传文件参数还是蛮复杂的&#xff0c;记录下过程 01、上传文件参数 1.选择请求方式 选择post请求方式&#xff0c;输入请求地址 2.填写Headers Key&#xff1a;Content-Type &#xff1b; Value&#xff1a;multipart/form-data …

【数学建模】层次分析法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。前言 – 人工智能教程 在数学建模问题求解中什么时候用到层次分析法 在数学建模问题求解中&#xff0c;层次分析法&#xff08;Analytic…

Python进阶04-网络编程

零、文章目录 Python进阶04-网络编程 1、计算机网络 网络相关知识请参考计算机网络详解 &#xff08;1&#xff09;IP地址的概念 IP 地址就是标识网络中设备的一个地址&#xff0c;好比现实生活中的家庭地址。 &#xff08;2&#xff09;IP地址的表现形式 IP 地址分为两类…

ArcGIS栅格裁剪与合并,制作等高线

1、下载高程数据&#xff08;DEM&#xff09; https://mp.weixin.qq.com/s/ewlUUVV0PwdcspPGtSdCog 项目区域对应的卫片&#xff0c;也可以在谷歌地图里看大致经纬度范围 2、项目区域 确定项目区域&#xff0c;例如某个县区范围 3、栅格裁剪与合并 将DEM多个栅格数据合并&#…

《黑神话:悟空》惊世背后,AI 究竟如何铸就数字人神话?

在游戏的广袤世界中&#xff0c;每一部新作的问世皆如一次扣人心弦的探险之旅。而《黑神话&#xff1a;悟空》的惊艳登场&#xff0c;无疑是一场震撼灵魂的奇幻冒险。它象征着中国游戏产业的一次石破天惊的飞跃&#xff0c;更是 AI 技术在游戏制作领域应用的杰出典范。 AI时代已…

【Pytorch】生成对抗网络实战

GAN框架基于两个模型的竞争&#xff0c;Generator生成器和Discriminator鉴别器。生成器生成假图像&#xff0c;鉴别器则尝试从假图像中识别真实的图像。作为这种竞争的结果&#xff0c;生成器将生成更好看的假图像&#xff0c;而鉴别器将更好地识别它们。 目录 创建数据集 定…

改变潜意识,让梦想照进现实

你是否经常感到困惑&#xff0c;为何努力不得其果&#xff1f;今天我们将一起探索如何通过重新规划潜意识&#xff0c;让你的内心世界和外在行动达到和谐统一&#xff0c;让潜意识成为你坚不可摧的后盾。 想象一下&#xff0c;如果你的潜意识全天候无休止地为你的梦想努力&…

故障电弧探测器在工业与民用建筑电气线路中的设计与应用

安科瑞徐赟杰 【摘要】&#xff1a;电气设备是建筑中不可缺少的一部分&#xff0c;具有较为重要的作用和意义&#xff0c;在应用过程中不仅能够提升建筑本身实用性能&#xff0c;而且可为消费者提供更加优良的生活环境。但设备一旦在运行过程中出现故障&#xff0c;不仅会影响…

合宙低功耗4G模组Air780EQ——硬件设计手册02

Air780EQ是一款基于移芯EC716E平台设计的LTECat1无线通信模组。 支持FDD-LTE/TDD-LTE的4G远距离无线 传输技术。 另外&#xff0c;模组提供了USB/UART/I2C等通用接口满足IoT行业的各种应用诉求。 本文将继续介绍合宙Air780EQ的硬件设计中的 应用接口&#xff0c;射频接口&am…

一分钟学会万用表

目录&#xff1a; 1、电池的安装 1&#xff09;指针万用表 2&#xff09;数字万用表 3&#xff09;高精度表 2、表笔的分类 3、表笔安装 5、常用测量方法 1&#xff09;二极管测量 2&#xff09;电阻与通断测量 3&#xff09;电压测量 4&#xff09;电流测量 …

面对孩子自闭症,我们该怎么办?

当得知孩子被诊断为自闭症时&#xff0c;家长们往往会感到震惊、无助甚至绝望。然而&#xff0c;面对这一挑战&#xff0c;我们需要做的是保持冷静&#xff0c;积极寻找应对策略&#xff0c;为孩子创造一个充满爱与希望的环境。 深入了解自闭症是关键。自闭症是一种复杂的神经发…

八款精品图纸加密软件强力推荐2024年图纸加密软件最佳选择!

在数字化时代&#xff0c;设计图纸的安全问题越来越受到企业的重视。为了保障企业的知识产权和核心竞争力&#xff0c;选择一款合适的图纸加密软件显得尤为重要。以下是2024年八款精品图纸加密软件的强力推荐&#xff0c;它们各具特色&#xff0c;能够满足不同企业的需求。 1.…

视频美颜SDK的核心技术:打造智能化主播美颜工具详解

视频美颜SDK不仅提升了视频质量&#xff0c;还为主播们提供了智能化、个性化的美颜功能。那么&#xff0c;视频美颜SDK的核心技术究竟是什么&#xff1f;又是如何为主播打造智能化美颜工具的呢&#xff1f; 1.人脸检测与特征点识别 视频美颜SDK技术通过深度学习算法&#xff…

H5带建站时长可自定义背景官网/引导页源码

源码名称&#xff1a;带建站时长可自定义背景官网/引导页源码 源码介绍&#xff1a;一款带动态时间显示建站时长的引导页源码&#xff0c;可用于引导页、工作室官网、个人主页等。源码为H5自适应手机端、电脑端。 需求环境&#xff1a;H5 下载地址&#xff1a; https://www.…

nefu暑假集训2 ST表 个人模板+例题汇总

前言&#xff1a; 比较简单的一个算法了&#xff0c;原理相当于是用二进制优化的区间dp了&#xff0c;用于求一个区间的最大或最小值。其实这类问题一般用线段树就可以直接解决&#xff0c;但如果查询次数过多的话可能会超时&#xff0c;这时就是ST表出场的时候了&#xff0c;因…