写入随机存储器地址时会发生什么?

时间:2015-01-14 08:02:36

标签: rust

extern crate core;
use core::ops::{Deref, DerefMut};

struct MutPtr<T>{
    ptr: *mut T
}
impl<T> MutPtr<T>{
    fn new(value: &mut T) -> MutPtr<T>{
        MutPtr{ptr: value} 
    }
}
impl<T> Deref for MutPtr<T>{
    type Target = T;
    fn deref(&self) -> &T{
        unsafe{
            &(*self.ptr)
        }
    }
}
impl<T> DerefMut for MutPtr<T>{
    fn deref_mut(&mut self) -> &mut T{
        unsafe{
            &mut (*self.ptr)
        }
    }
}
struct Bar{
    v: i32
}

fn error()-> MutPtr<Bar> {
    let mut b = Bar{v:42};
    let ptr_b =  MutPtr::new(&mut b);
    ptr_b
}

fn main(){
    let mut b      = Bar{v:42};
    let mut ptr_b  = MutPtr::new(&mut b);
    let mut ptr_b1 = MutPtr::new(&mut b);

    ptr_b.v = 10;
    println!("{}",b.v);
    ptr_b1.v = 21;
    println!("{}",b.v);

    let mut err = error();
    println!("{}",err.v);
    err.v = 42; // what happens here?
    println!("{}",err.v);
}

在第49行,我将写入一些内存地址

err.v = 42;

我知道这很糟糕,但我想知道究竟发生了什么?起初我预计它会崩溃但我希望我能够更改err.v地址的值。但写作没有做任何事情。

内存似乎是写保护的?

我只是“幸运”,写作没有改变什么?

1 个答案:

答案 0 :(得分:3)

  

我只是&#34;幸运&#34;写的没有改变什么?

是的,幸运的。

写入随机存储器是undefined behaviour:编译器认为它永远不会发生并优化假设。如果它确实发生,那么没有限制或保证可以对结果行为做出决定。例如。它可以change the return address在下一个函数调用结束时使用,使CPU跳转到某些&#34;随机&#34;一块记忆。它通常非常糟糕,这些事情可能是一个可利用的安全漏洞。

在这种情况下,你已经写过,可能因为err指向堆栈的低位而导致程序没有发生可怕的死亡,程序在写入发生时并没有使用。如果在使用堆栈的那个区域时发生了写操作,那么修改指针以指向无意义的事情很容易发生:

use std::mem;

#[inline(never)]
fn bad() -> &'static mut u32 {
    let mut x = 0u32;
    unsafe { mem::transmute(&mut x) }
}

#[inline(never)]
fn innocent(x: &mut u32) {
    println!("{:p}", &*x);
    *x = 0xDEADBEEF;

    println!("{:p}", x);
    *x = 0;
}

fn main() {
    let ptr = bad();
    innocent(ptr);
}

playpen-O2,此时会打印:

0x7fff03dbae84
0xdeadbeef03dbae84
playpen: application terminated abnormally with signal 4 (Illegal instruction)

第一行是x的实际值。 x之后的下一行是*x = 0xDEADBEEF; ...也就是说,写入直接发送到存储x本身的堆栈部分,将上半部分更改为0xDEADBEEF 。此时,x是一个无意义的值,因此*x = 0会导致段错误(由于Rust默认会覆盖某些信号处理程序而显示为中止)。

我说&#34;此刻&#34;因为程序的行为对确切的编译器版本/优化级别/源代码非常敏感,例如更改第一个print以删除&*会使程序打印0x7fff03dbae84两次然后中止(可能是因为正在修改返回地址而不是x)。

如果攻击者可以控制写入无效指针的内容,则他们可能/可能能够修改写指针以使程序跳转到piece of shellcode并打开您的应用程序。我看到可能因为even the smallest "unexploitable" problems被证明可以被剥削。

相关问题