Membuat Program C# Yang Membaca Data UserAssist


Sistem operasi Windows 7 adalah sebuah sistem operasi yang ‘pintar’. Contohnya, Windows memiliki fitur SuperFetch yang akan menganalisa pola penggunaan program berdasarkan hari dan jam sehingga Windows dapat menebak file-file apa saja yang mungkin akan dipakai pengguna. Berdasarkan informasi tersebut, Windows akan mengisi file ke memori sebelum dipakai sehingga mengurangi kemungkinan page fault. Selain itu, Windows juga terkadang sibuk mengurusi log NTFS di balik layar. Tergantung pada penggunanya, perilaku ‘pintar’ tidak selalu positif. Beberapa pengguna yang ingin punya kendali penuh bisa saja tidak senang dengan Windows yang suka sibuk sendiri tanpa disuruh.

Contoh ‘kepintaran’ Windows 7 yang bisa menuju ke arah berbahaya adalah ia selalu mencatat jumlah eksekusi sebuah program serta kapan sebuah program terakhir kali dijalankan ke lokasi registry HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist. Walaupun program dihapus, catatan ini tetap akan ada selama-lamanya🙂 Dengan fitur ini, Windows 7 dapat menampilkan program populer yang sering dipakai di menu Start. Masalahnya adalah banyak yang tidak tahu bahwa Windows 7 menyimpan catatan seperti ini. Sepertinya Microsoft berusaha menyembunyikan isi registry tersebut dari tangan jahil karena ia menyamarkan isi registry UserAssist tersebut dengan enkripsi ROT13. Ini adalah jenis enkripsi tidak aman yang sangat mudah dipecahkan; ROT13 hanya melakukan subtitusi huruf seperti A menjadi N, B menjadi O, C menjadi P, dan seterusnya. Walaupun mudah dipecahkan, penggunakan enkripsi ROT13 dan nilai dalam bentuk binary membuat saya sulit mencerna isi dari registry UserAssist dengan mudah.

Oleh sebab itu, saya akan mencoba membuat sebuah program C# yang akan membaca isi registry UserAssist tersebut dan menampilkan informasi dalam bentuk tabel yang lebih mudah dicerna. Program ini adalah sebuah aplikasi WPF yang saya ujikan pada Windows 7 32-bit dan 64-bit. Kode program secara lengkap dapat ditemukan di http://github.com/JockiHendry/ProgramExecutionCounter.

Kode program yang saya buat untuk membaca dari registry terlihat seperti berikut ini:

...
private void OnSearch()
{            
   countEntries.Clear();

   RegistryKey reg = Registry.CurrentUser.OpenSubKey(SelectedSourceType.Key);
   foreach (string valueName in reg.GetValueNames())
   {                
      CountEntry entry = new CountEntry();
      entry.Name = valueName;

      // filter by name
      if (!string.IsNullOrEmpty(NameFilter))
      {
          if (!entry.DecodedName.ToUpper().Contains(NameFilter.ToUpper())) continue;
      }

      entry.Value = (byte[]) reg.GetValue(valueName);
      entry.RegKey = reg.ToString();
      ...
      countEntries.Add(entry);
   }
}  
...      

Pada kode program di atas, saya memakai class Registry dari namespace Microsoft.Win32 untuk membaca isi registry. Saya kemudian melakukan konversi masing-masing value yang saya temukan menjadi sebuah object CountEntry.

Pada class CountEntry, saya menerjemahkan nama yang dienkripsi dengan algoritma ROT13 dengan menggunakan method dictionary lookup. Saya memilih cara ini karena lebih mudah dan jumlah kombinasi yang ada sangat sedikit (A-Z, a-z). Selain itu, nama di registry UserAssist juga mengandung GUID yang mewakili folder spesial di Windows (seperti MyComputer, Program Files, dan sebagainya). Saya bisa memperoleh informasi GUID untuk folder spesial di Windows dengan melihat isi header KnownFolders.h yang terdapat di folder Include di Windows SDK. Setelah membuat variabel static yang berisi dictionary lookup untuk ROT13 dan daftar terjemahan GUID folder, saya kemudian memulai proses dekripsi dengan kode program seperti berikut ini:

...
public String DecodedName
{
    get
    {
        if (string.IsNullOrEmpty(Name))
        {
            return "";
        }
        else
        {
            string result = new string(Name.ToCharArray().Select(c =>
            {
                return lookupTable.ContainsKey(c) ? lookupTable[c] : c;
            }).ToArray());
            foreach (var f in folderGUID)
            {
                if (result.Contains(f.Key)) result = result.Replace(f.Key, f.Value);
            }
            return result;
        }
    }
}
...

Nilai dari setiap key di registry UserAssist adalah deretan byte sebesar 72 byte. Tidak ada yang tahu persis apa saja informasi yang tersimpan, selain Microsoft selaku pencipta Windows (rasa waspada ini tidak perlu ada bila memakai sistem operasi open-source😉 ). Berdasarkan informasi yang diperoleh dari hasil pencarian Google, saya hanya akan mengambil 4 byte mulai dari posisi ke-4 yang mewakili jumlah eksekusi program dalam bilangan integer 32-bit. Untuk mengubah deretan byte menjadi sebuah int, saya memakai class BitConverter seperti yang terlihat pada kode program berikut ini:

...
public byte[] Value
{
    get
    {
        return this.value;
    }

    set
    {
        this.value = value;
        executionCount = BitConverter.ToInt32(value, 4);
    }
}
...

Tool sederhana ini juga memungkinkan pengguna untuk mengubah jumlah eksekusi secara langsung dari tabel. Untuk menerjemahkan bilangan int yang dimasukkan oleh pengguna menjadi byte array, saya kembali menggunakan class BitConverter dengan memanggil method GetBytes() seperti yang terlihat pada kode program berikut ini:

...
if (e.PropertyName == "ExecutionCount")
{
    try
    {                            
        byte[] newCount = BitConverter.GetBytes(countEntry.ExecutionCount);
        newCount.CopyTo(countEntry.Value, 4);
        Registry.SetValue(entry.RegKey, entry.Name, entry.Value);
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error Updating Registry: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}
...

Pada kode program diatas, saya memanggil method SetValue() dari class Registry untuk menulis perubahan ke registry.

Selain mengubah, tool ini juga memungkinkan pengguna untuk menghapus entry yang dipilihnya. Untuk itu saya perlu memanggil method DeleteValue() dari sebuah RegistryKey untuk menghapus nilai yang dipilih oleh pengguna, seperti yang terlihat pada kode program berikut ini:

public void OnDelete()
{
    if (MessageBox.Show("Do you really want delete this entry?", "Delete Confirmation",
        MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
    {
        RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKey.Replace(@"HKEY_CURRENT_USER", ""), true);
        if (key != null)
        {
            try
            {
                key.DeleteValue(Name);
                PropertyChanged(this, new PropertyChangedEventArgs("DeleteCommand"));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error Deleting Registry: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

    }
}

Sekarang, saya akan mencoba menjalankan program. Pada saat saya men-klik tombol Search, saya akan memperoleh hasil seperti pada gambar berikut ini:

Menampilkan seluruh entry yang ada

Menampilkan seluruh entry yang ada

Saya dapat langsung mengubah nilai jumlah eksekusi dengan men-double klik pada kolom angka, mengisi angka baru dan menekan tombol Enter, seperti yang terlihat pada gambar berikut ini:

Mengubah nilai registry untuk jumlah eksekusi

Mengubah nilai registry untuk jumlah eksekusi

Selain itu, saya dapat langsung menghapus sebuah entry dengan men-klik icon dengan tanda silang di baris yang bersesuaian, seperti yang terlihat pada gambar berikut ini:

Menghapus nilai dari registry

Menghapus nilai dari registry

Saya juga dapat menampilkan informasi detail untuk sebuah baris dengan men-klik icon kaca pembesar, seperti yang terlihat pada gambar berikut ini:

Menampilkan informasi detail untuk sebuah entry

Menampilkan informasi detail untuk sebuah entry

Lalu, apa manfaat dari tool sendiri ini? Karena registry UserAssist ini akan tetap menyimpan informasi program yang dijalankan walaupun program sudah dihapus atau di-uninstall, maka saya dapat menggunakannya untuk memeriksa apakah pengguna pernah menjalankan sebuah program atau tidak. Fungsi lainnya, misalnya saya dapat memeriksa apa saja program yang pernah dijalankan langsung melalui flash disk (dengan men-klik di Explorer) dengan fasilitas pencarian seperti pada gambar berikut ini:

Melakukan pencarian

Melakukan pencarian

Apakah kali ini ‘kepintaran’ Windows dirasa membuat pengguna khawatir dengan privasi mereka? Beruntungnya, Windows menyediakan fitur untuk mematikan fasilitas ini. Saya dapat menghilangkan pencatatan ini dengan men-klik kanan pada task bar yang kosong, memilih menu Properties. Pada dialog yang muncul, saya memilih tab Start Menu dan menghilangkan tanda centang pada Store and display recently opened programs in the Start menu seperti yang terlihat pada gambar berikut ini:

Menghilangkan pencatatan pada registry UserAssist

Menghilangkan pencatatan pada registry UserAssist

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: