All pastes #545607 Raw Edit

Untitled

public text v1 · immutable
·published 2007-06-06 20:15 UTC
rendered paste body
/************************************************************************
Function length calculation algorithm - by Darawk:

1.  Scan the function's code for branches, and record each branch.  Stop
	upon reaching an end-point*.  This group of instructions constitutes
	the current "block".
2.  QSort the branch list
3.  Recursively repeat steps 1 & 2 with each branch, skipping duplicates
	and intra-block branches.

	*end-point: A ret instruction or an unconditional backwards jump,
				that jumps to a previous block.
************************************************************************/
u32 GetFunctionLength(void *begin)
{
	void *end = GetFunctionEnd(begin);
	u32 delta = (u32)((DWORD_PTR)end - (DWORD_PTR)begin);
	delta    += mlde32(end);
	return delta;
}

void *GetFunctionEnd(void *func)
{
	void *block = func;
	vector<void *> branchList;
	//	ptr now points to the end of this block
	void *blockend = GetBranchListFromBlock(block, branchList);

	//	If there are no branches, then return
	//	the empty list.  If we don't have this
	//	here the loop will crash on an empty
	//	branch list.
	if(branchList.size() == 0) return blockend;

	//	Sort the list so that we can identify and
	//	discard, intra-block branches.  And optimize
	//	the removal of duplicates.
	std::sort(branchList.begin(), branchList.end());

	void *prev = NULL;
	vector<void *>::iterator branch;
	for(branch = branchList.begin(); branch != branchList.end(); branch++)
	{
		//	Skip branches that jump into a block we've already
		//	processed.  
		if(*branch < blockend || *branch == prev)
			continue;

		blockend = GetFunctionEnd(*branch);
		prev     = *branch;
	}

	return blockend;
}

void *GetBranchListFromBlock(void *block, vector<void *> &branchList)
{
	u8 *ptr = (u8 *)block;

	//	If we reach an end-point, then this block is complete
	while(!IsEndPoint(ptr, block))
	{
		//	Record all branching instructions that we encounter
		void *address = GetBranchAddress(ptr);
		if(address)
		{
			branchList.push_back(address);
		}

		//	Next instruction
		ptr += mlde32(ptr);
	}
	
	return ptr;
}


void *GetBranchAddress(u8 *instr)
{
	s32 offset = 0;
	//	This code will determine what type of branch it is, and
	//	determine the address it will branch to.
	switch(*instr)
	{
	case INSTR_SHORTJMP:
	case INSTR_RELJCX:
		offset  = (s32)(*(s8 *)(instr + 1));
		offset += 2;	
		break;
	case INSTR_RELJMP:
		offset  = *(s32 *)(instr + 1);
		offset += 5;
		break;
	case INSTR_NEAR_PREFIX:
		if(*(instr + 1) >= INSTR_NEARJCC_BEGIN && *(instr + 1) <= INSTR_NEARJCC_END)
		{
			offset  = *(s32 *)(instr + 2);
			offset += 5;
		}
		break;
	default:
		//	Check to see if it's in the valid range of JCC values.
		//	e.g. ja, je, jne, jb, etc..
		if(*instr >= INSTR_SHORTJCC_BEGIN && *instr <= INSTR_SHORTJCC_END)
		{
			offset  = (s32)*((s8 *)(instr + 1));
			offset += 2;
		}
		break;
	}

	if(offset == 0) return NULL;
	return instr + offset;
}

bool IsEndPoint(u8 *instr, void *curblock)
{
	void *address;
	s32 offset;
	switch(*instr)
	{
	case INSTR_RET:
	case INSTR_RETN:
	case INSTR_RETFN:
	case INSTR_RETF:
		return true;
		break;

	//	The following two checks, look for an instance in which
	//	an unconditional jump returns us to a previous block,
	//	thus creating a pseudo-endpoint.
	case INSTR_SHORTJMP:
		offset  = (s32)(*(s8 *)(instr + 1));
		address = instr + offset;
		if(address <= curblock) return true;
		break;
	case INSTR_RELJMP:
		offset  = *(s32 *)(instr + 1);
		address = instr + offset;
        if(address <= curblock) return true;
		break;
	default:
		return false;
		break;
	}

	return false;
}