Skip to content

Commit

Permalink
PreparedPaths, Общий путь WindowsServices, safe delete.
Browse files Browse the repository at this point in the history
добавлен PreparedPaths, упрощен поиск нескольких процессов USB-VIRUS'a до пути WindowsServices, удалены повторяющиеся модификаторы, добавлена конструкция try-catch для защиты от вылета при попытке удаления еще запущенного вируса, добавление функция для удаления вируса после завершения процесса.
  • Loading branch information
Statuxia committed Apr 4, 2023
1 parent 2338e96 commit bf2f0c1
Showing 1 changed file with 181 additions and 171 deletions.
352 changes: 181 additions & 171 deletions Antivirus/Catcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,200 +3,210 @@
#include <filesystem>
#include <winternl.h>
#include <tlhelp32.h>
#include "PreparedPaths.h"

using namespace std;
using namespace std::filesystem;

class Catcher {

private:
// Пути до AppData, {User} и WindowsServices
path appdata = temp_directory_path()
.parent_path()
.parent_path()
.parent_path(); // C:\\Users\\{User}\\AppData
path user = appdata.parent_path(); // C:\\Users\\{User}
path windowsServices = appdata.append("Roaming").append("WindowsServices");

// smss virus path
const path smssVirusPath = user.append("smss.exe");

// vbs virus
path helperVbsPath = path(windowsServices); //= path(windowsServices.string().append("\\helper.vbs"));
path installerVbsPath = path(windowsServices); // = path(windowsServices.string().append("\\installer.vbs"));
path movemenoregVbsPath = path(windowsServices); // = path(windowsServices.string().append("\\movemenoreg.vbs"));
path WindowsServicesExePath = path(windowsServices); // = path(windowsServices.string().append("\\WindowsServices.exe"));
// Пути вирусов
path smssVirusPath = PreparedPaths::getUser();
path windowsServicesPath = PreparedPaths::getAppData(); // Место скопление USB-VIRUS'а.

// Лист путей вирусов
list<path> listOfPaths;

public: Catcher() {
helperVbsPath.append("helper.vbs");
installerVbsPath.append("installer.vbs");
movemenoregVbsPath.append("movemenoreg.vbs");
WindowsServicesExePath.append("WindowsServices.exe");

listOfPaths = { smssVirusPath, helperVbsPath, installerVbsPath,
movemenoregVbsPath, WindowsServicesExePath };
// Для добавления можно как создать переменную и добавить в лист
// или инициализируем на месте через path("путь\\до\\файла.тип_файла")

while (true) {
detectProcesses(); // Нахождение и отключение процессов.
Sleep(2000); // Сон 2 секунды, чтобы удостовериться, что процессы вырубились.
deleteViruses(); // Удаление вирусов.
Sleep(10000); // Сон 10 секунд. Программам тоже нужно спать =)
}
}
// Удаляет вирусные файлы, если они существуют.
public: void deleteViruses() {
for (path path : listOfPaths) {
remove(path.string());
public:
Catcher() {
smssVirusPath.append("smss.exe");
windowsServicesPath.append("Roaming").append("WindowsServices");

listOfPaths = { smssVirusPath, windowsServicesPath };
// Для добавления можно как создать переменную и добавить в лист
// или инициализируем на месте через path("путь\\до\\файла_или_папки")

while (true) {
detectProcesses(); // Нахождение, отключение и удаление процессов.
Sleep(1000);
deleteViruses(); // Дополнительный проход по путям, чтобы удостовериться в удалении.
Sleep(1000);
}
}
}

// Темная магия от японца. Низкий поклон и сильное нежелание читать, так как оно работает.
// https://espresso3389.hatenablog.com/entry/20080723/1216815501
public: void detectProcesses() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return;
// Удаляет вирусные файлы, если они существуют.
// Проверка try-catch используется, чтобы программа не вылетала, если процесс не успел выключиться.
void deleteViruses() {
for (path path : listOfPaths) {
try {
remove(path.string());
Sleep(200); // В случае большого количества путей возможны сильные нагрузки на систему.
}
catch (...) {
throw;
}
}
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if (!Process32First(hSnapshot, &pe))
{
CloseHandle(hSnapshot);
return;

// Удаляет все, что находится на переданном пути.
// Проверка try-catch используется, чтобы программа не вылетала, если процесс не успел выключиться.
void deleteVirus(path path) {
try {
remove(path.string());
Sleep(200); // В случае большого количества путей возможны сильные нагрузки на систему.
}
catch (...) {
throw;
}
}
do
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe.th32ProcessID);
if (hProcess)

// Темная магия от японца. Низкий поклон и сильное нежелание читать, так как оно работает.
// https://espresso3389.hatenablog.com/entry/20080723/1216815501
void detectProcesses() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return;
}
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if (!Process32First(hSnapshot, &pe))
{
WCHAR buffer[MAX_PATH];
buffer[0] = 0;

if (GetRemoteCommandLineW(hProcess, buffer, MAX_PATH)) {
// Темная магия заканчивается. Просыпаются рукожопии.
string args;
for (int i = 0; i < (sizeof(buffer) / sizeof(buffer[0])); i++) {
args += buffer[i];
}
CloseHandle(hSnapshot);
return;
}
do
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe.th32ProcessID);
if (hProcess)
{
WCHAR buffer[MAX_PATH];
buffer[0] = 0;

if (GetRemoteCommandLineW(hProcess, buffer, MAX_PATH)) {
// Темная магия заканчивается. Просыпаются рукожопии.
string args;
for (int i = 0; i < (sizeof(buffer) / sizeof(buffer[0])); i++) {
args += buffer[i];
}

// Сравнение путей в аргументах процесса с вирусными.
for (path path : listOfPaths) {
size_t pathExists = args.find(path.string());
// Если совпало, вырубаем.
if (string::npos != pathExists) {
HANDLE killProcess = OpenProcess(PROCESS_TERMINATE, 0, pe.th32ProcessID);
TerminateProcess(killProcess, 1);
CloseHandle(killProcess);
// Сравнение путей в аргументах процесса с вирусными.
for (path path : listOfPaths) {
size_t pathExists = args.find(path.string());
// Если совпало, вырубаем.
if (string::npos != pathExists) {
HANDLE killProcess = OpenProcess(PROCESS_TERMINATE, 0, pe.th32ProcessID);
if (TerminateProcess(killProcess, 1) && CloseHandle(killProcess)) {
//Sleep(1000);
deleteVirus(path);
}
}
}
}
CloseHandle(hProcess);
}
CloseHandle(hProcess);
}
} while (Process32Next(hSnapshot, &pe));
CloseHandle(hSnapshot);
}
// Темная магия от японца. Низкий поклон и сильное нежелание читать, так как оно работает.
// https://espresso3389.hatenablog.com/entry/20080723/1216815501
private: DWORD GetRemoteCommandLineW(HANDLE hProcess, LPWSTR pszBuffer, UINT bufferLength)
{
struct RTL_USER_PROCESS_PARAMETERS_I
{
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
};

struct PEB_INTERNAL
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
struct PEB_LDR_DATA* Ldr;
RTL_USER_PROCESS_PARAMETERS_I* ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
struct PS_POST_PROCESS_INIT_ROUTINE* PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
};

typedef NTSTATUS(NTAPI* NtQueryInformationProcessPtr)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL);

typedef ULONG(NTAPI* RtlNtStatusToDosErrorPtr)(NTSTATUS Status);

// Locating functions
HINSTANCE hNtDll = GetModuleHandleW(L"ntdll.dll");
NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");
RtlNtStatusToDosErrorPtr RtlNtStatusToDosError = (RtlNtStatusToDosErrorPtr)GetProcAddress(hNtDll, "RtlNtStatusToDosError");

if (!NtQueryInformationProcess || !RtlNtStatusToDosError)
{
printf("Functions cannot be located.\n");
return 0;
} while (Process32Next(hSnapshot, &pe));
CloseHandle(hSnapshot);
}

private:
// Темная магия от японца. Низкий поклон и сильное нежелание читать, так как оно работает.
// https://espresso3389.hatenablog.com/entry/20080723/1216815501
DWORD GetRemoteCommandLineW(HANDLE hProcess, LPWSTR pszBuffer, UINT bufferLength) {
struct RTL_USER_PROCESS_PARAMETERS_I
{
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
};

// Get PROCESS_BASIC_INFORMATION
PROCESS_BASIC_INFORMATION pbi;
ULONG len;
NTSTATUS status = NtQueryInformationProcess(
hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
SetLastError(RtlNtStatusToDosError(status));
if (NT_ERROR(status) || !pbi.PebBaseAddress)
{
printf("NtQueryInformationProcess(ProcessBasicInformation) failed.\n");
return 0;
}
struct PEB_INTERNAL
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
struct PEB_LDR_DATA* Ldr;
RTL_USER_PROCESS_PARAMETERS_I* ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
struct PS_POST_PROCESS_INIT_ROUTINE* PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
};

typedef NTSTATUS(NTAPI* NtQueryInformationProcessPtr)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL);

typedef ULONG(NTAPI* RtlNtStatusToDosErrorPtr)(NTSTATUS Status);

// Locating functions
HINSTANCE hNtDll = GetModuleHandleW(L"ntdll.dll");
NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtDll, "NtQueryInformationProcess");
RtlNtStatusToDosErrorPtr RtlNtStatusToDosError = (RtlNtStatusToDosErrorPtr)GetProcAddress(hNtDll, "RtlNtStatusToDosError");

if (!NtQueryInformationProcess || !RtlNtStatusToDosError)
{
printf("Functions cannot be located.\n");
return 0;
}

// Read PEB memory block
SIZE_T bytesRead = 0;
PEB_INTERNAL peb;
if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), &bytesRead))
{
printf("Reading PEB failed.\n");
return 0;
}
// Get PROCESS_BASIC_INFORMATION
PROCESS_BASIC_INFORMATION pbi;
ULONG len;
NTSTATUS status = NtQueryInformationProcess(
hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &len);
SetLastError(RtlNtStatusToDosError(status));
if (NT_ERROR(status) || !pbi.PebBaseAddress)
{
printf("NtQueryInformationProcess(ProcessBasicInformation) failed.\n");
return 0;
}

// Obtain size of commandline string
RTL_USER_PROCESS_PARAMETERS_I upp;
if (!ReadProcessMemory(hProcess, peb.ProcessParameters, &upp, sizeof(upp), &bytesRead))
{
printf("Reading USER_PROCESS_PARAMETERS failed.\n");
return 0;
}
// Read PEB memory block
SIZE_T bytesRead = 0;
PEB_INTERNAL peb;
if (!ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), &bytesRead))
{
printf("Reading PEB failed.\n");
return 0;
}

if (!upp.CommandLine.Length)
{
printf("Command line length is 0.\n");
return 0;
}
// Obtain size of commandline string
RTL_USER_PROCESS_PARAMETERS_I upp;
if (!ReadProcessMemory(hProcess, peb.ProcessParameters, &upp, sizeof(upp), &bytesRead))
{
printf("Reading USER_PROCESS_PARAMETERS failed.\n");
return 0;
}

// Check the buffer size
DWORD dwNeedLength = (upp.CommandLine.Length + 1) / sizeof(wchar_t) + 1;
if (bufferLength < dwNeedLength)
{
// printf("Not enough buffer.\n");
return dwNeedLength;
}
if (!upp.CommandLine.Length)
{
printf("Command line length is 0.\n");
return 0;
}

// Get the actual command line
pszBuffer[dwNeedLength - 1] = L'\0';
if (!ReadProcessMemory(hProcess, upp.CommandLine.Buffer, pszBuffer, upp.CommandLine.Length, &bytesRead))
{
printf("Reading command line failed.\n");
return 0;
}
// Check the buffer size
DWORD dwNeedLength = (upp.CommandLine.Length + 1) / sizeof(wchar_t) + 1;
if (bufferLength < dwNeedLength)
{
// printf("Not enough buffer.\n");
return dwNeedLength;
}

return bytesRead / sizeof(wchar_t);
}
// Get the actual command line
pszBuffer[dwNeedLength - 1] = L'\0';
if (!ReadProcessMemory(hProcess, upp.CommandLine.Buffer, pszBuffer, upp.CommandLine.Length, &bytesRead))
{
printf("Reading command line failed.\n");
return 0;
}

return bytesRead / sizeof(wchar_t);
}
};

0 comments on commit bf2f0c1

Please sign in to comment.