380 lines
12 KiB
C++
380 lines
12 KiB
C++
#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>
|
|
#pragma comment(lib,"dbghelp.lib")
|
|
#include "tlhelp32.h"
|
|
#include "CdigitalSig.h"
|
|
BOOL Is64BitPorcess(HANDLE hProcess)
|
|
{
|
|
BOOL bIsWow64 = false;
|
|
IsWow64Process(hProcess, &bIsWow64);
|
|
return bIsWow64 == false;
|
|
}
|
|
BOOL EnableDebugPrivilege(BOOL bEnable)
|
|
{
|
|
//Enabling the debug privilege allows the application to see
|
|
//information about service application
|
|
BOOL fOK = FALSE; //Assume function fails
|
|
HANDLE hToken;
|
|
//Try to open this process's acess token
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
|
{
|
|
//Attempt to modify the "Debug" privilege
|
|
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;
|
|
}
|
|
|
|
void WCharToChar(const WCHAR* tchar, char* _char)
|
|
{
|
|
int iLength;
|
|
iLength = WideCharToMultiByte(CP_ACP, 0, tchar, -1, NULL, 0, NULL, NULL);
|
|
WideCharToMultiByte(CP_ACP, 0, tchar, -1, _char, iLength, NULL, NULL);
|
|
}
|
|
void CharToWchar(const char* _char, WCHAR* tchar)
|
|
{
|
|
int iLength;
|
|
iLength = MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, NULL, 0);
|
|
MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, tchar, iLength);
|
|
}
|
|
BOOL DosPathToNtPath(WCHAR* pszDosPath, LPTSTR pszNtPath)
|
|
{
|
|
TCHAR szDriveStr[500];
|
|
TCHAR szDrive[3];
|
|
TCHAR szDevName[100];
|
|
INT cchDevName;
|
|
INT i;
|
|
|
|
//检查参数
|
|
if (!pszDosPath || !pszNtPath)
|
|
return FALSE;
|
|
|
|
//获取本地磁盘字符串
|
|
if (GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr))
|
|
{
|
|
for (i = 0; szDriveStr[i]; i += 4)
|
|
{
|
|
if (!lstrcmpi(&(szDriveStr[i]), L"A:\\") || !lstrcmpi(&(szDriveStr[i]), L"B:\\"))
|
|
continue;
|
|
|
|
szDrive[0] = szDriveStr[i];
|
|
szDrive[1] = szDriveStr[i + 1];
|
|
szDrive[2] = '\0';
|
|
if (!QueryDosDevice(szDrive, szDevName, 100))//查询 Dos 设备名
|
|
return FALSE;
|
|
|
|
cchDevName = lstrlen(szDevName);
|
|
if (_wcsnicmp(pszDosPath, szDevName, cchDevName) == 0)//命中
|
|
{
|
|
lstrcpy(pszNtPath, szDrive);//复制驱动器
|
|
lstrcat(pszNtPath, pszDosPath + cchDevName);//复制路径
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
lstrcpy(pszNtPath, pszDosPath);
|
|
|
|
return FALSE;
|
|
}
|
|
DWORD64 GetProcessMoudleHandle(DWORD pid) {
|
|
MODULEENTRY32 moduleEntry;
|
|
HANDLE handle = NULL;
|
|
handle = ::CreateToolhelp32Snapshot(0x00000008, pid);
|
|
ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
|
|
moduleEntry.dwSize = sizeof(MODULEENTRY32);
|
|
if (!Module32First(handle, &moduleEntry)) {
|
|
CloseHandle(handle);
|
|
return NULL;
|
|
}
|
|
do {
|
|
CloseHandle(handle);
|
|
return (DWORD64)moduleEntry.hModule;
|
|
} while (Module32Next(handle, &moduleEntry));
|
|
return 0;
|
|
}
|
|
bool CheckThreadAddressIsExcute(DWORD64 pAddress,HANDLE pHandle, HANDLE pID, HANDLE Tid) {
|
|
|
|
DWORD64 ReadNum = 0;
|
|
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
|
|
|
if (VirtualQueryEx(pHandle, (LPCVOID)pAddress, &mbi, sizeof(mbi)))
|
|
{
|
|
if (mbi.AllocationBase) {
|
|
if (mbi.Type != MEM_IMAGE) {
|
|
if (mbi.AllocationProtect & PAGE_EXECUTE ||
|
|
mbi.AllocationProtect & PAGE_EXECUTE_READ ||
|
|
mbi.AllocationProtect & PAGE_EXECUTE_READWRITE ||
|
|
mbi.AllocationProtect & PAGE_EXECUTE_WRITECOPY)
|
|
{
|
|
printf("\t => [线程堆栈回溯] 检测到未知内存区域[VirtualAlloc免杀?] 地址 %p PID %d TID %d \n", pAddress, pID, Tid);
|
|
char PEStack[0x2];
|
|
if (ReadProcessMemory(pHandle, mbi.BaseAddress, PEStack, sizeof(PEStack), &ReadNum)) {
|
|
if (PEStack[0] == 'M' && PEStack[1] == 'Z') {
|
|
printf("\t => [!!!线程堆栈回溯!!!] 检测到内存加载程序 线程地址 %p PID %d TID %d 内存加载模块地址: %p\n", pAddress, pID, Tid, mbi.BaseAddress);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
void ThreadStackWalk() {
|
|
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
|
|
THREADENTRY32 te32;
|
|
DWORD ExitCode = 0;
|
|
hThreadSnap = CreateToolhelp32Snapshot(0x00000004, GetCurrentProcessId());
|
|
if (hThreadSnap)
|
|
{
|
|
te32.dwSize = sizeof(THREADENTRY32);
|
|
if (!Thread32First(hThreadSnap, &te32))
|
|
{
|
|
CloseHandle(hThreadSnap);
|
|
return;
|
|
}
|
|
do
|
|
{
|
|
if (te32.th32OwnerProcessID != GetCurrentProcessId() && te32.th32ThreadID != GetCurrentThreadId())
|
|
{
|
|
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, 0, te32.th32ThreadID);
|
|
if (hThread && hThread != (HANDLE)-1)
|
|
{
|
|
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, te32.th32OwnerProcessID);
|
|
if (hProcess) {
|
|
STACKFRAME_EX StackFarmeEx;
|
|
memset(&StackFarmeEx, 0, sizeof(STACKFRAME_EX));
|
|
if (Is64BitPorcess(hProcess)) {
|
|
CONTEXT context = { 0 };
|
|
context.ContextFlags = CONTEXT_ALL;
|
|
if (GetThreadContext(hThread, &context))
|
|
{
|
|
if (context.Dr0 != 0 || context.Dr1 != 0 || context.Dr2 != 0 || context.Dr3 != 0)
|
|
{
|
|
//hwbp hook
|
|
printf("\t => [线程堆栈回溯] 检测到HWBP Hook PID %d TID %d \n", te32.th32OwnerProcessID, te32.th32ThreadID);
|
|
}
|
|
CheckThreadAddressIsExcute(context.Rip, hProcess, (HANDLE)te32.th32OwnerProcessID, (HANDLE)te32.th32ThreadID);
|
|
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;
|
|
DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
|
|
while (true)
|
|
{
|
|
if (!StackWalkEx(machineType, hProcess, hThread, &StackFarmeEx, &context, NULL, NULL, NULL, NULL, NULL))
|
|
break;
|
|
if (StackFarmeEx.AddrFrame.Offset == 0)
|
|
break;
|
|
CheckThreadAddressIsExcute(StackFarmeEx.AddrPC.Offset, hProcess, (HANDLE)te32.th32OwnerProcessID, (HANDLE)te32.th32ThreadID);
|
|
}
|
|
}
|
|
} else {
|
|
WOW64_CONTEXT context = { 0 };
|
|
context.ContextFlags = CONTEXT_ALL;
|
|
if (Wow64GetThreadContext(hThread, &context))
|
|
{
|
|
if (context.Dr0 != 0 || context.Dr1 != 0 || context.Dr2 != 0 || context.Dr3 != 0)
|
|
{
|
|
//hwbp hook
|
|
printf("\t => [线程堆栈回溯] 检测到HWBP Hook PID %d TID %d \n", te32.th32OwnerProcessID, te32.th32ThreadID);
|
|
}
|
|
|
|
CheckThreadAddressIsExcute(context.Eip, hProcess, (HANDLE)te32.th32OwnerProcessID, (HANDLE)te32.th32ThreadID);
|
|
StackFarmeEx.AddrPC.Offset = context.Eip;
|
|
StackFarmeEx.AddrPC.Mode = AddrModeFlat;
|
|
StackFarmeEx.AddrStack.Offset = context.Esp;
|
|
StackFarmeEx.AddrStack.Mode = AddrModeFlat;
|
|
StackFarmeEx.AddrFrame.Offset = context.Ebp;
|
|
StackFarmeEx.AddrFrame.Mode = AddrModeFlat;
|
|
DWORD machineType = IMAGE_FILE_MACHINE_I386;//IMAGE_FILE_MACHINE_I386; IMAGE_FILE_MACHINE_AMD64;
|
|
while (true)
|
|
{
|
|
if (!StackWalkEx(machineType, hProcess, hThread, &StackFarmeEx, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
break;
|
|
if (StackFarmeEx.AddrFrame.Offset == 0)
|
|
break;
|
|
CheckThreadAddressIsExcute(StackFarmeEx.AddrPC.Offset, hProcess, (HANDLE)te32.th32OwnerProcessID, (HANDLE)te32.th32ThreadID);
|
|
}
|
|
}
|
|
}
|
|
CloseHandle(hProcess);
|
|
}
|
|
CloseHandle(hThread);
|
|
}
|
|
}
|
|
|
|
} while (Thread32Next(hThreadSnap, &te32));
|
|
CloseHandle(hThreadSnap);
|
|
}
|
|
}
|
|
void WalkProcessMoudle(DWORD pID,HANDLE pHandle,WCHAR* pMoudleName) {
|
|
|
|
MODULEENTRY32 moduleEntry;
|
|
HANDLE handle = NULL;
|
|
handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pID);
|
|
ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
|
|
moduleEntry.dwSize = sizeof(MODULEENTRY32);
|
|
char* AllocBuff = (char*)VirtualAlloc(NULL, 0x200, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
if (AllocBuff) {
|
|
if (!Module32First(handle, &moduleEntry)) {
|
|
CloseHandle(handle);
|
|
return;
|
|
}
|
|
do {
|
|
DWORD64 ReadNum = 0;
|
|
if (ReadProcessMemory(pHandle, moduleEntry.modBaseAddr, AllocBuff, 0x200, &ReadNum)) {
|
|
if (AllocBuff[0] == 'M' && AllocBuff[1] == 'Z') {
|
|
PIMAGE_DOS_HEADER CopyDosHead = (PIMAGE_DOS_HEADER)AllocBuff;
|
|
PIMAGE_NT_HEADERS CopyNthead = (PIMAGE_NT_HEADERS)((LPBYTE)AllocBuff + CopyDosHead->e_lfanew);
|
|
/*
|
|
DWORD64 BaseOfCode = 0;
|
|
DWORD64 SizeOfCode = 0;
|
|
if (CopyNthead->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) {
|
|
PIMAGE_NT_HEADERS64 CopyNthead64 = (PIMAGE_NT_HEADERS64)CopyNthead;
|
|
BaseOfCode = CopyNthead64->OptionalHeader.BaseOfCode;
|
|
SizeOfCode = CopyNthead64->OptionalHeader.SizeOfCode;
|
|
}
|
|
else {
|
|
PIMAGE_NT_HEADERS32 CopyNthead32 = (PIMAGE_NT_HEADERS32)CopyNthead;
|
|
BaseOfCode = CopyNthead32->OptionalHeader.BaseOfCode;
|
|
SizeOfCode = CopyNthead32->OptionalHeader.SizeOfCode;
|
|
}
|
|
*/
|
|
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)CopyNthead + sizeof(CopyNthead->Signature) + sizeof(CopyNthead->FileHeader) + CopyNthead->FileHeader.SizeOfOptionalHeader);
|
|
int FoundNum = 0;
|
|
for (WORD i = 0; i < CopyNthead->FileHeader.NumberOfSections; i++)
|
|
{
|
|
if (SectionHeader[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
FoundNum++;
|
|
}
|
|
if (FoundNum > 1) {
|
|
printf("\t => [进程检测] 检测到额外的可执行区段(.rdata免杀 or 加壳程序) 进程名 %ws 模块名 %ws 区段名字 %s \n", pMoudleName, moduleEntry.szExePath, SectionHeader[i].Name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (Module32Next(handle, &moduleEntry));
|
|
VirtualFree(AllocBuff, 0, MEM_RELEASE);
|
|
}
|
|
CloseHandle(handle);
|
|
}
|
|
void ProcessStackWalk() {
|
|
PROCESSENTRY32 pe32;
|
|
pe32.dwSize = sizeof(pe32);
|
|
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
if (hProcessSnap == INVALID_HANDLE_VALUE)
|
|
{
|
|
printf("CreateToolhelp32Snapshot error.\n");
|
|
return;
|
|
}
|
|
BOOL bProcess = Process32First(hProcessSnap, &pe32);
|
|
while (bProcess)
|
|
{
|
|
//打印进程名和进程ID
|
|
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pe32.th32ProcessID);
|
|
if (hProcess) {
|
|
WalkProcessMoudle(pe32.th32ProcessID, hProcess, pe32.szExeFile);
|
|
WCHAR szImagePath[MAX_PATH];
|
|
WCHAR pszFullPath[MAX_PATH];
|
|
if (GetProcessImageFileName(hProcess, szImagePath, MAX_PATH))
|
|
{
|
|
if (DosPathToNtPath(szImagePath, pszFullPath))
|
|
{
|
|
CdigitalSig DigitalSig(pszFullPath);
|
|
DWORD dDigitalState = DigitalSig.GetDigitalState();
|
|
if (dDigitalState == DIGITAL_SIGSTATE_REVOKED || dDigitalState == DIGITAL_SIGSTATE_EXPIRE) {
|
|
printf("\t => [进程扫描] 检测到可疑签名进程 路径 %ws static %d \n", pszFullPath, dDigitalState);
|
|
}
|
|
}
|
|
}
|
|
CloseHandle(hProcess);
|
|
}
|
|
bProcess = Process32Next(hProcessSnap, &pe32);
|
|
}
|
|
CloseHandle(hProcessSnap);
|
|
return;
|
|
|
|
}
|
|
void ScanSystemDrivers() {
|
|
DWORD cbNeeded = 0; // drivers[] 返回的字节数
|
|
LPVOID drivers[MAX_PATH] = { 0 }; // 驱动程序地址列表数组
|
|
int cDrivers = 0; // 驱动个数
|
|
Wow64EnableWow64FsRedirection(0);
|
|
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers)) // EnumDeviceDrivers 检索每个驱动文件的加载地址
|
|
{
|
|
char szDriver[MAX_PATH] = { 0 }; // 驱动文件名
|
|
char szPath[MAX_PATH] = { 0 }; // 存放驱动文件全路径
|
|
char szNtPath[MAX_PATH] = { 0 };
|
|
char szSystemPath[MAX_PATH] = { 0 }; // 存放 system32 文件夹路径
|
|
cDrivers = cbNeeded / sizeof(LPVOID); // 驱动个数
|
|
|
|
for (int i = 0; i < cDrivers; i++)
|
|
{
|
|
if (drivers[i]) {
|
|
if (GetDeviceDriverBaseNameA(drivers[i], szDriver, sizeof(szDriver) / sizeof(LPVOID)))
|
|
{
|
|
if (GetDeviceDriverFileNameA(drivers[i], szPath, sizeof(szPath))) {
|
|
bool isSystemDriver = true;
|
|
//只判断非系统驱动
|
|
if (szPath[1] == '?')
|
|
{
|
|
isSystemDriver = false;
|
|
int len = strlen(szPath);
|
|
szPath[len + 1] = '\0';
|
|
for (int j = 0; j < len; j++)
|
|
{
|
|
szPath[j] = szPath[j + 4];
|
|
}
|
|
WCHAR UnicodeFilePath[MAX_PATH << 1] = { 0 };
|
|
CharToWchar(szPath, UnicodeFilePath);
|
|
CdigitalSig DigitalSig(UnicodeFilePath);
|
|
DWORD dDigitalState = DigitalSig.GetDigitalState();
|
|
if (dDigitalState != DIGITAL_SIGSTATE_VALID) {
|
|
printf("\t => [驱动扫描] 检测到未知驱动 路径 %ws \n", UnicodeFilePath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Wow64EnableWow64FsRedirection(1);
|
|
}
|
|
int main()
|
|
{
|
|
printf("DuckMemoryScan By huoji 2021-02-23 \n");
|
|
if (EnableDebugPrivilege(true) == false) {
|
|
printf("权限提升失败,请以管理员身份运行 \n");
|
|
system("pause");
|
|
return 0;
|
|
}
|
|
printf("线程堆栈回溯检测 ... \n");
|
|
ThreadStackWalk();
|
|
printf("驱动检测... \n");
|
|
ScanSystemDrivers();
|
|
printf("进程检测... \n");
|
|
ProcessStackWalk();
|
|
printf("检测完毕 ... \n");
|
|
system("pause");
|
|
return 0;
|
|
} |