VOID ValidateCallAgainstRop( IN ULONG_PTR lpEspAddress, IN ROP_CALLEE RopCallee, IN LPVOID lpAddress, IN DWORD flProtect, IN ULONG GeneralRegisters /* edi, esi, ebp, esp, ebx, edx, ecx, eax */ ) { PNT_TIB ThreadInfo; if ( DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_NOT_SET ) { /* get the thread stack range from TIB. */ ThreadInfo = (PNT_TIB) __readfsdword( 0x18 ); /* monitor esp value if we supposed to */ if ( MCEDP_REGCONFIG.ROP.STACK_MONITOR ) { /* check if thread is passing the actual stack boundaries */ if ( lpEspAddress < (DWORD)ThreadInfo->StackLimit || lpEspAddress >= (DWORD)ThreadInfo->StackBase ) { /* set ROP flags */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG,NULL,"ROP Detected by STACK_MONITOR, out of bound stack!\n"); } } /* Monitor stack page permission change value if we supposed to */ if ( MCEDP_REGCONFIG.MEM.STACK_RWX ) { if ( lpAddress > ThreadInfo->StackLimit || lpAddress <= ThreadInfo->StackBase ) { /* if it is going to make the stack executable */ if ( ( flProtect & PAGE_EXECUTE ) || ( flProtect & PAGE_EXECUTE_READWRITE ) || ( flProtect & PAGE_EXECUTE_READ ) || ( flProtect & PAGE_EXECUTE_WRITECOPY ) ) { /* set ROP flag */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG,NULL,"ROP Detected by STACK_RWX, stack permission changed to be executable!\n"); } } } if ( MCEDP_REGCONFIG.ROP.PIVOT_DETECTION ) { /* NOT IMPLEMENTED */ } if ( MCEDP_REGCONFIG.ROP.CALL_VALIDATION ) { /* * Performing following checks on the caller * - The address of [esp - 4] could not be the starting address of current function, * otherwise this function is reached via retn instead of a call * - The returning point must points to an executable space * - A 'call' instruction should be existing preceeding to the returning point * - Under most cases, the 'call' instruction should (in)directly points to the start * of current function */ ULONG_PTR* lpPreviousStackPointer = (ULONG_PTR*)(lpEspAddress - sizeof(ULONG)); if(*lpPreviousStackPointer == (ULONG_PTR)GetCriticalFunctionAddress(RopCallee)) { /* Set ROP flag */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG, NULL, "ROP detected by CALL_VALIDATION, " "the address before [esp] points to function start." " [esp] = 0x%x, FunctionStart = 0x%x\n", *lpPreviousStackPointer, GetCriticalFunctionAddress(RopCallee)); } ULONG_PTR lpReturningAddress = *(ULONG_PTR*)lpEspAddress; // TODO: Cache it! MEMORY_BASIC_INFORMATION MemInfo = {0}; if(!VirtualQuery((VOID*)lpReturningAddress, &MemInfo, sizeof(MemInfo))) { DEBUG_PRINTF(LDBG, NULL, "Error in calling VirtualQuery() in ValidateCallAgainstRop().\n"); } else { if(!((MemInfo.Protect & PAGE_EXECUTE) || (MemInfo.Protect & PAGE_EXECUTE_READ) || (MemInfo.Protect & PAGE_EXECUTE_READWRITE) || (MemInfo.Protect & PAGE_EXECUTE_WRITECOPY))) { // The target page cannot be executed DbgSetRopFlag(); DEBUG_PRINTF(LDBG, NULL, "ROP detected by CALL_VALIDATION, " "the returning address 0x%08x cannot be executed.\n", lpReturningAddress); } } // Is there a call instruction preceeding to the returning address? if(!CheckCaller( lpReturningAddress, TRUE, RopCallee, &GeneralRegisters)) { /* Set ROP flag */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG, NULL, "ROP detected by CALL_VALIDATION, " "the returning address 0x%08x is not preceeded by a valid call instruction.\n", lpReturningAddress); } } if ( MCEDP_REGCONFIG.ROP.FORWARD_EXECUTION ) { /* Start simulation from the ret of current call */ ULONG* pGeneralRegisters = &GeneralRegisters; STATUS statSimulation; if((statSimulation = SimulateExecution( *(ULONG_PTR*)lpEspAddress, lpEspAddress, GENERAL_REGISTER(R_EBP), GetCriticalFunctionPoppingDwordsBeforeRet(RopCallee) )) == MCEDP_STATUS_POSSIBLE_ROP_CHAIN) { /* Set ROP flag */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG, NULL, "ROP detected by FORWARD_EXECUTION\n"); } else if(statSimulation != MCEDP_STATUS_SUCCESS) { /* Other errors occured */ switch(statSimulation) { case MCEDP_STATUS_INSUFFICIENT_BUFFER: DEBUG_PRINTF(LDBG, NULL, "FORWARD_EXECUTION returns MCEDP_STATUS_INSUFFICIENT_BUFFER, " "the stack space is not enough.\n"); break; case MCEDP_STATUS_INTERNAL_ERROR: DEBUG_PRINTF(LDBG, NULL, "FORWARD_EXECUTION returns MCEDP_STATUS_INTERNAL_ERROR.\n"); break; case MCEDP_ERROR_NOT_DECODABLE: DEBUG_PRINTF(LDBG, NULL, "FORWARD_EXECUTION returns MCEDP_ERROR_NOT_DECODABLE, " "we came across an undecodable instruction.\n"); break; default: DEBUG_PRINTF(LDBG, NULL, "FORWARD_EXECUTION returns %x.\n", statSimulation); break; } } } if ( DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_SET ) { if ( MCEDP_REGCONFIG.ROP.DUMP_ROP ) DbgReportRop((PVOID)lpEspAddress, RopCallee); if ( MCEDP_REGCONFIG.ROP.KILL_ROP) TerminateProcess(GetCurrentProcess(), STATUS_ACCESS_VIOLATION); } } }
BOOL WINAPI HookedCreateProcessInternalW( HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation, PHANDLE hNewToken ) { BOOL bReturn; CHAR szDllFullPath[MAX_PATH]; /* apply config rules if shellcode or ROP detected */ if ( DbgGetShellcodeFlag() == MCEDP_STATUS_SHELLCODE_FLAG_SET || DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_SET ) { if ( MCEDP_REGCONFIG.SHELLCODE.ANALYSIS_SHELLCODE ) { CHAR *szApplicationNameA = (CHAR *)LocalAlloc(LMEM_ZEROINIT, 1024); CHAR *szCommandLineA = (CHAR *)LocalAlloc(LMEM_ZEROINIT, 1024); PXMLNODE XmlLogNode; PXMLNODE XmlIDLogNode; if ( lpApplicationName != NULL ) wcstombs( szApplicationNameA, lpApplicationName, 1024); if ( lpCommandLine != NULL ) wcstombs( szCommandLineA, lpCommandLine, 1024); XmlIDLogNode = mxmlNewElement( XmlShellcode, "row"); /* type */ XmlLogNode = mxmlNewElement( XmlIDLogNode, "type"); mxmlNewText( XmlLogNode, 0, "1"); /* exec */ XmlLogNode = mxmlNewElement( XmlIDLogNode, "exec_process"); mxmlNewText( XmlLogNode, 0, szApplicationNameA); XmlLogNode = mxmlNewElement( XmlIDLogNode, "exec_cmd"); mxmlNewText( XmlLogNode, 0, szCommandLineA); /* save */ SaveXml( XmlLog ); LocalFree(szApplicationNameA); LocalFree(szCommandLineA); } /* if malware execution is not allowd then terminate the process */ if ( MCEDP_REGCONFIG.GENERAL.ALLOW_MALWARE_EXEC == FALSE ) TerminateProcess(GetCurrentProcess(), STATUS_ACCESS_VIOLATION); /* let the malware execute */ return (CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken)); } /* if the process is creating with CREATE_SUSPENDED flag, let it do its job */ if ( IsBitSet(dwCreationFlags, 2) ) { bReturn = CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken); if ( bReturn != FALSE ) { strncpy( szDllFullPath, MCEDP_REGCONFIG.MCEDP_MODULE_PATH, MAX_PATH ); if ( InjectDLLIntoProcess( szDllFullPath, lpProcessInformation->hProcess ) != MCEDP_STATUS_SUCCESS ) { DEBUG_PRINTF(LDBG, NULL, "Module failed to inject itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId); return bReturn; } DEBUG_PRINTF(LDBG, NULL, "Module injected itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId); /* Sleep for INIT_WAIT_TIME sec and let MCEDP init itself in newly created process TODO : use a messaging mechanism and resume process after init finished instead of sleeping! */ Sleep(INIT_WAIT_TIME); return bReturn; } } else { /* if the process is not creating with CREATE_SUSPENDED flag, force it do it */ bReturn = CreateProcessInternalW_( hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags | CREATE_SUSPENDED , lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken); if ( bReturn != FALSE ) { /* TODO : We dont need this if ther process is already added into Protection List in registry, so we should remove this lines */ strncpy( szDllFullPath, MCEDP_REGCONFIG.MCEDP_MODULE_PATH, MAX_PATH ); if ( InjectDLLIntoProcess( szDllFullPath, lpProcessInformation->hProcess ) != MCEDP_STATUS_SUCCESS ) { DEBUG_PRINTF(LDBG, NULL, "Module failed to inject itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId); ResumeThread(lpProcessInformation->hThread); return bReturn; } DEBUG_PRINTF(LDBG, NULL, "Module injected itself into newly created process , PID : %d\n", lpProcessInformation->dwProcessId); /* Sleep for INIT_WAIT_TIME sec and let MCEDP init itself in newly created process TODO : use a messaging mechanism and resume process after init finished instead of sleeping! */ Sleep(INIT_WAIT_TIME); ResumeThread(lpProcessInformation->hThread); return bReturn; } } return bReturn; }
VOID ValidateCallAgainstRop( IN ULONG_PTR lpEspAddress, IN ROP_CALLEE RopCallee, IN LPVOID lpAddress, IN DWORD flProtect ) { PNT_TIB ThreadInfo; if ( DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_NOT_SET ) { /* get the thread stack range from TIB. */ ThreadInfo = (PNT_TIB) __readfsdword( 0x18 ); /* monitor esp value if we supposed to */ if ( MCEDP_REGCONFIG.ROP.STACK_MONITOR ) { /* check if thread is passing the actual stack boundaries */ if ( lpEspAddress < (DWORD)ThreadInfo->StackLimit || lpEspAddress >= (DWORD)ThreadInfo->StackBase ) { /* set ROP flags */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG,NULL,"ROP Detected by STACK_MONITOR, out of bound stack!\n"); } } /* Monitor stack page permission change value if we supposed to */ if ( MCEDP_REGCONFIG.MEM.STACK_RWX ) { if ( lpAddress > ThreadInfo->StackLimit || lpAddress <= ThreadInfo->StackBase ) { /* if it is going to make the stack executable */ if ( ( flProtect & PAGE_EXECUTE ) || ( flProtect & PAGE_EXECUTE_READWRITE ) || ( flProtect & PAGE_EXECUTE_READ ) || ( flProtect & PAGE_EXECUTE_WRITECOPY ) ) { /* set ROP flag */ DbgSetRopFlag(); DEBUG_PRINTF(LDBG,NULL,"ROP Detected by STACK_RWX, stack permission changed to be executable!\n"); } } } if ( MCEDP_REGCONFIG.ROP.PIVOTE_DETECTION ) { /* NOT IMPLEMENTED */ } if ( MCEDP_REGCONFIG.ROP.CALL_VALIDATION ) { /* NOT IMPLEMENTED */ } if ( MCEDP_REGCONFIG.ROP.FORWARD_EXECUTION ) { /* NOT IMPLEMENTED */ } if ( DbgGetRopFlag() == MCEDP_STATUS_ROP_FLAG_SET ) { if ( MCEDP_REGCONFIG.ROP.DUMP_ROP ) DbgReportRop((PVOID)lpEspAddress,RopCallee); if ( MCEDP_REGCONFIG.ROP.KILL_ROP) TerminateProcess(GetCurrentProcess(), STATUS_ACCESS_VIOLATION); } } }