Windows'ta bir dosyayı sildiğinizde, özellikle Windows 10 Professional x64'te, dosya kullanıcının görüşünden kaldırılır ve kalıcı olarak silinmesi için geri dönüşüm kutusuna yerleştirilir. Bu kalıcı silme gerçekleştirildikten sonra 'dosya gerçekten gitti mi?' diye sorular oluşabilir. Cevap hayır, hemen değil! Hatta silinmeden sonra dosya yalnızca kullanılmayan bir alan olarak işaretlenir ve üzerine yazılabilir durumda olur.
Eğer NTFS'nin nasıl çalıştığı hakkında bilgi sahibi değilseniz, bu detaylı açıklamaya bakmanız önemlidir. Çünkü bu konu tek bir makalede ele alınabilecek kadar karmaşıktır. Bu yazının ayrıntılarını ve teorisini anlamak için bu dosya sistemine ve dosya verilerini nasıl depolayıp düzenlediğine dair bilgilere bu yazının sonlarına doğru referans vereceğim. Ancak başlamak için, sadece bir dosyayı silerken neler olduğunu basitleştireceğim.
Bir dosyayı seçip sonra Delete tuşuna bastığınızda, Windows UserMode modülü kernelbase.dll içinde DeleteFileW adlı bir rutini çağırır. Gerçekleşen ilk şey, sistemin dosyaya bir tanıtıcı alması gerektiğidir, bunu mevcut dosyayı, dizini veya kaynağı açmak ve üzerinde çalışacak bir tanıtıcı elde etmek için NtOpenFile kullanarak yapar. Dosya varsa ve geçerli bir tanıtıcı elde edilirse, sistem NtQueryInformationFile sistem rutini ile FileInformationClass bağımsız değişkeni olarak FileAttributeTagInformation enum değerini kullanarak dosya özniteliklerini sorgular. Bu çağrının nedeni, dosyanın, dosyayla ilişkili harici bilgileri bulmak için kullanılan bir yeniden ayrıştırma noktasına sahip olup olmadığını kontrol etmektir.
NtQueryInformationFile çağrısının ardından prosedür, ??C:UsersuintptrDesktoptecholay.exe gibi görünebilecek yerel yol adını serbest bırakarak devam eder. Bunu, dosyayı silinmeye hazır hale getirmek ve kalabilecek geçici verileri temizlemek için yapar. Uygun rutinleri çağırdıktan sonra, dosyanın silinmesini istemek için dosya eğilim bilgilerini ayarlamak için kullanılan NtSetInformationFile'ı çağırır. Bu istek bir IRP (I/O İstek Paketi) ile paketlendikten sonra kabul edilir ve tamamlanması için uygun cihaz nesnesine gönderilir. Bunu tamamlayan rutin, IRP'yi işlenmek üzere aygıt nesnesine gönderen IoCallDriver'dır.
Yukarıdakilerin tümü tamamlandığında ve dosya kullanıcının görüş alanı dışına çıktığında, dosyayla ilişkili _FILE_OBJECT yapısındaki DeletePending alanı true olarak ayarlanır ve dosyanın son tanıtıcısı serbest bırakıldığında dosya silinmek üzere işaretlenir. Dosyanın gerçek silme işlemi, ayrılan kümelerin ayrılmasını içerir ve IRP_MJ_CLEANUP sürücü tarafından işlenir. IRP_MJ_CLEANUP'ın işlenmesi, nesneye giden son tutamacın kapatıldığı anlamına gelir ancak dosya veya nesne için bekleyen G/Ç istekleri hala kuyrukta olabilir, bu da bir IRP_MJ_CLOSE işlenip hesaba katılana kadar dosyanın tamamlanmamış G/Ç istekleri için hala erişilebilir olduğu anlamına gelir. Bu, temizlemeden sonra bile verilerin hala kaldığı anlamına gelir, bu da kurtarmaya izin veren bir şeydir. Aslında, dosyanın son tanıtıcısı kapatıldıktan ve IRP_MJ_CLOSE işlendikten sonra bile, veriler diskte referans için kullanılabilir durumda kalır. Sadece geleneksel dosya açma yöntemleriyle kullanılamaz. Silinmediği veya üzerine yazılmadığı sürece, silinmiş bir dosyanın geleneksel olmayan bir şekilde nasıl kurtarılabileceğini açıklayacağım...
Teorik Olarak Kurtarma Yöntemi
Silinen dosyaları kurtarmanın pratik yönüyle ilgili zaten deneyimim olduğundan, bir NTFS biriminde silinen dosyaları kurtarma olasılığını ilk araştırmaya başladığımda sahip olduğum küçük bir teori ile başlayabileceğimi düşündüm.
Bir NTFS birimindeki Ana Dosya Tablosunu yinelemenin ve MFT'deki kayıtların her birinde PNG, MZ, DS vb. gibi belirli dosya biçimi başlıklarını aramak için bir hex editörü kullanmanın mümkün olacağına inanıyordum. Ancak bu yaklaşım son derece zahmetli olacaktır çünkü ortalama bir bilgisayar kullanıcısının makinesinde yüzlerce çalıştırılabilir dosya, muhtemelen çok sayıda resim (PNG veya JPEG) ve ilk olarak arayacağım dosya biçimi başlıklarına sahip diğer yaygın dosya türleri vardır. Eğer ilgilendiğim bu dosyayı kurtarmak isteseydim, sürücüdeki her bölümü, her sektörü, MFT'deki her kaydı incelemem, ortak bir dosya biçimi başlığına sahip bu kaydın dosya verilerini kopyalamam ve daha somut bir şey elde edene kadar aynı verilerle yeni bir dosya oluşturmam gerekirdi. Eminim bunu yapmanın başka yolları da vardır, ancak bunun gülünç derecede zaman alıcı ve etkisiz olacağını hemen fark ettim.
Bu yüzden daha pratik bir yaklaşım benimsedim ve MFT'deki kayıtları yineleyen, bilgileri düzgün bir şekilde biçimlendirilmiş bir şekilde depolayan ve ilgilenilen kayıtlarla etkileşim için kaba bir kullanıcı arayüzü sağlayan ve belirli bir kaydın verilerini analiz için yeni bir dosyaya geri yazmama izin veren bir kurtarma aracı yazdım.
Pratik Olarak Kurtarma Yöntemi
Bu dosya kurtarma aracının oluşturulmasının arkasındaki düşünce sürecini kısaca açıklayacağım. Dosya sistemi bilgisinin bu noktada faydalı olduğunu da belirtmek isterim çünkü dosya silindikten ve kümeler ayrıldıktan sonra bile geride hala bilgi kalmaktadır. Bu nedenle, kümelerinin üzerine henüz yeni veriler yazılmadığı sürece silinen dosyaları kurtarmanın mümkün olduğu belirtilmektedir. Ana Dosya Tablosunun bir NTFS birimindeki her dosyanın özniteliklerini, bayraklarını ve adını içerdiğinden kısaca bahsedeceğim. Dosyanın içeriği silinmediği veya üzerine yazılmadığı sürece, başka bir dosya kümenin üzerine yazılana kadar veriler kalmaya devam eder.
Teoride ve pratikte (yayınlamaya değer bir programım yok), diskte bulunan bölüm tabloları hakkında bilgi edinmek için önce fiziksel sürücüyü (\.PhysicalDriveN) açıp okuyarak silinen dosyaları kurtarabilirsiniz. Daha sonra, fiziksel diskin bölümlerini tarar ve bölüm biçimlendirmesini doğrularsınız, bu özel durumda NTFS'yi çağırırız. Genişletilmiş bölümleri de kontrol edebilirsiniz ve ben bunu tavsiye ederim. Sektör bilgilerini elde ettikten sonra, NTFS biriminin başlangıcını işaret edebilir, Ana Dosya Tablosu (MFT) bilgileri için önyükleme sektörünü okuyabilir, tüm mantıksal MFT kümesini yükleyebilir, her zaman $MFT kaydı olacak olan ilk kaydı okuyabilir ve ardından kayıttan bilgileri çıkarabilirsiniz. Tüm bu bilgileri tutmak için kolayca bir yapı veya sınıf oluşturulabilir ve bunların hepsi burada bağlantısı verilen MSDN referansında belirtilmiştir.
Eğer NTFS'nin nasıl çalıştığı hakkında bilgi sahibi değilseniz, bu detaylı açıklamaya bakmanız önemlidir. Çünkü bu konu tek bir makalede ele alınabilecek kadar karmaşıktır. Bu yazının ayrıntılarını ve teorisini anlamak için bu dosya sistemine ve dosya verilerini nasıl depolayıp düzenlediğine dair bilgilere bu yazının sonlarına doğru referans vereceğim. Ancak başlamak için, sadece bir dosyayı silerken neler olduğunu basitleştireceğim.
Bir dosyayı seçip sonra Delete tuşuna bastığınızda, Windows UserMode modülü kernelbase.dll içinde DeleteFileW adlı bir rutini çağırır. Gerçekleşen ilk şey, sistemin dosyaya bir tanıtıcı alması gerektiğidir, bunu mevcut dosyayı, dizini veya kaynağı açmak ve üzerinde çalışacak bir tanıtıcı elde etmek için NtOpenFile kullanarak yapar. Dosya varsa ve geçerli bir tanıtıcı elde edilirse, sistem NtQueryInformationFile sistem rutini ile FileInformationClass bağımsız değişkeni olarak FileAttributeTagInformation enum değerini kullanarak dosya özniteliklerini sorgular. Bu çağrının nedeni, dosyanın, dosyayla ilişkili harici bilgileri bulmak için kullanılan bir yeniden ayrıştırma noktasına sahip olup olmadığını kontrol etmektir.
NtQueryInformationFile çağrısının ardından prosedür, ??C:UsersuintptrDesktoptecholay.exe gibi görünebilecek yerel yol adını serbest bırakarak devam eder. Bunu, dosyayı silinmeye hazır hale getirmek ve kalabilecek geçici verileri temizlemek için yapar. Uygun rutinleri çağırdıktan sonra, dosyanın silinmesini istemek için dosya eğilim bilgilerini ayarlamak için kullanılan NtSetInformationFile'ı çağırır. Bu istek bir IRP (I/O İstek Paketi) ile paketlendikten sonra kabul edilir ve tamamlanması için uygun cihaz nesnesine gönderilir. Bunu tamamlayan rutin, IRP'yi işlenmek üzere aygıt nesnesine gönderen IoCallDriver'dır.
Yukarıdakilerin tümü tamamlandığında ve dosya kullanıcının görüş alanı dışına çıktığında, dosyayla ilişkili _FILE_OBJECT yapısındaki DeletePending alanı true olarak ayarlanır ve dosyanın son tanıtıcısı serbest bırakıldığında dosya silinmek üzere işaretlenir. Dosyanın gerçek silme işlemi, ayrılan kümelerin ayrılmasını içerir ve IRP_MJ_CLEANUP sürücü tarafından işlenir. IRP_MJ_CLEANUP'ın işlenmesi, nesneye giden son tutamacın kapatıldığı anlamına gelir ancak dosya veya nesne için bekleyen G/Ç istekleri hala kuyrukta olabilir, bu da bir IRP_MJ_CLOSE işlenip hesaba katılana kadar dosyanın tamamlanmamış G/Ç istekleri için hala erişilebilir olduğu anlamına gelir. Bu, temizlemeden sonra bile verilerin hala kaldığı anlamına gelir, bu da kurtarmaya izin veren bir şeydir. Aslında, dosyanın son tanıtıcısı kapatıldıktan ve IRP_MJ_CLOSE işlendikten sonra bile, veriler diskte referans için kullanılabilir durumda kalır. Sadece geleneksel dosya açma yöntemleriyle kullanılamaz. Silinmediği veya üzerine yazılmadığı sürece, silinmiş bir dosyanın geleneksel olmayan bir şekilde nasıl kurtarılabileceğini açıklayacağım...
Teorik Olarak Kurtarma Yöntemi
Silinen dosyaları kurtarmanın pratik yönüyle ilgili zaten deneyimim olduğundan, bir NTFS biriminde silinen dosyaları kurtarma olasılığını ilk araştırmaya başladığımda sahip olduğum küçük bir teori ile başlayabileceğimi düşündüm.
Bir NTFS birimindeki Ana Dosya Tablosunu yinelemenin ve MFT'deki kayıtların her birinde PNG, MZ, DS vb. gibi belirli dosya biçimi başlıklarını aramak için bir hex editörü kullanmanın mümkün olacağına inanıyordum. Ancak bu yaklaşım son derece zahmetli olacaktır çünkü ortalama bir bilgisayar kullanıcısının makinesinde yüzlerce çalıştırılabilir dosya, muhtemelen çok sayıda resim (PNG veya JPEG) ve ilk olarak arayacağım dosya biçimi başlıklarına sahip diğer yaygın dosya türleri vardır. Eğer ilgilendiğim bu dosyayı kurtarmak isteseydim, sürücüdeki her bölümü, her sektörü, MFT'deki her kaydı incelemem, ortak bir dosya biçimi başlığına sahip bu kaydın dosya verilerini kopyalamam ve daha somut bir şey elde edene kadar aynı verilerle yeni bir dosya oluşturmam gerekirdi. Eminim bunu yapmanın başka yolları da vardır, ancak bunun gülünç derecede zaman alıcı ve etkisiz olacağını hemen fark ettim.
Bu yüzden daha pratik bir yaklaşım benimsedim ve MFT'deki kayıtları yineleyen, bilgileri düzgün bir şekilde biçimlendirilmiş bir şekilde depolayan ve ilgilenilen kayıtlarla etkileşim için kaba bir kullanıcı arayüzü sağlayan ve belirli bir kaydın verilerini analiz için yeni bir dosyaya geri yazmama izin veren bir kurtarma aracı yazdım.
Pratik Olarak Kurtarma Yöntemi
Bu dosya kurtarma aracının oluşturulmasının arkasındaki düşünce sürecini kısaca açıklayacağım. Dosya sistemi bilgisinin bu noktada faydalı olduğunu da belirtmek isterim çünkü dosya silindikten ve kümeler ayrıldıktan sonra bile geride hala bilgi kalmaktadır. Bu nedenle, kümelerinin üzerine henüz yeni veriler yazılmadığı sürece silinen dosyaları kurtarmanın mümkün olduğu belirtilmektedir. Ana Dosya Tablosunun bir NTFS birimindeki her dosyanın özniteliklerini, bayraklarını ve adını içerdiğinden kısaca bahsedeceğim. Dosyanın içeriği silinmediği veya üzerine yazılmadığı sürece, başka bir dosya kümenin üzerine yazılana kadar veriler kalmaya devam eder.
Teoride ve pratikte (yayınlamaya değer bir programım yok), diskte bulunan bölüm tabloları hakkında bilgi edinmek için önce fiziksel sürücüyü (\.PhysicalDriveN) açıp okuyarak silinen dosyaları kurtarabilirsiniz. Daha sonra, fiziksel diskin bölümlerini tarar ve bölüm biçimlendirmesini doğrularsınız, bu özel durumda NTFS'yi çağırırız. Genişletilmiş bölümleri de kontrol edebilirsiniz ve ben bunu tavsiye ederim. Sektör bilgilerini elde ettikten sonra, NTFS biriminin başlangıcını işaret edebilir, Ana Dosya Tablosu (MFT) bilgileri için önyükleme sektörünü okuyabilir, tüm mantıksal MFT kümesini yükleyebilir, her zaman $MFT kaydı olacak olan ilk kaydı okuyabilir ve ardından kayıttan bilgileri çıkarabilirsiniz. Tüm bu bilgileri tutmak için kolayca bir yapı veya sınıf oluşturulabilir ve bunların hepsi burada bağlantısı verilen MSDN referansında belirtilmiştir.