@@ -4,6 +4,8 @@ use crate::vfs;
44use alloc:: collections:: BTreeMap ;
55use alloc:: format;
66use alloc:: string:: { String , ToString } ;
7+ use alloc:: vec:: Vec ;
8+ use regf:: Hive ;
79use spin:: { Lazy , Mutex } ;
810
911pub type NtStatus = i32 ;
@@ -370,6 +372,7 @@ pub enum ObjectType {
370372 Directory ,
371373 SymbolicLink ,
372374 File ,
375+ Key ,
373376 Section ,
374377 Process ,
375378 Thread ,
@@ -382,6 +385,11 @@ pub struct FileObject {
382385 pub vfs_handle : i32 ,
383386}
384387
388+ #[ derive( Debug , Clone ) ]
389+ pub struct KeyObject {
390+ pub path : String ,
391+ }
392+
385393#[ derive( Debug , Clone , Copy ) ]
386394pub struct EventObject {
387395 pub signaled : bool ,
@@ -417,6 +425,7 @@ pub enum ObjectData {
417425 Directory ,
418426 SymbolicLink { target : String } ,
419427 File ( FileObject ) ,
428+ Key ( KeyObject ) ,
420429 Section ( SectionObject ) ,
421430 Process ( ProcessObject ) ,
422431 Thread ( ThreadObject ) ,
@@ -445,6 +454,14 @@ static OBJECTS: Lazy<Mutex<ObjectManager>> = Lazy::new(|| {
445454 } )
446455} ) ;
447456
457+ #[ derive( Default ) ]
458+ struct RegistryState {
459+ loaded : bool ,
460+ system_hive : Option < Hive > ,
461+ }
462+
463+ static REGISTRY : Lazy < Mutex < RegistryState > > = Lazy :: new ( || Mutex :: new ( RegistryState :: default ( ) ) ) ;
464+
448465pub fn init_namespace ( ) {
449466 let mut objects = OBJECTS . lock ( ) ;
450467 if !objects. named . is_empty ( ) {
@@ -454,6 +471,8 @@ pub fn init_namespace() {
454471 let _ = create_named ( & mut objects, "\\ " , ObjectData :: Directory ) ;
455472 let _ = create_named ( & mut objects, "\\ Device" , ObjectData :: Directory ) ;
456473 let _ = create_named ( & mut objects, "\\ ??" , ObjectData :: Directory ) ;
474+ let _ = create_named ( & mut objects, "\\ Registry" , ObjectData :: Directory ) ;
475+ let _ = create_named ( & mut objects, "\\ Registry\\ Machine" , ObjectData :: Directory ) ;
457476 let _ = create_named ( & mut objects, "\\ KnownDlls" , ObjectData :: Directory ) ;
458477 let _ = create_named ( & mut objects, "\\ Device\\ Crabfs0" , ObjectData :: Directory ) ;
459478 let _ = create_named (
@@ -517,13 +536,120 @@ fn object_type_of(data: &ObjectData) -> ObjectType {
517536 ObjectData :: Directory => ObjectType :: Directory ,
518537 ObjectData :: SymbolicLink { .. } => ObjectType :: SymbolicLink ,
519538 ObjectData :: File ( _) => ObjectType :: File ,
539+ ObjectData :: Key ( _) => ObjectType :: Key ,
520540 ObjectData :: Section ( _) => ObjectType :: Section ,
521541 ObjectData :: Process ( _) => ObjectType :: Process ,
522542 ObjectData :: Thread ( _) => ObjectType :: Thread ,
523543 ObjectData :: Event ( _) => ObjectType :: Event ,
524544 }
525545}
526546
547+ fn read_file_all ( path : & str ) -> Result < Vec < u8 > , NtStatus > {
548+ let fd = vfs:: open ( path, 0 ) . map_err ( |_| STATUS_OBJECT_NAME_NOT_FOUND ) ?;
549+ let mut data = Vec :: new ( ) ;
550+ let mut buf = [ 0u8 ; 4096 ] ;
551+ loop {
552+ let n = vfs:: read ( fd, & mut buf) . map_err ( |_| STATUS_UNSUCCESSFUL ) ?;
553+ if n == 0 {
554+ break ;
555+ }
556+ data. extend_from_slice ( & buf[ ..n] ) ;
557+ }
558+ let _ = vfs:: close ( fd) ;
559+ Ok ( data)
560+ }
561+
562+ fn ensure_system_hive_loaded ( ) -> Result < ( ) , NtStatus > {
563+ let mut reg = REGISTRY . lock ( ) ;
564+ if reg. loaded {
565+ return Ok ( ( ) ) ;
566+ }
567+ let data = read_file_all ( "/Windows/System32/config/SYSTEM" ) ?;
568+ let hive = Hive :: parse ( & data) . map_err ( |_| STATUS_INVALID_IMAGE_FORMAT ) ?;
569+ reg. system_hive = Some ( hive) ;
570+ reg. loaded = true ;
571+ Ok ( ( ) )
572+ }
573+
574+ fn system_hive_subkey ( path : & str ) -> Option < String > {
575+ let canonical = canonicalize_nt_path ( path) ;
576+ let lower = canonical. to_ascii_lowercase ( ) ;
577+ let prefix = "\\ registry\\ machine\\ system" ;
578+ if lower == prefix {
579+ return Some ( String :: new ( ) ) ;
580+ }
581+ if !lower. starts_with ( prefix) {
582+ return None ;
583+ }
584+ let mut rest = & canonical[ prefix. len ( ) ..] ;
585+ while rest. starts_with ( '\\' ) {
586+ rest = & rest[ 1 ..] ;
587+ }
588+ Some ( rest. to_string ( ) )
589+ }
590+
591+ pub fn open_key ( path : & str ) -> Result < u32 , NtStatus > {
592+ init_namespace ( ) ;
593+ ensure_system_hive_loaded ( ) ?;
594+ let Some ( subkey) = system_hive_subkey ( path) else {
595+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
596+ } ;
597+ let reg = REGISTRY . lock ( ) ;
598+ let Some ( hive) = reg. system_hive . as_ref ( ) else {
599+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
600+ } ;
601+ if !hive. has_key ( & subkey) {
602+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
603+ }
604+ drop ( reg) ;
605+ let mut objects = OBJECTS . lock ( ) ;
606+ Ok ( insert_unnamed (
607+ & mut objects,
608+ ObjectData :: Key ( KeyObject {
609+ path : canonicalize_nt_path ( path) ,
610+ } ) ,
611+ ) )
612+ }
613+
614+ pub fn query_key_value ( object_id : u32 , value_name : & str ) -> Result < ( u32 , Vec < u8 > ) , NtStatus > {
615+ ensure_system_hive_loaded ( ) ?;
616+ let key_path = {
617+ let objects = OBJECTS . lock ( ) ;
618+ let Some ( record) = objects. objects . get ( & object_id) else {
619+ return Err ( STATUS_INVALID_HANDLE ) ;
620+ } ;
621+ match & record. data {
622+ ObjectData :: Key ( key) => key. path . clone ( ) ,
623+ _ => return Err ( STATUS_OBJECT_TYPE_MISMATCH ) ,
624+ }
625+ } ;
626+ let Some ( subkey) = system_hive_subkey ( & key_path) else {
627+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
628+ } ;
629+ let reg = REGISTRY . lock ( ) ;
630+ let Some ( hive) = reg. system_hive . as_ref ( ) else {
631+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
632+ } ;
633+ let Some ( value) = hive. query_value ( & subkey, value_name) else {
634+ return Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ;
635+ } ;
636+ Ok ( ( value. ty , value. data . clone ( ) ) )
637+ }
638+
639+ pub fn object_name ( object_id : u32 ) -> Result < String , NtStatus > {
640+ let objects = OBJECTS . lock ( ) ;
641+ let Some ( record) = objects. objects . get ( & object_id) else {
642+ return Err ( STATUS_INVALID_HANDLE ) ;
643+ } ;
644+ if let Some ( name) = & record. name {
645+ return Ok ( name. clone ( ) ) ;
646+ }
647+ match & record. data {
648+ ObjectData :: Key ( key) => Ok ( key. path . clone ( ) ) ,
649+ _ => Err ( STATUS_OBJECT_NAME_NOT_FOUND ) ,
650+ }
651+ }
652+
527653pub fn create_file ( path : String , vfs_handle : i32 ) -> u32 {
528654 let mut objects = OBJECTS . lock ( ) ;
529655 insert_unnamed (
0 commit comments