ዛሬ እኛ ከኢንኖፖሊስ ዩኒቨርሲቲ ወጣቶች ጋር በመሆን ተጠቃሚው በተቻለ ፍጥነት በማሽናቸው ላይ ከሽንፈት በኋላ መስራት እንዲጀምር የሚያስችል የActive Restore ቴክኖሎጂን እየፈጠርን እንዳለን ታሪኩን እንቀጥላለን። ስለ ቤተኛ የዊንዶውስ አፕሊኬሽኖች እንነጋገራለን, የእነሱን አፈጣጠር እና አጀማመርን ጨምሮ. ከመቁረጡ በታች ስለ ፕሮጀክታችን ትንሽ ነው, እንዲሁም ቤተኛ መተግበሪያዎችን እንዴት እንደሚጽፉ ተግባራዊ መመሪያ ነው.
በቀደሙት ጽሁፎች ውስጥ ስለ ምን እንደሆነ አስቀድመን ተናግረናል
- አገልግሎቱን ራሱ በጣም ቀደም ብሎ ያስጀምሩ
- መጠባበቂያው በጣም ቀደም ብሎ የሚገኝበትን ደመና ያነጋግሩ
- ስርዓቱ በምን አይነት ሁነታ ላይ እንዳለ ለመረዳት በጣም ቀደም ብሎ - መደበኛ ቡት ወይም መልሶ ማግኘት
- አስቀድመው ለማገገም በጣም ያነሱ ፋይሎች
- ተጠቃሚው በፍጥነት እንዲጀምር ይፍቀዱለት።
ለማንኛውም ቤተኛ መተግበሪያ ምንድነው?
ለዚህ ጥያቄ መልስ ለማግኘት ስርዓቱ የሚያደርገውን የጥሪ ቅደም ተከተል እንመልከት፣ ለምሳሌ፣ በማመልከቻው ውስጥ ያለ ፕሮግራመር ፋይል ለመፍጠር ከሞከረ።
ፓቬል ዮሲፍቪች - የዊንዶውስ ከርነል ፕሮግራሚንግ (2019)
ፕሮግራም አውጪው ተግባሩን ይጠቀማል
የቤተኛ መተግበሪያዎች ዋነኛው ጠቀሜታ ntdll ከ kernel32 በጣም ቀደም ብሎ ወደ ስርዓቱ መጫኑ ነው። ይህ ምክንያታዊ ነው፣ ምክንያቱም kernel32 ለመስራት ntdll ይፈልጋል። በውጤቱም, ቤተኛ ተግባራትን የሚጠቀሙ መተግበሪያዎች በጣም ቀደም ብለው መስራት ሊጀምሩ ይችላሉ.
ስለዚህም ዊንዶውስ ቤተኛ አፕሊኬሽኖች በዊንዶውስ ቡት መጀመሪያ ሊጀምሩ የሚችሉ ፕሮግራሞች ናቸው። ከ ntdll ብቻ ተግባራትን ይጠቀማሉ። የእንደዚህ አይነት መተግበሪያ ምሳሌ
ምን ያስፈልገናል?
ዲዲኬ (የአሽከርካሪ ልማት ኪት)፣ አሁን WDK 7 (Windows Driver Kit) በመባል ይታወቃል።- ምናባዊ ማሽን (ለምሳሌ ዊንዶውስ 7 x64)
- አስፈላጊ አይደለም፣ ነገር ግን ሊወርዱ የሚችሉ የራስጌ ፋይሎች ሊረዱ ይችላሉ።
እዚህ
በኮዱ ውስጥ ያለው ምንድን ነው?
እስቲ ትንሽ እንለማመድ እና ለምሳሌ ትንሽ መተግበሪያን እንፃፍ፡-
- በስክሪኑ ላይ መልእክት ያሳያል
- የተወሰነ ማህደረ ትውስታን ይመድባል
- የቁልፍ ሰሌዳ ግቤት ይጠብቃል።
- ያገለገለ ማህደረ ትውስታን ነፃ ያደርጋል
በቤተኛ ትግበራዎች ውስጥ፣ የመግቢያ ነጥቡ ዋና ወይም አሸናፊ አይደለም፣ ነገር ግን የ NtProcessStartup ተግባር፣ በእውነቱ በስርዓቱ ውስጥ አዳዲስ ሂደቶችን ስለምንጀምር ነው።
በስክሪኑ ላይ መልእክት በማሳየት እንጀምር። ለዚህ ደግሞ ተወላጅ ተግባር አለን።
//usage: WriteLn(L"Here is my textn");
void WriteLn(LPWSTR Message)
{
UNICODE_STRING string;
RtlInitUnicodeString(&string, Message);
NtDisplayString(&string);
}
የ ntdll ተግባራት ብቻ ለእኛ ስለሚገኙ እና እስካሁን ድረስ በማህደረ ትውስታ ውስጥ ሌሎች ቤተ-መጻሕፍት ስለሌሉ በእርግጠኝነት የማስታወስ ችሎታን እንዴት መመደብ እንዳለብን እንቸገራለን ። አዲሱ ኦፕሬተር እስካሁን የለም (ምክንያቱም ከ C ++ ከፍተኛ ደረጃ ካለው ዓለም የመጣ ነው) እና ምንም የማሎክ ተግባር የለም (የ Runtime 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) ሊሆን ይችላል ፣ ከዚያ የመስክ ዋጋው ሾፌር መሆን አለበት ፣ ቤተ-መጽሐፍት (.lib) ከሆነ ፣ እሴቱ ቤተ-መጽሐፍት ነው። በእኛ ሁኔታ, ሊተገበር የሚችል ፋይል (.exe) እንፈልጋለን, ስለዚህ እሴቱን ወደ PROGRAM እናዘጋጃለን.
- UMTYPE - ለዚህ መስክ ሊሆኑ የሚችሉ እሴቶች-ኮንሶል ለኮንሶል መተግበሪያ ፣ በዊንዶውስ ሁነታ ለመስራት መስኮቶች። ነገር ግን ቤተኛ መተግበሪያ ለማግኘት nt ን መግለጽ አለብን።
- BUFFER_OVERFLOW_CHECKS - ቋጥኙን ቋት ሞልቶ ካለመፈተሽ ነው፣ በሚያሳዝን ሁኔታ የእኛ ጉዳይ አይደለም፣ እናጠፋዋለን።
- MINWIN_SDK_LIB_PATH - ይህ እሴት የኤስዲኬ_LIB_PATH ተለዋዋጭን ያመለክታል፣እንዲህ አይነት የስርዓት ተለዋዋጭ የተገለጸ ስለሌልዎት አይጨነቁ፣የተረጋገጠ ግንባታን ከዲዲኬ ስናሄድ ይህ ተለዋዋጭ ይገለጻል እና ወደ አስፈላጊ ቤተ-መጻሕፍት ይጠቁማል።
- ምንጮች - የፕሮግራምዎ ምንጮች ዝርዝር።
- ያካትታል - ለመገጣጠም የሚያስፈልጉ የራስጌ ፋይሎች። እዚህ ብዙውን ጊዜ ከዲዲኬ ጋር ወደሚመጡት ፋይሎች የሚወስደውን መንገድ ያመለክታሉ፣ ነገር ግን ሌላ ማንኛውንም መግለጽ ይችላሉ።
- TARGETLIBS - መገናኘት ያለባቸው የቤተ-መጻህፍት ዝርዝር።
- USE_NTDLL ግልጽ በሆኑ ምክንያቶች ወደ 1 መዋቀር ያለበት አስፈላጊ መስክ ነው።
- USER_C_FLAGS - የመተግበሪያ ኮድ ሲያዘጋጁ በቅድመ ፕሮሰሰር መመሪያዎች ውስጥ ሊጠቀሙባቸው የሚችሉ ማንኛቸውም ባንዲራዎች።
ስለዚህ ለመገንባት x86 (ወይም x64) የተረጋገጠ ግንባታን ማስኬድ፣ የስራ ማውጫውን ወደ ፕሮጄክቱ አቃፊ መቀየር እና የግንባታ ትዕዛዙን ማስኬድ አለብን። በቅጽበታዊ ገጽ እይታ ውስጥ ያለው ውጤት አንድ ሊተገበር የሚችል ፋይል እንዳለን ያሳያል።
ይህ ፋይል በቀላሉ ማስጀመር አይቻልም፣ ስርዓቱ ይረግማል እና ባህሪውን በሚከተለው ስህተት እንድናስብ ይልካል።
ቤተኛ መተግበሪያ እንዴት እንደሚጀመር?
Autochk ሲጀምር የፕሮግራሞች ጅምር ቅደም ተከተል የሚወሰነው በመዝገቡ ቁልፍ እሴት ነው፡
HKLMSystemCurrentControlSetControlSession ManagerBootExecute
የክፍለ-ጊዜው አስተዳዳሪ ፕሮግራሞችን ከዚህ ዝርዝር አንድ በአንድ ያስፈጽማል. የክፍለ-ጊዜው አስተዳዳሪ በስርዓት32 ማውጫ ውስጥ ሊተገበሩ የሚችሉ ፋይሎችን ራሳቸው ይፈልጋል። የመመዝገቢያ ቁልፍ እሴት ቅርጸት እንደሚከተለው ነው-
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 አቃፊ ይቅዱ
- ወደ መዝገቡ ቁልፍ ያክሉ
- ማሽኑን ዳግም አስነሳ
ለአመቺነት፣ ቤተኛ መተግበሪያን ለመጫን ዝግጁ የሆነ ስክሪፕት ይኸውና፡
ጫን.ባት
@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
ከተጫነ እና ዳግም ከተነሳ በኋላ የተጠቃሚ ምርጫ ማያ ገጽ ከመታየቱ በፊት እንኳን የሚከተለውን ስዕል እናገኛለን።
ውጤቱ
የእንደዚህ ዓይነቱን ትንሽ መተግበሪያ ምሳሌ በመጠቀም በዊንዶውስ ቤተኛ ደረጃ አፕሊኬሽኑን ማካሄድ በጣም እንደሚቻል እርግጠኛ ነበርን። በመቀጠል እኔ እና የኢንኖፖሊስ ዩኒቨርሲቲ ወጣቶች ከአሽከርካሪው ጋር ያለውን ግንኙነት ሂደት ከቀደመው የፕሮጀክታችን ስሪት በጣም ቀደም ብሎ የሚጀምር አገልግሎት መገንባታችንን እንቀጥላለን። እና የዊን32 ሼል መምጣት, መቆጣጠሪያውን ወደ ተዘጋጀ ሙሉ አገልግሎት ማስተላለፍ ምክንያታዊ ይሆናል (በዚህ ላይ ተጨማሪ
በሚቀጥለው ጽሁፍ ሌላ የActive Restore አገልግሎትን ማለትም የUEFI ሾፌርን እንነካለን። ቀጣዩ ልጥፍ እንዳያመልጥዎ ለብሎጋችን ይመዝገቡ።
ምንጭ: hab.com