1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use std::prelude::v1::*;

use std::convert::TryInto;

use memflow::architecture::{ArchitectureObj, Endianess};
use memflow::error::{Error, ErrorKind, ErrorOrigin, Result};
use memflow::mem::MemoryView;
use memflow::types::Address;

use widestring::U16CString;

pub trait VirtualReadUnicodeString {
    fn read_unicode_string(&mut self, proc_arch: ArchitectureObj, addr: Address) -> Result<String>;
}

// TODO: split up cpu and proc arch in read_helper.rs
impl<'a, T: MemoryView> VirtualReadUnicodeString for T {
    fn read_unicode_string(&mut self, proc_arch: ArchitectureObj, addr: Address) -> Result<String> {
        /*
        typedef struct _windows_unicode_string32 {
            uint16_t length;
            uint16_t maximum_length;
            uint32_t pBuffer; // pointer to string contents
        } __attribute__((packed)) win32_unicode_string_t;

        typedef struct _windows_unicode_string64 {
            uint16_t length;
            uint16_t maximum_length;
            uint32_t padding; // align pBuffer
            uint64_t pBuffer; // pointer to string contents
        } __attribute__((packed)) win64_unicode_string_t;
        */

        // length is always the first entry
        let mut length = 0u16;
        self.read_into(addr, &mut length)?;
        if length == 0 {
            return Err(Error(ErrorOrigin::OsLayer, ErrorKind::Encoding)
                .log_debug("unable to read unicode string length (length is zero)"));
        }

        // TODO: chek if length exceeds limit
        // buffer is either aligned at 4 or 8
        let buffer = match proc_arch.bits() {
            64 => self.read_addr64(addr + 8)?,
            32 => self.read_addr32(addr + 4)?,
            _ => {
                return Err(Error(ErrorOrigin::OsLayer, ErrorKind::InvalidArchitecture));
            }
        };
        if buffer.is_null() {
            return Err(Error(ErrorOrigin::OsLayer, ErrorKind::Encoding)
                .log_debug("unable to read unicode string buffer"));
        }

        // check if buffer length is mod 2 (utf-16)
        if length % 2 != 0 {
            return Err(Error(ErrorOrigin::OsLayer, ErrorKind::Encoding)
                .log_debug("unicode string length is not a multiple of two"));
        }

        // read buffer
        let mut content = vec![0; length as usize + 2];
        self.read_raw_into(buffer, &mut content)?;
        content[length as usize] = 0;
        content[length as usize + 1] = 0;

        let content16 = content
            .chunks_exact(2)
            .map(|b| {
                b[0..2]
                    .try_into()
                    .map_err(|_| Error(ErrorOrigin::OsLayer, ErrorKind::Encoding))
            })
            .filter_map(Result::ok)
            .map(|b| match proc_arch.endianess() {
                Endianess::LittleEndian => u16::from_le_bytes(b),
                Endianess::BigEndian => u16::from_be_bytes(b),
            })
            .collect::<Vec<u16>>();
        Ok(U16CString::from_vec_truncate(content16).to_string_lossy())
    }
}