添加项目文件。
This commit is contained in:
31
sleep_duck.sln
Normal file
31
sleep_duck.sln
Normal file
@@ -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
|
||||
24
sleep_duck/head.h
Normal file
24
sleep_duck/head.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <dbghelp.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
#include "tlhelp32.h"
|
||||
|
||||
#include "include/capstone/capstone.h"
|
||||
#include "include/capstone/x86.h"
|
||||
#include <optional>
|
||||
|
||||
#pragma comment(lib, "capstone64.lib")
|
||||
|
||||
#include "tools.h"
|
||||
#include "stack_tracker.h"
|
||||
210
sleep_duck/sleep_duck.cpp
Normal file
210
sleep_duck/sleep_duck.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "head.h"
|
||||
|
||||
auto PrintProcessInfoFromHandle(HANDLE hProcess) -> void {
|
||||
DWORD pid = GetProcessId(hProcess);
|
||||
DWORD bufferSize = MAX_PATH;
|
||||
std::vector<wchar_t> 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<std::pair<uint64_t, uint64_t>>& 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<std::pair<uint64_t, uint64_t>> 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<void, decltype(handleDeleter)> hThread(
|
||||
OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID),
|
||||
handleDeleter);
|
||||
std::unique_ptr<void, decltype(handleDeleter)> 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<DWORD>(std::stoul(argv[++i]));
|
||||
}
|
||||
else {
|
||||
std::cerr << "[!] Unknown argument ,go scan all: " << arg << "\n";
|
||||
scanAll = true;
|
||||
}
|
||||
}
|
||||
|
||||
DoLittleHackerMemeDetect(targetPid, scanAll);
|
||||
return 0;
|
||||
}
|
||||
161
sleep_duck/sleep_duck.vcxproj
Normal file
161
sleep_duck/sleep_duck.vcxproj
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{8a01cc2b-278c-411f-beb7-286dc920e493}</ProjectGuid>
|
||||
<RootNamespace>sleepduck</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<LibraryPath>F:\project\white_patch_detect\white_patch_detect\libs;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>F:\project\white_patch_detect\white_patch_detect\capstone-master;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>F:\project\white_patch_detect\white_patch_detect\capstone-master;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>F:\project\white_patch_detect\white_patch_detect\libs;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sleep_duck.cpp" />
|
||||
<ClCompile Include="stack_tracker.cpp" />
|
||||
<ClCompile Include="tools.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="head.h" />
|
||||
<ClInclude Include="stack_tracker.h" />
|
||||
<ClInclude Include="tools.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
39
sleep_duck/sleep_duck.vcxproj.filters
Normal file
39
sleep_duck/sleep_duck.vcxproj.filters
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sleep_duck.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tools.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stack_tracker.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="tools.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="head.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stack_tracker.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
231
sleep_duck/stack_tracker.cpp
Normal file
231
sleep_duck/stack_tracker.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
#include "stack_tracker.h"
|
||||
auto StackTracker::rpm(uintptr_t address, size_t readSize)
|
||||
-> std::vector<char> {
|
||||
size_t NumOfRead = 0;
|
||||
std::vector<char> 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<size_t>(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<const uint8_t*>(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<cs_insn>(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<const uint8_t*>(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<cs_insn>(code));
|
||||
}
|
||||
this->readSuccess = true;
|
||||
} while (false);
|
||||
*/
|
||||
}
|
||||
|
||||
auto StackTracker::getNextIns() -> std::shared_ptr<cs_insn> {
|
||||
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 <typename T, typename B>
|
||||
auto StackTracker::matchCode(
|
||||
T match_fn, B process_fn, std::optional<uint32_t> num_operands,
|
||||
std::vector<std::optional<x86_op_type>> 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<bool, uint64_t> {
|
||||
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<char> 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<uint64_t*>(pointerBuffer.data());
|
||||
}
|
||||
else { // 32位
|
||||
callAddress = *reinterpret_cast<uint32_t*>(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};
|
||||
}
|
||||
39
sleep_duck/stack_tracker.h
Normal file
39
sleep_duck/stack_tracker.h
Normal file
@@ -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<std::shared_ptr<cs_insn>> 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<cs_insn>;
|
||||
auto LookslikeValidEntry(cs_insn* insn, size_t count) -> bool;
|
||||
inline auto is_call(cs_insn* ins) -> bool;
|
||||
template <typename T, typename B>
|
||||
auto matchCode(T match_fn, B process_fn,
|
||||
std::optional<uint32_t> num_operands,
|
||||
std::vector<std::optional<x86_op_type>> operand_types)
|
||||
-> bool;
|
||||
auto rpm(uintptr_t address, size_t readSize) -> std::vector<char>;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
_features feature;
|
||||
StackTracker(HANDLE hProcess, uint64_t StartAddress, size_t trackSize,
|
||||
bool isX32);
|
||||
~StackTracker();
|
||||
auto CalcNextJmpAddress() -> std::pair<bool, uint64_t>;
|
||||
auto TryFindValidDisasm(uint64_t baseAddr, size_t maxOffset) -> bool;
|
||||
};
|
||||
23
sleep_duck/tools.cpp
Normal file
23
sleep_duck/tools.cpp
Normal file
@@ -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
|
||||
6
sleep_duck/tools.h
Normal file
6
sleep_duck/tools.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "head.h"
|
||||
namespace Tools {
|
||||
auto EnableDebugPrivilege(bool bEnable) -> bool;
|
||||
auto Is64BitPorcess(HANDLE hProcess) -> bool;
|
||||
};
|
||||
Reference in New Issue
Block a user