Rust逆向——02.函数

例子1:

原题

fn main() {
    call_me();
}

修改后:

fn call_me() {

}

fn main() {
    call_me();
}

这里添加了一个函数定义,我们看下结果

例子2:

fn main() {
    call_me(3);
}

fn call_me(num:) {
    for i in 0..num {
        println!("Ring! Call number {}", i + 1);
    }
}

修改后:

fn main() {
    call_me(3);
}

fn call_me(num:i32) {
    for i in 0..num {
        println!("Ring! Call number {}", i + 1);
    }
}

例子3:

原题:

fn main() {
    call_me();
}

fn call_me(num: u32) {
    for i in 0..num {
        println!("Ring! Call number {}", i + 1);
    }
}

修改后:

fn main() {
    call_me(2);
}

fn call_me(num: u32) {
    for i in 0..num {
        println!("Ring! Call number {}", i + 1);
    }
}

例子4:

原题:

fn main() {
    let original_price = 51;
    println!("Your sale price is {}", sale_price(original_price));
}

fn sale_price(price: i32) -> {
    if is_even(price) {
        price - 10
    } else {
        price - 3
    }
}

fn is_even(num: i32) -> bool {
    num % 2 == 0
}


修改后:

fn main() {
    let original_price = 51;
    println!("Your sale price is {}", sale_price(original_price));
}

fn sale_price(price: i32) -> i32 {
    if is_even(price) {
        price - 10
    } else {
        price - 3
    }
}

fn is_even(num: i32) -> bool {
    num % 2 == 0
}

例子5:

原题:

fn main() {
    let answer = square(3);
    println!("The answer is {}", answer);
}

fn square(num: i32) -> i32 {
    num * num;
}

修改后:

fn main() {
    let answer = square(3);
    println!("The answer is {}", answer);
}

fn square(num: i32) -> i32 {
    num * num
}

Rust逆向——01.变量

我们拿 rust rustling 的练习拿来做例子。如果大家不懂Rust语法,也可以通过这些例子来学下语法。

例子1:

原题:

fn main() {
    x = 5;
    println!("x has the value {}", x);
}

修改后:

fn main() {
    let x = 5;
    println!("x has the value {}", x);
}

Rust的变量定义使用let, let创建的变量为绑定,let x=5指的是把x和5创建了一种关联关系 。

扩展: Rust中常量为什么用let不用const,变量用let mut不用var?

放到r2上自动分析一下。

用Cutter带的Ghidra反编译器试试:

看main函数, let x=5; 是把5赋给了一个dword双字节的地址,lea 加载变量的有效地址,然后直接fmt和调用print,注意这里的println!是一个宏。

例子2:

原题:


fn main() {
    let x: i32;
    if x == 10 {
        println!("Ten!");
    } else {
        println!("Not ten!");
    }
}

修改后:
fn main() {
    let x: i32 = 5;
    if x == 10 {
        println!("Ten!");
    } else {
        println!("Not ten!");
    }
}

Rust出于内存安全的考虑,不允许变量未初始化。如果你写了let x=5; Rust编译器会自动推断,但是最好是自己加一下类型,主要是因为推断的类型不一定对。

例子3:

原题:

fn main() {
    let x = 3;
    println!("Number {}", x);
    x = 5; // don't change this line
    println!("Number {}", x);
}

修改后:


fn main() {
    let mut x = 3;
    println!("Number {}", x);
    x = 5; // don't change this line
    println!("Number {}", x);
}

Rust不允许重复赋值,因为默认变量不可变。 需要加mut来变成可变的变量。

不可变绑定和可变绑定的区别:

问题: 为什么要设计默认变量是不可变的?

例子4:

原题:

fn main() {
    let x: i32;
    println!("Number {}", x);
}

修改后:

fn main() {
    let x: i32 = 0;
    println!("Number {}", x);
}

也是未初始化的问题

例子5:

原题:

fn main() {
    let number = "T-H-R-E-E"; // don't change this line
    println!("Spell a Number : {}", number);
    number = 3;
    println!("Number plus two is : {}", number + 2);
}

修改后:

fn main() {
    let number = "T-H-R-E-E"; // don't change this line
    println!("Spell a Number : {}", number);
    let number = 3;
    println!("Number plus two is : {}", number + 2);
}

第一个number 是不可变的字符串类型,然后下面的赋值 number=3是一个整型,肯定不对。需要重新绑定number,把number改为整型并赋值为3

例子6:

原题:

const NUMBER = 3;

fn main() {
    println!("Number {}", NUMBER);
}

修改后:

const NUMBER: i32 = 3;
fn main() {
    println!("Number {}", NUMBER);
}

Rust的常量必须加类型。那为什么常量不推导呢? 这是因为故意这样设计的,指定类型就不会因为自动推导类型出问题。

扩展: Why is type declaration necessary in constants?

去看看这个0x10003c588是什么内容

Rust的常量是全局的,而是自动内联的。 如果我们把const 换成static,那么它会被存储在静态存储区中,有一个固定的内存地址,而且不会被内联。

我们来试试:

Rust 逆向——00.Hello,World

fn main() {
    println!("Hello, world!");
}

我尝试使用-O 和 -C opt-level=3 来编译,发现编译出来的程序没有任何区别。

如果你使用-o 的话,就会发现生成的程序是没有优化的,会大一些,有461K。

使用GDB来调试

你在编译的时候,需要加-g 来添加调试信息

(gdb) list
1       fn main() {
2           println!("Hello, world!");
3       }
(gdb) 
Line number 4 out of range; helloworld.rs has 3 lines.
(gdb) 
Line number 4 out of range; helloworld.rs has 3 lines.
(gdb) b 2
Breakpoint 1 at 0x100004228: file helloworld.rs, line 2.

使用逆向工具

使用Cutter的jsdec反编译结果。看起来生成的C++/C的代码

使用Ghira的结果