1- use std:: ffi:: CString ;
2-
31#[ derive( Debug ) ]
42pub struct ModuleInfo {
53 pub base_address : usize ,
@@ -9,31 +7,35 @@ pub struct ModuleInfo {
97#[ derive( Debug ) ]
108pub enum ModuleError {
119 NotFound ,
12- InvalidName ,
10+ InvalidBase ,
1311 SystemError ( String ) ,
1412}
1513
1614impl std:: fmt:: Display for ModuleError {
1715 fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
1816 match self {
1917 ModuleError :: NotFound => write ! ( f, "Module not found" ) ,
20- ModuleError :: InvalidName => write ! ( f, "Invalid module name " ) ,
18+ ModuleError :: InvalidBase => write ! ( f, "Invalid module base address " ) ,
2119 ModuleError :: SystemError ( msg) => write ! ( f, "System error: {}" , msg) ,
2220 }
2321 }
2422}
2523
2624impl std:: error:: Error for ModuleError { }
2725
28- pub fn get_module_info ( module_name : & str ) -> Result < ModuleInfo , ModuleError > {
26+ pub fn get_module_info ( module_base : u64 ) -> Result < ModuleInfo , ModuleError > {
27+ if module_base == 0 || module_base > usize:: MAX as u64 {
28+ return Err ( ModuleError :: InvalidBase ) ;
29+ }
30+
2931 #[ cfg( target_os = "windows" ) ]
3032 {
31- get_module_info_windows ( module_name )
33+ get_module_info_windows ( module_base as usize )
3234 }
3335
3436 #[ cfg( target_os = "linux" ) ]
3537 {
36- get_module_info_linux ( module_name )
38+ get_module_info_linux ( module_base as usize )
3739 }
3840
3941 #[ cfg( not( any( target_os = "windows" , target_os = "linux" ) ) ) ]
@@ -43,21 +45,18 @@ pub fn get_module_info(module_name: &str) -> Result<ModuleInfo, ModuleError> {
4345}
4446
4547#[ cfg( target_os = "windows" ) ]
46- fn get_module_info_windows ( module_name : & str ) -> Result < ModuleInfo , ModuleError > {
48+ fn get_module_info_windows ( module_base : usize ) -> Result < ModuleInfo , ModuleError > {
4749 use std:: mem;
4850 use winapi:: shared:: minwindef:: { FALSE , HMODULE } ;
49- use winapi:: um:: libloaderapi:: GetModuleHandleA ;
5051 use winapi:: um:: processthreadsapi:: GetCurrentProcess ;
5152 use winapi:: um:: psapi:: { GetModuleInformation , MODULEINFO } ;
5253
53- let c_name = CString :: new ( module_name) . map_err ( |_| ModuleError :: InvalidName ) ?;
54+ if module_base == 0 {
55+ return Err ( ModuleError :: InvalidBase ) ;
56+ }
5457
5558 unsafe {
56- let h_module: HMODULE = GetModuleHandleA ( c_name. as_ptr ( ) ) ;
57-
58- if h_module. is_null ( ) {
59- return Err ( ModuleError :: NotFound ) ;
60- }
59+ let h_module: HMODULE = module_base as HMODULE ;
6160
6261 let mut mod_info: MODULEINFO = mem:: zeroed ( ) ;
6362 let result = GetModuleInformation (
@@ -68,9 +67,14 @@ fn get_module_info_windows(module_name: &str) -> Result<ModuleInfo, ModuleError>
6867 ) ;
6968
7069 if result == FALSE {
71- return Err ( ModuleError :: SystemError (
72- "GetModuleInformation failed" . to_string ( ) ,
73- ) ) ;
70+ const ERROR_INVALID_HANDLE : i32 = 6 ;
71+ let error = std:: io:: Error :: last_os_error ( ) ;
72+ if error. raw_os_error ( ) == Some ( ERROR_INVALID_HANDLE ) {
73+ return Err ( ModuleError :: NotFound ) ;
74+ }
75+ return Err ( ModuleError :: SystemError ( format ! (
76+ "GetModuleInformation failed with error: {error}"
77+ ) ) ) ;
7478 }
7579
7680 Ok ( ModuleInfo {
@@ -81,46 +85,97 @@ fn get_module_info_windows(module_name: &str) -> Result<ModuleInfo, ModuleError>
8185}
8286
8387#[ cfg( target_os = "linux" ) ]
84- fn get_module_info_linux ( module_name : & str ) -> Result < ModuleInfo , ModuleError > {
88+ fn get_module_info_linux ( module_base : usize ) -> Result < ModuleInfo , ModuleError > {
8589 use std:: fs:: File ;
8690 use std:: io:: { BufRead , BufReader } ;
8791
92+ if module_base == 0 {
93+ return Err ( ModuleError :: InvalidBase ) ;
94+ }
95+
8896 let maps_file = File :: open ( "/proc/self/maps" )
8997 . map_err ( |e| ModuleError :: SystemError ( format ! ( "Cannot open /proc/self/maps: {}" , e) ) ) ?;
9098
9199 let reader = BufReader :: new ( maps_file) ;
92100 let mut base_address: Option < usize > = None ;
93101 let mut end_address: Option < usize > = None ;
102+ let mut module_path: Option < String > = None ;
103+ let mut module_dev: Option < String > = None ;
104+ let mut module_inode: Option < String > = None ;
94105
95106 for line in reader. lines ( ) {
96107 let line = line. map_err ( |e| ModuleError :: SystemError ( format ! ( "Read error: {}" , e) ) ) ?;
97108
98- if line. contains ( module_name) {
99- let parts: Vec < & str > = line. split_whitespace ( ) . collect ( ) ;
100- if parts. is_empty ( ) {
101- continue ;
109+ let trimmed = line. trim ( ) ;
110+ if trimmed. is_empty ( ) {
111+ continue ;
112+ }
113+
114+ let parts: Vec < & str > = trimmed. split_whitespace ( ) . collect ( ) ;
115+ if parts. is_empty ( ) {
116+ continue ;
117+ }
118+
119+ let addr_range: Vec < & str > = parts[ 0 ] . split ( '-' ) . collect ( ) ;
120+ if addr_range. len ( ) != 2 {
121+ continue ;
122+ }
123+
124+ let start = usize:: from_str_radix ( addr_range[ 0 ] , 16 )
125+ . map_err ( |_| ModuleError :: SystemError ( "Invalid address format" . to_string ( ) ) ) ?;
126+ let end = usize:: from_str_radix ( addr_range[ 1 ] , 16 )
127+ . map_err ( |_| ModuleError :: SystemError ( "Invalid address format" . to_string ( ) ) ) ?;
128+
129+ let current_dev = parts. get ( 3 ) . map ( |s| s. to_string ( ) ) ;
130+ let current_inode = parts. get ( 4 ) . map ( |s| s. to_string ( ) ) ;
131+ let current_path = if parts. len ( ) > 5 {
132+ Some ( parts[ 5 ..] . join ( " " ) )
133+ } else {
134+ None
135+ } ;
136+
137+ if base_address. is_none ( ) {
138+ if start == module_base {
139+ base_address = Some ( start) ;
140+ end_address = Some ( end) ;
141+ module_path = current_path;
142+ module_dev = current_dev;
143+ module_inode = current_inode;
102144 }
145+ continue ;
146+ }
147+
148+ let matches_path = match ( & module_path, & current_path) {
149+ ( Some ( expected) , Some ( actual) ) => expected == actual,
150+ ( None , None ) => true ,
151+ _ => false ,
152+ } ;
103153
104- let addr_range : Vec < & str > = parts [ 0 ] . split ( '-' ) . collect ( ) ;
105- if addr_range . len ( ) != 2 {
106- continue ;
154+ let matches_identity = match ( & module_dev , & module_inode , & current_dev , & current_inode ) {
155+ ( Some ( expected_dev ) , Some ( expected_inode ) , Some ( dev ) , Some ( inode ) ) => {
156+ expected_dev == dev && expected_inode == inode
107157 }
158+ _ => false ,
159+ } ;
108160
109- let start = usize:: from_str_radix ( addr_range[ 0 ] , 16 )
110- . map_err ( |_| ModuleError :: SystemError ( "Invalid address format" . to_string ( ) ) ) ?;
111- let end = usize:: from_str_radix ( addr_range[ 1 ] , 16 )
112- . map_err ( |_| ModuleError :: SystemError ( "Invalid address format" . to_string ( ) ) ) ?;
161+ let contiguous = end_address. map_or ( false , |current_end| start == current_end) ;
113162
114- if base_address. is_none ( ) {
115- base_address = Some ( start) ;
163+ if matches_path || matches_identity || contiguous {
164+ match end_address {
165+ Some ( ref mut stored_end) if end > * stored_end => * stored_end = end,
166+ None => end_address = Some ( end) ,
167+ _ => { }
116168 }
169+ continue ;
170+ }
117171
118- end_address = Some ( end) ;
172+ if start > module_base {
173+ break ;
119174 }
120175 }
121176
122177 match ( base_address, end_address) {
123- ( Some ( base) , Some ( end) ) => Ok ( ModuleInfo {
178+ ( Some ( base) , Some ( end) ) if end > base => Ok ( ModuleInfo {
124179 base_address : base,
125180 size : end - base,
126181 } ) ,
0 commit comments