// Delete the first mov immediate
static VOID deleteMov (RTN rtn)
{
    for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins))
    {
        if (INS_IsMov(ins) && INS_HasImmediateOperand(ins))
        {
            INS_Delete(ins);
            instrumentationCount++;
            return;
        }
    }
}
// Insert a direct branch over the first mov immediate
static VOID insertJump (RTN rtn)
{
    for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins))
    {
        if (INS_IsMov(ins) && INS_HasImmediateOperand(ins))
        {
            INS_InsertDirectJump(ins, IPOINT_BEFORE, INS_Address(ins) + INS_Size(ins));
            instrumentationCount++;
            return;
        }
    }
}
// Insert an indirect branch over the first mov immediate
static VOID insertIndirectJump (RTN rtn)
{
    for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins))
    {
        if (INS_IsMov(ins) && INS_HasImmediateOperand(ins))
        {
            INS_InsertCall(ins, IPOINT_BEFORE,
                           AFUNPTR(returnValue),
                           IARG_ADDRINT, INS_Address(ins) + INS_Size(ins),
                           IARG_RETURN_REGS, scratchReg, IARG_END);

            INS_InsertIndirectJump(ins, IPOINT_BEFORE, scratchReg);
            instrumentationCount++;
            return;
        }
    }
}
void PINshield::avoidEvasion(INS ins){
	
	ADDRINT curEip = INS_Address(ins);
	ProcInfo *pInfo = ProcInfo::getInstance();
	Config *config = Config::getInstance();
	FilterHandler *filterHandler = FilterHandler::getInstance();
	//Filter instructions inside a known library (only graphic dll)
	if(filterHandler->isFilteredLibraryInstruction(curEip)){
		return;
	}
	// Pattern matching in order to avoid the dead path of obsidium
	if(strcmp( (INS_Disassemble(ins).c_str() ),"xor eax, dword ptr [edx+ecx*8+0x4]") == 0){
		MYTEST("Obsidium_evasion");
		REGSET regsIn;
		REGSET_AddAll(regsIn);
		REGSET regsOut;
		REGSET_AddAll(regsOut);
		if(INS_HasFallThrough(ins)){
			INS_InsertCall(ins,IPOINT_AFTER,(AFUNPTR)KillObsidiumDeadPath, IARG_PARTIAL_CONTEXT, &regsIn, &regsOut,IARG_END); 
		}
		}
	// 1 - single instruction detection
	if(config->ANTIEVASION_MODE_INS_PATCHING && this->evasionPatcher.patchDispatcher(ins, curEip)){
		return;
	}
	// 2 - memory read 
	// Checking if there is a read at addresses that the application shouldn't be aware of
	if(config->ANTIEVASION_MODE_SREAD){
		for (UINT32 op = 0; op<INS_MemoryOperandCount(ins); op++) {
			if (INS_MemoryOperandIsRead(ins,op)) {
				//if first read initialize the FakeReadHandler		
				if(firstRead == 0){
					fakeMemH.initFakeMemory();
					firstRead=1;
				}			
				REG scratchReg = GetScratchReg(op);		
				INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(handleRead),
					IARG_INST_PTR,
					IARG_MEMORYOP_EA, op,
					IARG_PTR, &fakeMemH,
					IARG_RETURN_REGS, scratchReg,
					IARG_END);			
				INS_RewriteMemoryOperand(ins, op, scratchReg); 
			}
		}
	}
	//3. memory write filter
	if(config->ANTIEVASION_MODE_SWRITE){	
		for (UINT32 op = 0; op<INS_MemoryOperandCount(ins); op++) {
			if(INS_MemoryOperandIsWritten(ins,op) && INS_IsMov(ins)){
				REG writeReg = GetScratchReg(op);			
				INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(handleWrite),
					IARG_INST_PTR,
					IARG_MEMORYOP_EA, op,
					IARG_PTR, &fakeWriteH,
					IARG_RETURN_REGS, writeReg, // this is an output param
					IARG_END);	
				INS_RewriteMemoryOperand(ins, op, writeReg); 		
			}	
		}	
	}
}