Skip to content

Commit 463785a

Browse files
author
etke
committed
Add proc maps for linux target
1 parent 4033e5b commit 463785a

File tree

5 files changed

+297
-106
lines changed

5 files changed

+297
-106
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ path = "src/main.rs"
4848

4949
[features]
5050
color = ["colored", "colored_json"]
51-
default = ["elf", "macho", "pe", "color"]
51+
default = ["elf", "macho", "pe", "color", "maps"]
5252
elf = ["shared"]
5353
macho = ["shared"]
54+
maps = []
5455
pe = []
5556
shared = []

src/binary.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
use colored::Colorize;
33
use serde::{Deserialize, Serialize};
44
use std::fmt;
5+
#[cfg(all(feature = "maps", target_os = "linux"))]
6+
use std::fs;
7+
#[cfg(all(feature = "maps", target_os = "linux"))]
8+
use std::io::Error;
9+
#[cfg(all(feature = "maps", target_os = "linux"))]
10+
use std::io::ErrorKind;
11+
#[cfg(all(feature = "maps", target_os = "linux"))]
12+
use std::path::PathBuf;
13+
use std::usize;
514

615
#[cfg(feature = "elf")]
716
use checksec::elf;
@@ -135,15 +144,170 @@ impl Binaries {
135144
}
136145
}
137146

147+
#[cfg(all(feature = "maps", target_os = "linux"))]
148+
#[derive(Deserialize, Serialize)]
149+
pub struct Region {
150+
pub start: usize,
151+
pub end: usize,
152+
}
153+
#[cfg(all(feature = "maps", target_os = "linux"))]
154+
impl Region {
155+
pub fn new(start: usize, end: usize) -> Self {
156+
Self { start, end }
157+
}
158+
}
159+
160+
#[cfg(all(feature = "maps", target_os = "linux"))]
161+
#[derive(Deserialize, Serialize)]
162+
pub struct MapFlags {
163+
pub r: bool,
164+
pub w: bool,
165+
pub x: bool,
166+
}
167+
#[cfg(all(feature = "maps", target_os = "linux"))]
168+
impl MapFlags {
169+
pub fn new(flagstr: &str) -> Self {
170+
let r = flagstr.get(0..1) == Some("r");
171+
let w = flagstr.get(1..2) == Some("w");
172+
let x = flagstr.get(2..3) == Some("x");
173+
Self { r, w, x }
174+
}
175+
}
176+
#[cfg(all(not(feature = "color"), feature = "maps", target_os = "linux"))]
177+
impl fmt::Display for MapFlags {
178+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179+
write!(
180+
f,
181+
"{}{}{}",
182+
if self.r { "r" } else { "-" },
183+
if self.w { "w" } else { "-" },
184+
if self.x { "x" } else { "-" }
185+
)
186+
}
187+
}
188+
#[cfg(all(feature = "color", feature = "maps", target_os = "linux"))]
189+
impl fmt::Display for MapFlags {
190+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191+
if self.r & self.w & self.x {
192+
return write!(f, "{}", "rwx".red());
193+
}
194+
write!(
195+
f,
196+
"{}{}{}",
197+
if self.r { "r" } else { "-" },
198+
if self.w { "w" } else { "-" },
199+
if self.x { "x" } else { "-" }
200+
)
201+
}
202+
}
203+
204+
#[cfg(all(feature = "maps", target_os = "linux"))]
205+
#[derive(Deserialize, Serialize)]
206+
pub struct MapEntry {
207+
pub region: Region,
208+
pub flags: MapFlags,
209+
pub pathname: Option<PathBuf>,
210+
}
211+
#[cfg(all(not(feature = "color"), feature = "maps", target_os = "linux"))]
212+
impl fmt::Display for MapEntry {
213+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214+
write!(
215+
f,
216+
"0x{:x}->0x{:x} {} {}",
217+
self.region.start,
218+
self.region.end,
219+
self.flags,
220+
match &self.pathname {
221+
Some(pathname) => pathname.display().to_string(),
222+
None => "".to_string(),
223+
}
224+
)
225+
}
226+
}
227+
#[cfg(all(feature = "color", feature = "maps", target_os = "linux"))]
228+
impl fmt::Display for MapEntry {
229+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230+
if self.flags.r & self.flags.w & self.flags.x {
231+
write!(
232+
f,
233+
"{} {}",
234+
format!(
235+
"0x{:x}->0x{:x} {}",
236+
self.region.start, self.region.end, self.flags
237+
)
238+
.red(),
239+
match &self.pathname {
240+
Some(pathname) => pathname.display().to_string().red(),
241+
None => "".to_string().red(),
242+
}
243+
)
244+
} else {
245+
write!(
246+
f,
247+
"0x{:x}->0x{:x} {} {}",
248+
self.region.start,
249+
self.region.end,
250+
self.flags,
251+
match &self.pathname {
252+
Some(pathname) => pathname.display().to_string(),
253+
None => "".to_string(),
254+
}
255+
)
256+
}
257+
}
258+
}
259+
138260
#[derive(Deserialize, Serialize)]
139261
pub struct Process {
140262
pub pid: usize,
141263
pub binary: Vec<Binary>,
264+
#[cfg(all(feature = "maps", target_os = "linux"))]
265+
pub maps: Option<Vec<MapEntry>>,
142266
}
143267
impl Process {
268+
#[cfg(any(not(feature = "maps"), not(target_os = "linux")))]
144269
pub fn new(pid: usize, binary: Vec<Binary>) -> Self {
145270
Self { pid, binary }
146271
}
272+
#[cfg(all(feature = "maps", target_os = "linux"))]
273+
pub fn new(pid: usize, binary: Vec<Binary>) -> Self {
274+
match Process::parse_maps(pid) {
275+
Ok(maps) => Self { pid, binary, maps: Some(maps) },
276+
Err(_) => Self { pid, binary, maps: None },
277+
}
278+
}
279+
#[cfg(all(feature = "maps", target_os = "linux"))]
280+
pub fn parse_maps(pid: usize) -> Result<Vec<MapEntry>, Error> {
281+
let mut maps: Vec<MapEntry> = Vec::new();
282+
if let Ok(maps_str) = fs::read_to_string(format!("/proc/{}/maps", pid))
283+
{
284+
for line in maps_str.lines() {
285+
let mut split_line = line.split_whitespace();
286+
let (start_str, end_str) = split_line
287+
.next()
288+
.ok_or(ErrorKind::InvalidData)?
289+
.split_once('-')
290+
.ok_or(ErrorKind::InvalidData)?;
291+
let region = Region::new(
292+
usize::from_str_radix(start_str, 16).unwrap_or(0),
293+
usize::from_str_radix(end_str, 16).unwrap_or(0),
294+
);
295+
let flags = MapFlags::new(
296+
split_line.next().ok_or(ErrorKind::InvalidData)?,
297+
);
298+
split_line.next(); // skip offset
299+
split_line.next(); // skip dev
300+
split_line.next(); // skip inode
301+
let pathname =
302+
Some(split_line.collect::<Vec<&str>>().join(" "))
303+
.filter(|x| !x.is_empty())
304+
.map(PathBuf::from);
305+
maps.push(MapEntry { region, flags, pathname });
306+
}
307+
return Ok(maps);
308+
}
309+
Err(Error::last_os_error())
310+
}
147311
}
148312

149313
#[derive(Deserialize, Serialize)]

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ pub mod elf;
4949
#[cfg(feature = "macho")]
5050
pub mod macho;
5151
pub mod macros;
52+
pub mod output;
5253
#[cfg(feature = "pe")]
5354
pub mod pe;
5455
#[cfg(feature = "shared")]
5556
#[macro_use]
5657
pub mod shared;
57-
pub mod output;

0 commit comments

Comments
 (0)