1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426:
|
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <windows.h>
#define O_CALL 0xE8 #define O_JMP 0xE9
#define TEMP_FILE_NAME "C:\_$temp.vir"
void scan_file(char *name); bool try_disinfect(char *name, DWORD where_ctx, DWORD caller, DWORD upa, DWORD sv);
int main(int argc, char *argv[]) {
printf("---------------------------------------------------------------------------\n"); printf(" EPO-SCANNER - (c) Piotr Bania\n"); printf(" http://pb.specialised.info\n"); printf("---------------------------------------------------------------------------\n");
if (argc<2) { printf("[!] Usage: EPO-s.exe <file>\n"); printf("[!] Press any key to exit.\n"); getch(); return 0; }
printf("[+] Trying to scan: %s\n",argv[1]); scan_file(argv[1]); return 0; }
void scan_file(char *name) { HANDLE file,map; void* mymap; DWORD startrange = NULL, endrange = NULL, i = NULL, loc = NULL, temp_loc = NULL, upa = NULL; DWORD where_ctx = NULL,caller = NULL, sv = NULL; PIMAGE_DOS_HEADER pMZ = NULL; PIMAGE_NT_HEADERS pPE = NULL; PIMAGE_SECTION_HEADER pSH = NULL,pSHC = NULL; char *temp_name = TEMP_FILE_NAME; WORD sections; int count=0;
if (!CopyFile(name,temp_name,FALSE)) { printf("[-] Error: copying file failed - no future disinfection possible, error: %d\n",GetLastError()); }
if ((file = CreateFile(name,GENERIC_READ | FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE) { printf("[-] Error: Cannot open file - error: %d\n",GetLastError()); goto error_mode1; }
if ((map = CreateFileMapping(file,NULL,PAGE_READWRITE | SEC_COMMIT,NULL,NULL,NULL)) == NULL) { printf("[-] Error: Cannot create map of file - error: %d\n",GetLastError()); goto error_mode2; }
if ((mymap = MapViewOfFile(map,FILE_MAP_ALL_ACCESS,NULL,NULL,NULL)) == NULL) { printf("[-] Error: Cannot create map view of file - error: %d\n",GetLastError()); goto error_mode3; }
pMZ=(PIMAGE_DOS_HEADER) mymap;
if (pMZ->e_magic != IMAGE_DOS_SIGNATURE) { printf("[-] Error: Bad MZ signature\n"); goto error_mode4; }
pPE=(PIMAGE_NT_HEADERS) ((DWORD)mymap + pMZ->e_lfanew);
if (IsBadReadPtr((VOID*)pPE,sizeof(PIMAGE_NT_HEADERS)) == TRUE) { printf("[-] Error: Bad PE file\n"); goto error_mode4; }
if (pPE->Signature != IMAGE_NT_SIGNATURE || pPE->FileHeader.NumberOfSections == NULL) { printf("[-] Error: Bad PE file\n"); goto error_mode4; }
if (pPE->OptionalHeader.ImageBase <= 0 || pPE->OptionalHeader.AddressOfEntryPoint <= 0 || pPE->FileHeader.NumberOfSections <= 0) { printf("[-] Error: Bad PE file\n"); goto error_mode4; }
printf("[+] Imagebase: 0x%.08x - Entrypoint: 0x%.08x (0x%.08x)\n",pPE->OptionalHeader.ImageBase,pPE->OptionalHeader.AddressOfEntryPoint,pPE->OptionalHeader.ImageBase+pPE->OptionalHeader.AddressOfEntryPoint);
sections = pPE->FileHeader.NumberOfSections; pSH = (PIMAGE_SECTION_HEADER)((DWORD)mymap+pMZ->e_lfanew + sizeof(IMAGE_NT_HEADERS)); while (sections != 0) { if (IsBadReadPtr(&pSH,sizeof(PIMAGE_SECTION_HEADER)) == TRUE) { printf("[-] Error: Bad PE file\n"); goto error_mode4; }
char *secname=(char *) pSH->Name; if (secname == NULL) strcpy(secname,"NONAME");
startrange=(DWORD) pSH->VirtualAddress + pPE->OptionalHeader.ImageBase; endrange=(DWORD) startrange + pSH->Misc.VirtualSize;
if (startrange <=0 || startrange <= pPE->OptionalHeader.ImageBase || endrange <=0 || pPE->OptionalHeader.ImageBase <= 0 || pSH->Misc.PhysicalAddress < 0 || pSH->SizeOfRawData < 0) { printf("[-] Error: The %s section is broken\n",secname); goto error_mode4; }
if (pSH->VirtualAddress <= pPE->OptionalHeader.AddressOfEntryPoint && pPE->OptionalHeader.AddressOfEntryPoint < pSH->VirtualAddress + pSH->Misc.VirtualSize) { printf("[+] Checking call/jump requests from %s section (EP)\n",secname); pSHC = pSH; }
pSH++; sections--; }
pSH--; if (pSHC == NULL) { printf("[-] Error: invalid entrypoint\n"); goto error_mode4; }
printf("[+] Starting heuristics scan on %s section...\n\n",pSHC->Name);
if (pSHC == pSH) { printf("[!] Alert: Entrypoint points to last section (%s) -> 0x%.08x\n",pSH->Name,pPE->OptionalHeader.AddressOfEntryPoint + pPE->OptionalHeader.ImageBase); printf("[!] Alert: The file may be infected!\n"); printf("[+] No deep-scan action was performed\n"); goto error_mode4; }
printf("[+] Starting from offset: 0x%.08x\n",pPE->OptionalHeader.ImageBase + pSHC->VirtualAddress);
for (i = 0; (i != pSHC->SizeOfRawData); i++) { loc = (DWORD)((DWORD)mymap + pSHC->PointerToRawData) + i; if ((*(BYTE*)loc) == O_CALL || (*(BYTE*)loc) == O_JMP ) { loc++; temp_loc = (DWORD)((DWORD)pSHC->VirtualAddress + i + (*(DWORD*)loc)) + 5; if (temp_loc >= pSH->VirtualAddress && temp_loc <= pSH->VirtualAddress + pSH->Misc.VirtualSize) { printf("[!] Alert: Detected request to %s(0x%.08x) section at: 0x%.08x\n",pSH->Name,pPE->OptionalHeader.ImageBase + temp_loc, pSHC->VirtualAddress + pPE->OptionalHeader.ImageBase + i); if (where_ctx == NULL) { where_ctx = (DWORD)(pPE->OptionalHeader.ImageBase + temp_loc); caller = (DWORD)(pSHC->VirtualAddress + pPE->OptionalHeader.ImageBase + i); upa = (DWORD)(pSH->VirtualAddress + pPE->OptionalHeader.ImageBase); sv = loc - 1; } count++; } loc--; }
} printf("[+] Scan finished, %d suspected instruction(s) found.\n",count); if (count != 0) { printf("[!] Warning: the file may be infected!\n"); printf("\n[?] Do you want to try dis-infect the file?\n"); printf("[?] Warning: the file may be executed if this is not the CTX.Phage\n"); printf(" infection.\n"); printf("[?] Disinfect: (y)es / (n)o ? \n");
if (getch() == 'y') try_disinfect(name, where_ctx, caller, upa, sv);
}
error_mode4: UnmapViewOfFile(mymap);
error_mode3: CloseHandle(map); error_mode2: CloseHandle(file);
error_mode1: DeleteFile(temp_name);
}
bool try_disinfect(char *name, DWORD where_ctx, DWORD caller, DWORD upa, DWORD sv) { STARTUPINFO si; PROCESS_INFORMATION pi; CONTEXT tc; DEBUG_EVENT de; DWORD stack_v = NULL, _GetProcAddress = NULL, oldp; unsigned char patch[4] = { 0x90, 0x90, 0xCC }; unsigned char ctx_sig[15] = { 0x6A, 0x00, 0x6A, 0x05, 0xE8, 0x05, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x50 }; unsigned char ctx_fly[15]; char *temp_name = TEMP_FILE_NAME; int fe=NULL, found=NULL;
_GetProcAddress = (DWORD) GetProcAddress(LoadLibrary("KERNEL32.DLL"), "GetProcAddress");
GetStartupInfo(&si); if (!CreateProcess(NULL,temp_name,NULL,NULL,FALSE,DEBUG_PROCESS + DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi)) { printf("[-] Error: cannot create process, error: %d\n",GetLastError()); goto error_di; }
printf("\n[+] Process created, pid=0x%.08x\n",pi.dwProcessId); printf("[+] Starting emulation engine...\n");
while (1) { WaitForDebugEvent(&de,INFINITE); if (de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { printf("[!] Error: ups process exited...\n"); goto error_term; }
if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { if (de.u.Exception.dwFirstChance == TRUE) { printf("[+] Exception occured at: 0x%.08x, passing to program.\n",de.u.Exception.ExceptionRecord.ExceptionAddress); ContinueDebugEvent(de.dwProcessId,de.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); } else { printf("[-] Hard error occured, terminating the program\n"); printf("[-] Disinfecting failed\n"); goto error_term; }
}
if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) {
if (fe == NULL) { fe = 1; printf("[+] Reached break point at 0x%.08x\n",de.u.Exception.ExceptionRecord.ExceptionAddress); printf("[+] Modifing 4 bytes at host stack\n");
tc.ContextFlags = CONTEXT_CONTROL; if (!GetThreadContext(pi.hThread, &tc)) { printf("[-] Failed to get thread context, error: %d\n",GetLastError()); printf("[-] Disinfecting failed\n"); goto error_term; }
ReadProcessMemory(pi.hProcess, (void*)tc.Esp, &stack_v,4,NULL);
if (stack_v == NULL) { printf("[-] Error: reading from stack failed\n"); printf("[-] Disinfecting failed\n"); goto error_term; }
tc.Esp = tc.Esp - 4; caller += 5;
if (!WriteProcessMemory(pi.hProcess, (void*)tc.Esp, &caller, 4, NULL)) { printf("[-] Error: writing to stack failed\n"); printf("[-] Disinfecting failed\n"); goto error_term; } printf("[+] Stack modified, 0x%.08x added caller -> 0x%.08x\n",tc.Esp, caller);
printf("[+] Redirecting EIP to 0x%.08x...\n",where_ctx); tc.Eip = where_ctx;
if (!SetThreadContext(pi.hThread, &tc)) { printf("[-] Failed to set thread context, error: %d\n",GetLastError()); printf("[-] Disinfecting failed\n"); goto error_term; }
VirtualProtectEx(pi.hProcess, (void*) _GetProcAddress, sizeof(patch), PAGE_READWRITE, &oldp); WriteProcessMemory(pi.hProcess, (void*) _GetProcAddress, &patch, sizeof(patch), NULL); VirtualProtectEx(pi.hProcess, (void*) _GetProcAddress, sizeof(patch), oldp, &oldp);
printf("[+] Placed breaker at 0x%.08x\n",_GetProcAddress);
ContinueDebugEvent(de.dwProcessId,de.dwThreadId,DBG_CONTINUE); } if ((DWORD) de.u.Exception.ExceptionRecord.ExceptionAddress > _GetProcAddress && (DWORD) de.u.Exception.ExceptionRecord.ExceptionAddress < _GetProcAddress + sizeof(patch)) { printf("[+] Virus reached the breaker at 0x%.08x\n",de.u.Exception.ExceptionRecord.ExceptionAddress);
tc.ContextFlags = CONTEXT_CONTROL; if (!GetThreadContext(pi.hThread, &tc)) { printf("[-] Failed to get thread context, error: %d\n",GetLastError()); printf("[-] Disinfecting failed\n"); goto error_term; } ReadProcessMemory(pi.hProcess, (void*)tc.Esp, &stack_v, 4, NULL); printf("[+] Virus request captured from 0x%.08x\n",stack_v); printf("[+] Scanning backwards to 0x%.08x\n",upa);
while (1) { if (!ReadProcessMemory(pi.hProcess, (void*)stack_v, &ctx_fly, sizeof(ctx_sig), NULL)) break; if (stack_v <= upa) break; found = 1; for (int ii=0; ii < sizeof(ctx_sig); ii++) { if (ctx_sig[ii] != ctx_fly[ii]) { if (ctx_sig[ii] != 0x90) { found = 0; break; } } } if (found == 1) { printf("[+] Orginal bytes were found at 0x%.08x\n",stack_v + 9); printf("[!] Repairing the broken instruction.\n"); ReadProcessMemory(pi.hProcess, (void*)(stack_v + 9), (void*) sv, 5, NULL); printf("[!] The file was disinfected!\n"); getch(); goto error_term; }
stack_v--; }
if (found == 0) { printf("[-] Error: no signature was found.\n"); printf("[-] Disinfecting failed\n"); goto error_term; }
goto error_term; } }
}
ContinueDebugEvent(de.dwProcessId,de.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
}
error_term: TerminateProcess(pi.hProcess,NULL);
error_di: return TRUE;
} |