1use std::{fs, io::IoSliceMut, path::PathBuf};
2
3use nix::{
4 errno::Errno,
5 sys::uio::{process_vm_readv, RemoteIoVec},
6 unistd::Pid,
7};
8
9use crate::{
10 error::ProcessError,
11 process::{MemoryRegion, Process, ProcessTraits},
12};
13
14use super::signature::{find_signature, Signature};
15
16impl ProcessTraits for Process {
17 fn initialize(
18 proc_name: &str,
19 exclude: &[&str],
20 ) -> Result<Process, super::error::ProcessError> {
21 let process = Process::find_process(proc_name, exclude)?;
22 process.read_regions()
23 }
24
25 fn find_process(
26 proc_name: &str,
27 exclude: &[&str],
28 ) -> Result<Process, ProcessError> {
29 let paths = fs::read_dir("/proc")?;
30
31 'path_loop: for path in paths {
32 let p = path?.path();
33
34 if !p.is_dir() {
35 continue;
36 }
37
38 let cmd_line = p.join("cmdline");
39
40 if !cmd_line.exists() {
41 continue;
42 }
43
44 let mut cmd_buff = fs::read_to_string(cmd_line)?;
45
46 let line = cmd_buff.split(' ').next().unwrap();
47
48 if line.contains(proc_name) {
49 for exclude_word in exclude {
50 if line.contains(exclude_word) {
51 continue 'path_loop;
52 }
53 }
54
55 let stat = p.join("stat");
56 let buff = fs::read_to_string(stat)?;
57
58 cmd_buff.retain(|c| c != '\0');
60 cmd_buff = cmd_buff.replace('\\', "/");
61
62 cmd_buff.remove(0);
63 cmd_buff.remove(0);
64
65 let executable_path = PathBuf::from(cmd_buff);
66 let executable_dir =
67 executable_path.parent().map(|v| v.to_path_buf());
68
69 let pid_str = buff.split(' ').next().unwrap();
70
71 let pid = pid_str.parse()?;
72
73 return Ok(Self {
74 pid,
75 maps: Vec::new(),
76 executable_dir,
77 });
78 }
79 }
80
81 Err(ProcessError::ProcessNotFound)
82 }
83
84 fn read_regions(mut self) -> Result<Process, ProcessError> {
85 let path = format!("/proc/{}/maps", &self.pid);
86 let mut v = Vec::new();
87
88 let buff = fs::read_to_string(path)?;
89
90 for line in buff.split('\n') {
91 if line.is_empty() {
92 break;
93 }
94
95 let mut split = line.split_whitespace();
96 let range_raw = split.next().unwrap();
97 let mut permissions_raw_chars = split.next().unwrap().chars();
98
99 let mut range_split = range_raw.split('-');
100
101 let from_str = range_split.next().unwrap();
102 let to_str = range_split.next().unwrap();
103
104 let from = usize::from_str_radix(from_str, 16)?;
105 let to = usize::from_str_radix(to_str, 16)?;
106
107 let read = permissions_raw_chars.next().unwrap();
108 let write = permissions_raw_chars.next().unwrap();
109
110 if read == 'r' && write == 'w' {
111 v.push(MemoryRegion {
112 from,
113 size: to - from,
114 });
115 }
116 }
117
118 self.maps = v;
119 Ok(self)
120 }
121
122 fn read_signature<T: TryFrom<usize>>(
123 &self,
124 sign: &Signature,
125 ) -> Result<T, ProcessError> {
126 let mut buff = Vec::new();
127
128 for region in &self.maps {
129 let remote = RemoteIoVec {
130 base: region.from,
131 len: region.size,
132 };
133
134 buff.resize(region.size, 0);
135
136 let slice = IoSliceMut::new(buff.as_mut_slice());
137
138 let res = process_vm_readv(
139 Pid::from_raw(self.pid),
140 &mut [slice],
141 &[remote],
142 );
143
144 if let Err(e) = res {
145 match e {
146 Errno::EPERM | Errno::ESRCH => return Err(e.into()),
147 _ => continue,
148 }
149 }
150
151 if let Some(offset) = find_signature(buff.as_slice(), sign) {
152 return (remote.base + offset)
153 .try_into()
154 .map_err(|_| ProcessError::AddressConvertError);
155 }
156 }
157
158 Err(ProcessError::SignatureNotFound(sign.to_string()))
159 }
160
161 fn read<T: TryInto<usize>>(
162 &self,
163 addr: T,
164 len: usize,
165 buff: &mut [u8],
166 ) -> Result<(), ProcessError> {
167 let addr: usize = addr
168 .try_into()
169 .map_err(|_| ProcessError::AddressConvertError)?;
170
171 let remote = RemoteIoVec { base: addr, len };
172
173 let slice = IoSliceMut::new(buff);
174
175 let res =
176 process_vm_readv(Pid::from_raw(self.pid), &mut [slice], &[remote]);
177
178 match res {
179 Ok(_) => (),
180 Err(e) => match e {
181 nix::errno::Errno::EFAULT => {
182 return Err(ProcessError::BadAddress(addr, len))
183 }
184 _ => return Err(e.into()),
185 },
186 }
187
188 Ok(())
189 }
190}