interceptor_rs/
ptr.rs

1use pete::Tracee;
2use std::{
3    cell::RefCell,
4    ffi::{c_char, CStr, CString},
5    fs::read,
6    mem::size_of,
7    rc::Rc,
8    thread::sleep,
9    time::Duration,
10};
11use tracing::warn;
12
13pub struct RemoteMem {
14    base: usize,
15    offset: usize,
16    max: usize,
17}
18
19impl RemoteMem {
20    fn new(pid: i32) -> Self {
21        let mut retry = 5;
22        loop {
23            match read(inter_mem::mem_block_info_file().with_extension(pid.to_string()))
24                .map(|b| usize::from_le_bytes(b.try_into().unwrap_or_default()))
25            {
26                Err(e) => {
27                    if retry >= 0 {
28                        warn!("remote memory not ready try again, error: {:?}", e);
29                        retry -= 1;
30                        sleep(Duration::from_millis(50));
31                        continue;
32                    } else {
33                        panic!("remote memory can not setup");
34                    }
35                }
36                Ok(base) => {
37                    return Self {
38                        base,
39                        offset: 0,
40                        max: inter_mem::MEM_BLOCK_SIZE,
41                    };
42                }
43            }
44        }
45    }
46}
47
48pub trait Read {
49    type InnerType;
50
51    fn read(remote: &mut Tracee, u: u64) -> MayBePtr<Self::InnerType>;
52}
53
54/// help to read content from ptr to ptr
55pub fn read_ptr_to_ptr(p: *const *const c_char) -> Vec<Vec<u8>> {
56    let mut offset = 0usize;
57    let mut result = Vec::new();
58    let mut buf = Vec::new();
59    loop {
60        let b: u8 = unsafe { std::ptr::read((p as usize + offset) as *const u8) };
61        if buf.is_empty() && b == 0 {
62            break;
63        }
64
65        buf.push(b);
66        if b == 0 {
67            result.push(buf);
68            buf = Vec::new();
69        }
70
71        offset += 1;
72    }
73
74    result
75}
76
77/// help to write content back to ptr to ptr
78pub fn write_ptr_to_ptr(p: *const *const c_char, v: Vec<Vec<u8>>) {
79    let addr = p as usize;
80    let mut offset = 0usize;
81    v.into_iter().for_each(|x| unsafe {
82        std::ptr::copy_nonoverlapping(x.as_ptr() as *const u8, (addr + offset) as *mut u8, x.len());
83        offset += x.len()
84    });
85}
86
87pub trait Number {
88    fn from_u64(u: u64) -> Self;
89    fn to_u64(self) -> u64;
90}
91
92impl Read for *const *const c_char {
93    type InnerType = Vec<u8>;
94
95    fn read(remote: &mut Tracee, u: u64) -> MayBePtr<Self::InnerType> {
96        let mut mbp = MayBePtr {
97            inner: Vec::new(),
98            origin: u,
99        };
100
101        let mut offset = 0usize;
102        loop {
103            let mut buf = vec![0; size_of::<u64>()];
104            let n = remote
105                .read_memory_mut(u + offset as u64, &mut buf)
106                .unwrap_or_default();
107            let ptr = &buf[..n];
108            offset += size_of::<u64>();
109            let pdata =
110                remote.read_bytes_with_nul(u64::from_le_bytes(ptr.try_into().unwrap_or_default()));
111            if pdata.is_empty() {
112                mbp.inner.push(b'\0');
113                break;
114            }
115
116            mbp.inner.extend(pdata);
117        }
118
119        mbp
120    }
121}
122
123trait LendingIterator {
124    type Item<'a>
125    where
126        Self: 'a;
127    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
128}
129
130struct MayBePtrIter<'a> {
131    offset: usize,
132    inner: &'a MayBePtr<Vec<u8>>,
133}
134
135impl MayBePtr<Vec<u8>> {
136    fn iter(&self) -> MayBePtrIter {
137        MayBePtrIter {
138            offset: 0,
139            inner: self,
140        }
141    }
142}
143
144impl<'a> LendingIterator for MayBePtrIter<'a> {
145    type Item<'i> = &'i [u8] where Self: 'i;
146
147    fn next<'i>(&'i mut self) -> Option<Self::Item<'i>> {
148        let mut next = 0;
149        while let Some(v) = self.inner.inner.get(self.offset + next) {
150            if *v == 0 {
151                let offset = self.offset;
152                self.offset += next + 1;
153                return Some(&self.inner.inner[offset..=offset + next]);
154            }
155
156            next += 1;
157        }
158
159        None
160    }
161}
162
163impl Write<*const *const c_char> for MayBePtr<Vec<u8>> {
164    fn write(
165        &mut self,
166        remote: &mut Tracee,
167        _remote_mem: Rc<RefCell<Option<RemoteMem>>>,
168        v: Option<*const *const c_char>,
169    ) -> Option<u64> {
170        if let Some(v) = v {
171            if self.inner.as_ptr() != v as *const u8 {
172                panic!("*const *const c_char doesn't support change pointer");
173            }
174
175            let mut offset = 0usize;
176            let mut iter = self.iter();
177            loop {
178                let mut buf = vec![0; size_of::<u64>()];
179                let n = remote
180                    .read_memory_mut(self.origin + offset as u64, &mut buf)
181                    .unwrap_or_default();
182                let ptr = &buf[..n];
183                offset += size_of::<u64>();
184                let addr = u64::from_le_bytes(ptr.try_into().unwrap_or_default());
185                if addr != 0 {
186                    let next = iter.next();
187                    if let Some(next) = next {
188                        remote
189                            .write_memory(addr, next)
190                            .expect("write remote memory for ptr to ptr error");
191                    } else {
192                        break;
193                    }
194                } else {
195                    break;
196                }
197            }
198
199            Some(self.origin)
200        } else {
201            None
202        }
203    }
204}
205
206impl Ptr<*const *const c_char> for MayBePtr<Vec<u8>> {
207    fn get(&self) -> *const *const c_char {
208        self.inner.as_ptr() as *const *const c_char
209    }
210}
211
212trait ReadRemote {
213    fn read_bytes_with_nul(&mut self, addr: u64) -> Vec<u8>;
214}
215
216impl ReadRemote for Tracee {
217    fn read_bytes_with_nul(&mut self, addr: u64) -> Vec<u8> {
218        let mut data = Vec::new();
219        if addr != 0 {
220            let mut offset = 0usize;
221            loop {
222                let mut buf = vec![0; size_of::<u64>()];
223                let n = self
224                    .read_memory_mut(addr + offset as u64, &mut buf)
225                    .unwrap_or_default();
226                if n == 0 {
227                    break;
228                }
229                let buf = &buf[..n];
230                if let Some(i) = buf.iter().position(|x| *x == b'\0') {
231                    data.extend(&buf[..=i]);
232                    break;
233                }
234
235                offset += size_of::<u64>();
236                data.extend(buf);
237            }
238        }
239        data
240    }
241}
242
243macro_rules! ptr_impl {
244    ($t: ty) => {
245        impl Read for $t {
246            type InnerType = Vec<u8>;
247
248            fn read(remote: &mut Tracee, u: u64) -> MayBePtr<Vec<u8>> {
249                MayBePtr {
250                    inner: remote.read_bytes_with_nul(u),
251                    origin: u,
252                }
253            }
254        }
255
256        impl Ptr<$t> for MayBePtr<Vec<u8>> {
257            fn get(&self) -> $t {
258                self.inner.as_ptr() as $t
259            }
260        }
261
262        impl Write<$t> for MayBePtr<Vec<u8>> {
263            fn write(
264                &mut self,
265                remote: &mut Tracee,
266                remote_mem: Rc<RefCell<Option<RemoteMem>>>,
267                v: Option<$t>,
268            ) -> Option<u64> {
269                if let Some(v) = v {
270                    if self.inner.as_ptr() == v as *const u8 {
271                        // origin inner's pointer not changed by argument
272                        remote
273                            .write_memory(self.origin, &self.inner)
274                            .expect("write origin memory error");
275                        Some(self.origin)
276                    } else {
277                        // pointer changed, meaning user allocate new memory in rust
278                        let c = unsafe { CStr::from_ptr(v).to_bytes_with_nul() };
279                        let remote_addr = alloc_remote_mem(remote, remote_mem, c.len()) as u64;
280                        remote
281                            .write_memory(remote_addr, &c)
282                            .expect("write remote memory error");
283                        drop(unsafe { CString::from_raw(v as *mut c_char) });
284                        Some(remote_addr)
285                    }
286                } else {
287                    None
288                }
289            }
290        }
291    };
292}
293
294fn alloc_remote_mem(
295    remote: &mut Tracee,
296    remote_mem: Rc<RefCell<Option<RemoteMem>>>,
297    size: usize,
298) -> usize {
299    let mut mem = remote_mem.borrow_mut();
300    if mem.is_none() {
301        *mem = Some(RemoteMem::new(remote.pid.as_raw()));
302    }
303
304    let mut mem = mem.as_mut().unwrap();
305    if size > mem.max {
306        panic!("changed content is too large");
307    }
308
309    let addr = mem.base + mem.offset;
310    if mem.offset + size > mem.max {
311        mem.offset = 0;
312    } else {
313        mem.offset += size;
314    }
315
316    addr
317}
318
319pub trait Write<T> {
320    fn write(
321        &mut self,
322        remote: &mut Tracee,
323        remote_mem: Rc<RefCell<Option<RemoteMem>>>,
324        v: Option<T>,
325    ) -> Option<u64>;
326}
327
328macro_rules! not_ptr_impl {
329    ($t: ty) => {
330        impl Read for $t {
331            type InnerType = $t;
332
333            fn read(_: &mut Tracee, u: u64) -> MayBePtr<Self::InnerType> {
334                MayBePtr {
335                    inner: u as $t,
336                    origin: u,
337                }
338            }
339        }
340
341        impl Write<$t> for MayBePtr<$t> {
342            fn write(
343                &mut self,
344                _remote: &mut Tracee,
345                _remote_mem: Rc<RefCell<Option<RemoteMem>>>,
346                v: Option<$t>,
347            ) -> Option<u64> {
348                v.map(|x| x as u64)
349            }
350        }
351
352        impl Ptr<$t> for MayBePtr<$t> {
353            fn get(&self) -> $t {
354                self.inner
355            }
356        }
357
358        impl Number for $t {
359            fn from_u64(u: u64) -> Self {
360                u as Self
361            }
362
363            fn to_u64(self) -> u64 {
364                self as u64
365            }
366        }
367    };
368}
369
370ptr_impl!(*const c_char);
371ptr_impl!(*mut c_char);
372not_ptr_impl!(i8);
373not_ptr_impl!(i16);
374not_ptr_impl!(i32);
375not_ptr_impl!(i64);
376not_ptr_impl!(isize);
377not_ptr_impl!(u8);
378not_ptr_impl!(u16);
379not_ptr_impl!(u32);
380not_ptr_impl!(u64);
381not_ptr_impl!(usize);
382
383pub trait Ptr<T> {
384    fn get(&self) -> T;
385}
386
387pub struct MayBePtr<T> {
388    inner: T,
389    origin: u64,
390}