19.05.2026

Güvenli önyükleme sertifikaları

Bir süredir hayatımızda güvenli önyükleme (secure boot) diye bir şey var, rootkit'lerin veya benzeri zararlı yazılımların bilgisayarın ilk açılış aşamasında devreye girmesini engellemek için. Bu sistem, etkinleştirildikten sonra çalışacak olan önyükleme kodunun yetkilendirilmiş olup olmadığını anlamak için sertifikalar kullanılıyor. İşin içinde sertifika varsa bir de geçerlilik süresi vardır. Ve bu sene de, 2011'de kullanılmaya başlayan (nedendir bilinmez) Microsoft sertifikalarının son senesi. Güncellenmeleri lazım.

Süreç prüzsüz işliyor. Güvenli önyükleme firmware'de etkinleştirilmişse (aksi takdirde 1796 Microsoft-Windows-TPM-WMI olay kaydedilir) işletim sistemi, yeni sertifikaları kurup güvenliği sağlıyor. Süreci kontrol etmek isteyenler için Ayarlar>Gizlilik ve Güvenlik>Cihaz Güvenliği adımında "Güvenli Önyükleme" bölümündeki mesaja bakılabilir. Eğer aşağıdaki gibi bir durumdaysa herşey olması gerektiği gibi işlemiş demektir. Kurulum üst üste birkaç kez yeniden başlatma istiyor.

 

İşleri powershell ile kontrol etmek için Get-SecureBootUEFI cmdlet'i kullanılabilir. Bu cmdlet'in -Name parametresine DB ve KEK (depoları) verilerek istenen sertifikaların sistemde mevcut olup olmadığı kontrol edilebilir. Olması gereken sertifika isimleri, depo ismi ve son kullanma tarihleri şöyle:

Sertfika adıDepo adıSon kullanma tarihi
Windows UEFI CA 2023DB2035-06-13 22:08:29Z
Microsoft Option ROM UEFI CA 2023DB2038-10-26 22:12:20Z
Microsoft UEFI CA 2023DB2038-06-13 22:31:47Z
Microsoft Corporation KEK 2K CA 2023KEK2038-03-02 23:31:35Z

Tüm sertifikaların isimlerinde 2023 geçmesi sebebiyle bu kontrolü aşağıdaki gibi otomatikleştirebilirim.

$kek = Get-SecureBootUEFI -Name KEK -Decoded
$db  = Get-SecureBootUEFI -Name db  -Decoded

$arr1 ="Windows UEFI CA 2023","Microsoft UEFI CA 2023","Microsoft Option ROM UEFI CA 2023"

$res1 = $db  | Where-Object {$_.Subject -match "2023"} |
        Select-Object @{N="Subj";E={$_.Subject.split(",")[0].replace("CN=","")}},
                        @{N="Store";E={"DB"}}, ValidFrom, ValidTo,
                        @{N="Stat";E={if ($_.Subject.split(",")[0].replace("CN=","") -in $arr1) {"OK"} else {"NOT OK"}}}

$res1 += $kek  | Where-Object {$_.Subject -match "2023"} |
        Select-Object @{N="Subj";E={$_.Subject.split(",")[0].replace("CN=","")}},
                        @{N="Store";E={"KEK"}}, ValidFrom, ValidTo,
                        @{N="Stat";E={if ($_.Subject.split(",")[0].replace("CN=","") -eq "Microsoft Corporation KEK 2K CA 2023") {"OK"} else {"NOT OK"}}}
$res1 | Format-Table -AutoSize -Wrap

Sertifikaların kurulması sırasında ve sonrasında sistem olay günlüğüne Microsoft-Windows-TPM-WMI sağlayıcı ismi altında aşağıdaki olaylar kaydediliyor.

IDSağlayıcıSeviyeMesaj
1800Microsoft-Windows-TPM-WMIUyarıA reboot is required before installing the Secure Boot update.
Reason: Boot Manager (2023)
1801Microsoft-Windows-TPM-WMIHataUpdated Secured Boot certificates are available on this device but
have not yet been applied to the firmware.
1043Microsoft-Windows-TPM-WMIBilgiSecure Boot KEK update applied successfully
1045Microsoft-Windows-TPM-WMIBilgi

Secure Boot DB update to install Microsoft UEFI CA 2023
certificate applied successfully

1044Microsoft-Windows-TPM-WMIBilgiSecure Boot DB update to install Microsoft Option ROM
UEFI CA 2023 certificate applied successfully
1036Microsoft-Windows-TPM-WMIBilgiSecure Boot Db update applied successfully
1808Microsoft-Windows-TPM-WMIBilgiThis device has updated Secure Boot CA/keys.

En son 1808 ID'li olay, sistem nihai seviyeye ulaştıktan sonra kaydedildi. 

Bu sertifikaların olması sistemin korunduğu anlamına gelmiyor, bir veya daha fazla yeniden başlatma bekliyor olabilir. Nihai durum için hem firmware'de güvenli önyükleme açık olmalı hem de cihaz güvenliğinde yukarıda bahsettiğim mesaj görüntülenmeli.

Genel olarak bir KB ile başlayan güncelleştirme kodu bu sertifikaların yüklenmesi ile ilişkilendirilmemiş ama ben KB5089549 ve KB5092762 güncelleştirmelerini buldum, tam yüklenme sonrasında.

Linux tarafında mokutil ile sertifikaların varlığı kontrol edilebilir:

sudo mokutil --db | grep -B 1 "2023"
sudo mokutil --kek | grep -B 1 "2023"

Bu komutun sonucu ilk verdiğim tablo ile örtüşmeli. Güncel sertifikalar yoksa fwupdmgr ile firmware güncellemesi denetlenebilir.

sudo fwupdmgr refresh
sudo fwupdmgr get-updates
sudo fwupdmgr update

Ama sertifikaların varlığı yetmiyor, yeni sertifika ile imzalanmış bir shimx64.efi dosyasına ihtiyaç var. Bu dosyanın imzandığı sertifikayı görmek için pesign aracı kullanılabilir (varsayılan olarak kurulu değildir, kurmak için aynı isimli paket kurulmalı).

sudo pesign -S -i /boot/efi/EFI/fedora/shimx64.efi

Benim makinemde bu şöyle bir sonuç döndü:

---------------------------------------------
certificate address is 0x7f321a9fd6d0
Content was not encrypted.
Content is detached; signature cannot be verified.
The signer's common name is Microsoft Windows UEFI Driver Publisher
No signer email address.
No signing time included.
There were certs or crls included.
---------------------------------------------

Bu da henüz imzalı bir shim olmadığını gösteriyor. Önümüzdeki günlerde sanıyorum ki güncel sürüm gelir.

6.05.2026

Şişmiş bir CapabilityAccessManager.db-wal dosyası

Bir bilgisayarda C: sürücüsünde yer kalmamış. Sysinternals aracı du64 ile diski adım adım inceledim.

du64 -q -l 1 C:\
du64 -q -l 1 C:\ProgramData
du64 -q -l 1 C:\ProgramData\Microsoft
... 

ve sonunda

C:\Programdata\Microsoft\Windows\CapabilityAccessManager\CapabilityAccessManager.db-wal

dosyasının boyutunun +130 GB olduğunu gördüm. Bu dosyaya kamera, mikrofon ve konum gibi bilgilere erişim isteyen uygulamalar kaydediliyor. Bu dosyaya erişen hizmet ise camsvc. Bu klasöre ve altındaki dosyalara sadece NT AUTHORITY\SYSTEM hesabı erişebiliyor. Bu dosya bir SQLite veritabanı. Dosyayı incelemek için önce sahibini ve yetkilerini değiştirmem gerekti.

gsv camsvc | spsv
Set-Service camsvc -startuptype disabled
$dosya = "C:\Programdata\Microsoft\Windows\CapabilityAccessManager\CapabilityAccessManager.db-wal"
$acl1 = Get-Acl $path
$acl1.SetOwner([System.Security.Principal.NTAccount]"DOMAIN\user")
$kural1 = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAIN\user","Read","Allow")
$acl1.AddAccessRule($kural1)
Set-Acl $path $acl1

Daha sonra bu .db-wal uzatılı dosya ile birlikte .db ve .db-shm dosyaları bilgisayarıma aktarıp (yukarıdaki yetkilendirmeyi onlara da yaptıktan sonra) SQLite ile incelemek istedim. Bu aşamada sqlitebrowser.org adresinden DB Browser for SQLite'ı indirip .db uzantılı dosyayı açtım. Aşağıdaki SQLite sorgusunu kullanarak ezici bir çoğunlukla +56000 kez konum bilgisinin ExpressConnectNetworkService tarafından talep edildiğini gördüm.

SELECT
    b.StringValue AS ExecutablePath,
    c.StringValue AS CapabilityName,
    COUNT(*) AS RequestCount
FROM NonPackagedUsageHistory h
JOIN BinaryFullPaths b ON b.rowid = h.BinaryFullPath
JOIN Capabilities c ON c.rowid = h.Capability
GROUP BY h.BinaryFullPath, h.Capability
ORDER BY RequestCount DESC
LIMIT 20;

ExpressConnectNetworkService'in vazgeçilmez bir bileşen olmadığı (bir bloatware?) ortada. Şimdilik devre dışı bıraktım.

gsv 'ExpressConnect Network Service' | spsv
set-service 'ExpressConnect Network Service' -StartupType disabled

Hatta DellOptimizer hizmetini de devre dışı bıraktım. Ama Dell hizmetlerinin bir süre sonra tekrar kendiliğinden etkinleşmek gibi kötü huyları var. Bir süre izleyip göreceğim.

3.05.2026

Bash ile tekrarlayan dosyaları bulma

Linux'ta terminalde tekrarlayan dosyaları bulmak için

find . ! -empty -type f -exec md5sum {} + | sort | uniq -w32 -dD

Yapılanların kısa özeti:

find .                # mevcut klasör ve alt klasörleri ara
! -empty          # boş olmayanları bul
-type f        # dosyaları bul
-exec md5sum {} + # bulunan dosyaların md5 hash'lerini hesapla
| sort        # önceki komutun çıktısını sırala
| uniq -w32    # sıralananların içinde ilk 32 karakter için benzersizlik (uniq) karşılaştırması yap
-d          # tekrarlayanları göter
-D          # tekrarlayan tüm kopyaları listele 

10.04.2026

Tek elemanlı diziler

Bir dizi (array) oluşturuyorum.

$tamliste = @()

Sonra bu dizinin içini dolduruyorum. Ama işin bir yerinde bu diziyi, bir kritere göre filtrelemek istiyorum.

$filtrelenmis = $tamliste | Where-Object { $_.Name -match $anahtarkelime }

Sonrasında filtrelenmiş $filtrelenmis üzerinde bir for döngüsü ile işlem yapmam gerek.

for ($i = 0; $i -lt $filtrelenmis.Count; $i++) {
    Write-Host "[$i] $($filtrelenmis[$i].Name)"
}

Ama öncesinde boş bir dizi dönüp dönmediğini denetliyorum. Boş bir dizi döndüyse bunu bildirmem gerek.

if ($filtrelenmis.Count -eq 0) {
    Write-Host "Bos liste dondu."
} else {
    Write-Host "Bulunan:`r`n------"
    for ($i = 0; $i -lt $filtrelenmis.Count; $i++) {
        Write-Host "[$i] $($filtrelenmis[$i].Name)"
    }
}

$filtrelenmis değişkeninin sadece 1 elemanlı olması durumunda $filterelenmis.Count'un 1 dönmesini bekleriz. Ama dizinin 1 elemanlı olması durumunda bu artık bir dizi olmuyor, sadece düz bir değişken oluyor. Bu sebeple de .Count tanımlı değil.

Bu durumu düzeltmek için filtreleme satırını

$filtrelenmis = @($tamliste | Where-Object { $_.Name -match $anahtarkelime })

şeklinde düzeltmek gerek.

8.04.2026

Bluetooth kulaklığın batarya seviyesi

Android'de olduğu gibi bluetooth kulaklığın batarya seviyesini görebilsek güzel olurdu. GNOME arayüzünde yok, bilemiyorum KDE veya diğer grafik arayüzlerde var mıdır. Ama terminalde görmek için önce

bluetoothctl

ile etkileşimli ortama girmek lazım. Sonra bu etkileşimi ortamda

devices

diyerek bağlı cihazları listelemek gerek. Burada istediğimiz cihazın MAC adresine benzeyen xx:xx:xx:xx:xx:xx formatındaki cihaz kimliğini kopyaladıktan sonra

info xx:xx:xx:xx:xx:xx

ile ayrıntılarını sorgulamak lazım. Burada en altta (hep böyle midir?)

Battery percentage: 0x47 (70)

gibi bir noktada batarya seviyemiz görülebilir. İlk yazan, tahmin edilebileceği gibi onaltılık sistemde 70'in karşılığı. Alışık olduğumuz onluk sistemde yüzde değerimiz 70.

4.04.2026

Linux terminalde basit matematik işlemleri

Powershell'de her türlü matematiksel işlem yapılırken bash veya diğer shell'lerde 4 işlem bile mümkün değil. Ama çözümü var: bc

bc yazıp giriş yaptığımızda etkileşimli bir ortam karşılıyor bizi. Çıkmak için quit yazmak gerek, exit işe yaramıyor. ctrl+c de işe yarar. Buraya girmeden basit bir şekilde sonucu öğrenmek için

echo '33*47' | bc

yazılabilir.

Trigonometrik fonksiyonlar gibi karışık işler için python kullanılabilir. Ama varsayılan shell'de math kütüphanesi gelmediği için önce import math ile kütüphaneyi eklemek gerek:

import math
math.sin(math.pi/2)

 

1.04.2026

HTML ayrıştırma

Invoke-WebRequest cmdlet'i ile HTML içinde istenen öğelerin hızlı ayrıştırması yapılabilir. Örneğin şu sayfada yapılmış bir örnekte github üzerindeki görsellerin indirilmesi için powershell kullanılmış. Hedef sayfamız 

$url = "https://github.com/PrateekKumarSingh/CheatSheets/tree/master/Powershell"

 ile belirtilmiş. Bu sayfanın içeriği Invoke-WebRequest ile $page değişkenine atanmış.

$page = Invoke-WebRequest -UseBasicParsing -Uri $url

Bu aşamadan sonra sayfadaki bütün bağlantılara $page.Links ile ulaşmak mümkün. Hatta bir miktar biçimlendirme ile

$page.Links | Where-Object title | Select-Object -Property title, href

gibi bir tablo oluşturulmuş. Daha önce duvar kağıdı indirme için şu örneği yapmıştım, yine Links kullanarak.

Daha karışık bir örnek için live.sysinternals.com/files sayfasında yer alan araçların bir listesini oluşturmak istediğimizi düşünelim. Yine $page.Links ile sayfadaki bağlantılara erişmek mümkün ama bir de sayfada yer alan ama bir şekilde Links veya diğer property'ler ile görüntülenemeyen araçların güncellenme tarihi almak istediğimizi varsayalım. Bunun için sayfanın ham (raw) HTML kaynağını bir HTMLFile nesnesine atarak içinde adım adım ilerlememiz gerek.

İlk iş bir HTMLFile nesnesi oluşturmak

    $htmObj = New-Object -ComObject "HTMLFile"

Daha sonra $page.Content verisini bu nesnenin içine alalım.

    $htmObj.IHTMLDocument2_write($list.Content)

Yukarıdaki satır bazı durumlarda (Office yüklü olmayan bilgisayarlar veya Powershell 6+ sürümlerde)

method invocation failed because [system.__comobject] does not contain a method named 'IHTMLDocument2_write'

hatası verebilir. Bu durumda IHTMLDocument2_write satırını aşağıdaki 2 satır ile değiştirmek gerekebilir.

    $bytes = [System.Text.Encoding]::Unicode.GetBytes($page.content)
    $htmObj.write($bytes)

try/catch bloğu ile iki yöntemin birleşimini sayfanın altına yazıyorum, burası daha fazla karışmasın. 

Sayfadaki tarih ve saat verisi 

     Saturday, March 21, 2026 11:18 AM

şeklinde olduğu için bu yapıyla eşleşebilecek bir regex oluşturalım.

$pattern = '(\w+,\s+\w+\s+\d+,\s+\d+\s+\d+:\d+\s+[AP]M)\s+(\d+)\s+(\S+)'

Sayfanın kaynak kodunda yer alan header bilgisi gibi işimizi yaramayacak verilerden kurtulmak için ilk tarih saat bilgisinin geçtiği konumu bulalım.

$indxStart = ($htmObj.body.outerText | sls -Pattern $pattern).Matches[0].Index

İlk kez tarih ve saat formatının geçtiği yer baz alacağımız başlangıç noktası olacak. Buradan sayfanın sonuna kadar olan yer ile ilgileniyoruz.

    $indxEnd = ($htmObj.body.outerText).Length
    $raw = $htmObj.body.outerText.Substring($indxStart, $indxEnd-$indxStart)

Sıra bu kalıba uyan verileri ayrıştırma adımına geldi. $pattern değişkeninin içinde 3 gruplandırma kullandım, parantezler içinde. Aşağıdaki Groups bölümleri (nesneleri, dizileri, neyse) buna göre oluşturuldu.

$results = [regex]::Matches($raw, $pattern) | ForEach-Object {
    [PSCustomObject]@{
        Date     = $_.Groups[1].Value.Trim()
        Size     = [int]$_.Groups[2].Value
        FileName = $_.Groups[3].Value
    }
}

live.sysinternals.com/files sayfasında bir değişiklik olana kadar bunun çalışacağını umuyorum.

    $results | Out-GridView

Sayfada Date, Size veya FileName alanlarına ait bir veri etiketi/başlık/alan adı bulunmuyor. Bunu en son ayrıştırma aşamasında yaptım. Bu bölümdeki her alan için $pattern değişkeni içindeki bölümlerle eşleşme şöyle:

DateGroups[1](\w+,\s+\w+\s+\d+,\s+\d+\s+\d+:\d+\s+[AP]M)
SizeGroups[2](\d+)
FileNameGroups[3]   
(\S+)

---

$htmObj = New-Object -ComObject "HTMLFile"
$page = iwr -useb "live.sysinternals.com/files"

try {
    # Bu yöntem genellikle MS Office yüklü sistemlerde ve Windows PowerShell'de çalışır
    $html.IHTMLDocument2_write($content)
}
catch {
    # Office yüklü değilse veya PowerShell Core kullanıyorsanız bu yöntem çalışır
    $bytes = [System.Text.Encoding]::Unicode.GetBytes($page.Content)
    $htmObj.write($bytes)
}