Java openrasp记录-01

例子1

https://github.com/anbai-inc/javaweb-expression  一个hook ognl、spel、MVEL表达式注入的例子

用的是asm5进行字节码修改

采用premain进行插桩,重写transform方法

expClassList是要hook的类,这里定义在MethodHookDesc

这里判断hook点通过类名,具体其中的方法名,以及方法的描述符

其中expClassList中定义了具体要hook的类,就mvel、ognl、spel三种

 

 匹配到以上三种类后即重写visitMethod方法,匹配具体要hook的方法名和方法描述符,如果匹配到了,则重写MethodVisitor的visitCode方法,进行字节码修改,这里因为是表达式注入,因此这里涉及到string类型的表达式,因此获取传到hook函数处的表达式字符串压入操作数栈,并通过调用expression方法弹出该值进行检测,这里要涉及到操作数栈和局部变量表,因此要清楚原本的方法帧中局部变量表下标索引几代表的是输入的表达式:

ognl:

ognl对应的是parseExpression这个方法,其中expressoin参数是具体解析的表达式

其对应的字节码指令如下所示,Aload0即对应的即为表达式,通过invokeSpecial调用

也可以通过jclasslib来查看

 

spel:

这里的hook点时init方法,这里的expression即为表达式

其init方法中aload1对应赋值时的栈顶元素,所以其为表达式,因此下标对应的是1

 

 

mvel:

这个用的局部变量表的下标也是1,然而实际上取表达式值时用的为下标为0的this来取

 

根据局部变量表中的表达式的值传入expression方法进行处理

 

其中expression将打印出当前的函数调用栈,该例子只是一个插桩+hook方法字节码修改的例子,并没有最终的判断入侵的检测规则

 

例子2

https://toutiao.io/posts/4kt0al/preview 中给了一个例子,也是用asm进行字节码的修改

整体设计分析:

premain方式进行插桩,调用init方法,进一步调用Config.initConfig方法进行初始化配置

此时用到resources/main.config文件,读取其内容,从其格式来看其为json文件,以不同的模块名来区分不同的hook类别

{
	"module":
	[
		{
			"moduleName": "java/lang/ProcessBuilder",
			"loadClass": "xbear.javaopenrasp.visitors.rce.ProcessBuilderVisitor",
			"mode": "block",
			"whiteList":["javac"],
			"blackList": 
			[
			"calc", "etc", "var", "opt", "apache", "bin", "passwd", "login", "cshrc", "profile",
			"ifconfig", "tcpdump", "chmod", "cron", "sudo", "su", "rm", "wget", "sz", "kill", "apt-get",
			"find", "/applications/calculator.app/contents/macos/calculator"
			]
		},
		{
			"moduleName": "java/io/ObjectInputStream",
			"loadClass": "xbear.javaopenrasp.visitors.rce.DeserializationVisitor",
			"mode": "black", 
			"whiteList":[],
			"blackList":
			[
			"org.apache.commons.collections.functors.InvokerTransformer", 
			"org.apache.commons.collections.functors.InstantiateTransformer",
			"org.apache.commons.collections4.functors.InvokerTransformer",
			"org.apache.commons.collections4.functors.InstantiateTransformer",
			"org.codehaus.groovy.runtime.ConvertedClosure",
			"org.codehaus.groovy.runtime.MethodClosure",
			"org.springframework.beans.factory.ObjectFactory"
			]
		},
		{
			"moduleName": "ognl/Ognl",
			"loadClass": "xbear.javaopenrasp.visitors.rce.OgnlVisitor",
			"mode": "black",
			"whiteList":[],
			"blackList": 
			[
			"ognl.OgnlContext", 
			"ognl.TypeConverter",
			"ognl.MemberAccess",
			"_memberAccess",
			"ognl.ClassResolver",
			"java.lang.Runtime",
			"java.lang.Class",
			"java.lang.ClassLoader",
			"java.lang.System",
			"java.lang.ProcessBuilder",
			"java.lang.Object",
			"java.lang.Shutdown",
			"java.io.File",
			"javax.script.ScriptEngineManager",
			"com.opensymphony.xwork2.ActionContext",
			]
		},
		{
			"moduleName": "com/mysql/jdbc/StatementImpl",
			"loadClass": "xbear.javaopenrasp.visitors.sql.MySQLVisitor",
			"mode": "check", 
			"whiteList":[],
			"blackList":[]
		},
		{
			"moduleName": "com/microsoft/jdbc/base/BaseStatement",
			"loadClass": "xbear.javaopenrasp.visitors.sql.SQLServerVisitor",
			"mode": "check", 
			"whiteList":[],
			"blackList":[]
		}
	]
}

接着取到module中的值放入ConcurrentHashmap中,对于每一个moduleName都对应一个ConcurrentHashmap,那么后面运行过程中根据moudlename就能获取到每种hook点的信息

 对于jvm将要加载的类,如果module中包含该类名,则使用asm来进行字节码修改,这里创建ClassVisitor通过Reflections.createVisitorIns方法,因为通常在这里将需要设计具体如何对class进行检查,那么对于不同的需要进行hook的类处理逻辑不同,因此这里是一个分支点,例子1也是相同的。

 

 根据当前的类名得到其相对应的loadclass的类名然后利用反射进行实例化

 

 这里定义了rce和sql两个大类

 

 具体对应的hook的类名和具体的loadclass类名映射关系为:

java/lang/ProcessBuilder -> xbear.javaopenrasp.visitors.rce.ProcessBuilderVisitor   //命令执行
java/io/ObjectInputStream -> xbear.javaopenrasp.visitors.rce.DeserializationVisitor  //反序列化
ognl/Ognl -> xbear.javaopenrasp.visitors.rce.OgnlVisitor //ognl表达式注入
com/mysql/jdbc/StatementImpl -> xbear.javaopenrasp.visitors.sql.MySQLVisitor  //sql注入
com/microsoft/jdbc/base/BaseStatement -> xbear.javaopenrasp.visitors.sql.SQLServerVisitor  //sql注入

从大体上整个插桩过程分析结束,初始化的主要工作还是对各种hook点如何进行初始配置,方便后面hook进行中的具体细化操作。

hook点处理分析:

命令执行hook点:

java中命令执行一般常用的有两种,Runtime.exec和Processbuilder.start,但是Runtime.exec实际上也是利用的Processbuilder,而Processbuilder最终利用的是ProcessImpl来执行命令,那么实际上这里选择hook点,选择Processbuilder的start即可,因为只要执行命令,都将走到该类的start方法,在这里就能拿到具体要执行的命令。

具体的逻辑如下,这里重写了onMethodEnter方法,asm5中的,即进入start内部之前执行

    @Override
    protected void onMethodEnter() {
        mv.visitTypeInsn(NEW,
                "xbear/javaopenrasp/filters/rce/PrcessBuilderFilter"); //new一个命令执行过滤的对象压入栈
        mv.visitInsn(DUP); //再次压入该对象
        mv.visitMethodInsn(INVOKESPECIAL, 
                "xbear/javaopenrasp/filters/rce/PrcessBuilderFilter", "<init>", "()V", false); //弹出对象进行初始化,此时栈中大小为2-1=1
        mv.visitVarInsn(ASTORE, 1); //弹出存储该对象到局部变量表1处,此时栈的大小为1-1=0
        mv.visitVarInsn(ALOAD, 1);  //加载局部变量表1处的对象压入栈,此时栈的大小为0+1=1
        mv.visitVarInsn(ALOAD, 0); //加载this压入栈,此时栈大小为1+1=2
        mv.visitFieldInsn(GETFIELD, 
                "java/lang/ProcessBuilder", "command", "Ljava/util/List;"); //取this.command的值压入栈,栈大小为2
        mv.visitMethodInsn(INVOKEVIRTUAL,
                "xbear/javaopenrasp/filters/rce/PrcessBuilderFilter", "filter", //调用filer方法,弹出的值的数量为filter的方法参数大小1+1=2,栈顶的this.command的值作为参数,并将filter
方法的处理结果压入栈中,filter返回一个Boolean值,此时栈中大小为1
                "(Ljava/lang/Object;)Z", false);

        Label l92 = new Label();  //new一个label用来跳转
        mv.visitJumpInsn(IFNE, l92); //此时弹出filter处理的结果和0进行比较,如果不等与0,则跳到192lable,说明执行的当前的命令可以执行,则正常执行start方法,否则执行下一条指令,栈大小为0
        mv.visitTypeInsn(NEW, "java/io/IOException"); //new 一个io异常对象
        mv.visitInsn(DUP); //再次压入该对象,栈大小2
        mv.visitLdcInsn("invalid character in command because of security"); //压入该字符串,栈大小3
        mv.visitMethodInsn(INVOKESPECIAL,
                "java/io/IOException", "<init>", "(Ljava/lang/String;)V", false); //弹出1+1=2个值,初始化该异常对象,栈顶元素作为io异常的初始化参数,此时栈大小为1
        mv.visitInsn(ATHROW); //抛出该异常
        mv.visitLabel(l92);

    }

先看start方法部分如下:

这里如果直接用asm字节码指令来写就要结合源码和bytecode字节码指令来写,可以看到0处放入的即为this,最终command.toArray的结果放到局部变量表1处,上面写指令码的时候也ASTORE_1了一次,这里并不一定直到1处是否有值,但是指令码这里直接ASTORE1,因此我们不需要担心1处是否有值

 

这样就完成了hook点的构造,取command的值调用filter进行过滤,命令执行的filter如下所示:

    public boolean filter(Object forCheck) {
        String moduleName = "java/lang/ProcessBuilder"; 
        List<String> commandList = (List<String>) forCheck;
        String command = StringUtils.join(commandList, " ").trim().toLowerCase();
        Console.log("即将执行命令:" + command);
        String mode = (String) Config.moduleMap.get(moduleName).get("mode"); //取对应的命令执行逻辑,mode为block,即阻断
        switch (mode) { 
            case "block":
                Console.log("> 阻止执行命令:" + command);
                return false;  //如果直接为block,那么所有命令都执行不了,也可以更改模式,用黑白名单过滤
            case "white":
                if (Config.isWhite(moduleName, command)) {
                    Console.log("> 允许执行命令:" + command);
                    return true;
                }
                Console.log("> 阻止执行命令:" + command);
                return false;
            case "black":
                if (Config.isBlack(moduleName, command)) {
                    Console.log("> 阻止执行命令:" + command);
                    return false;
                }
                Console.log("> 允许执行命令:" + command);
                return true;
            case "log":
            default:
                Console.log("> 允许执行命令:" + command);
                Console.log("> 输出打印调用栈\r\n" + StackTrace.getStackTrace());
                return true;
        }
    }

 asm感觉还是挺麻烦的,语句越复杂要用到的指令越多,稍微不熟练就会出错

反序列化hook点:

在java.io.ObjectInputStream处进行hook,这里定义了一些反序列化的黑名单

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
                                     String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
        if ("resolveClass".equals(name) && "(Ljava/io/ObjectStreamClass;)Ljava/lang/Class;".equals(desc)) {
            mv = new DeserializationVisitorAdapter(mv, access, name, desc);
        }
        return mv;
    }

为什么选择resolveClass作为hook的方法?只要记住我们的目的是拿到将要反序列化的类名,那么实际上的反序列化过程中resolveClass的代码如下:

    protected Class<?> resolveClass(ObjectStreamClass desc)
        throws IOException, ClassNotFoundException
    {
        String name = desc.getName();
        try {
            return Class.forName(name, false, latestUserDefinedLoader());
        } catch (ClassNotFoundException ex) {
            Class<?> cl = primClasses.get(name);
            if (cl != null) {
                return cl;
            } else {
                throw ex;
            }
        }
    }

入口参数是ObjectStreamClass,那么在序列化过程中生成的序列化数据的过程中调用该类的lookup方法将生成类的描述信息,其中就包括的类名和SUID,那么调用该类的getName实际上就能拿到反序列化类的名字,所以只需拿到类描述符即可,从resolveClass的逻辑中将以类名通过反射进行类的加载获取反序列化类的class对象,以CommonsCollections2为例,涉及到PriorityQueue和InvokerTrasnformer和TransformingComparator,那么肯定要涉及到这两个类的反序列化

 比如如下图所示就能拿到反序列化的类名,然后再与黑名单进行匹配即可

对应的hook逻辑如下:

 @Override
    protected void onMethodEnter() {
        mv.visitTypeInsn(NEW, "xbear/javaopenrasp/filters/rce/DeserializationFilter"); //new一个反序列化过滤对象压入栈,栈大小1
        mv.visitInsn(DUP); //再次压入该对象,栈大小为2
        mv.visitMethodInsn(INVOKESPECIAL, "xbear/javaopenrasp/filters/rce/DeserializationFilter", "<init>", "()V", false); //弹出一个对象进行实例化,栈大小为1
        mv.visitVarInsn(ASTORE, 2); //存储该对象到局部变量表,栈大小为0
        mv.visitVarInsn(ALOAD, 2); //取出该对象到栈,栈大小为1
        mv.visitVarInsn(ALOAD, 1); //这里要涉及到取局部变量表的值, 所以又得去看该方法的字节码指令,取到的即为desc,压入操作数栈,栈大小为1+1=2
        mv.visitMethodInsn(INVOKEVIRTUAL, "xbear/javaopenrasp/filters/rce/DeserializationFilterr", "filter", "(Ljava/lang/Object;)Z", false); //调用反序列化过滤方法,弹出1+1=2个值,栈顶的desc作为参数

        Label l92 = new Label(); //new一个label
        mv.visitJumpInsn(IFNE, l92); //过滤的返回值和0比
        mv.visitTypeInsn(NEW, "java/io/IOException"); //如果等于0,则new一个异常对象
        mv.visitInsn(DUP); //再次压入
        mv.visitLdcInsn("invalid class in deserialization because of security"); //错误信息压栈
        mv.visitMethodInsn(INVOKESPECIAL, "java/io/IOException", "<init>", "(Ljava/lang/String;)V", false); //实例化异常
        mv.visitInsn(ATHROW); //抛出异常
        mv.visitLabel(l92); //不等于0,则说明反序列化的类不在黑名单中,进行正常反序列化过程

    }

从下图可以看到aload1,然后调用栈顶元素的getname方法,并把结果压入栈中,所以desc类描述符是在该方法的局部变量表1处存着,并且2处不管之前放什么元素,这里将被类名进行覆盖

 

在对应的过滤方法中再通过类描述符调用getName拿到类名,然后通过对应的mode为black,因此

 

 接着只要拿到预先配置好的黑名单来进行过滤即可

 

ognl的hook点:

hook的是ognl.Ognl的parseExpression这个方法,和第一个例子选择的hook点是相同的,因为该方法就能拿到要执行的表达式

那么对于对应的class文件直接看该方法的局部变量表就能看到表达式再局部变量表的0处,因此只要将该值传入过滤函数即可

 

 对应的hook处的逻辑:

    protected void onMethodEnter() {

        Label l30 = new Label(); //new一个label
        mv.visitLabel(l30); //访问该label(貌似没有意义)
        mv.visitVarInsn(ALOAD, 0); //加载局部表量表0处的表达式值到栈
        mv.visitMethodInsn(INVOKESTATIC, "xbear/javaopenrasp/filters/rce/OgnlFilter", "staticFilter", "(Ljava/lang/Object;)Z", false);//调用过滤函数,传入表达式的值,因为是static方法,所以只需要提供入口参数即可
        Label l31 = new Label(); //new一个label
        mv.visitJumpInsn(IFNE, l31); //如果过滤表达式不为0,则表达式正常执行
        Label l32 = new Label(); //new label,貌似没有
        mv.visitLabel(l32);
        mv.visitTypeInsn(NEW, "ognl/OgnlException"); //new一个异常对象
        mv.visitInsn(DUP); //再次压栈
        mv.visitLdcInsn("invalid class in ognl expression because of security"); //异常信息压栈
        mv.visitMethodInsn(INVOKESPECIAL, "ognl/OgnlException", "<init>", "(Ljava/lang/String;)V", false); //传入异常信息进行异常对象初始化
        mv.visitInsn(ATHROW); //抛出异常
        mv.visitLabel(l31);
    }

RASP绕过

1.多种姿势openrasp命令执行绕过-安全客 - 安全资讯平台

第一种是根据线程中rce,绕过了rasp对context url的判断,没有url则直接返回正常

第二种直接关掉了rasp的开关

两种措施都必须有代码执行的权限,也就是说必须有shell的前提下

2.de1ctf中的一道绕rasp的思路,思路虽然在园长的javaseccode中提到过,defineclass来绕过rasp检测,但是这种类的确不好找?

LandGrey's Blog

关于springboot为何能绕过rasp,首先defineclass,然后addclass说明已经添加到jvm中,然后class.forname再反射拿到该类时会进行类的链接从而执行static静态区的代码,不需要再重新loadclass

此时classforname时native方法直接加载加载该类,因此绕过了rasp对类加载机制的拦截

 

rasp的用途

1.代码审计

可以对一些漏洞,比如反序列化,ognl、spel等的关键函数处进行hook并记录,然后可以输出成类似日志的格式,结合其调用栈以及其入口参数提供给白盒代码审计工具进行自动化审计

2.0day捕获

对一些危险函数进行hook,并在执行时及时告警,比如Runtime.exec,Processs,但是个人感觉这样效率可能有点低,不如交给ids进行捕获效率更高

3.DevOps

因为进行hook时,asm中提供了大量有用的方法从而能够获得hook点处详细的信息:调用栈、代码行号、接口、父类等

rasp的缺陷

1.首先rasp拦截是侵入程序代码内部的,那么它实际上是和具体的语言强相关的,因此不同语言之间并不通用,需针对不同语言的特性进行开发

2.rasp是对关键函数进行hook,那么意味着无论攻击路径从哪条路走,最终都将汇集于某一个点,因此高效率的拦截要求设计rasp的hook规则时,开发者本身即必须对各种漏洞的利用方式以及一些关键函数点熟悉,因此存在遗漏的可能。

甲方如何应用rasp

1.直接根据开源的openrasp来进行二次开发,针对企业具体应用进行适配

问题:推广周期长,运维难度大,以及要保证现有的业务在布置rasp后仍旧能够正常运行,有一定的风险

2.在现有的APM程序上(cat,wiseapm)进行修改,弥补推广的周期,在稳定性也有一定的保证,只需要将rasp的一些想法加入到APM程序中,企业快速实践部署IAST/RASP的一种新思路 - FreeBuf网络安全行业门户这篇文章中介绍到平安银行是利用cat搜集的一些信息进行输出进行审计,比如apm本身就自带一些监控sql语句执行的功能

结合扫描器

如果能够得到具体的hook日志,则可以

1.流量设置标志位,对所有测试流量加某种标志位,如果hook的某个点有标志位进入,则认为该处可能存在漏洞(存在拼接且有入口)(例如sql注入,程序内部也可能有很多sql执行,这样能筛选出外部输入)

2.黑名单检测,检测hook点处函数入参是否在黑名单内,比如反序列化gadget的关键sink的黑名单或者sql注入的一些payload的黑名单(规则可以参考waf),sql注入还可以判断单引号的个数

3.判断request url中的参数和hook点处的参数是否相同,相同则为存在安全漏洞,hook点处的value是否包含一些敏感字符,比如sql注入的反斜杠 空格等关键payload

rasp和应用引入的第三方jar包之间版本问题

本地测试:

premain方式插桩,rasp引入fastjsonj1.2.48,应用引入fastjson1.2.47,使用1.2.47通杀payload进行尝试:

a.插桩之前:

b.插桩之后:

直接报autotype not support,说明此时理论上应用在使用fastjson时自动使用了rasp的1.2.48版本的fastjson

列出的jvm进程id来看,agent并非以独立进程运行,而是和应用统一jvm进程,用的同一个jvm虚拟机,那么类加载器都用的同一套,因此实际上类加载时,肯定不存在冲突问题,相同的类只会加载一次,此时主要就是看不同版本是加载哪里的,如下图所示:

此时可以看到应用在使用fastjson时将加载rasp指定目录下的fastjson,难道并不是智能地选择高版本????此时控制变量,改变rasp引入的fastjson为1.2.47,应用使用1.2.48,效果如下:

弹了。。。

因此结论为:

如果rasp中引入的第三方jar包的版本和应用引入的第三方jar包版本不同,此时应用在使用jar包时将优先加载rasp引入的对应版本的jar包。

参考

http://blog.nsfocus./rasp-tech/  已看

浅谈RASP技术攻防之基础篇 - FreeBuf网络安全行业门户 已看

https://www.03sec.com/3239.shtml 例子

https://toutiao.io/posts/4kt0al/preview 例子

https://paper.seebug.org/1041/

https://www.cnblogs.com/2014asm/p/10834818.html  有例子

Java RASP浅析--以百度OpenRASP为例 | c0d3p1ut0s  讲openrasp

多种姿势openrasp命令执行绕过-安全客 - 安全资讯平台 rasp绕过

OpenRASP梳理总结 - FreeBuf网络安全行业门户  openrasp梳理

OpenRASP 初探(二)之项目部署_openrasp部署-CSDN博客

IAST原理分析以及在SDL中的应用 - FreeBuf网络安全行业门户  rasp的应用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kafka 3.x.x 入门到精通(03)——对标尚硅谷Kafka教程

Kafka 3.x.x 入门到精通&#xff08;03&#xff09;——对标尚硅谷Kafka教程 2. Kafka基础2.1 集群部署2.2 集群启动2.3 创建主题2.4 生产消息2.4.1 生产消息的基本步骤2.4.2 生产消息的基本代码2.4.3 发送消息2.4.3.1 拦截器2.4.3.1.1 增加拦截器类2.4.3.1.2 配置拦截器 2.4.3…

RDD编程初级实践

参考链接 spark入门实战系列--8MLlib spark 实战_mob6454cc68310b的技术博客_51CTO博客https://blog.51cto.com/u_16099212/7454034 Spark和Hadoop的安装-CSDN博客https://blog.csdn.net/weixin_64066303/article/details/138021948?spm1001.2014.3001.5501 1. spark-shell…

JAVAEE—HTTPS和ssl证书

0[toc] 什么是HTTPS HTTPS 也是一个应用层协议. 是在 HTTP 协议的基础上引入了一个加密层. HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现一些被篡改的情况而HTTPS则是新采用加密的方式进行传输 为什么需要HTTPS 为什么要使用HTTPS呢&#xff1f;这…

【SpringCloud】LoadBalance负载均衡服务调用快速入门

【SpringCloud】LoadBalance负载均衡服务调用快速入门 文章目录 【SpringCloud】LoadBalance负载均衡服务调用快速入门1. 概述2. 引入依赖3. 配置、验证3.1 配置3.2 验证 1. 概述 官网地址&#xff1a;点击跳转 Spring Cloud LoadBalancer 是由 SpringCloud 官方提供的一个开…

2024高级卫生职称考试报名时间汇总

20地报名时间汇总&#xff0c;其他时间安排见图 上海&#xff1a;4.23-5.24 黑龙江&#xff1a;4.23-5.24 陕西&#xff1a;4.23-5.24 重庆&#xff1a;4.23-5.24 浙江&#xff1a;4.23-5.24 20地报名时间汇总 甘肃&#xff1a;4.23-5.24 江西&#xff1a;4.28-5.10 河北&#…

五一劳动节活动策划案怎么写?

分享一个五一劳动节活动策划万能模板&#xff0c;直接照着写就好。 一、活动主题&#xff1a; 五一户外露营Party 二、活动时间&#xff1a; 五一节当天&#xff0c;上午点至下午点 三、活动地点&#xff1a; 城市郊外的公园或大型绿地 四、参与人员&#xff1a; 公司员…

ChatGPT付费创作系统V2.8.4独立版 WEB+H5+小程序端 (新增Pika视频+短信宝+DALL-E-3+Midjourney接口)

小狐狸GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序&#xff0c;是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。当前全民热议ChatGPT&#xff0c;流量超级大&#xff0c;引流不要太简单&#xff01;一键下单即可拥有自己的GPT&#xff01;无限多…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别 一、简单介绍 二、简单进行人脸训练与识别 1、LBPH…

政安晨:【Keras机器学习示例演绎】(十六)—— 用于图像分类的混合增强

目录 简介 设置 准备数据集 定义超参数 将数据转换为 TensorFlow 数据集对象 定义混合技术函数 可视化新的增强数据集 模型制作 1.使用混合数据集训练模型 2.在没有混合数据集的情况下训练模型 说明 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评…

BGP的基本配置

l 按照以下步骤配置BGP协议&#xff1a; 第1步&#xff1a;设备基本参数配置&#xff0c;AS内配置IGP确保内部网络连通性&#xff1b; l 配置IGP&#xff08;OSPF协议等&#xff09;路由解决peer对等体的源和目标IP之间连通性&#xff0c;确保peer之间TCP&#xff08;179&a…

SpringBoot学习之Redis下载安装启动【Mac版本】(三十七)

一、下载Redis 1、下载地址:Downloads - Redis 往下滑,找到Downloads区域,这里有若干版本,这里我们选择了7.0的稳定版本 2、我们下载的是redis-7.0.15.tar.gz,这是一个压缩包,我们双击解压这个压缩包,可以得到如下文件 二、安装Redis 1、我们进入redis根目录安装mak…

IDEA使用技巧(常用设置、快捷键等)

IDEA使用技巧 一、IDEA常用基本设置设置代码背景颜色/主题/字体Ctrl鼠标滚轮缩放字体大小设置字符编码左右两侧的Project&#xff0c;Structure&#xff0c;Maven等按钮消失新增类似sout,psvm的模版切换某个模块编译的JDK版本 二、常用快捷键CtrlAltT包裹代码Alt回车联想补全Ct…

Qt : 禁用控件默认的鼠标滚轮事件

最近在写一个模拟器&#xff0c;在item中添加了很多的控件&#xff0c;这些控件默认是支持鼠标滚动事件的。在数据量特别大的时候&#xff0c;及容易不小心就把数据给修改了而不自知。所有&#xff0c;我们这里需要禁用掉这些控件的鼠标滚轮事件。 实现的思想很简单&#xff0c…

数据结构篇其二---单链表(C语言+超万字解析)

目录 前言&#xff1a; 一、顺序表的缺点和链表的引入。 二、链表概述 实现一个简单的链表 空链表的概念 三、链表的功能实现 链表的打印 链表节点的创建 链表的头插&#xff08;自上而下看完分析&#xff0c;相信你会有所收获&#xff09; 头插的前置分析 传值调用和…

一、路由基础

1.路由协议的优先级 路由器分别定义了外部优先级和内部优先级&#xff08;越小越优&#xff09; 路由选择顺序&#xff1a;外部优先级>>内部优先级&#xff08;相同时&#xff09; ①外部优先级&#xff1a;用户可以手工为各路由协议配置的优先级 ②内部优先级&#xf…

汽车信息安全--如何理解TrustZone(2)

目录 1.概述 2 如何切换安全状态 3 TrustZone里实现了什么功能&#xff1f; 4. 与HSM的比较 1.概述 汽车信息安全--如何理解TrustZone(1)-CSDN博客讲解了什么是Trustzone&#xff0c;下面我们继续讲解与HSM的区别。 2 如何切换安全状态 在引入安全扩展后&#xff0c;Arm…

太速科技-多路PCIe的阵列计算全国产化服务器

多路PCIe的阵列计算全国产化服务器 多路PCIe的阵列计算全国产化服务器以国产化处理器&#xff08;海光、飞腾ARM、算能RSIC V&#xff09;为主板&#xff0c;扩展6-8路PCIe3.0X4计算卡&#xff1b; 计算卡为全国产化的AI处理卡&#xff08;瑞星微ARM&#xff0c;算能AI&#x…

MMSeg搭建模型的坑

Input type(torch.suda.FloatTensor) and weight type (torch.FloatTensor) should be same 自己搭建模型的时候&#xff0c;经常会遇到二者不匹配&#xff0c;以这种情况为例&#xff0c;是因为部分模型没有加载到CUDA上面造成的。 注意搭建模型的时候&#xff0c;所有层都应…

Oracle之RMAN联机和脱机备份(二)

rman脱机备份,首先使用rman登入数据库服务器,然后关闭数据库后,启动数据库到mount状态,在执行backup database指定备份整个数据库。 1、启动mount归档模式 sys@ORCL>archive log list; Database log mode Archive Mode Automatic archival Enabl…

STM32H750外设ADC之开始和结束数据转换功能

目录 概述 1 开始转换 1.1 使能ADSTART 1.2 使能JADSTART 1.3 ADSTART 通过硬件清零 2 转换时序 3 停止正在进行的转换&#xff08; ADSTP、 JADSTP&#xff09; 3.1 停止转换功能实现 3.2 停止转换流程图 概述 本文主要讲述了STM32H750外设ADC之开始和结束数据转换…