Hari ini kami melanjutkan kisah tentang bagaimana kami, bersama dengan orang-orang dari Universitas Innopolis, sedang mengembangkan teknologi Active Restore untuk memungkinkan pengguna untuk mulai bekerja pada mesin mereka sesegera mungkin setelah kegagalan. Kami akan berbicara tentang aplikasi Windows asli, termasuk fitur pembuatan dan peluncurannya. Di bawah potongan - sedikit tentang proyek kami, serta panduan praktis tentang cara menulis aplikasi asli.

Dalam posting sebelumnya, kita sudah berbicara tentang apa itu
Active Restore dan bagaimana siswa dari Innopolis mengembangkan
layanan . Hari ini saya ingin fokus pada aplikasi asli, ke tingkat yang kami ingin "mengubur" layanan pemulihan aktif kami. Jika semuanya berhasil, maka kita dapat:
- Jauh lebih awal untuk memulai layanan itu sendiri
- Jauh lebih awal untuk menghubungi cloud tempat cadangan berada
- Jauh lebih awal untuk memahami mode apa yang ada di sistem - boot normal atau pemulihan
- Untuk memulihkan lebih sedikit file di muka
- Izinkan pengguna memulai lebih cepat.
Apa yang dimaksud dengan aplikasi asli secara umum?
Untuk menjawab pertanyaan ini, mari kita lihat urutan panggilan yang dibuat oleh sistem, misalnya, jika seorang programmer dalam aplikasinya mencoba membuat file.
Pavel Yosifovich - Pemrograman Kernel Windows (2019)Programmer menggunakan fungsi
CreateFile , yang dideklarasikan dalam file header fileapi.h dan diimplementasikan dalam Kernel32.dll. Namun, fungsi ini sendiri tidak membuat file, hanya memeriksa argumen pada input dan memanggil fungsi
NtCreateFile (awalan Nt hanya menunjukkan bahwa fungsi tersebut asli). Fungsi ini dideklarasikan dalam file header winternl.h dan diimplementasikan dalam ntdll.dll. Dia bersiap untuk melompat ke ruang nuklir, setelah itu dia membuat panggilan sistem untuk membuat file. Dalam kasus ini, ternyata Kernel32 hanyalah pembungkus untuk Ntdll. Salah satu alasan mengapa hal ini dilakukan, Microsoft dengan demikian memiliki kemampuan untuk mengubah fungsi dunia asli, tetapi tidak menyentuh antarmuka standar. Microsoft tidak merekomendasikan langsung menjalankan fungsi asli dan tidak mendokumentasikan sebagian besar dari mereka. Omong-omong, fitur tidak berdokumen dapat ditemukan di
sini .
Keuntungan utama dari aplikasi asli adalah bahwa ntdll memuat ke dalam sistem lebih awal dari kernel32. Ini logis, karena kernel32 membutuhkan ntdll untuk berfungsi. Akibatnya, aplikasi yang menggunakan fungsi asli dapat mulai bekerja lebih awal.
Dengan demikian, Aplikasi Asli Windows adalah program yang dapat berjalan pada tahap awal dalam mem-boot Windows. Mereka menggunakan fungsi HANYA dari ntdll. Contoh aplikasi semacam itu:
autochk yang menjalankan
utilitas chkdisk untuk memeriksa kesalahan pada disk sebelum memulai layanan utama. Pada level ini kami ingin melihat Pemulihan Aktif kami.
Apa yang kita butuhkan
- DDK (Driver Development Kit), sekarang juga dikenal sebagai WDK 7 (Windows Driver Kit).
- Mesin virtual (mis. Windows 7 x64)
- Tidak harus, tetapi file header bisa diunduh di sini.
Apa yang ada dalam kode?
Mari kita berlatih sedikit dan sebagai contoh kita akan menulis aplikasi kecil yang:
- Menampilkan pesan di layar.
- Mengalokasikan sedikit memori
- Menunggu input keyboard
- Membebaskan memori yang sibuk
Dalam aplikasi asli, titik masuknya bukan main atau winmain, tetapi fungsi NtProcessStartup, karena kita sebenarnya langsung memulai proses baru dalam sistem.
Mari kita mulai dengan menampilkan pesan di layar. Untuk melakukan ini, kami memiliki fungsi asli
NtDisplayString , yang mengambil sebagai argumen penunjuk ke objek struktur UNICODE_STRING. RtlInitUnicodeString akan membantu kami menginisialisasi itu. Akibatnya, untuk menampilkan teks di layar, kita dapat menulis fungsi sekecil itu:
Karena hanya fungsi-fungsi dari ntdll yang tersedia untuk kita, dan tidak ada perpustakaan lain di memori, kita pasti akan memiliki masalah dengan bagaimana mengalokasikan memori. Operator baru belum ada (karena berasal dari dunia C ++ tingkat tinggi), juga tidak ada fungsi malloc (perlu pustaka runtime C). Tentu saja Anda hanya dapat menggunakan tumpukan. Tetapi jika kita perlu mengalokasikan memori secara dinamis, kita harus melakukan ini di heap (mis. Heap). Karena itu, mari kita buat banyak untuk diri kita sendiri dan kita akan mengambil memori darinya ketika kita membutuhkannya.
Fungsi
RtlCreateHeap cocok untuk tugas ini. Selanjutnya, menggunakan RtlAllocateHeap dan RtlFreeHeap, kami akan mengisi dan membebaskan memori saat kami membutuhkannya.
PVOID memory = NULL; PVOID buffer = NULL; ULONG bufferSize = 42;
Ayo beralih untuk menunggu input keyboard.
Yang perlu kita lakukan adalah menggunakan
NtReadFile pada perangkat yang terbuka, dan tunggu sampai keyboard mengembalikan klik kepada kita. Jika tombol ESC ditekan, kami akan terus bekerja. Untuk membuka perangkat, kita perlu memanggil fungsi NtCreateFile (Anda harus membuka \ Device \ KeyboardClass0). Kami juga akan memanggil
NtCreateEvent untuk menginisialisasi objek untuk menunggu. Kami akan mendeklarasikan secara independen struktur KEYBOARD_INPUT_DATA yang mewakili data keyboard. Ini akan memudahkan pekerjaan kita.
Aplikasi asli diakhiri dengan panggilan ke fungsi
NtTerminateProcess , karena kita baru saja mematikan proses kita sendiri.
Semua kode aplikasi kecil kami:
#include "ntifs.h"
PS: Kita dapat dengan mudah menggunakan fungsi DbgBreakPoint () dalam kode untuk berhenti di debugger. Benar, Anda harus menghubungkan WinDbg ke mesin virtual untuk debugging kernel. Petunjuk tentang cara melakukan ini dapat ditemukan di
sini atau cukup gunakan
VirtualKD .
Kompilasi dan perakitan
Cara termudah untuk membangun aplikasi asli adalah dengan menggunakan
DDK (Driver Development Kit). Kami membutuhkan versi ketujuh yang lama, karena versi selanjutnya memiliki pendekatan yang sedikit berbeda dan bekerja sama dengan Visual Studio. Jika kita menggunakan DDK, maka proyek kita hanya membutuhkan Makefile dan sumber.
Makefile !INCLUDE $(NTMAKEENV)\makefile.def
sumber: TARGETNAME = MyNative TARGETTYPE = PROGRAM UMTYPE = nt BUFFER_OVERFLOW_CHECKS = 0 MINWIN_SDK_LIB_PATH = $(SDK_LIB_PATH) SOURCES = source.c INCLUDES = $(DDK_INC_PATH); \ C:\WinDDK\7600.16385.1\ndk; TARGETLIBS = $(DDK_LIB_PATH)\ntdll.lib \ $(DDK_LIB_PATH)\nt.lib USE_NTDLL = 1
Makefile Anda akan persis sama, tetapi marilah kita memikirkan sumbernya lebih terinci. File ini berisi sumber program Anda (file .c), opsi pembuatan dan parameter lainnya.
- TARGETNAME - nama file yang dapat dieksekusi, yang seharusnya hasilnya.
- TARGETTYPE - jenis file yang dapat dieksekusi, dapat berupa driver (.sys), maka nilai field harus DRIVER, jika perpustakaan (.lib), maka nilainya adalah PERPUSTAKAAN. Dalam kasus kami, kami memerlukan file yang dapat dieksekusi (.exe), jadi kami menetapkan nilainya ke PROGRAM.
- UMTYPE - nilai yang mungkin untuk bidang ini: konsol untuk aplikasi konsol, jendela untuk beroperasi dalam mode berjendela. Tetapi kita perlu menentukan nt untuk mendapatkan aplikasi asli.
- BUFFER_OVERFLOW_CHECKS - memeriksa stack untuk buffer overflow, sayangnya bukan pada kasus kami, matikan.
- MINWIN_SDK_LIB_PATH - nilai ini merujuk ke variabel SDK_LIB_PATH, jangan khawatir bahwa Anda belum mendeklarasikan variabel sistem seperti itu, saat kami menjalankan bangunan yang diperiksa dari DDK, variabel ini akan dideklarasikan dan akan mengarah ke perpustakaan yang diperlukan.
- SUMBER - daftar sumber program Anda.
- TERMASUK - file header yang diperlukan untuk perakitan. Mereka biasanya menunjukkan path ke file yang datang dengan DDK, tetapi Anda dapat secara opsional menentukan yang lain.
- TARGETLIBS - daftar perpustakaan yang perlu ditautkan.
- USE_NTDLL adalah bidang wajib yang harus disetel ke posisi 1. Untuk alasan yang jelas.
- USER_C_FLAGS - bendera apa pun yang dapat Anda gunakan dalam arahan preprosesor saat menyiapkan kode aplikasi.
Jadi untuk membangun, kita perlu menjalankan x86 (atau x64) Checked Build, ubah direktori kerja ke folder proyek dan jalankan perintah Build. Hasil dalam tangkapan layar menunjukkan bahwa kami telah mengumpulkan satu file yang dapat dieksekusi.

File ini tidak dapat dijalankan dengan mudah, sistem bersumpah dan mengirim kami untuk memikirkan perilakunya dengan kesalahan berikut:
Bagaimana cara menjalankan aplikasi asli?
Pada awal autochk, urutan startup program ditentukan oleh nilai kunci registri:
HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute
Manajer sesi menjalankan program dari daftar ini satu per satu. Manajer sesi itu sendiri mencari file yang dapat dieksekusi di direktori system32. Format nilai kunci registri adalah sebagai berikut:
autocheck autochk *MyNative
Nilai harus dalam format heksadesimal, dan tidak dalam ASCII biasa, oleh karena itu, kunci yang disajikan di atas akan memiliki format:
61,75,74,6f,63,68,65,63,6b,20,61,75,74,6f,63,68,6b,20,2a,00,4d,79,4e,61,74,69,76,65,00,00
Untuk mengonversi nama, Anda dapat menggunakan layanan online, misalnya, yang
ini .
Ternyata untuk menjalankan aplikasi asli, kita perlu:
- Salin file yang dapat dieksekusi ke folder system32
- Tambahkan kunci ke registri
- Mesin boot ulang
Untuk kenyamanan, berikut ini skrip yang sudah jadi untuk menginstal aplikasi asli:
install.bat @echo off copy MyNative.exe %systemroot%\system32\. regedit /s add.reg echo Native Example Installed pause
add.reg REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager] "BootExecute"=hex(7):61,75,74,6f,63,68,65,63,6b,20,61,75,74,6f,63,68,6b,20,2a,00,4d,79,4e,61,74,69,76,65,00,00
Setelah instalasi dan reboot, bahkan sebelum layar pemilihan pengguna muncul, kita mendapatkan gambar berikut:

Ringkasan
Menggunakan contoh aplikasi sekecil itu, kami yakin sangat mungkin menjalankan aplikasi pada level Windows Native. Lebih jauh, orang-orang dari Universitas Innopolis akan terus membangun layanan yang akan memulai proses berinteraksi dengan pengemudi lebih awal daripada dalam versi sebelumnya dari proyek kami. Dan dengan munculnya shell win32, akan masuk akal untuk mentransfer kontrol ke layanan lengkap yang telah dikembangkan (lebih lanjut tentang ini di
sini ).
Pada artikel selanjutnya, kita akan menyentuh komponen lain dari layanan Active Restore, yaitu driver UEFI. Berlangganan ke blog kami untuk tidak ketinggalan posting berikutnya.