├── util.cpp ├── ntdll_undoc.h ├── procmon_check.h ├── classic_antivm.h ├── classic_antidbg.h ├── kernelmode_antidbg.h ├── README.md ├── neutrino_checks.h ├── util.h ├── CMakeLists.txt ├── .appveyor.yml ├── kernelmode_antidbg.cpp ├── classic_antivm.cpp ├── procmon_check.cpp ├── classic_antidbg.cpp ├── main.cpp └── neutrino_checks.cpp /util.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ntdll_undoc.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasherezade/antianalysis_demos/HEAD/ntdll_undoc.h -------------------------------------------------------------------------------- /procmon_check.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | BOOL is_procmon_sc_present(void); 6 | -------------------------------------------------------------------------------- /classic_antivm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool cpuid_bit_check(); 6 | 7 | bool cpuid_brand_check(); 8 | -------------------------------------------------------------------------------- /classic_antidbg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool exception_is_dbg(); 6 | bool hardware_bp_is_dbg(); 7 | bool is_debugger_api(); 8 | bool antidbg_timer_check(); 9 | bool is_single_stepping(); 10 | -------------------------------------------------------------------------------- /kernelmode_antidbg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef enum kdb_mode { 6 | KDB_UNKNOWN = (-1), 7 | KDB_DISABLED = 0, 8 | KDB_LOCAL_ENABLED = 1, 9 | KDB_REMOTE_ENABLED = 3 10 | } t_kdb_mode; 11 | 12 | t_kdb_mode is_kernelmode_dbg_enabled(); 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # anti-analysis_demos 2 | [![Build status](https://ci.appveyor.com/api/projects/status/076pfxtyg5t84t82?svg=true)](https://ci.appveyor.com/project/hasherezade/antianalysis-demos) 3 | 4 | Set of antianalysis techniques found in malware 5 | 6 | Check also: 7 | + https://github.com/a0rtega/pafish 8 | + https://github.com/LordNoteworthy/al-khaser 9 | -------------------------------------------------------------------------------- /neutrino_checks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | Performs defensive environment check - against VM, sandbox, monitoring tools etc. 5 | Implementation by Hasherezade, based on Neutrino Bot Loader 6 | read more: https://blog.malwarebytes.com/threat-analysis/2017/02/new-neutrino-bot-comes-in-a-protective-loader/ 7 | */ 8 | bool find_by_neutrino_checks(const char *log_filename = nullptr); 9 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace util { 6 | 7 | inline DWORD rotl32a(DWORD x, DWORD n) 8 | { 9 | return (x << n) | (x >> (32 - n)); 10 | } 11 | 12 | inline char to_lower(char c) 13 | { 14 | if (c >= 'A' && c <= 'Z') { 15 | c = c - 'A' + 'a'; 16 | } 17 | return c; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8...3.0) 2 | 3 | project ( antianalysis_demos ) 4 | 5 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 6 | 7 | set (hdrs 8 | util.h 9 | classic_antidbg.h 10 | classic_antivm.h 11 | neutrino_checks.h 12 | kernelmode_antidbg.h 13 | procmon_check.h 14 | ) 15 | 16 | set (srcs 17 | util.cpp 18 | classic_antidbg.cpp 19 | classic_antivm.cpp 20 | neutrino_checks.cpp 21 | kernelmode_antidbg.cpp 22 | procmon_check.cpp 23 | ) 24 | 25 | add_executable ( ${PROJECT_NAME} ${exe_hdrs} ${srcs} main.cpp ) 26 | target_link_libraries ( antianalysis_demos fltlib.lib ) 27 | 28 | INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) 29 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - Visual Studio 2015 3 | 4 | platform: x64 5 | - x64 6 | 7 | branches: 8 | only: 9 | - master 10 | 11 | install: 12 | - set PATH=C:\Program Files\CMake\bin;%PATH% 13 | 14 | build: 15 | verbosity: detailed 16 | 17 | configuration: 18 | - Release 19 | 20 | environment: 21 | artifactName: $(APPVEYOR_PROJECT_NAME)-$(APPVEYOR_REPO_COMMIT)-$(CONFIGURATION) 22 | matrix: 23 | - env_arch: "x64" 24 | - env_arch: "x86" 25 | 26 | before_build: 27 | - mkdir build 28 | - cd build 29 | - if [%env_arch%]==[x64] ( 30 | cmake .. -A x64 ) 31 | - if [%env_arch%]==[x86] ( 32 | cmake .. ) 33 | - cmake -DCMAKE_INSTALL_PREFIX:PATH=%APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT% .. 34 | 35 | build_script: 36 | - cmake --build . --config %CONFIGURATION% --target install 37 | 38 | after_build: 39 | - mkdir %artifactName% 40 | - cp %APPVEYOR_BUILD_FOLDER%/%APPVEYOR_REPO_COMMIT%/* %artifactName% 41 | 42 | artifacts: 43 | - path: build\%artifactName% 44 | 45 | -------------------------------------------------------------------------------- /kernelmode_antidbg.cpp: -------------------------------------------------------------------------------- 1 | #include "kernelmode_antidbg.h" 2 | 3 | #include 4 | 5 | #define KUSER_SHARED_VA 0x7FFE0000 6 | #define KUSER_SHARED_SIZE 0x3B8 7 | 8 | inline bool is_kuser_shared_mapped() 9 | { 10 | if (IsBadReadPtr((BYTE*)KUSER_SHARED_VA, KUSER_SHARED_SIZE)) { 11 | std::cerr << "KDB: Failed to retrieve KUSER_SHARED_DATA\n"; 12 | return false; 13 | } 14 | return true; 15 | } 16 | 17 | // from Hidden Bee malware: 18 | t_kdb_mode is_kernelmode_dbg_enabled() 19 | { 20 | const ULONGLONG KdDebuggerEnable_offset = 0x2d4; 21 | if (!is_kuser_shared_mapped()) { 22 | return KDB_UNKNOWN; 23 | } 24 | BYTE *KdDebuggerEnable = (BYTE*)(KUSER_SHARED_VA + KdDebuggerEnable_offset); 25 | if (*KdDebuggerEnable) { 26 | /* 27 | this flag is selected if: 28 | bcdedit /debug on 29 | */ 30 | if (*KdDebuggerEnable == 3) { 31 | std::cout << "KDB: Remote enabled!\n"; 32 | return KDB_REMOTE_ENABLED; 33 | } 34 | std::cout << "KDB: Local enabled!\n"; 35 | return KDB_LOCAL_ENABLED; 36 | } 37 | std::cout << "KDB: Disabled\n"; 38 | return KDB_DISABLED; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /classic_antivm.cpp: -------------------------------------------------------------------------------- 1 | #include "classic_antivm.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | bool cpuid_bit_check() 8 | { 9 | #ifndef _WIN64 10 | bool is_bit_set = false; 11 | __asm { 12 | mov eax, 1 13 | cpuid 14 | bt ecx, 0x1f 15 | jnc finish 16 | mov is_bit_set, 1 17 | finish: 18 | } 19 | std::cout << "Is VM bit set? " << is_bit_set << "\n"; 20 | return is_bit_set; 21 | #endif 22 | std::cerr << __FUNCTION__ << ": Currently not implemented for 64 bit!\n"; 23 | return false; 24 | } 25 | 26 | bool _cpuid_brand_check(std::set &vm_brands) 27 | { 28 | #ifndef _WIN64 29 | bool is_vm_brand = false; 30 | char brand_str[sizeof(DWORD) * 4] = { 0 }; 31 | 32 | DWORD v0, v1, v2; 33 | v0 = v1 = v2 = 0; 34 | 35 | __asm { 36 | mov eax, 0x40000000 37 | cpuid 38 | mov v0, ebx 39 | mov v1, ecx 40 | mov v2, edx 41 | } 42 | 43 | memcpy(brand_str, &v0, sizeof(DWORD)); 44 | memcpy(brand_str + sizeof(DWORD), &v1, sizeof(DWORD)); 45 | memcpy(brand_str + sizeof(DWORD) * 2, &v2, sizeof(DWORD)); 46 | 47 | char *ptr = (char*)brand_str; 48 | std::cout << "BrandID: " << ptr << "\n"; 49 | if (vm_brands.find(brand_str) != vm_brands.end()) { 50 | return true; 51 | } 52 | return false; 53 | #endif 54 | std::cerr << __FUNCTION__ << ": Currently not implemented for 64 bit!\n"; 55 | return false; 56 | } 57 | 58 | bool cpuid_brand_check() 59 | { 60 | std::set vm_brands; 61 | vm_brands.insert("KVMKVMKVM"); 62 | vm_brands.insert("VMwareVMware"); 63 | vm_brands.insert("XenVMMXenVMM"); 64 | vm_brands.insert("VBoxVBoxVBox"); 65 | vm_brands.insert("Microsoft Hv"); 66 | 67 | return _cpuid_brand_check(vm_brands); 68 | } 69 | -------------------------------------------------------------------------------- /procmon_check.cpp: -------------------------------------------------------------------------------- 1 | #include "procmon_check.h" 2 | #include 3 | 4 | static NTSTATUS is_procmon_sc_registered(const wchar_t* service_name, const size_t service_name_size); 5 | 6 | static HRESULT tryopen_procmon_sc(const wchar_t* service_name); 7 | 8 | static BOOL do_is_procmon_present(const wchar_t* service_name, const size_t service_name_size); 9 | 10 | static NTSTATUS is_procmon_sc_registered(const wchar_t* service_name, const size_t service_name_size) { 11 | HKEY hk; 12 | wchar_t w_subkey[1024] = L""; 13 | wcsncpy_s(w_subkey, sizeof(w_subkey) / sizeof(w_subkey[0]) - 2, L"System\\CurrentControlSet\\Services\\", 14 | wcslen(L"System\\CurrentControlSet\\Services\\")); 15 | wcsncat_s(w_subkey, sizeof(w_subkey) / sizeof(w_subkey[0]) - 2, service_name, service_name_size); 16 | NTSTATUS retval = RegOpenKeyExW(HKEY_LOCAL_MACHINE, w_subkey, 0, KEY_QUERY_VALUE, &hk); 17 | if (retval == ERROR_SUCCESS) { 18 | RegCloseKey(hk); 19 | } 20 | return retval; 21 | } 22 | 23 | static HRESULT tryopen_procmon_sc(const wchar_t* service_name) { 24 | HFILTER filter; 25 | HRESULT res = FilterCreate(service_name, &filter); 26 | if (res == S_OK) { 27 | FilterClose(filter); 28 | } 29 | return res; 30 | } 31 | 32 | static BOOL do_is_procmon_present(const wchar_t* service_name, const size_t service_name_size) { 33 | HRESULT res = tryopen_procmon_sc(service_name); 34 | switch (res) { 35 | case S_OK: 36 | return TRUE; 37 | 38 | case E_ACCESSDENIED: 39 | return (is_procmon_sc_registered(service_name, service_name_size) == ERROR_SUCCESS); 40 | } 41 | return FALSE; 42 | } 43 | 44 | BOOL is_procmon_sc_present(void) { 45 | static const wchar_t* procmon_scs[] = { 46 | L"PROCMON24", 47 | L"PROCMON23", 48 | }; 49 | static const size_t procmon_scs_nr = sizeof(procmon_scs) / sizeof(procmon_scs[0]); 50 | const wchar_t** service = &procmon_scs[0]; 51 | const wchar_t** service_end = service + procmon_scs_nr; 52 | BOOL is = FALSE; 53 | while (!is && service != service_end) { 54 | is = do_is_procmon_present(*service, wcslen(*service)); 55 | service++; 56 | } 57 | return is; 58 | } 59 | -------------------------------------------------------------------------------- /classic_antidbg.cpp: -------------------------------------------------------------------------------- 1 | #include "classic_antidbg.h" 2 | 3 | #include 4 | 5 | bool exception_is_dbg() 6 | { 7 | __try { 8 | RaiseException(DBG_PRINTEXCEPTION_C, 0, 0, 0); 9 | } 10 | __except (EXCEPTION_EXECUTE_HANDLER) { 11 | std::cout << "Exception handler executed!\n"; 12 | return false; 13 | } 14 | return true; 15 | } 16 | 17 | bool is_single_stepping() 18 | { 19 | #ifndef _WIN64 20 | std::cout << "Trying to set the Trap Flag!\n"; 21 | bool is_exception = false; 22 | __try 23 | { 24 | __asm 25 | { 26 | pushfd // push EFLAGS on the stack 27 | or dword ptr[esp], 0x100 // set the Trap Flag 28 | popfd // load EFLAGS from the stack 29 | nop // make one more step 30 | } 31 | } 32 | __except (EXCEPTION_EXECUTE_HANDLER) 33 | { 34 | std::cout << "Trap generated exception!\n"; 35 | is_exception = true; 36 | } 37 | // no exception: single stepping detected! 38 | return !is_exception; 39 | #else 40 | std::cerr << __FUNCTION__ << ": Currently not implemented for 64 bit!\n"; 41 | return false; 42 | #endif 43 | } 44 | 45 | bool hardware_bp_is_dbg() 46 | { 47 | CONTEXT ctx = { 0 }; 48 | bool is_hardware_bp = false; 49 | 50 | HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId()); 51 | ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 52 | if (GetThreadContext(thread, &ctx)) { 53 | is_hardware_bp = (ctx.Dr0 | ctx.Dr1 | ctx.Dr2 | ctx.Dr3) != 0; 54 | } 55 | CloseHandle(thread); 56 | 57 | return is_hardware_bp; 58 | } 59 | 60 | bool is_debugger_api() 61 | { 62 | if (IsDebuggerPresent()) return true; 63 | 64 | BOOL has_remote = FALSE; 65 | CheckRemoteDebuggerPresent(GetCurrentProcess(), &has_remote); 66 | 67 | return has_remote ? true : false; 68 | } 69 | 70 | //--- 71 | // timer 72 | 73 | bool antidbg_timer_check() 74 | { 75 | static ULONGLONG time = 0; 76 | if (time == 0) { 77 | time = __rdtsc(); 78 | std::cout << "First Time: " << std::hex << time << "\n"; 79 | return false; 80 | } 81 | ULONGLONG second_time = __rdtsc(); 82 | std::cout << "Second Time: " << std::hex << second_time << "\n"; 83 | ULONGLONG diff = (second_time - time) >> 20; 84 | std::cout << "Time diff: " << std::hex << diff << "\n"; 85 | if (diff > 0x100) { 86 | time = second_time; 87 | return true; 88 | } 89 | return false; 90 | } 91 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "classic_antidbg.h" 5 | #include "classic_antivm.h" 6 | #include "neutrino_checks.h" 7 | #include "kernelmode_antidbg.h" 8 | #include "procmon_check.h" 9 | #include "ntdll_undoc.h" 10 | 11 | //#define SINGLE_STEPPING_CHECK 12 | 13 | int main(); 14 | 15 | bool checkProcessDebugFlags() 16 | { 17 | // ProcessDebugFlags 18 | const int ProcessDebugFlags = 0x1f; 19 | auto _NtQueryInformationProcess = reinterpret_cast(GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationProcess")); 20 | // Other Vars 21 | NTSTATUS Status; 22 | DWORD NoDebugInherit = 0; 23 | 24 | Status = _NtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, &NoDebugInherit, sizeof(DWORD), NULL); 25 | std::cout << "ProcessDebugFlags: " << std::hex << NoDebugInherit << "\n"; 26 | 27 | return (Status == 0 && NoDebugInherit == 0) ? true : false; 28 | } 29 | 30 | bool clearProcessDebugFlags() 31 | { 32 | // ProcessDebugFlags 33 | const int ProcessDebugFlags = 0x1f; 34 | 35 | auto _NtSetInformationProcess = reinterpret_cast(GetProcAddress(GetModuleHandleA("ntdll"), "NtSetInformationProcess")); 36 | // Other Vars 37 | NTSTATUS Status; 38 | DWORD NoDebugInherit = 1; 39 | 40 | Status = _NtSetInformationProcess(GetCurrentProcess(), ProcessDebugFlags, &NoDebugInherit, sizeof(DWORD)); 41 | return (Status == 0); 42 | } 43 | 44 | #ifndef _WIN64 45 | bool exec_int2d() 46 | { 47 | __try 48 | { 49 | __asm xor eax, eax; 50 | __asm int 0x2d; 51 | __asm nop; 52 | return true; 53 | } 54 | __except (EXCEPTION_EXECUTE_HANDLER) 55 | { 56 | return false; 57 | } 58 | } 59 | #endif 60 | 61 | // from: https://anti-debug.checkpoint.com/techniques/process-memory.html#anti-step-over 62 | bool CheckForSpecificByte(BYTE cByte, PVOID pMemory, SIZE_T nMemorySize = 0) 63 | { 64 | PBYTE pBytes = (PBYTE)pMemory; 65 | for (SIZE_T i = 0; ; i++) 66 | { 67 | // Break on RET (0xC3) if we don't know the function's size 68 | if (((nMemorySize > 0) && (i >= nMemorySize)) || 69 | ((nMemorySize == 0) && (pBytes[i] == 0xC3))) 70 | break; 71 | 72 | if (pBytes[i] == cByte) 73 | return true; 74 | } 75 | return false; 76 | } 77 | 78 | bool IsCCSet() 79 | { 80 | PVOID functionsToCheck[] = { 81 | &main 82 | }; 83 | for (auto funcAddr : functionsToCheck) 84 | { 85 | if (CheckForSpecificByte(0xCC, funcAddr)) 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | int main() 92 | { 93 | if (clearProcessDebugFlags()) { 94 | std::cout << "Flag cleared!\n"; 95 | } 96 | bool is_detected = false; 97 | if (IsCCSet()) { 98 | is_detected = true; 99 | std::cout << "[*] Software breakpoints detected!\n"; 100 | } 101 | #ifndef _WIN64 102 | if (exec_int2d()) { 103 | is_detected = true; 104 | std::cout << "[*] Debugger detected by 2D interrupt\n"; 105 | } 106 | #endif 107 | 108 | antidbg_timer_check(); 109 | if (checkProcessDebugFlags()) { 110 | is_detected = true; 111 | std::cout << "[*] Debugger detected by ProcessDebugFlags!\n"; 112 | } 113 | if (exception_is_dbg()) { 114 | is_detected = true; 115 | std::cout << "[*] Debugger detected by Exception check!\n"; 116 | } 117 | if (hardware_bp_is_dbg()) { 118 | is_detected = true; 119 | std::cout << "[*] Debugger detected by Hardware Breakpoints!\n"; 120 | } 121 | if (is_debugger_api()) { 122 | is_detected = true; 123 | std::cout << "[*] Debugger detected by API check!\n"; 124 | } 125 | if (antidbg_timer_check()) { 126 | is_detected = true; 127 | std::cout << "[*] Debugger detected by time check!\n"; 128 | } 129 | #ifdef SINGLE_STEPPING_CHECK 130 | if (is_single_stepping()) { 131 | is_detected = true; 132 | std::cout << "Single stepping detected!\n"; 133 | } 134 | #endif 135 | 136 | // Anti-VM 137 | if (cpuid_bit_check()) { 138 | std::cout << "[*] VM Detected by CPUID Check!\n"; 139 | } 140 | if (cpuid_brand_check()) { 141 | std::cout << "[*] VM Detected by Brand ID!\n"; 142 | } 143 | 144 | if (find_by_neutrino_checks()) { 145 | is_detected = true; 146 | std::cout << "[*] Analysis detected by Neutrino set of checks\n"; 147 | } 148 | t_kdb_mode kdb_mode = is_kernelmode_dbg_enabled(); 149 | if (kdb_mode == KDB_LOCAL_ENABLED || kdb_mode == KDB_REMOTE_ENABLED) { 150 | is_detected = true; 151 | std::cout << "[*] Kernelmode debugging enabled!\n"; 152 | } 153 | if (is_procmon_sc_present()) { 154 | is_detected = true; 155 | std::cout << "[*] ProcMon service is present!\n"; 156 | } 157 | if (is_detected) { 158 | MessageBoxA(NULL, "Analysis environment detected!", "Detected", MB_ICONEXCLAMATION | MB_OK); 159 | } 160 | else { 161 | MessageBoxA(NULL, "No analysis environment detected!", "Not Detected", MB_ICONINFORMATION | MB_OK); 162 | } 163 | system("pause"); 164 | return 0; 165 | } 166 | -------------------------------------------------------------------------------- /neutrino_checks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | #include "neutrino_checks.h" 11 | 12 | std::ofstream logFile; 13 | 14 | void log_checksum(DWORD checksum, char *name) 15 | { 16 | std::cout << "[!] " << std::hex << checksum << " : "<< name << std::endl; 17 | 18 | if (!logFile.is_open()) { 19 | logFile << "[!] " << std::hex << checksum << " : " << name << std::endl; 20 | } 21 | } 22 | 23 | DWORD calc_checksum(char *str, bool enable_tolower) 24 | { 25 | if (str == NULL) return 0; 26 | 27 | DWORD checksum = 0; 28 | size_t len = strlen(str); 29 | for (int i = 0; i < len; i++) { 30 | checksum = util::rotl32a(checksum, 7); 31 | char c = str[i]; 32 | if (enable_tolower) { 33 | c = util::to_lower(c); 34 | } 35 | checksum ^= c; 36 | } 37 | return checksum; 38 | } 39 | 40 | size_t find_denied_processes(std::set &process_list, bool enable_tolower) 41 | { 42 | size_t found = 0; 43 | HANDLE hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); 44 | PROCESSENTRY32 process_entry = { 0 }; 45 | process_entry.dwSize = sizeof(process_entry); 46 | 47 | if (!Process32First(hProcessSnapShot, &process_entry)) { 48 | return 0; 49 | } 50 | 51 | DWORD checksum = calc_checksum(process_entry.szExeFile, enable_tolower); 52 | if (process_list.find(checksum) != process_list.end()) { 53 | log_checksum(checksum, process_entry.szExeFile); 54 | found++; 55 | } 56 | 57 | while (Process32Next(hProcessSnapShot, &process_entry)) { 58 | checksum = calc_checksum(process_entry.szExeFile, enable_tolower); 59 | if (process_list.find(checksum) != process_list.end()) { 60 | log_checksum(checksum, process_entry.szExeFile); 61 | found++; 62 | } 63 | } 64 | 65 | // Close the handle 66 | CloseHandle(hProcessSnapShot); 67 | return found; 68 | } 69 | 70 | size_t find_denied_modules(std::set &modules_list, bool enable_tolower) 71 | { 72 | size_t found = 0; 73 | HANDLE hProcessSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, GetCurrentProcessId()); 74 | MODULEENTRY32 module_entry = { 0 }; 75 | module_entry.dwSize = sizeof(module_entry); 76 | 77 | if (!Module32First(hProcessSnapShot, &module_entry)) { 78 | return 0; 79 | } 80 | 81 | DWORD checksum = calc_checksum(module_entry.szModule, enable_tolower); 82 | if (modules_list.find(checksum) != modules_list.end()) { 83 | found++; 84 | log_checksum(checksum, module_entry.szModule); 85 | } 86 | 87 | while (Module32Next(hProcessSnapShot, &module_entry)) { 88 | checksum = calc_checksum(module_entry.szModule, enable_tolower); 89 | if (modules_list.find(checksum) != modules_list.end()) { 90 | found++; 91 | log_checksum(checksum, module_entry.szModule); 92 | } 93 | } 94 | 95 | // Close the handle 96 | CloseHandle(hProcessSnapShot); 97 | return found; 98 | } 99 | 100 | size_t find_denied_devices(std::set &devs_list) 101 | { 102 | size_t found = 0; 103 | char dev[0x20000] = { 0 }; 104 | char dev2[0x2000] = { 0 }; 105 | DWORD res = QueryDosDeviceA(0, dev, 0x20000); 106 | 107 | char* ptr = dev; 108 | size_t total_len = 0; 109 | 110 | while (total_len < res) { 111 | DWORD res2 = QueryDosDeviceA(ptr, dev2, sizeof(dev2)); 112 | if (!res2) break; 113 | 114 | DWORD checksum = calc_checksum(ptr, false); 115 | if (devs_list.find(checksum) != devs_list.end()) { 116 | log_checksum(checksum, ptr); 117 | found++; 118 | } 119 | size_t len = strlen(ptr) + 1; 120 | ptr += len; 121 | total_len += len; 122 | } 123 | return found; 124 | } 125 | 126 | typedef struct { 127 | std::set classes_checksums; 128 | bool hide_found_window; 129 | size_t found; 130 | } t_class_check_param; 131 | 132 | BOOL CALLBACK check_window(HWND hWnd, LPARAM lParam) 133 | { 134 | t_class_check_param *param = (t_class_check_param*) lParam; 135 | if (param == nullptr) { 136 | return FALSE; 137 | } 138 | 139 | std::set &denied_classes = param->classes_checksums; 140 | 141 | char class_name[MAX_PATH]; 142 | GetClassName(hWnd, class_name, MAX_PATH); 143 | 144 | DWORD checksum = calc_checksum(class_name, true); 145 | if (denied_classes.find(checksum) != denied_classes.end()) { 146 | log_checksum(checksum, class_name); 147 | param->found++; 148 | if (param->hide_found_window) { 149 | ShowWindow(hWnd, SW_HIDE); 150 | } 151 | else { 152 | ShowWindow(hWnd, SW_SHOW); 153 | } 154 | } 155 | return TRUE; 156 | } 157 | 158 | bool find_by_neutrino_checks(const char *log_filename) 159 | { 160 | size_t total_found = 0; 161 | size_t found = 0; 162 | 163 | if (log_filename) { 164 | logFile.open(log_filename); 165 | } 166 | 167 | std::set processes_checksums; 168 | processes_checksums.insert(0x6169078A); 169 | processes_checksums.insert(0x47000343); 170 | processes_checksums.insert(0xC608982D); 171 | processes_checksums.insert(0x46EE4F10); // VMwareTray.exe 172 | processes_checksums.insert(0xF6EC4B30); 173 | processes_checksums.insert(0xB1CBC652); // VBoxService.exe 174 | processes_checksums.insert(0x6D3E6FDD); // VBoxTray.exe 175 | processes_checksums.insert(0x583EB7E8); 176 | processes_checksums.insert(0xC03EAA65); 177 | 178 | found = find_denied_processes(processes_checksums, false); 179 | found += find_denied_processes(processes_checksums, true); 180 | std::cout << "[!] Found suspicious processes: " << found << "\n"; 181 | total_found += found; 182 | 183 | std::set modules_checksums; 184 | modules_checksums.insert(0x1C669D6A); 185 | modules_checksums.insert(0xC2F56A18); 186 | modules_checksums.insert(0x7457D9DD); 187 | modules_checksums.insert(0xC106E17B); 188 | modules_checksums.insert(0x5608BCC4); 189 | modules_checksums.insert(0x6512F9D0); 190 | modules_checksums.insert(0xC604D52A); // snxhk.dll 191 | modules_checksums.insert(0x4D0651A5); 192 | modules_checksums.insert(0xAC12B9FB); // sbiedll.dll 193 | modules_checksums.insert(0x5B747561); 194 | modules_checksums.insert(0x53309C85); 195 | modules_checksums.insert(0xE53ED522); 196 | 197 | found = find_denied_modules(modules_checksums, false); 198 | found += find_denied_modules(modules_checksums, true); 199 | std::cout << "[!] Found suspicious modules: " << found << "\n"; 200 | total_found += found; 201 | 202 | std::set devs_checksums; 203 | devs_checksums.insert(0x642742FF); // VBoxMiniRdrDN 204 | devs_checksums.insert(0x283CC630); // VBoxGuest 205 | devs_checksums.insert(0x911E353); 206 | devs_checksums.insert(0xEDB71E9); 207 | found = find_denied_devices(devs_checksums); 208 | std::cout << "[!] Found suspicious devices: " << found << "\n"; 209 | total_found += found; 210 | 211 | t_class_check_param param; 212 | param.hide_found_window = false; 213 | param.found = 0; 214 | 215 | param.classes_checksums.insert(0xFE9EA0D5); 216 | param.classes_checksums.insert(0x6689BB92); 217 | param.classes_checksums.insert(0x3C5FF312); // procexpl 218 | param.classes_checksums.insert(0x9B5A88D9); // procmon_window_class 219 | param.classes_checksums.insert(0x4B4576B5); 220 | param.classes_checksums.insert(0xAED304FC); 221 | param.classes_checksums.insert(0x225FD98F); 222 | param.classes_checksums.insert(0x6D3FA1CA); 223 | param.classes_checksums.insert(0xCF388E01); 224 | param.classes_checksums.insert(0xD486D951); 225 | param.classes_checksums.insert(0x39177889); 226 | EnumWindows(&check_window, (LPARAM)¶m); 227 | total_found += param.found; 228 | 229 | if (logFile.is_open()) { 230 | logFile.close(); 231 | } 232 | std::cout << "[!!] Total found: " << total_found << "\n"; 233 | return (total_found > 0) ? true : false; 234 | } 235 | --------------------------------------------------------------------------------