近日同事做调试分析时使用livekd发现用不了,对比了下环境,与系统版本有关,24H2以上的livekd启动有问题,运行后象下图这样就退出了:
我这位同事很牛,他继续调试了livekd,发现是livekd在调用NtQuerySystemInformation去获取ntoskrnl.exe的基址为0,导致不通继续执行。
网上搜了下,是微软在24H2后不允许普通程序获取内核模块地址:
当进程以管理员权限运行并且设置了SeDebugPrivilege为TRUE的情况下,这个问题就解决了。
方法有好几种:
- 用Process hacker或SystemInformer中的Runas功能,以System帐号启动livekd
- PowerShell以管理员权限运行后,再运行livekd
- 写个类似的程序来启动livekd, 附上代码备忘:
#include
#include
#include
bool EnableDebugPrivilege() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tokenPrivileges;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
std::cerr << "OpenProcessToken failed: " << GetLastError() << std::endl;
return false;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
std::cerr << "LookupPrivilegeValue failed: " << GetLastError() << std::endl;
CloseHandle(hToken);
return false;
}
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luid;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
std::cerr << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl;
CloseHandle(hToken);
return false;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
std::cerr << "The token does not have the specified privilege." << std::endl;
CloseHandle(hToken);
return false;
}
CloseHandle(hToken);
return true;
}
bool CreateProcessWithDebugPrivilege(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, STARTUPINFO& si, PROCESS_INFORMATION& pi) {
HANDLE hToken;
HANDLE hNewToken;
LUID luid;
TOKEN_PRIVILEGES tokenPrivileges;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
std::cerr << "OpenProcessToken failed: " << GetLastError() << std::endl;
return false;
}
if (!DuplicateTokenEx(hToken, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_IMPERSONATE, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) {
std::cerr << "DuplicateTokenEx failed: " << GetLastError() << std::endl;
CloseHandle(hToken);
return false;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
std::cerr << "LookupPrivilegeValue failed: " << GetLastError() << std::endl;
CloseHandle(hToken);
CloseHandle(hNewToken);
return false;
}
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Luid = luid;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hNewToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
std::cerr << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl;
CloseHandle(hToken);
CloseHandle(hNewToken);
return false;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
std::cerr << "The token does not have the specified privilege." << std::endl;
CloseHandle(hToken);
CloseHandle(hNewToken);
return false;
}
CloseHandle(hToken);
if (!CreateProcessAsUserW(hNewToken, lpApplicationName, lpCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
std::cerr << "CreateProcessAsUserW failed: " << GetLastError() << std::endl;
CloseHandle(hNewToken);
return false;
}
CloseHandle(hNewToken);
return true;
}
int main(int argc, char* argv[])
{
if (!EnableDebugPrivilege()) {
std::cerr << "Failed to enable debug privilege." << std::endl;
return 1;
}
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;
wchar_t szArgv[MAX_PATH] = { 0 };
if (argc < 2)
{
mbstowcs(szArgv, "c:\\symbols", strlen("c:\\symbols"));
}
else
{
mbstowcs(szArgv, argv[1], strlen(argv[1]));
}
wchar_t szCmdline[MAX_PATH] = { 0 };
swprintf_s(szCmdline, _countof(szCmdline), L"livekd64.exe -y srv*%s*https://msdl.microsoft.com/download/symbols", szArgv);
if (CreateProcessWithDebugPrivilege(NULL, szCmdline, si, pi)) {
std::cout << "Process created with debug privilege." << std::endl;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else {
std::cerr << "Failed to create process." << std::endl;
return 1;
}
return 0;
}