Rust语言之交互

时间:2024-03-16 10:51:52

文章目录

  • 一、获取用户输入
    • 1.读取单行数据
    • 2.读取多行数据
  • 二、一个猜数字的游戏
    • 1.创建一个新项目
    • 2.生成一个随机目标
    • 3.进行一次猜测
    • 4.多次猜测
  • 三、CTF自测工具
    • 1.整理资料
    • 2.写一个检查函数
    • 3.整合代码
    • 4.增加回答次数
  • 四、编译程序


一、获取用户输入

在Rust语言中,你可以使用标准库中的std::io模块来获取用户的输入。

1.读取单行数据

use std::io;  
  
fn main() {  
    println!("请输入一些文本:");  
  
    let mut input = String::new();  
    match io::stdin().read_line(&mut input) {  
        Ok(_) => println!("你输入了:{}", input),  
        Err(error) => println!("读取错误:{:?}", error),  
    }  
}

2.读取多行数据

use std::io::BufRead;  
  
fn main() {  
    println!("请输入一些文本:");  
  
    for line in std::io::stdin().lock().lines() { // 直接使用std::io::stdin()  
        match line {  
            Ok(n) if n == "quit" => break,
            Ok(l) => println!("你输入了:{}", l),  
            Err(error) => println!("读取错误:{:?}", error),  
        }  
    }  
}

二、一个猜数字的游戏

这也是官方提供的案例

1.创建一个新项目

cargo new guessing_game

  • 编写cargo.toml文件
[dependencies]
rand = "0.9.0-alpha.0"

2.生成一个随机目标

use rand::Rng;

fn main() {
    println!("Guess the number!");
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("The secret number is: {secret_number}");
}

3.进行一次猜测

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Guess the number!");
    // 随机获取一个1-100之间的随机数
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("The secret number is: {secret_number}");
    // 
    let mut guess = String::new();
    io::stdin()
        .read_line(&mut guess)
        .expect("Failed to read line");

    let guess: u32 = guess.trim().parse().expect("Please type a number!");

    println!("You guessed: {guess}");

    match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => println!("You win!"),
    }
}

4.多次猜测

在单次猜测外面嵌套一个loop,注意loop是无条件循环,注意设置循环结束条件

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Guess the number!");
    // 随机获取一个1-100之间的随机数
    let secret_number = rand::thread_rng().gen_range(1..=100);
    println!("The secret number is: {secret_number}");
    // 

    loop {
        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess: u32 = guess.trim().parse().expect("Please type a number!");

        println!("You guessed: {guess}");

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                return;},
        }
    }
}

测试没有问题就把打印秘密数字的语句注释掉,利用cargo build进行编译,一个简单的猜数字游戏就完成了。

三、CTF自测工具

由于英文不过关,学习CTF的时候好多单词、语句记不住,利用Rust实现一个自测工具,一方面巩固Rust基础,另一方面每天一练形成肌肉记忆。

1.整理资料

// 东西不多,用Hashmap整理题目和答案的对应。
use std::collections::HashMap;

fn main(){
    let mut questions = HashMap::new();
    questions.insert(String::from("SQL注入中查询数据库库名的语句"), "select group_concat(schema_name) from information_schema.schemata --+".to_string());
    questions.insert(String::from("SQL注入中查询数据库表名的语句"),"select group_concat(table_name) from information_schema.tables where table_schema= 'databases' --+".to_string());
    questions.insert(String::from("SQL注入中查询数据库字段名的语句"),"select group_concat(column_name) from information_schema.columns where table_name= 'tables' and table_schema= 'databases' --+".to_string());
    questions.insert(String::from("利用sqlmap默认选项注入,绕过空格,读取key"),"python sqlmap.py -r a.txt --batch --file-read \"./key\" --tamper 'space2comment'".to_string());
    questions.insert(String::from("利用php伪协议读取文件,base64"), "Php://filter/read-convert.base64-encode/resource=../key".to_string());
    questions.insert(String::from("使用data伪协议执行命令"), "data://text/plain,<?=system('whoami');?>".to_string());
    for (question,answer)in &questions{
        println!("question:{},answer:{}",question,answer);
    }
}

2.写一个检查函数

// 向函数传递问题和答案,获取用户输入匹配答案,返回是否正确。
fn check_answer(question: &str, answer: &str) -> bool {  
    println!("{} ", question);  
  
    let stdin = io::stdin();  
    let mut reader = stdin.lock();  
    let mut input = String::new();  
  
    reader.read_line(&mut input).unwrap(); // 读取一行输入  
    let trimmed_input = input.trim(); // 移除可能的前后空白字符,包括换行符  
  
    // 检查用户输入是否与正确答案匹配  
    trimmed_input == answer  
}  

3.整合代码

use std::collections::HashMap;
use std::io::{self, BufRead};  

fn main(){
    let mut questions = HashMap::new();
    questions.insert(String::from("SQL注入中查询数据库库名的语句"), "select group_concat(schema_name) from information_schema.schemata --+".to_string());
    questions.insert(String::from("SQL注入中查询数据库表名的语句"),"select group_concat(table_name) from information_schema.tables where table_schema= 'databases' --+".to_string());
    questions.insert(String::from("SQL注入中查询数据库字段名的语句"),"select group_concat(column_name) from information_schema.columns where table_name= 'tables' and table_schema= 'databases' --+".to_string());
    questions.insert(String::from("利用sqlmap默认选项注入,绕过空格,读取key"),"python sqlmap.py -r a.txt --batch --file-read \"./key\" --tamper 'space2comment'".to_string());
    questions.insert(String::from("利用php伪协议读取文件,base64"), "Php://filter/read-convert.base64-encode/resource=../key".to_string());
    questions.insert(String::from("使用data伪协议执行命令"), "data://text/plain,<?=system('whoami');?>".to_string());
    for (question,answer)in &questions{
        if check_answer(question, answer) {  
            println!("Correct!");  
        } else {  
            println!("Incorrect!");  
            println!("correct answer:{}",answer)
        }  
    }
}
fn check_answer(question: &str, answer: &str) -> bool {  
    println!("{} ", question);  
  
    let stdin = io::stdin();  
    let mut reader = stdin.lock();  
    let mut input = String::new();  
  
    reader.read_line(&mut input).unwrap(); // 读取一行输入  
    let trimmed_input = input.trim(); // 移除可能的前后空白字符,包括换行符  
  
    // 检查用户输入是否与正确答案匹配  
    trimmed_input == answer  
}  

4.增加回答次数

// 在主函数增加次数条件
    for (question,answer)in &questions{
        let mut i = 0; // 回答次数计数器
        loop {
            if check_answer(question, answer) {
                println!("Correct!");  
                break;
            } else {  
                println!("Incorrect!");  
            }
            i += 1;
            // 判断是否达到次数上限
            if i == 3{ 
                println!("correct answer:{}",answer);
                break;
            }
        }  
    }

四、编译程序

如果使用高版本linux编译,在低版本Linux中运行,会提示glibc不匹配,所以编译是使用使用musl替代glibc
错误: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33’ not found (required by ./ctf)

  1. 配置Cargo:
[target.x86_64-unknown-linux-musl]  
linker = "rust-lld" # 或者其他适合musl的链接器

注意:这里假设你使用了lld链接器,但你也可以使用其他支持musl的链接器。

  1. 安装musl工具链:
rustup target add x86_64-unknown-linux-musl
  1. 编译程序:
cargo build --target x86_64-unknown-linux-musl --release

**然后再项目文件夹下的/target/x86_64-unknown-linux-musl/release文件夹下,就可以找到编译好的程序了