අද අපි Innopolis විශ්ව විද්යාලයේ පිරිමි ළමයින් සමඟ එක්ව, පරිශීලකයාට අසාර්ථක වූ පසු හැකි ඉක්මනින් ඔවුන්ගේ යන්ත්රයේ වැඩ ආරම්භ කිරීමට ඉඩ දීම සඳහා Active Restore තාක්ෂණය සංවර්ධනය කරන ආකාරය පිළිබඳ කතාව දිගටම කරගෙන යන්නෙමු. අපි දේශීය වින්ඩෝස් යෙදුම් ගැන කතා කරමු, ඒවායේ නිර්මාණයේ සහ දියත් කිරීමේ විශේෂාංග ඇතුළුව. කප්පාදුවට පහළින් අපගේ ව්යාපෘතිය ගැන ටිකක් මෙන්ම දේශීය යෙදුම් ලියන ආකාරය පිළිබඳ ප්රායෝගික මාර්ගෝපදේශයකි.
කලින් පෝස්ට් වල අපි දැනටමත් කතා කරලා තියෙනවා ඒ මොකක්ද කියලා
- සේවාව බොහෝ කලකට පෙර දියත් කරන්න
- බොහෝ කලකට පෙර උපස්ථය පිහිටා ඇති වලාකුළ අමතන්න
- පද්ධතිය කුමන ආකාරයෙන්ද යන්න තේරුම් ගැනීමට බොහෝ කලකට පෙර - සාමාන්ය ඇරඹුම් හෝ ප්රතිසාධනය
- කල්තියා ප්රතිසාධනය කිරීමට ගොනු ප්රමාණය අඩුය
- පරිශීලකයාට ඊටත් වඩා වේගයෙන් ආරම්භ කිරීමට ඉඩ දෙන්න.
කෙසේ වෙතත් ස්වදේශීය යෙදුමක් යනු කුමක්ද?
මෙම ප්රශ්නයට පිළිතුරු සැපයීම සඳහා, පද්ධතිය ලබා දෙන ඇමතුම් අනුපිළිවෙල දෙස බලමු, උදාහරණයක් ලෙස, ඔහුගේ යෙදුමේ ක්රමලේඛකයෙකු ගොනුවක් සෑදීමට උත්සාහ කරන්නේ නම්.
Pavel Yosifovich - Windows Kernel Programming (2019)
ක්රමලේඛකයා ශ්රිතය භාවිතා කරයි
දේශීය යෙදුම්වල ප්රධාන වාසිය නම් ntdll kernel32 ට වඩා බොහෝ කලින් පද්ධතියට පටවා තිබීමයි. මෙය තර්කානුකූලයි, මන්ද kernel32 වැඩ කිරීමට ntdll අවශ්ය වේ. එහි ප්රතිඵලයක් වශයෙන්, ස්වදේශීය ශ්රිත භාවිතා කරන යෙදුම් බොහෝ කලකට පෙර වැඩ කිරීමට පටන් ගත හැක.
මේ අනුව, Windows Native Applications යනු වින්ඩෝස් ආරම්භයේදීම ආරම්භ කළ හැකි වැඩසටහන් වේ. ඔවුන් ntdll වෙතින් කාර්යයන් පමණක් භාවිතා කරයි. එවැනි යෙදුමක උදාහරණයක්:
අපට අවශ්ය කුමක්ද?
DDK (Driver Development Kit), දැන් WDK 7 (Windows Driver Kit) ලෙසද හැඳින්වේ.- අතථ්ය යන්ත්රය (උදාහරණයක් ලෙස, Windows 7 x64)
- අවශ්ය නොවේ, නමුත් බාගත කළ හැකි ශීර්ෂ ගොනු උපකාර විය හැක
මෙහි
කේතයේ ඇත්තේ කුමක්ද?
අපි ටිකක් පුහුණු වෙමු, උදාහරණයක් ලෙස, කුඩා යෙදුමක් ලියන්න:
- තිරය මත පණිවිඩයක් පෙන්වයි
- යම් මතකයක් වෙන් කරයි
- යතුරුපුවරු ආදානය සඳහා රැඳී සිටියි
- භාවිතා කළ මතකය නිදහස් කරයි
ස්වදේශීය යෙදුම් වලදී, ඇතුල්වීමේ ස්ථානය ප්රධාන හෝ වින්මේන් නොවේ, නමුත් NtProcessStartup ශ්රිතය, අපි ඇත්ත වශයෙන්ම පද්ධතිය තුළ නව ක්රියාවලි දියත් කරන බැවින්.
තිරය මත පණිවිඩයක් පෙන්වීමෙන් ආරම්භ කරමු. මේ සඳහා අපට දේශීය කාර්යයක් ඇත
//usage: WriteLn(L"Here is my textn");
void WriteLn(LPWSTR Message)
{
UNICODE_STRING string;
RtlInitUnicodeString(&string, Message);
NtDisplayString(&string);
}
අපට ලබා ගත හැක්කේ ntdll වෙතින් වන කාර්යයන් පමණක් වන අතර, තවමත් මතකයේ වෙනත් පුස්තකාල නොමැති බැවින්, මතකය වෙන් කරන්නේ කෙසේද යන්න පිළිබඳව අපට අනිවාර්යයෙන්ම ගැටළු ඇති වේ. නව ක්රියාකරු තවමත් නොපවතියි (එය C++ හි ඉතා ඉහළ මට්ටමේ ලෝකයෙන් පැමිණෙන නිසා), සහ malloc ශ්රිතයක් නොමැත (එයට ධාවන කාල C පුස්තකාල අවශ්ය වේ). ඇත්ත වශයෙන්ම, ඔබට භාවිතා කළ හැක්කේ තොගයක් පමණි. නමුත් අපට මතකය ගතිකව වෙන් කිරීමට අවශ්ය නම්, අපට එය ගොඩ මත (එනම් ගොඩ) කිරීමට සිදුවේ. ඒ නිසා අපි අපිටම ගොඩක් හදාගෙන අවශ්ය වෙලාවට මතකය ලබා ගනිමු.
මෙම කාර්යය සඳහා කාර්යය සුදුසු වේ
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);
යතුරුපුවරු ආදානය සඳහා රැඳී සිටීමට අපි ඉදිරියට යමු.
// 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;
}
}
අපට අවශ්ය වන්නේ භාවිතා කිරීමයි
ස්වදේශීය යෙදුම ක්රියාකාරී ඇමතුමකින් අවසන් වේ
අපගේ කුඩා යෙදුම සඳහා සියලුම කේතය:
#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: අපගේ කේතයේ ඇති DbgBreakPoint() ශ්රිතය නිදොස්කරණයේදී එය නැවැත්වීමට අපට පහසුවෙන් භාවිත කළ හැක. සත්ය, ඔබ කර්නල් නිදොස්කරණය සඳහා WinDbg අථත්ය යන්ත්රයකට සම්බන්ධ කිරීමට අවශ්ය වනු ඇත. මෙය කරන්නේ කෙසේද යන්න පිළිබඳ උපදෙස් සොයාගත හැකිය
සම්පාදනය සහ එකලස් කිරීම
ස්වදේශීය යෙදුමක් තැනීමට ඇති පහසුම ක්රමය වන්නේ භාවිතා කිරීමයි
Makefile
!INCLUDE $(NTMAKEENV)makefile.def
ආරංචි මාර්ග:
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
ඔබේ Makefile හරියටම සමාන වනු ඇත, නමුත් අපි මූලාශ්ර ටිකක් විස්තරාත්මකව බලමු. මෙම ගොනුව ඔබගේ වැඩසටහනේ මූලාශ්ර (.c ගොනු), ගොඩනැගීමේ විකල්ප සහ අනෙකුත් පරාමිති නියම කරයි.
- TARGETNAME - අවසානයේ නිපදවිය යුතු ක්රියාත්මක කළ හැකි ගොනුවේ නම.
- TARGETTYPE – ක්රියාත්මක කළ හැකි ගොනු වර්ගය, එය ධාවකයක් (.sys) විය හැක, එවිට ක්ෂේත්ර අගය DRIVER විය යුතුය, පුස්තකාලයක් (.lib) නම්, අගය පුස්තකාලය වේ. අපගේ නඩුවේදී, අපට ක්රියාත්මක කළ හැකි ගොනුවක් (.exe) අවශ්ය වේ, එබැවින් අපි අගය PROGRAM වෙත සකසන්නෙමු.
- UMTYPE - මෙම ක්ෂේත්රය සඳහා විය හැකි අගයන්: කොන්සෝල යෙදුමක් සඳහා කොන්සෝලය, කවුළු ප්රකාරයේදී වැඩ කිරීම සඳහා කවුළු. නමුත් ස්වදේශීය යෙදුමක් ලබා ගැනීමට අපි nt සඳහන් කළ යුතුය.
- BUFFER_OVERFLOW_CHECKS - බෆර් පිටාර ගැලීම සඳහා තොගය පරීක්ෂා කිරීම, අවාසනාවකට අපගේ නඩුව නොවේ, අපි එය අක්රිය කරමු.
- MINWIN_SDK_LIB_PATH - මෙම අගය SDK_LIB_PATH විචල්යයට යොමු කරයි, ඔබ සතුව එවැනි පද්ධති විචල්යයක් ප්රකාශ කර නොමැති බව කණගාටු නොවන්න, අපි DDK වෙතින් පරීක්ෂා කළ ගොඩනැගීම ධාවනය කරන විට, මෙම විචල්යය ප්රකාශ කර අවශ්ය පුස්තකාල වෙත යොමු කරනු ඇත.
- මූලාශ්ර - ඔබේ වැඩසටහන සඳහා මූලාශ්ර ලැයිස්තුවක්.
- ඇතුළත් - එකලස් කිරීම සඳහා අවශ්ය ශීර්ෂ ගොනු. මෙහිදී ඔවුන් සාමාන්යයෙන් DDK සමඟ එන ලිපිගොනු වෙත යන මාර්ගය දක්වයි, නමුත් ඔබට අතිරේකව වෙනත් ඕනෑම දෙයක් සඳහන් කළ හැකිය.
- TARGETLIBS - සම්බන්ධ කළ යුතු පුස්තකාල ලැයිස්තුව.
- USE_NTDLL යනු පැහැදිලි හේතූන් මත 1 ට සැකසිය යුතු අවශ්ය ක්ෂේත්රයකි.
- USER_C_FLAGS - යෙදුම් කේතය සකස් කිරීමේදී ඔබට පෙර සැකසුම් විධානවල භාවිතා කළ හැකි ඕනෑම ධජයක්.
එබැවින් ගොඩනැගීමට, අපි x86 (හෝ x64) පරීක්ෂා කළ ගොඩනැගීම ධාවනය කළ යුතු අතර, වැඩ කරන නාමාවලිය ව්යාපෘති ෆෝල්ඩරයට වෙනස් කර Build විධානය ක්රියාත්මක කළ යුතුය. Screenshot හි ප්රතිඵලය අපට එක් ක්රියාත්මක කළ හැකි ගොනුවක් ඇති බව පෙන්වයි.
මෙම ගොනුව එතරම් පහසුවෙන් දියත් කළ නොහැක, පද්ධතිය ශාප කර පහත දෝෂය සමඟ එහි හැසිරීම ගැන සිතීමට අපව එවයි:
ස්වදේශීය යෙදුමක් දියත් කරන්නේ කෙසේද?
autochk ආරම්භ වන විට, වැඩසටහන් වල ආරම්භක අනුපිළිවෙල රෙජිස්ට්රි යතුරේ අගය අනුව තීරණය වේ:
HKLMSystemCurrentControlSetControlSession ManagerBootExecute
සැසි කළමනාකරු මෙම ලැයිස්තුවෙන් වැඩසටහන් එකින් එක ක්රියාත්මක කරයි. සැසි කළමනාකරු system32 බහලුම තුළම ක්රියාත්මක කළ හැකි ගොනු සොයයි. රෙජිස්ට්රි යතුරු අගය ආකෘතිය පහත පරිදි වේ:
autocheck autochk *MyNative
අගය සාමාන්ය ASCII නොව ෂඩ් දශම ආකෘතියේ විය යුතුය, එබැවින් ඉහත පෙන්වා ඇති යතුර ආකෘතියේ වනු ඇත:
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
මාතෘකාව පරිවර්තනය කිරීම සඳහා, ඔබට සබැඳි සේවාවක් භාවිතා කළ හැකිය, උදාහරණයක් ලෙස,
ස්වදේශීය යෙදුමක් දියත් කිරීමට අපට අවශ්ය බව පෙනේ:
- ක්රියාත්මක කළ හැකි ගොනුව system32 ෆෝල්ඩරයට පිටපත් කරන්න
- රෙජිස්ට්රි එකට යතුරක් එකතු කරන්න
- යන්ත්රය නැවත ආරම්භ කරන්න
පහසුව සඳහා, ස්වදේශීය යෙදුමක් ස්ථාපනය කිරීම සඳහා සූදානම් කළ පිටපතක් මෙන්න:
install.bat
@echo off
copy MyNative.exe %systemroot%system32.
regedit /s add.reg
echo Native Example Installed
pause
add.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
ස්ථාපනය කර නැවත පණගැන්වීමෙන් පසුව, පරිශීලක තේරීම් තිරය දිස්වීමට පෙර පවා, අපට පහත පින්තූරය ලැබෙනු ඇත:
ප්රතිඵලය
එවැනි කුඩා යෙදුමක උදාහරණය භාවිතා කරමින්, Windows Native මට්ටමින් යෙදුම ධාවනය කිරීමට බෙහෙවින් හැකි බව අපට ඒත්තු ගියේය. ඊළඟට, ඉනොපොලිස් විශ්ව විද්යාලයේ පිරිමි ළමයින් සහ මම අපගේ ව්යාපෘතියේ පෙර අනුවාදයට වඩා බොහෝ කලකට පෙර රියදුරු සමඟ අන්තර් ක්රියා කිරීමේ ක්රියාවලිය ආරම්භ කරන සේවාවක් ගොඩනඟන්නෙමු. Win32 කවචයේ පැමිණීමත් සමඟ, දැනටමත් සංවර්ධනය කර ඇති සම්පූර්ණ සේවාවකට පාලනය මාරු කිරීම තාර්කික වනු ඇත (මේ පිළිබඳ වැඩි විස්තර
මීළඟ ලිපියෙන් අපි Active Restore සේවාවේ තවත් අංගයක් වන UEFI ධාවකය ස්පර්ශ කරන්නෙමු. අපගේ බ්ලොගයට දායක වන්න එවිට ඔබට මීළඟ සටහන මග හැරිය නොහැක.
මූලාශ්රය: www.habr.com