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); } } }
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); } } }