Skip to content
Snippets Groups Projects
P1_utility.cpp 8.88 KiB
Newer Older
/*
 * Copyright (c) 2013, 2014 - University of Virginia 
 *
 * This file may be used and modified for non-commercial purposes as long as 
 * all copyright, permission, and nonwarranty notices are preserved.  
 * Redistribution is prohibited without prior written consent from the University 
 * of Virginia.
 *
 * Please contact the authors for restrictions applying to commercial use.
 *
 * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: University of Virginia
 * e-mail: jwd@virginia.com
 * URL   : http://www.cs.virginia.edu/
 *
 */

#include "P1_utility.hpp"
using namespace std;
using namespace IRDB_SDK;

map<Function_t*, set<Instruction_t*> > inserted_instr; //used to undo inserted instructions
map<Function_t*, set<AddressID_t*> > inserted_addr; //used to undo inserted addresses


void setExitCode(FileIR_t* virp, Instruction_t* exit_code);


Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target)
{
	Instruction_t* newInsn = IRDB_SDK::insertAssemblyBefore(virp, first, assembly, target);
	Function_t* func = newInsn->getFunction();
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


Instruction_t* P1_insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly)
{
	Instruction_t* newInsn = IRDB_SDK::insertAssemblyBefore(virp, first, assembly);
	Function_t* func = newInsn->getFunction();
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target)
{
	Instruction_t* newInsn = IRDB_SDK::insertAssemblyAfter(virp, first, assembly, target);
	Function_t* func = newInsn->getFunction();
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly)
{
	Instruction_t* newInsn = IRDB_SDK::insertAssemblyAfter(virp, first, assembly);
	Function_t* func = newInsn->getFunction();
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target)
{
	Instruction_t* newInsn = IRDB_SDK::insertDataBitsAfter(virp, first, dataBits, target);
	Function_t* func = newInsn->getFunction();
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


#if 0
Instruction_t* P1_copyInstruction(Instruction_t* instr)
{
	return IRDB_SDK::copyInstruction(instr);
}


void P1_copyInstruction(Instruction_t* src, Instruction_t* dest)
{
	IRDB_SDK::copyInstruction(src, dest);
}
#endif

Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID, Function_t* func)
{
//	Instruction_t* newInsn = IRDB_SDK::allocateNewInstruction(virp, p_fileID, func);
	auto newAddr=virp->addNewAddress(virp->getFile()->getBaseID(),0);
	auto newInsn=virp->addNewInstruction(newAddr, func);

	inserted_instr[func].insert(newInsn);
	inserted_addr[func].insert(newInsn->getAddress());
	return newInsn;
}


Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr)
{
// 	Instruction_t* newInsn = IRDB_SDK::allocateNewInstruction(virp, template_instr);
	auto fileId=virp->getFile()->getBaseID();
	Function_t* func = template_instr->getFunction();
	auto newInsn=P1_allocateNewInstruction(virp,fileId,func);
	inserted_instr[func].insert(newInsn);
        inserted_addr[func].insert(newInsn->getAddress());
        return newInsn;
}


void P1_setInstructionAssembly(FileIR_t* virp,Instruction_t *p_instr, string p_assembly, Instruction_t *p_fallThrough, Instruction_t *p_target)
{
	IRDB_SDK::setInstructionAssembly(virp, p_instr, p_assembly, p_fallThrough, p_target);
}


string getRetDataBits()
{
	string dataBits;
	dataBits.resize(1);
	dataBits[0] = 0xc3;
	return dataBits;
}

string getJumpDataBits()
{
	string dataBits;
	dataBits.resize(5);
	dataBits[0] = 0xe9;
	dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later
	dataBits[2] = 0x00; // value doesn't matter -- we will fill it in later
	dataBits[3] = 0x00; // value doesn't matter -- we will fill it in later
	dataBits[4] = 0x00; // value doesn't matter -- we will fill it in later
	return dataBits;
}

// jns - jump not signed
string getJnsDataBits()
{
	string dataBits;
	dataBits.resize(2);
	dataBits[0] = 0x79;
	dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later
	return dataBits;
}

// jz - jump zero
string	getJzDataBits()
{
	string dataBits;
	dataBits.resize(2);
	dataBits[0] = 0x74;
	dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later

	return dataBits;
}

// jnz - jump not zero
string getJnzDataBits()
{
	string dataBits;
	dataBits.resize(2);
	dataBits[0] = 0x75;
	dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later

	return dataBits;	
}

// jecxz - jump ecx zero
string getJecxzDataBits()
{
	string dataBits;
	dataBits.resize(2);
	dataBits[0] = 0xe3;
	dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later

	return dataBits;	
}

Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exit_code)
{
	auto handler_code=(Instruction_t *)nullptr;

	if (policy == P_CONTROLLED_EXIT) 
	{
		string exit_code_str = 
			virp->getArchitectureBitWidth()==64 ? 
				"mov rdi, " + std::to_string(exit_code) : 
				"mov ebx, " + std::to_string(exit_code);

		handler_code = P1_allocateNewInstruction(virp,fallthrough);

		P1_setInstructionAssembly(virp,handler_code,exit_code_str.c_str(), NULL,NULL);
		Instruction_t* syscall_num = 
			virp->getArchitectureBitWidth()==64 ? 
				P1_insertAssemblyAfter(virp,handler_code,"mov rax, 60",NULL):  
				P1_insertAssemblyAfter(virp,handler_code,"mov eax, 1",NULL);
		Instruction_t* syscall_i = P1_insertAssemblyAfter(virp,syscall_num,"syscall",NULL);
		syscall_i->setFallthrough(fallthrough);
	}
	else if (policy == P_HARD_EXIT) 
	{
		handler_code= P1_allocateNewInstruction(virp,fallthrough);
		P1_setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL);
		handler_code->setComment("hlt ; hard exit requested");
		handler_code->setFallthrough(fallthrough);
	}
	else
	{
		handler_code= P1_allocateNewInstruction(virp,fallthrough);
		P1_setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL);
		handler_code->setComment("hlt ; Make this into a callback: jdh@getHandlerCode");
		handler_code->setFallthrough(fallthrough);
	}

	return handler_code;
}

Instruction_t* insertCanaryCheckBefore(FileIR_t* virp,Instruction_t *first, unsigned int canary_val, int esp_offset, Instruction_t *fail_code)
{
	auto do_zero=(first->getDisassembly().find("ret")!=string::npos);
	stringstream ss;
	const char *sp_reg="esp";
	if(virp->getArchitectureBitWidth()==64)
		sp_reg="rsp";

	ss<<"cmp dword ["<<sp_reg;

	bool esp_neg=false;
	if(esp_offset <0)
	{
		ss<<"-";
		esp_offset = esp_offset*-1;
		esp_neg=true;
	}
	else
		ss<<"+";

	ss<<"0x"<<hex<<esp_offset<<"], 0x"<<hex<<canary_val;

	//Insert the cmp before 
	Instruction_t* next = P1_insertAssemblyBefore(virp,first,ss.str());

	//Then insert the jmp after the compare. 
	//The fallthrough of the inserted jmp will be a copy of the original
	//instruction, still pointed to by "first".
	P1_insertDataBitsAfter(virp,first,getJnzDataBits(),fail_code);
	first->setComment("Canary Check: "+first->getComment());

	//TODO: move canary zero to option 
	if(esp_neg)
		esp_offset *= -1;

	if(do_zero)
		insertCanaryZeroAfter(virp,first,esp_offset,fail_code); 

	return next;

}

Instruction_t* insertCanaryZeroAfter(FileIR_t* virp, Instruction_t *first, int esp_offset, Instruction_t *fail_code)
{
	stringstream ss;
	const char *sp_reg="esp";
        if(virp->getArchitectureBitWidth()==64)
	{
                sp_reg="rsp";
        	ss<<"mov qword ["<<sp_reg; // clear all 64-bits
	}
	else
	{
        	ss<<"mov dword ["<<sp_reg;
	}

        if(esp_offset <0)
        {
                ss<<"-";
                esp_offset = esp_offset*-1;
        }
        else
                ss<<"+";

        ss<<"0x"<<hex<<esp_offset<<"], 0x0";

        //Insert the cmp before 
        Instruction_t* next = P1_insertAssemblyAfter(virp,first,ss.str());
        first->setComment("Canary Zero: "+first->getComment());

        return next;
}

Relocation_t* createNewRelocation(FileIR_t* firp, Instruction_t* insn, string type, int offset)
{
	/*
        Relocation_t* reloc=new Relocation_t;
        insn->getRelocations().insert(reloc);
        firp->getRelocations().insert(reloc);

	reloc->SetType(type);
	reloc->SetOffset(offset);
	*/
	auto reloc=firp->addNewRelocation(insn,offset,type);

        return reloc;
}