From 5eccbbb5e5067197dc13559b83dbae639a323d09 Mon Sep 17 00:00:00 2001 From: Huoji's <1296564236@qq.com> Date: Sun, 13 Jul 2025 16:23:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sleep_duck.sln | 31 ++++ sleep_duck/head.h | 24 +++ sleep_duck/sleep_duck.cpp | 210 +++++++++++++++++++++++ sleep_duck/sleep_duck.vcxproj | 161 ++++++++++++++++++ sleep_duck/sleep_duck.vcxproj.filters | 39 +++++ sleep_duck/stack_tracker.cpp | 231 ++++++++++++++++++++++++++ sleep_duck/stack_tracker.h | 39 +++++ sleep_duck/tools.cpp | 23 +++ sleep_duck/tools.h | 6 + 9 files changed, 764 insertions(+) create mode 100644 sleep_duck.sln create mode 100644 sleep_duck/head.h create mode 100644 sleep_duck/sleep_duck.cpp create mode 100644 sleep_duck/sleep_duck.vcxproj create mode 100644 sleep_duck/sleep_duck.vcxproj.filters create mode 100644 sleep_duck/stack_tracker.cpp create mode 100644 sleep_duck/stack_tracker.h create mode 100644 sleep_duck/tools.cpp create mode 100644 sleep_duck/tools.h diff --git a/sleep_duck.sln b/sleep_duck.sln new file mode 100644 index 0000000..c7cd36b --- /dev/null +++ b/sleep_duck.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.35731.53 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sleep_duck", "sleep_duck\sleep_duck.vcxproj", "{8A01CC2B-278C-411F-BEB7-286DC920E493}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Debug|x64.ActiveCfg = Debug|x64 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Debug|x64.Build.0 = Debug|x64 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Debug|x86.ActiveCfg = Debug|Win32 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Debug|x86.Build.0 = Debug|Win32 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Release|x64.ActiveCfg = Release|x64 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Release|x64.Build.0 = Release|x64 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Release|x86.ActiveCfg = Release|Win32 + {8A01CC2B-278C-411F-BEB7-286DC920E493}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {52DFFDE6-0BC8-468E-8698-A824D5F47E90} + EndGlobalSection +EndGlobal diff --git a/sleep_duck/head.h b/sleep_duck/head.h new file mode 100644 index 0000000..a8dd022 --- /dev/null +++ b/sleep_duck/head.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "dbghelp.lib") +#include "tlhelp32.h" + +#include "include/capstone/capstone.h" +#include "include/capstone/x86.h" +#include + +#pragma comment(lib, "capstone64.lib") + +#include "tools.h" +#include "stack_tracker.h" diff --git a/sleep_duck/sleep_duck.cpp b/sleep_duck/sleep_duck.cpp new file mode 100644 index 0000000..e55ac11 --- /dev/null +++ b/sleep_duck/sleep_duck.cpp @@ -0,0 +1,210 @@ +#include "head.h" + +auto PrintProcessInfoFromHandle(HANDLE hProcess) -> void { + DWORD pid = GetProcessId(hProcess); + DWORD bufferSize = MAX_PATH; + std::vector pathBuffer(bufferSize); + if (!QueryFullProcessImageNameW(hProcess, 0, pathBuffer.data(), + &bufferSize)) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + pathBuffer.resize(bufferSize); + if (!QueryFullProcessImageNameW(hProcess, 0, pathBuffer.data(), + &bufferSize)) { + throw std::runtime_error( + "Failed to query process image name on second attempt. " + "Error code: " + + std::to_string(GetLastError())); + } + } else { + throw std::runtime_error( + "Failed to query process image name. Error code: " + + std::to_string(GetLastError())); + } + } + std::wstring processPath(pathBuffer.data(), bufferSize); + printf("target process %d -> %ws \n", pid, pathBuffer.data()); +} + +auto SimpleCheckIn2020(HANDLE hProcess, uint64_t Address) -> bool { + MEMORY_BASIC_INFORMATION mbi = {0}; + SIZE_T ReadNum = 0; + bool detect = false; + do { + if (VirtualQueryEx(hProcess, (PVOID)Address, &mbi, sizeof(mbi)) == + false) { + break; + } + if (mbi.Type == MEM_IMAGE) { + break; + } + bool CheckExcuteFlag = mbi.AllocationProtect & PAGE_EXECUTE || + mbi.AllocationProtect & PAGE_EXECUTE_READ || + mbi.AllocationProtect & PAGE_EXECUTE_READWRITE || + mbi.AllocationProtect & PAGE_EXECUTE_WRITECOPY; + if (CheckExcuteFlag) { + printf("rwx memory detect-> \n\t"); + PrintProcessInfoFromHandle(hProcess); + detect = true; + char PEStack[0x2]; + if (ReadProcessMemory(hProcess, mbi.BaseAddress, PEStack, + sizeof(PEStack), &ReadNum)) { + if (PEStack[0] == 'M' && PEStack[1] == 'Z') { + printf("rwx memory has pe module-> \n\t"); + PrintProcessInfoFromHandle(hProcess); + } + } + } else if (mbi.AllocationProtect & PAGE_READONLY || + mbi.AllocationProtect & PAGE_READWRITE || + mbi.AllocationProtect & PAGE_NOACCESS) { + printf("no-excute-page detect at %p \n\t", Address); + PrintProcessInfoFromHandle(hProcess); + detect = true; + } + } while (false); + return detect; +} +auto DoCFTrackX64(HANDLE hProcess, + std::vector>& stackArrays) + -> void { + for (size_t i = stackArrays.size() - 1; i > 0; i--) { + auto ripAddr = stackArrays[i].first; + auto retAddr = stackArrays[i].second; + //printf("stack walk: %p\n", ripAddr); + + if (retAddr == 0) { + continue; + } + auto rawAddress = ripAddr - 0x16; + StackTracker stackTrack(hProcess, rawAddress, 0x30, false); + if (stackTrack.TryFindValidDisasm(rawAddress, 0x30) == false) { + printf("\nSleepMask Encryption Memory Detected: %p\n\t", rawAddress); + PrintProcessInfoFromHandle(hProcess); + continue; + } + auto [successTrack, nextJmpAddress] = stackTrack.CalcNextJmpAddress(); + + if (successTrack == false && + stackTrack.feature != _features::kCallRip && + stackTrack.feature != _features::kCallReg && + stackTrack.feature != _features::kSyscall) { + printf("\nNon-integrity Stack Detect: %p\n\t", rawAddress); + PrintProcessInfoFromHandle(hProcess); + break; + } + + } + return; +} +auto DoX64StackDetect(HANDLE hProcess, HANDLE hThread) -> void { + STACKFRAME64 StackFarmeEx = {}; + CONTEXT context = {0}; + context.ContextFlags = CONTEXT_ALL; + std::vector> stackArrays; + SymInitialize(hProcess, nullptr, TRUE); + //printf("scan tid: %d \n", GetThreadId(hThread)); + do { + if (GetThreadContext(hThread, &context) == false) { + break; + } + + StackFarmeEx.AddrPC.Offset = context.Rip; + StackFarmeEx.AddrPC.Mode = AddrModeFlat; + StackFarmeEx.AddrStack.Offset = context.Rsp; + StackFarmeEx.AddrStack.Mode = AddrModeFlat; + StackFarmeEx.AddrFrame.Offset = context.Rsp; + StackFarmeEx.AddrFrame.Mode = AddrModeFlat; + bool detect = false; + while (true) { + if (StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, + &StackFarmeEx, &context, NULL, + SymFunctionTableAccess, SymGetModuleBase, + NULL) == false) { + break; + } + if (StackFarmeEx.AddrFrame.Offset == 0) { + break; + } + if (SimpleCheckIn2020(hProcess, StackFarmeEx.AddrPC.Offset)) { + detect = true; + //break; + } + stackArrays.push_back( + {StackFarmeEx.AddrPC.Offset, StackFarmeEx.AddrReturn.Offset}); + } + //if (detect) { + // break; + //} + DoCFTrackX64(hProcess, stackArrays); + } while (false); + SymCleanup(hProcess); +} + +// 主扫描函数 +auto DoLittleHackerMemeDetect(DWORD pidFilter = 0, bool scanAll = false) -> void { + HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // 所有线程 + THREADENTRY32 te32 = {}; + te32.dwSize = sizeof(THREADENTRY32); + + if (hThreadSnap == INVALID_HANDLE_VALUE || !Thread32First(hThreadSnap, &te32)) + return; + + do { + // 跳过当前线程 + if (te32.th32OwnerProcessID == GetCurrentProcessId() && + te32.th32ThreadID == GetCurrentThreadId()) + continue; + + // 判断是否过滤进程 + if (!scanAll && pidFilter != 0 && te32.th32OwnerProcessID != pidFilter) + continue; + + if (!scanAll && pidFilter == 0 && te32.th32OwnerProcessID != GetCurrentProcessId()) + continue; + + auto handleDeleter = [](HANDLE h) { + if (h && h != INVALID_HANDLE_VALUE) CloseHandle(h); + }; + + std::unique_ptr hThread( + OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID), + handleDeleter); + std::unique_ptr hProcess( + OpenProcess(PROCESS_ALL_ACCESS, FALSE, te32.th32OwnerProcessID), + handleDeleter); + + if (!hProcess || hProcess.get() == INVALID_HANDLE_VALUE || + !hThread || hThread.get() == INVALID_HANDLE_VALUE) + continue; + + if (!Tools::Is64BitPorcess(hProcess.get())) + continue; + DoX64StackDetect(hProcess.get(), hThread.get()); + + } while (Thread32Next(hThreadSnap, &te32)); + + CloseHandle(hThreadSnap); +} + +int main(int argc, char* argv[]) { + bool scanAll = true; + DWORD targetPid = 0; + + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + + if (arg == "-all") { + scanAll = true; + } + else if (arg == "-pid" && i + 1 < argc) { + scanAll = false; + targetPid = static_cast(std::stoul(argv[++i])); + } + else { + std::cerr << "[!] Unknown argument ,go scan all: " << arg << "\n"; + scanAll = true; + } + } + + DoLittleHackerMemeDetect(targetPid, scanAll); + return 0; +} diff --git a/sleep_duck/sleep_duck.vcxproj b/sleep_duck/sleep_duck.vcxproj new file mode 100644 index 0000000..7a3dd5a --- /dev/null +++ b/sleep_duck/sleep_duck.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {8a01cc2b-278c-411f-beb7-286dc920e493} + sleepduck + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + F:\project\white_patch_detect\white_patch_detect\libs;$(LibraryPath) + F:\project\white_patch_detect\white_patch_detect\capstone-master;$(IncludePath) + + + false + F:\project\white_patch_detect\white_patch_detect\capstone-master;$(IncludePath) + F:\project\white_patch_detect\white_patch_detect\libs;$(LibraryPath) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + MultiThreaded + + + Console + true + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sleep_duck/sleep_duck.vcxproj.filters b/sleep_duck/sleep_duck.vcxproj.filters new file mode 100644 index 0000000..2aaf645 --- /dev/null +++ b/sleep_duck/sleep_duck.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + \ No newline at end of file diff --git a/sleep_duck/stack_tracker.cpp b/sleep_duck/stack_tracker.cpp new file mode 100644 index 0000000..6942f7f --- /dev/null +++ b/sleep_duck/stack_tracker.cpp @@ -0,0 +1,231 @@ +#include "stack_tracker.h" +auto StackTracker::rpm(uintptr_t address, size_t readSize) + -> std::vector { + size_t NumOfRead = 0; + std::vector buffer(readSize); + + if (ReadProcessMemory(this->targetProcess, (LPCVOID)address, buffer.data(), + readSize, &NumOfRead) == false || + NumOfRead != readSize) { + return {}; + } + return buffer; +} +auto StackTracker::LookslikeValidEntry(cs_insn* insn, size_t count) -> bool { + if (insn == nullptr || count == 0) + return false; + + int threshold_score = 2; + int score = 0; + + // 限制最多检查前几条指令 + size_t check_limit = min(count, static_cast(8)); + + for (size_t i = 0; i < check_limit; ++i) { + const cs_insn& inst = insn[i]; + + switch (inst.id) { + case X86_INS_PUSH: + if (strcmp(inst.mnemonic, "push") == 0) + score++; + break; + case X86_INS_MOV: + if (strstr(inst.op_str, "rbp") != nullptr || strstr(inst.op_str, "rsp") != nullptr) + score++; + break; + case X86_INS_SUB: + case X86_INS_ADD: + if (strstr(inst.op_str, "rsp") != nullptr) + score++; + break; + case X86_INS_CALL: + score += 1; + break; + case X86_INS_LEA: + if (strstr(inst.op_str, "rip") != nullptr) + score++; + break; + case X86_INS_TEST: + case X86_INS_CMP: + case X86_INS_JE: + case X86_INS_JNE: + case X86_INS_JMP: + score++; + break; + case X86_INS_NOP: + break; // 忽略 + default: + if (score == 0) + score -= 1; //杂指令降低一点分数 + break; + } + + if (score >= threshold_score) { + return true; + } + } + return score >= threshold_score; +} +auto StackTracker::TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool { + for (size_t i = 0; i < maxOffset; ++i) { + auto buf = this->rpm(baseAddr + i, this->trackSize); + if (buf.size() != this->trackSize) continue; + cs_insn* testInsn = nullptr; + auto cnt = cs_disasm(this->capstoneHandle, + reinterpret_cast(buf.data()), + this->trackSize, baseAddr + i, 0, &testInsn); + if (cnt > 0 && LookslikeValidEntry(testInsn, cnt)) { + this->baseAddr += i; + if (this->insn != nullptr) { + cs_free(this->insn, this->disasmCount); + } + this->insn = testInsn; + this->disasmCount = cnt; + for (size_t j = 0; j < cnt; ++j) { + this->insList.push_back(std::make_shared(this->insn[j])); + } + this->readSuccess = true; + return true; + } + } + return false; +} +StackTracker::StackTracker(HANDLE hProcess, uint64_t StartAddress, + size_t trackSize, bool isX32) { + this->isWow64 = isX32; + this->targetProcess = hProcess; + this->baseAddr = StartAddress; + this->trackSize = trackSize; + if (cs_open(CS_ARCH_X86, this->isWow64 ? CS_MODE_32 : CS_MODE_64, + &capstoneHandle) != CS_ERR_OK) { + __debugbreak(); + } + cs_option(capstoneHandle, CS_OPT_DETAIL, CS_OPT_ON); + cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON); + /* + do { + auto bufferArrays = this->rpm(StartAddress, trackSize); + if (bufferArrays.size() != trackSize) { + break; + } + disasmCount = + cs_disasm(capstoneHandle, + reinterpret_cast(bufferArrays.data()), + trackSize, StartAddress, 0, &insn); + if (disasmCount == 0) { + break; + } + for (size_t index = 0; index < disasmCount; index++) { + const auto code = insn[index]; + this->insList.push_back(std::make_shared(code)); + } + this->readSuccess = true; + } while (false); + */ +} + +auto StackTracker::getNextIns() -> std::shared_ptr { + if (this->ins_ip >= this->insList.size()) { + return nullptr; + } + const auto result = this->insList[this->ins_ip]; + this->ins_ip++; + this->ins_ip_address = result->address; + return result; +} +StackTracker::~StackTracker() { + if (insn) { + cs_free(insn, disasmCount); + cs_close(&capstoneHandle); + } +} +template +auto StackTracker::matchCode( + T match_fn, B process_fn, std::optional num_operands, + std::vector> operand_types) -> bool { + while (auto instruction = getNextIns()) { + if (&process_fn != nullptr) { + process_fn(instruction.get()); + } + if (num_operands) { + if (instruction->detail->x86.op_count != *num_operands) continue; + bool operand_type_mismatch = false; + for (uint32_t i = 0; i < *num_operands; i++) { + auto& target_type = operand_types[i]; + if (target_type && + target_type != instruction->detail->x86.operands[i].type) { + operand_type_mismatch = true; + break; + } + } + if (operand_type_mismatch) continue; + } + if (match_fn(instruction.get())) return true; + } + return false; +} + +inline auto StackTracker::is_call(cs_insn* ins) -> bool { + return ins->id == X86_INS_CALL; +} +auto StackTracker::CalcNextJmpAddress() -> std::pair { + if (this->readSuccess == false) { + return {false , 0}; + } + this->feature = _features::kNonCallOnly; + + uint64_t callAddress = 0; + auto isMatchCall = matchCode( + [&](cs_insn* instruction) { + + if (instruction->id != X86_INS_CALL) { + if (instruction->id == X86_INS_SYSCALL) { + this->feature = _features::kSyscall; + } + return false; + } + if (instruction->detail->x86.op_count != 1) { + return false; + } + const cs_x86_op& operand = instruction->detail->x86.operands[0]; + if (operand.type == X86_OP_IMM) { + callAddress = + instruction->address + instruction->size + operand.imm; + return true; + } + else if (operand.type == X86_OP_MEM) { + const x86_op_mem& mem = operand.mem; + // 我们只处理可以静态计算的 RIP 相对寻址 + if (mem.base == X86_REG_RIP) { + uint64_t pointerAddress = instruction->address + instruction->size + mem.disp; + size_t pointerSize = this->isWow64 ? 4 : 8; + std::vector pointerBuffer = this->rpm(pointerAddress, pointerSize); + if (pointerBuffer.empty()) { + std::cerr << "Failed to read pointer at 0x" << std::hex << pointerAddress << std::endl; + return false; + } + if (pointerSize == 8) { + callAddress = *reinterpret_cast(pointerBuffer.data()); + } + else { // 32位 + callAddress = *reinterpret_cast(pointerBuffer.data()); + } + + //std::cout << "Found RIP-relative call at 0x" << std::hex << instruction->address + // << ". Pointer at 0x" << pointerAddress + // << ". Final Target: 0x" << callAddress << std::endl; + return true; + } + //std::cout << "Skipping non-RIP-relative memory call at 0x" << std::hex << instruction->address << std::endl; + this->feature = _features::kCallRip; + return false; + } + else if (operand.type == X86_OP_REG) { + this->feature = _features::kCallReg; + return false; + } + return false; + }, + [&](cs_insn* instruction) {}, {}, {}); + return {isMatchCall, callAddress}; +} diff --git a/sleep_duck/stack_tracker.h b/sleep_duck/stack_tracker.h new file mode 100644 index 0000000..1e21597 --- /dev/null +++ b/sleep_duck/stack_tracker.h @@ -0,0 +1,39 @@ +#pragma once +#include "head.h" +enum class _features { + kNone, + kNonCallOnly, + kCallRip, + kCallReg, + kSyscall +}; +class StackTracker { + private: + bool readSuccess; + bool isWow64; + HANDLE targetProcess; + std::vector> insList; + cs_insn* insn = nullptr; + size_t disasmCount = 0; + csh capstoneHandle; + uint64_t ins_ip, ins_ip_address, baseAddr, trackSize; + auto getNextIns() -> std::shared_ptr; + auto LookslikeValidEntry(cs_insn* insn, size_t count) -> bool; + inline auto is_call(cs_insn* ins) -> bool; + template + auto matchCode(T match_fn, B process_fn, + std::optional num_operands, + std::vector> operand_types) + -> bool; + auto rpm(uintptr_t address, size_t readSize) -> std::vector; + + + + public: + _features feature; + StackTracker(HANDLE hProcess, uint64_t StartAddress, size_t trackSize, + bool isX32); + ~StackTracker(); + auto CalcNextJmpAddress() -> std::pair; + auto TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool; +}; diff --git a/sleep_duck/tools.cpp b/sleep_duck/tools.cpp new file mode 100644 index 0000000..e4fb95c --- /dev/null +++ b/sleep_duck/tools.cpp @@ -0,0 +1,23 @@ +#include "tools.h" +namespace Tools { +auto Is64BitPorcess(HANDLE hProcess) -> bool { + BOOL bIsWow64 = false; + IsWow64Process(hProcess, &bIsWow64); + return bIsWow64 == false; +} +auto EnableDebugPrivilege(bool bEnable) -> bool { + bool fOK = FALSE; // Assume function fails + HANDLE hToken; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, + &hToken)) { + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); + tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; + AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); + fOK = (GetLastError() == ERROR_SUCCESS); + CloseHandle(hToken); + } + return fOK; +} +}; // namespace Tools diff --git a/sleep_duck/tools.h b/sleep_duck/tools.h new file mode 100644 index 0000000..1b4b0bb --- /dev/null +++ b/sleep_duck/tools.h @@ -0,0 +1,6 @@ +#pragma once +#include "head.h" +namespace Tools { + auto EnableDebugPrivilege(bool bEnable) -> bool; + auto Is64BitPorcess(HANDLE hProcess) -> bool; +};