Windows Native Applications a gwasanaeth Acronis Active Restore

Heddiw rydyn ni'n parhau Γ’'r stori am sut rydyn ni, ynghyd Γ’'r bechgyn o Brifysgol Innopolis, yn datblygu technoleg Active Restore i ganiatΓ‘u i'r defnyddiwr ddechrau gweithio ar eu peiriant cyn gynted Γ’ phosibl ar Γ΄l methiant. Byddwn yn siarad am gymwysiadau Windows brodorol, gan gynnwys nodweddion eu creu a'u lansio. O dan y toriad mae ychydig am ein prosiect, yn ogystal Γ’ chanllaw ymarferol ar sut i ysgrifennu cymwysiadau brodorol.

Windows Native Applications a gwasanaeth Acronis Active Restore

Mewn swyddi blaenorol rydym eisoes wedi siarad am yr hyn ydyw Adfer Actif, a sut mae myfyrwyr o Innopolis yn datblygu gwasanaeth. Heddiw, rwyf am ganolbwyntio ar gymwysiadau brodorol, i'r lefel yr ydym am β€œgladdu” ein gwasanaeth adferiad gweithredol. Os bydd popeth yn gweithio allan, yna byddwn yn gallu:

  • Lansio'r gwasanaeth ei hun yn llawer cynharach
  • Cysylltwch Γ’'r cwmwl lle mae'r copi wrth gefn wedi'i leoli'n llawer cynharach
  • Yn llawer cynharach i ddeall ym mha fodd y mae'r system - cychwyn arferol neu adferiad
  • Llawer llai o ffeiliau i'w hadennill ymlaen llaw
  • Gadewch i'r defnyddiwr ddechrau hyd yn oed yn gyflymach.

Beth yw ap brodorol beth bynnag?

I ateb y cwestiwn hwn, gadewch i ni edrych ar y dilyniant o alwadau y mae'r system yn eu gwneud, er enghraifft, os yw rhaglennydd yn ei gais yn ceisio creu ffeil.

Windows Native Applications a gwasanaeth Acronis Active Restore
Pavel Yosifovich - Rhaglennu Cnewyllyn Windows (2019)

Mae'r rhaglennydd yn defnyddio'r swyddogaeth CreateFile, sy'n cael ei ddatgan yn y ffeil pennawd fileapi.h a'i weithredu yn Kernel32.dll. Fodd bynnag, nid yw'r swyddogaeth hon ei hun yn creu'r ffeil, mae'n gwirio'r dadleuon mewnbwn yn unig ac yn galw'r swyddogaeth NtCreateFile (mae'r rhagddodiad Nt yn dangos bod y ffwythiant yn frodorol). Mae'r swyddogaeth hon yn cael ei datgan yn y ffeil pennawd winternl.h a'i gweithredu yn ntdll.dll. Mae'n paratoi i neidio i mewn i ofod niwclear, ac ar Γ΄l hynny mae'n gwneud galwad system i greu ffeil. Yn yr achos hwn, mae'n ymddangos mai dim ond deunydd lapio ar gyfer Ntdll yw Kernel32. Un o'r rhesymau pam y gwnaed hyn yw bod gan Microsoft y gallu felly i newid swyddogaethau'r byd brodorol, ond heb gyffwrdd Γ’'r rhyngwynebau safonol. Nid yw Microsoft yn argymell galw swyddogaethau brodorol yn uniongyrchol ac nid yw'n dogfennu'r rhan fwyaf ohonynt. Gyda llaw, gellir dod o hyd i swyddogaethau heb eu dogfennu yma.

Prif fantais cymwysiadau brodorol yw bod ntdll yn cael ei lwytho i'r system yn llawer cynharach na chnewyllyn32. Mae hyn yn rhesymegol, oherwydd mae cnewyllyn32 yn gofyn am ntdll i weithio. O ganlyniad, gall cymwysiadau sy'n defnyddio swyddogaethau brodorol ddechrau gweithio'n llawer cynharach.

Felly, mae Cymwysiadau Brodorol Windows yn rhaglenni a all gychwyn yn gynnar yng nghist Windows. DIM OND maent yn defnyddio swyddogaethau o ntdll. Enghraifft o gais o'r fath: autochk sy'n perfformio cyfleustodau chkdisk i wirio'r ddisg am wallau cyn dechrau'r prif wasanaethau. Dyma'r union lefel yr ydym am i'n Active Restore fod.

Beth sydd ei angen arnom?

  • DDK (Pecyn Datblygu Gyrwyr), a elwir bellach hefyd yn WDK 7 (Pecyn Gyrwyr Windows).
  • Peiriant rhithwir (er enghraifft, Windows 7 x64)
  • Ddim yn angenrheidiol, ond gall ffeiliau pennawd y gellir eu llwytho i lawr fod o gymorth yma

Beth sydd yn y cod?

Gadewch i ni ymarfer ychydig ac, er enghraifft, ysgrifennu cymhwysiad bach sy'n:

  1. Yn dangos neges ar y sgrin
  2. Yn dyrannu rhywfaint o gof
  3. Yn aros am fewnbwn bysellfwrdd
  4. Yn rhyddhau cof ail-law

Mewn cymwysiadau brodorol, nid y pwynt mynediad yw'r prif neu winmain, ond swyddogaeth NtProcessStartup, gan ein bod mewn gwirionedd yn lansio prosesau newydd yn y system yn uniongyrchol.

Gadewch i ni ddechrau trwy arddangos neges ar y sgrin. Ar gyfer hyn mae gennym swyddogaeth frodorol NtDisplayString, sy'n cymryd pwyntydd i wrthrych strwythur UNICODE_STRING fel dadl. Bydd RtlInitUnicodeString yn ein helpu i'w gychwyn. O ganlyniad, i arddangos testun ar y sgrin gallwn ysgrifennu'r swyddogaeth fach hon:

//usage: WriteLn(L"Here is my textn");
void WriteLn(LPWSTR Message)
{
    UNICODE_STRING string;
    RtlInitUnicodeString(&string, Message);
    NtDisplayString(&string);
}

Gan mai dim ond swyddogaethau o ntdll sydd ar gael i ni, ac yn syml, nid oes unrhyw lyfrgelloedd eraill yn y cof eto, byddwn yn bendant yn cael problemau gyda sut i ddyrannu cof. Nid yw'r gweithredwr newydd yn bodoli eto (gan ei fod yn dod o fyd lefel rhy uchel C ++), ac nid oes swyddogaeth malloc (mae angen llyfrgelloedd amser rhedeg C). Wrth gwrs, dim ond pentwr y gallwch chi ei ddefnyddio. Ond os oes angen i ni ddyrannu cof yn ddeinamig, bydd yn rhaid i ni ei wneud ar y domen (h.y. pentwr). Felly gadewch i ni greu pentwr i ni ein hunain a chymryd y cof ohono pryd bynnag y bydd ei angen arnom.

Mae'r swyddogaeth yn addas ar gyfer y dasg hon RtlCreateHeap. Nesaf, gan ddefnyddio RtlAllocateHeap a RtlFreeHeap, byddwn yn meddiannu ac yn rhyddhau cof pan fydd ei angen arnom.

PVOID memory = NULL;
PVOID buffer = NULL;
ULONG bufferSize = 42;

// create heap in order to allocate memory later
memory = RtlCreateHeap(
  HEAP_GROWABLE, 
  NULL, 
  1000, 
  0, NULL, NULL
);

// allocate buffer of size bufferSize
buffer = RtlAllocateHeap(
  memory, 
  HEAP_ZERO_MEMORY, 
  bufferSize
);

// free buffer (actually not needed because we destroy heap in next step)
RtlFreeHeap(memory, 0, buffer);

RtlDestroyHeap(memory);

Gadewch i ni symud ymlaen i aros am fewnbwn bysellfwrdd.

// https://docs.microsoft.com/en-us/windows/win32/api/ntddkbd/ns-ntddkbd-keyboard_input_data
typedef struct _KEYBOARD_INPUT_DATA {
  USHORT UnitId;
  USHORT MakeCode;
  USHORT Flags;
  USHORT Reserved;
  ULONG  ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

//...

HANDLE hKeyBoard, hEvent;
UNICODE_STRING skull, keyboard;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK Iosb;
LARGE_INTEGER ByteOffset;
KEYBOARD_INPUT_DATA kbData;

// inialize variables
RtlInitUnicodeString(&keyboard, L"DeviceKeyboardClass0");
InitializeObjectAttributes(&ObjectAttributes, &keyboard, OBJ_CASE_INSENSITIVE, NULL, NULL);

// open keyboard device
NtCreateFile(&hKeyBoard,
			SYNCHRONIZE | GENERIC_READ | FILE_READ_ATTRIBUTES,
			&ObjectAttributes,
			&Iosb,
			NULL,
			FILE_ATTRIBUTE_NORMAL,
			0,
			FILE_OPEN,FILE_DIRECTORY_FILE,
			NULL, 0);

// create event to wait on
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &ObjectAttributes, 1, 0);

while (TRUE)
{
	NtReadFile(hKeyBoard, hEvent, NULL, NULL, &Iosb, &kbData, sizeof(KEYBOARD_INPUT_DATA), &ByteOffset, NULL);
	NtWaitForSingleObject(hEvent, TRUE, NULL);

	if (kbData.MakeCode == 0x01)    // if ESC pressed
	{
			break;
	}
}

Y cyfan sydd ei angen arnom yw ei ddefnyddio NtReadFile ar ddyfais agored, ac aros nes bod y bysellfwrdd yn dychwelyd unrhyw wasg i ni. Os caiff yr allwedd ESC ei wasgu, byddwn yn parhau i weithio. I agor y ddyfais, bydd angen i ni alw'r swyddogaeth NtCreateFile (bydd angen i ni agor DeviceKeyboardClass0). Byddwn hefyd yn galw Digwyddiad NTCreatei gychwyn y gwrthrych aros. Byddwn yn datgan y strwythur KEYBOARD_INPUT_DATA ein hunain, sy'n cynrychioli data'r bysellfwrdd. Bydd hyn yn gwneud ein gwaith yn haws.

Daw'r cais brodorol i ben gyda galwad swyddogaeth NtTerminateProcessoherwydd, yn syml, yr ydym yn lladd ein proses ein hunain.

Yr holl god ar gyfer ein cais bach:

#include "ntifs.h" // WinDDK7600.16385.1incddk
#include "ntdef.h"

//------------------------------------
// Following function definitions can be found in native development kit
// but I am too lazy to include `em so I declare it here
//------------------------------------

NTSYSAPI
NTSTATUS
NTAPI
NtTerminateProcess(
  IN HANDLE               ProcessHandle OPTIONAL,
  IN NTSTATUS             ExitStatus
);

NTSYSAPI 
NTSTATUS
NTAPI
NtDisplayString(
	IN PUNICODE_STRING String
);

NTSTATUS 
NtWaitForSingleObject(
  IN HANDLE         Handle,
  IN BOOLEAN        Alertable,
  IN PLARGE_INTEGER Timeout
);

NTSYSAPI 
NTSTATUS
NTAPI
NtCreateEvent(
    OUT PHANDLE             EventHandle,
    IN ACCESS_MASK          DesiredAccess,
    IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
    IN EVENT_TYPE           EventType,
    IN BOOLEAN              InitialState
);



// https://docs.microsoft.com/en-us/windows/win32/api/ntddkbd/ns-ntddkbd-keyboard_input_data
typedef struct _KEYBOARD_INPUT_DATA {
  USHORT UnitId;
  USHORT MakeCode;
  USHORT Flags;
  USHORT Reserved;
  ULONG  ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

//----------------------------------------------------------
// Our code goes here
//----------------------------------------------------------

// usage: WriteLn(L"Hello Native World!n");
void WriteLn(LPWSTR Message)
{
    UNICODE_STRING string;
    RtlInitUnicodeString(&string, Message);
    NtDisplayString(&string);
}

void NtProcessStartup(void* StartupArgument)
{
	// it is important to declare all variables at the beginning
	HANDLE hKeyBoard, hEvent;
	UNICODE_STRING skull, keyboard;
	OBJECT_ATTRIBUTES ObjectAttributes;
	IO_STATUS_BLOCK Iosb;
	LARGE_INTEGER ByteOffset;
	KEYBOARD_INPUT_DATA kbData;
	
	PVOID memory = NULL;
	PVOID buffer = NULL;
	ULONG bufferSize = 42;

	//use it if debugger connected to break
	//DbgBreakPoint();

	WriteLn(L"Hello Native World!n");

	// inialize variables
	RtlInitUnicodeString(&keyboard, L"DeviceKeyboardClass0");
	InitializeObjectAttributes(&ObjectAttributes, &keyboard, OBJ_CASE_INSENSITIVE, NULL, NULL);

	// open keyboard device
	NtCreateFile(&hKeyBoard,
				SYNCHRONIZE | GENERIC_READ | FILE_READ_ATTRIBUTES,
				&ObjectAttributes,
				&Iosb,
				NULL,
				FILE_ATTRIBUTE_NORMAL,
				0,
				FILE_OPEN,FILE_DIRECTORY_FILE,
				NULL, 0);

	// create event to wait on
	InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
	NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &ObjectAttributes, 1, 0);
	
	WriteLn(L"Keyboard readyn");
	
	// create heap in order to allocate memory later
	memory = RtlCreateHeap(
	  HEAP_GROWABLE, 
	  NULL, 
	  1000, 
	  0, NULL, NULL
	);
	
	WriteLn(L"Heap readyn");

	// allocate buffer of size bufferSize
	buffer = RtlAllocateHeap(
	  memory, 
	  HEAP_ZERO_MEMORY, 
	  bufferSize
	);
	
	WriteLn(L"Buffer allocatedn");

	// free buffer (actually not needed because we destroy heap in next step)
	RtlFreeHeap(memory, 0, buffer);

	RtlDestroyHeap(memory);
	
	WriteLn(L"Heap destroyedn");
	
	WriteLn(L"Press ESC to continue...n");

	while (TRUE)
	{
		NtReadFile(hKeyBoard, hEvent, NULL, NULL, &Iosb, &kbData, sizeof(KEYBOARD_INPUT_DATA), &ByteOffset, NULL);
		NtWaitForSingleObject(hEvent, TRUE, NULL);

		if (kbData.MakeCode == 0x01)    // if ESC pressed
		{
				break;
		}
	}

	NtTerminateProcess(NtCurrentProcess(), 0);
}

PS: Gallwn ddefnyddio'r swyddogaeth DbgBreakPoint() yn ein cod yn hawdd i'w atal yn y dadfygiwr. Yn wir, bydd angen i chi gysylltu WinDbg Γ’ pheiriant rhithwir ar gyfer dadfygio cnewyllyn. Gellir dod o hyd i gyfarwyddiadau ar sut i wneud hyn yma neu dim ond defnyddio RhithKD.

Casglu a chynulliad

Y ffordd hawsaf o adeiladu cymhwysiad brodorol yw ei ddefnyddio DDK (Pecyn Datblygu Gyrwyr). Mae angen y seithfed fersiwn hynafol arnom, gan fod gan fersiynau diweddarach ddull ychydig yn wahanol ac maent yn gweithio'n agos gyda Visual Studio. Os ydym yn defnyddio'r DDK, yna dim ond Makefile a ffynonellau sydd eu hangen ar ein prosiect.

Gwneud ffeil

!INCLUDE $(NTMAKEENV)makefile.def

Ffynonellau:

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:WinDDK7600.16385.1ndk;

TARGETLIBS 			= $(DDK_LIB_PATH)ntdll.lib	
				  $(DDK_LIB_PATH)nt.lib

USE_NTDLL			= 1

Bydd eich Makefile yn union yr un fath, ond gadewch i ni edrych ar ffynonellau yn fwy manwl. Mae'r ffeil hon yn nodi ffynonellau eich rhaglen (ffeiliau. c), opsiynau adeiladu, a pharamedrau eraill.

  • TARGETNAME - enw'r ffeil gweithredadwy y dylid ei chynhyrchu yn y diwedd.
  • TARGETTYPE – math o ffeil gweithredadwy, gall fod yn yrrwr (.sys), yna dylai'r gwerth maes fod yn GYRRWR, os llyfrgell (.lib), yna mae'r gwerth yn LLYFRGELL. Yn ein hachos ni, mae angen ffeil gweithredadwy (.exe), felly rydyn ni'n gosod y gwerth i RHAGLEN.
  • UMTYPE – gwerthoedd posibl ar gyfer y maes hwn: consol ar gyfer cymhwysiad consol, ffenestri ar gyfer gweithio yn y modd ffenestr. Ond mae angen i ni nodi nt i gael cais brodorol.
  • BUFFER_OVERFLOW_CHECKS – gwirio’r pentwr am orlif byffer, yn anffodus nid ein hachos ni, rydym yn ei ddiffodd.
  • MINWIN_SDK_LIB_PATH - mae'r gwerth hwn yn cyfeirio at y newidyn SDK_LIB_PATH, peidiwch Γ’ phoeni nad oes gennych newidyn system o'r fath wedi'i ddatgan, pan fyddwn yn rhedeg adeiladu wedi'i wirio o'r DDK, bydd y newidyn hwn yn cael ei ddatgan a bydd yn pwyntio at y llyfrgelloedd angenrheidiol.
  • FFYNONELLAU – rhestr o ffynonellau ar gyfer eich rhaglen.
  • YN CYNNWYS - ffeiliau pennawd sydd eu hangen ar gyfer cydosod. Yma maen nhw fel arfer yn nodi'r llwybr i'r ffeiliau sy'n dod gyda'r DDK, ond gallwch chi hefyd nodi unrhyw rai eraill.
  • TARGEDLIBS – rhestr o lyfrgelloedd sydd angen eu cysylltu.
  • Mae USE_NTDLL yn faes gofynnol y mae'n rhaid ei osod i 1 am resymau amlwg.
  • USER_C_FLAGS – unrhyw fflagiau y gallwch eu defnyddio mewn cyfarwyddebau rhagbrosesydd wrth baratoi cod cais.

Felly i adeiladu, mae angen i ni redeg x86 (neu x64) Wedi'i Wirio Adeiladu, newid y cyfeiriadur gweithio i'r ffolder prosiect a rhedeg y gorchymyn Adeiladu. Mae'r canlyniad yn y sgrin yn dangos bod gennym un ffeil gweithredadwy.

Windows Native Applications a gwasanaeth Acronis Active Restore

Ni ellir lansio'r ffeil hon mor hawdd, mae'r system yn melltithio ac yn ein hanfon i feddwl am ei hymddygiad gyda'r gwall canlynol:

Windows Native Applications a gwasanaeth Acronis Active Restore

Sut i lansio cais brodorol?

Pan fydd autochk yn cychwyn, mae dilyniant cychwyn rhaglenni yn cael ei bennu gan werth allwedd y gofrestrfa:

HKLMSystemCurrentControlSetControlSession ManagerBootExecute

Mae'r rheolwr sesiwn yn gweithredu rhaglenni o'r rhestr hon fesul un. Mae'r rheolwr sesiwn yn edrych am y ffeiliau gweithredadwy eu hunain yn y cyfeiriadur system32. Mae fformat gwerth allwedd y gofrestrfa fel a ganlyn:

autocheck autochk *MyNative

Rhaid i'r gwerth fod mewn fformat hecsadegol, nid yr ASCII arferol, felly bydd yr allwedd a ddangosir uchod yn y fformat:

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

I drosi'r teitl, gallwch ddefnyddio gwasanaeth ar-lein, er enghraifft, hyn.

Windows Native Applications a gwasanaeth Acronis Active Restore
Mae'n ymddangos bod angen y canlynol arnom i lansio cais brodorol:

  1. CopΓ―wch y ffeil gweithredadwy i'r ffolder system32
  2. Ychwanegu allwedd i'r gofrestrfa
  3. Ailgychwyn y peiriant

Er hwylustod, dyma sgript parod ar gyfer gosod cymhwysiad brodorol:

gosod.bat

@echo off
copy MyNative.exe %systemroot%system32.
regedit /s add.reg
echo Native Example Installed
pause

ychwanegu.reg

REGEDIT4

[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession 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

Ar Γ΄l gosod ac ailgychwyn, hyd yn oed cyn i'r sgrin dewis defnyddiwr ymddangos, byddwn yn cael y llun canlynol:

Windows Native Applications a gwasanaeth Acronis Active Restore

Cyfanswm

Gan ddefnyddio'r enghraifft o gais mor fach, roeddem yn argyhoeddedig ei bod yn eithaf posibl rhedeg y rhaglen ar lefel Brodorol Windows. Nesaf, bydd y bechgyn o Brifysgol Innopolis a minnau yn parhau i adeiladu gwasanaeth a fydd yn cychwyn y broses o ryngweithio Γ’'r gyrrwr yn llawer cynharach nag yn fersiwn flaenorol ein prosiect. A chyda dyfodiad cragen win32, byddai'n rhesymegol trosglwyddo rheolaeth i wasanaeth cyflawn sydd eisoes wedi'i ddatblygu (mwy am hyn yma).

Yn yr erthygl nesaf byddwn yn cyffwrdd ag elfen arall o'r gwasanaeth Active Restore, sef gyrrwr UEFI. Tanysgrifiwch i'n blog fel nad ydych chi'n colli'r post nesaf.

Ffynhonnell: hab.com

Ychwanegu sylw