如果调用 RtlSetProcessIsCritical,将使用 lstrcmpW 将命令行与值进行比较将使程序崩溃

If RtlSetProcessIsCritical is called, comparing the commandline to a value using lstrcmpW will crash the programm

本文关键字:程序 比较 崩溃 lstrcmpW RtlSetProcessIsCritical 调用 如果 命令行      更新时间:2023-10-16

我现在正在做一个更大的项目,我遇到了一个奇怪的问题。 正如标题所述,如果命令行中的第二个参数与使用lstrcmpW的预设值匹配,我将调用RtlSetProcessIsCritical函数,然后尝试执行代码块。

从我的项目中重建的项目,投影结构器

主 CPP 文件:

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
int nArgs;
LPWSTR* szArglist = CommandLineToArgvW(GetCommandLine(), &nArgs);
// Check if ArgumentList was Created, if not: Exit Malware
if (!szArglist) {
MessageBox(NULL, L"Couldn't parse Commandline", L"CommandLineToArgvW", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
ExitProcess(EXIT_FAILURE);
}
if (nArgs > 1) {
if (!lstrcmp(szArglist[1], L"/exec") {
// Some Code here...
} else if (!lstrcmp(szArglist[1], L"/host")) {
// Some Code here...
if (NTImportDLLFUNC()) {
if (NTSetProcessIsCritical(TRUE)) {
// Debug Message
MessageBox(NULL, L"HostProcess is now Critical", L"N0T-iLLerka.X", MB_OK | MB_SYSTEMMODAL | MB_ICONWARNING);
}
}
if (nArgs > 2) {
if (!lstrcmp(szArglist[2], L"/init")) {
// Some Code here...
}
}
// Deadlock here
}
}
// Some Code here...
}

实用程序文件:

#define OPTION_SHUTDOWN_SYSTEM 6
#define SE_DEBUG_PRIVILEGE 20
typedef NTSTATUS(CALLBACK* pRTLADJUSTPRIVILEGE)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
pRTLADJUSTPRIVILEGE RtlAdjustPrivilege;
typedef NTSTATUS(CALLBACK* pRTLSETPROCESSISCRITICAL)(BOOLEAN, BOOLEAN*, BOOLEAN);
pRTLSETPROCESSISCRITICAL RtlSetProcessIsCritical;
bool NTImportDLLFUNC() {
HINSTANCE hNtdll = LoadLibrary(L"ntdll.dll");
if (hNtdll) {
RtlAdjustPrivilege = (pRTLADJUSTPRIVILEGE)GetProcAddress(hNtdll, "RtlAdjustPrivilege");
if (!RtlAdjustPrivilege) {
MessageBox(NULL, L""RtlAdjustPrivilege" is invalid", L"GetProcAddress", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
FreeLibrary(hNtdll);
return FALSE;
}
RtlSetProcessIsCritical = (pRTLSETPROCESSISCRITICAL)GetProcAddress(hNtdll, "RtlSetProcessIsCritical");
if (!RtlSetProcessIsCritical) {
MessageBox(NULL, L""RtlSetProcessIsCritical" is invalid", L"GetProcAddress", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
FreeLibrary(hNtdll);
return FALSE;
}
} else {
MessageBox(NULL, L"Couldn't load "ntdll.dll"", L"N0T-iLLerka.X", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
return FALSE;
}
FreeLibrary(hNtdll);
return TRUE;
}
bool NTSetProcessIsCritical(BOOLEAN blIscritical) {
BOOLEAN bl;
if (!RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &bl)) {
if (!RtlSetProcessIsCritical(blIscritical, NULL, FALSE)) {
return TRUE;
} else {
MessageBox(NULL, L"Couldn't set Process Critical", L"RtlSetProcessIsCritical", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
return FALSE;
}
} else {
MessageBox(NULL, L"Couldn't set Debug Privileges", L"RtlAdjustPrivilege", MB_OK | MB_SYSTEMMODAL | MB_ICONERROR);
return FALSE;
}
return FALSE;
}

现在的问题是,当我调用RtlSetProcessIsCritical(对它得到的设置并不重要(并且命令行参数得到比较时,应用程序崩溃,但是如果我不调用RtlSetProcessIsCritical程序无论出于何种原因都可以完美运行。

我发现问题出在RtlSetProcessIsCritical函数和这条行if (!lstrcmp(szArglist[2], L"/init")) {

我还尝试使用相同的代码结构器在另一个项目中重现这个"错误",但它在那里完美无缺,我现在没有想法了。

如果您需要其余的代码,您可以在我的Github上阅读它,链接到2个文件:

主要CPP

公用事业 CPP

(在我的 Github 上的主文件中,对RtlSetProcessIsCritical的调用是在 if 语句之后。这是暂时的,这只是一个快速的解决方法,所以我至少可以测试软件的其余部分。在发布版本中,这应该按照前面描述的顺序!

声明

typedef NTSTATUS(CALLBACK* pRTLSETPROCESSISCRITICAL)(BOOLEAN, BOOLEAN*, BOOLEAN);

是错误的。正确的函数定义是

NTSYSAPI
NTSTATUS
STDAPIVCALLTYPE
RtlSetProcessIsCritical(
_In_ BOOLEAN NewValue,
_Out_opt_ PBOOLEAN OldValue,
_In_ BOOLEAN CheckFlag
);

这是STDAPIVCALLTYPE- 与__cdecl相同,而不是CALLBACK(又名__stdcall(。 对于 NTDLL API 来说,这是非常罕见的例外。 当然对于x64没有什么不同,所以我确定你的代码是x86。 因此,调用RtlSetProcessIsCritical后的堆栈是错误的

作为旁注 - 你不需要LoadLibraryGetProcAddress(有趣 - 如何在没有第一次呼叫和GetProcAddress(LoadLibrary("kernel32"), "GetProcAddress")的情况下调用GetProcAddress? 存在ntdll.lib和ntdllp.lib- 只需与它链接即可。