【安全攻防】网络安全中的序列化与反序列

1.序列化与反序列化

首先要了解序列化与反序列化的定义,以及序列化反序列化所用到的基本函数。

序列化:把对象转换为字节序列的过程称为对象的序列化,相当于游戏中的存档。

PHP中的序列化函数serialize()

**serialize()**函数用于序列化对象数组,并返回一个字符串。serialize()函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变

语法string serialize ( mixed $value )
参数说明$value: 要序列化的对象或数组。
返回值返回一个字符串。

示例:

<?php
highlight_file(__FILE__);
$sites=array('I', 'Like', 'PHP');
echo'<br/>';
var_dump(serialize($sites));    //把这个对象进行序列化
echo'<br/>';
​
classman{
public$name="xiaocui";
public$sex="man";
private$age=26;
}
$M=newman();//创建一个对象
var_dump(serialize($M)); //把这个对象进行序列化
​
?>

输出结果为:

string(47) "a:3:{i:0;s:1:"I";i:1;s:4:"Like";i:2;s:3:"PHP";}"
string(79) "O:3:"man":3:{s:4:"name";s:7:"xiaocui";s:3:"sex";s:3:"man";s:8:"manage";i:26;}"

参数说明:

数组的序列化:
a 代表一数组  
3 代表数组中有3个元素
i 代表数组的下标
0 代表I元素的下标值
s 代表元素I的数据类型为字符型
1 代表元素I的长度为1
对象的序列化:
O 代表是一个对象
3 代表类名man的长度
3 代表类中的字段数
s 代表属性name的类型为字符型
4 代表属性name的长度//后面的以此类推,序列化字符串中字段内容以{开始,;}结束

反序列化:把字节序列恢复为对象的过程称为对象的反序列化,相当于游戏中的读档。

【一一帮助安全学习,所有资源获取处一一】
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥信息收集80条搜索语法
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

PHP中的反序列化函数unserialize()

**unserialize()**函数用于将序列化后的字符串在还原为原来的数组或对象的过程。**unserialize()**函数可以快速将序列化的字符串还原出来,用来完成它本来的功能。

语法mixed unserialize ( string $str )
参数说明$str: 序列化后的字符串。
返回值返回的是转换之后的值,可为 integer、float、string、array 或 object。不可反序列化时返回FALSE,并抛出提醒。

示例代码:

<?php
highlight_file(__FILE__);
$sites=array('I', 'Like', 'PHP');
echo'<br/>';
echo$ser=serialize($sites).'<br/>';    //把这个对象进行序列化
var_dump(unserialize($ser)); //把序列化的字符串进行反序列化
echo'<br/>';
classman{
public$name="xiaocui";
public$sex="man";
private$age=26;
}
$M=newman();//创建一个对象
echo$ser=serialize($M).'<br/>'; //把这个对象进行序列化
var_dump(unserialize($ser));   //把序列化的字符串进行反序列化
​
?>

输出结果为:

a:3:{i:0;s:1:"I";i:1;s:4:"Like";i:2;s:3:"PHP";}
array(3) { [0]=>string(1) "I"[1]=>string(4) "Like"[2]=>string(3) "PHP"}
​
O:3:"man":3:{s:4:"name";s:7:"xiaocui";s:3:"sex";s:3:"man";s:8:"manage";i:26;}
object(man)#2 (3) { ["name"]=> string(7) "xiaocui" ["sex"]=> string(3) "man" ["age":"man":private]=> int(26) } 

可以看出上述反序列化后的数组或对象,与原数据没有任何变化。

序列化与反序列化在系统中的作用

①把对象的字节序列永久放在磁盘中,需要时可以随时调用,大大节省磁盘占用空间。

②在传输过程中可以直接传输字节序列,而不是对象,这可以大大提高传输速率。

在业务系统中,需要对一些对象进行序列化存储,让他们离开内存空间,存放在一个文件中,以便持久化保存。例如:在用户注册并登录系统时,会将用户信息如用户名,密码,cookie等信息先通过序列化存储起来,当用户再次登录时将序列化后的字节序列通过反序列化成原对象到内存进行使用,可以大大节省内存开销。

2.魔术方法

PHP将所有以__(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以__为前缀。

PHP中常见魔术方法

__construct()

具有 __construct函数的类会在每次创建新对象时先调用此方法,适合在使用对象之前做一些初始化工作。

代码示例:

<?php
highlight_file(__FILE__);
classdemo{
public$name="xiaocui";
public$sex="man";
private$age=26;
publicfunction__construct()
{
echo"<br/>"."类被实例化时调用我!";
}
}
$D=newdemo();   //实例化对象
​
?>

输出结果:

类被实例化时调用我!

__destruct()

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

代码示例:

<?php
highlight_file(__FILE__);
class demo{
public $name="xiaocui";
public $sex="man";
private $age=26;
public function __construct()
{
echo "<br/>"."类被实例化时调用我!"."<br/>";
}
public function num($a,$b){
echo $c = $a + $b.'<br/>';
return $c;
}
public function __destruct(){
echo "当类中的所有方法都被销毁时调用我!";
}
public function person($per){
echo "We are $per !!!".'<br/>';
}
}
$D=new demo();   //实例化对象
$D->num(5,6);   //调用num()方法
$D->person(man);  //调用person()方法
?>

输出结果:

类被实例化时调用我!
11
Weareman!!!
当类中的所有方法都被销毁时调用我!

上述输出结果可以很直观的看到代码的执行顺序:__construct()=>num(5,6)=>person(nanren)=>__destruct()

实例化对象时首先要执行构造方法__construct(),然后接着执行类中的实例num()person(),当所有方法都执行完成销毁时,最后调用析构方法__destruct()

__wakeup()

在使用unserialize()时,会检查是否存在一个__wakeup()魔术方法。如果存在,则该方法会先被调用,预先准备对象需要的资源。

代码示例:

<?php
highlight_file(__FILE__);
classdemo{
public$name="xiaocui";
protected$sex="man";
private$age=26;
publicfunction__construct()
{
echo"<br/>"."类被实例化时调用我!"."<br/>";
}
publicfunction__destruct(){
echo"<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";
}
publicfunction__wakeup()
{
echo"<br/>"."当反序列时首先调用我 !".'<br/>';
}
}
$D=newdemo();   //实例化对象
echo$ser=serialize($D);      //序列化对象$D
var_dump(unserialize($ser));    //反序列化字符串$ser
​
?>

输出结果:

由于$age为私有属性,在序列化时会在前后加空白字符%00,原本的字符长度为7,而在两侧加入空白字符则字符长度就会变为9

类被实例化时调用我!
O:4:"demo":3:{s:4:"name";s:7:"xiaocui";s:6:"*sex";s:3:"man";s:9:"demoage";i:26;}
当反序列时调用我 !
object(demo)#2(3) { ["name"]=> string(7) "xiaocui" ["sex":protected]=> 
string(3) "man" ["age":"demo":private]=> int(26) }
当类中的所有方法都被销毁时调用我!
​
当类中的所有方法都被销毁时调用我!

上述输出结果可以很直观的看到代码的执行顺序:__construct()=>serialize($D)=>__wakeup()=>unserialize($ser)=>__destruct()=>__destruct()

实例化对象时首先要执行构造方法__construct(),然后执行序列化serialize($D),然后再反序列化之前要执行__wakeup()方法,然后执行反序列化unserialize($ser),当所有方法都执行完成销毁时最后执行__destruct()析构方法,由于反序列化后将原来的序列化字符串还原又执行一次__destruct()

__toString()

__toString()方法用于定义一个类被当成字符串时该如何处理。

示例代码:

<?php
highlight_file(__FILE__);
class demo{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function __wakeup(){echo "<br/>"."当反序列时调用我 !".'<br/>';}public function __toString(){return "<br/>"."类被当成字符串处理时调用我!"."<br/>";}
}
$D=new demo();   //实例化对象
echo $D;   //类被当成字符串输出?>

输出结果:

类被实例化时调用我!
​
类被当成字符串处理时调用我!
​
当类中的所有方法都被销毁时调用我!

上述输出结果可以看到,当类被当成字符串echo时,__toString()方法被调用并执行。

如果该类中没有__toString()方法,进行echo输出时,PHP会抛出致命性错误,错误如下:

Catchablefatalerror: ObjectofclassdemocouldnotbeconvertedtostringinD:\XXXX\phpstudy_pro\WWW\two\demo.phponline30

__sleep()

在使用serialize()函数时,程序会检查类中是否存在一个__sleep()魔术方法。如果存在,则该方法会先被调用,然后再执行序列化操作。

__sleep()方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,该函数就起到了很好的清理作用。

示例代码:

<?php
highlight_file(__FILE__);
class demo{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function __wakeup(){echo "<br/>"."当反序列时调用我 !".'<br/>';}public function __sleep(){echo "<br/>"."当序列时调用我 !".'<br/>';return array("name","sex","age");    //这里必须返回一个数值,里边的元素表示返回的属性名称}}
$D=new demo();   //实例化对象echo $ser = serialize($D);  //序列化对象?>

输出结果:

类被实例化时调用我!
当序列时调用我!
O:4:"demo":3:{s:4:"name";s:7:"xiaocui";s:6:"*sex";s:3:"man";s:9:"demoage";i:26;}
当类中的所有方法都被销毁时调用我!

上述输出结果可以看到,当类被序列化时首先调用了__sleep()方法,该函数必须返回一个数值。如果该函数没有返回属性的话,序列化时会将属性清空。

__invoke()

当尝试以调用函数的方式调用一个对象时,__invoke方法会被自动调用。(本特性只在 PHP 5.3.0 及以上版本有效。)

代码示例:

<?php
highlight_file(__FILE__);
class demo{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function __wakeup(){echo "<br/>"."当反序列化时调用我 !".'<br/>';}public function __sleep(){echo "<br/>"."当序列化时调用我 !".'<br/>';return array("name","sex","age");}public function __invoke(){echo "<br/>"."当以函数的方式调用对象时会调用我!".'<br/>';}}
$D=new demo();   //实例化对象$D();    //以函数的方式调用对象
?>

结果输出:

类被实例化时调用我!
​
当以函数的方式调用对象时会调用我!
​
当类中的所有方法都被销毁时调用我!

上述结果可以看到当使用函数的方法调用对象时,就会调用__invoke()方法.

如果没有类中没有该方法,那么PHP会报出致命性错误,如下:

Fatalerror:UncaughtError: 
FunctionnamemustbeastringinD:\xxxxx\phpstudy_pro\WWW\two\demo.php:42Stacktrace:#0 {main} thrown in D:\xxxxx\phpstudy_pro\WWW\two\demo.php on line 42

__call()

在对象中调用一个不存在或者不可访问方法时,__call会被调用。

代码示例:

<?php
highlight_file(__FILE__);
class demo{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function num($a,$b){echo "<br/>".$c = $a + $b.'<br/>';return $c;}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function person($per){echo "<br/>"."We are $per !!!".'<br/>';}public function __wakeup(){echo "<br/>"."当反序列化时调用我 !".'<br/>';}public function __sleep(){echo "<br/>"."当序列时调用我 !".'<br/>';return array("name","sex","age");}public function __call($arg1,$arg2){echo  "<br/>"."当对象调用一个不存在或者不可访问的方法时调用我!".'<br/>';}}
$D=new demo();   //实例化对象
$D->num1(1,2);   //调用一个不存在的方法
?>

结果输出:

类被实例化时调用我!
​
当对象调用一个不存在或者不可访问的方法时调用我!
​
当类中的所有方法都被销毁时调用我!

__set()

给不可访问属性赋值时,__set会被调用。

代码示例:

<?php
highlight_file(__FILE__);
class demo extends demo1{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function person($per){echo "<br/>"."We are $per !!!".'<br/>';}public function __set($arg1,$arg2){echo "<br/>"."当给不存在或者不可访问的属性赋值时调用我!"."<br/>";}
}class demo1{private $weight;public  $height;public function people(){echo $this->weight;echo $this->height;}
}$D=new demo();   //实例化对象
$D->weight=74; //给不可访问的属性赋值
?>

输出结果:

类被实例化时调用我!
当给不存在或者不可访问的属性赋值时调用我!
当类中的所有方法都被销毁时调用我!

__isset()

对不可访问属性调用isset()empty()时,__iset()会被调用。

__unset()

对不可访问属性调用unset()时,__unset()会被调用。

__get()

读取不可访问属性的值时,__get会被调用。

代码示例:

<?php
highlight_file(__FILE__);
class demo extends demo1{public $name="xiaocui";protected $sex="man";private $age=26;public function __construct(){echo "<br/>"."类被实例化时调用我!"."<br/>";}public function __destruct(){echo "<br/>"."当类中的所有方法都被销毁时调用我!"."<br/>";}public function __get($arg1){echo "<br/>"."读取不存在或不可访问的属性时调用我!";}
}class demo1{private $weight = 0;public  $height;public function people(){echo $this->weight;echo $this->height;}
}$D=new demo();   //实例化对象$D->weight;   //读取父类中不可访问的属性
?>

输出结果:

类被实例化时调用我!
读取不存在或不可访问的属性时调用我!
当类中的所有方法都被销毁时调用我!

3.反序列化漏洞

3.1 反序列化漏洞利用条件

① unserialize()函数中参数可控
② 存在可利用的类,且类中有魔术方法

代码示例1:

<?php
highlight_file(__FILE__);class demo
{public $arg1 = "0";public function __destruct(){echo $this->arg1;  //输出用户传递的arg1值}}$a=$_GET['arg'];     //接收前端传递的arg1变量
$unser = unserialize($a);    //反序列化传递的arg1
?>

上述的代码满足反序列化漏洞的两个条件,arg参数可控,也就是unserialize()函数的参数可控;存在可利用的类demo,且demo类中有可利用的魔术方法__destruct(),然而__destruct()魔术方法中使用echo输出变量了arg

通过arg参数,构造序列化字符串,通过unserialize()函数进行反序列化,最后通过__destruct()魔术方法输出变量,造成XSS

image.png

1656063927_62b587b782d1ce26d9662.png

示例代码2

<?php
highlight_file(__FILE__);class demo
{public $arg1 = "0";public function __destruct(){eval($this->arg1);  //eval()去执行用户传递的arg1值}}$a=$_GET['arg'];     //接收前端传递的arg1变量
$unser = unserialize($a);    //反序列化传递的arg1
var_dump($unser);
?>

如果魔术方法中存在eval(),且参数可控,那么通过构造序列化字符串,通过反序列化漏洞造成RCE

1656063978_62b587ea396a1888f7509.png

3.2 __wakeup()函数绕过

在序列化时传递对象的属性大于实际对象的属性时,__wakeup()魔术方法将不会被执行,从而导致绕过。

PHP版本<=5.6.25或者PHP版本<=7.0.11

示例代码:

<?php
highlight_file(__FILE__);class demo
{public $arg1 = "0";public function __destruct(){eval($this->arg1);  //eval()去执行用户传递的arg1值}public function __wakeup(){foreach(get_object_vars($this) as $k => $v) {$this->$k = '';          //将传入的参数遍历,全部赋值为空}}}$a=$_GET['arg'];     //接收前端传递的arg1变量
$unser = unserialize($a);    //反序列化传递的arg1
var_dump($unser);
?>

如果属性值与对象实际属性值相同,则会在反序列化时执行__wakeup()函数将传入的变量值替换为空。
1656064048_62b58830a44fdeca601a9.png
如果属性值设置大于实际对象属性值则会绕过__wakeup()函数。
1656064071_62b588476b877e1951bf6.png

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

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

相关文章

VScode使用ssh连接服务器

VScode是一款有丰富插件的编译器&#xff0c;非常好用&#xff01;除非你不会用&#xff0c;因为太过繁琐或着频繁出错导致想把电脑砸了&#xff1b; 插件选择 ssh 配置文件 Host myblablaHostName xxx.xx.xxx.xxxUser username用户名一般是服务器上创建有什么用户名&#xf…

【Vue】使用html、css实现鱼骨组件

文章目录 组件测试案例预览图 组件 <template><div class"context"><div class"top"><div class"label-context"><div class"label" v-for"(item, index) in value" :key"index">…

深入探讨JavaScript中的队列,结合leetcode全面解读

前言 队列作为一种基本的数据结构&#xff0c;为解决许多实际问题提供了有效的组织和处理方式&#xff0c;对于提高系统的稳定性、可靠性和效率具有重要作用&#xff0c;所以理解队列是很重要的。 本文深入探讨JavaScript中的队列这种数据结构,结合leetcode题目讲解 题目直达…

DolphinScheduler部署安装or基础介绍(一)

DolphinScheduler概述 Apache DolphinScheduler是一个分布式、易扩展的可视化DAG工作流任务调度平台。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用 DolphinScheduler核心架构 DolphinScheduler的主要角色如下&#xff1a; Ma…

2024攻防演练:亚信安全推出MSS/SaaS短期定制服务

随着2024年攻防演练周期延长的消息不断传出&#xff0c;各参与方将面临前所未有的挑战。面对强大的攻击队伍和日益严格的监管压力&#xff0c;防守单位必须提前进行全面而周密的准备和部署。为应对这一形势&#xff0c;亚信安全特别推出了为期三个月的MSS/SaaS短期订阅方案。该…

一站式配套,全方位服务升级——全力打造企业新家园

国际数字影像产业园通过完善配套设施和优化服务&#xff0c;为入园企业提供了高效、便捷、专业的服务支持&#xff0c;助力企业实现快速发展和转型升级。同时&#xff0c;园区的数字化和智能化发展策略也为整个数字影像产业的繁荣发展提供了有力支撑。 一、完善配套设施 1、高…

程序包lombok不存在,解决办法。

当前方法是针对于代码没有报错&#xff0c;本身有lombok jar包的情况 1.找到本地maven仓库中的已经下载好的lombok包&#xff0c;删掉。 2. 直接刷新maven&#xff0c;会重新下载lombok jar包&#xff0c;此时再启动项目时就可以正常运行了。

UE4_材质基础_切线空间与法线贴图

学习笔记&#xff0c;不喜勿喷&#xff0c;侵权立删&#xff0c;祝愿大家生活越来越好&#xff01; 一、切线空间 在《OpenGL基础11&#xff1a;空间》中提到了观察空间、裁剪空间、世界空间等。切线空间和它们一样&#xff0c;都属于坐标空间 上面就是一个…

Lesson 46 Can you ... ?

Lesson 46 Can you … ? 词汇 lift v. 拿起&#xff0c;搬起 n. 电梯&#xff08;直梯&#xff09; 用法&#xff1a;1. lift … up 拎起……    例句&#xff1a;我可以拎起那只小猫。       I can lift that cat up.    2. take a lift    例句&#xff1a…

如何在Docker容器中,修改MySQL密码

如果MySQL运行在Docker容器中&#xff0c;修改MySQL密码的方法稍有不同。以下是如何在Docker中修改MySQL密码的步骤&#xff1a; 方法1&#xff1a;使用MySQL命令行工具 1. 找到MySQL容器的ID或者名字&#xff1a; docker ps 2. 进入MySQL容器&#xff1a; docker exec -i…

mongodb在windows环境安装部署

一、mongodb 1.释义 MongoDB 是一种开源的文档型 NoSQL 数据库管理系统&#xff0c;使用 C 编写&#xff0c;旨在实现高性能、高可靠性和易扩展性。MongoDB 采用了面向文档的数据模型&#xff0c;数据以 JSON 风格的 BSON&#xff08;Binary JSON&#xff09;文档存储&#x…

VSCode使用SSH无需输入密码远程连接服务器

目录 一、密钥生成 1、使用windows11自带的命令行 2、使用putty工具 二、查看密钥 三、设置服务器 这个过程是比较简单的&#xff0c;为了方便后续留用和查看&#xff0c;整理个笔记放着。 一、密钥生成 1、使用windows11自带的命令行 在任一文件夹中&#xff0c;空白处…

数据融合平台的概述、特点及技术方案

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;数据的分散存储和格式不一&#xff0c;常常导致数据孤岛现象&#xff0c;使得数据的潜在价值难以被充分挖掘和利用。在这样的背景下&#xff0c;数据融合平台应运而生&#xff0c;它的意义不仅在…

amis中条件组合器condition-builder的使用 和 解析

1.amis中配置一个条件组合器&#xff0c;condition-builder。并根据自己业务需求配置source。这里用了一些自定义filter来进行预处理。 {"type": "condition-builder","label": "条件组合","name": "node.conditions&q…

Python 插入、替换、提取、或删除Excel中的图片

Excel是主要用于处理表格和数据的工具&#xff0c;我们也能在其中插入、编辑或管理图片&#xff0c;为工作表增添视觉效果&#xff0c;提升报告的吸引力。本文将详细介绍如何使用Python操作Excel中的图片&#xff0c;包含以下4个基础示例&#xff1a; 文章目录 Python 在Excel…

.NET 漏洞情报 | 某整合管理平台SQL注入

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

AI-算力集群通往AGI

背景&#xff1a; 自GPT-4发布以来&#xff0c;全球AI能力的发展势头有放缓的迹象。 但这并不意味着Scaling Law失效&#xff0c;也不是因为训练数据不够&#xff0c;而是结结实实的遇到了算力瓶颈。 具体来说&#xff0c;GPT-4的训练算力约2e25 FLOP&#xff0c;近期发布的几个…

驱使ai学习搭子,写出一份“完美”的代码“文档”

自己把控“核心关键”&#xff0c;ai会把文档写得比您预想的“完美”。 (笔记模板由python脚本于2024年07月04日 10:44:39创建&#xff0c;本篇笔记适合喜欢结伴ai学习的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff…

PHP房产小程序微信小程序系统源码

&#x1f3e0;—— 购房租房&#xff0c;一“指”搞定&#x1f3e1; &#x1f50d;【开篇&#xff1a;房产新视界&#xff0c;尽在掌握】 在这个信息爆炸的时代&#xff0c;找房子不再是一场漫长的奔波。有了“房产微信小程序”&#xff0c;无论是购房还是租房&#xff0c;都…

【PCIe】P2P DMA

PCIe P2P (peer-to-peer communication)是PCIe的一种特性&#xff0c;它使两个PCIe设备之间可以直接传输数据&#xff0c;而不需要使用主机RAM作为临时存储。如下图3的走向 比如EP1要发送和数据给EP2,操作流程如下&#xff1a; 1. 打开EP1的dma控制器&#xff1b;--client侧 …