Here is a somewhat more refined code Base..as well as a User mode test of the concept..
nothing to big..
Code:
char push_0[2] = {0x6a,0x00};
char push_eax = 0x50;            
char push_dwds[2] = {0xff,0x35};
char push_dwptr[2] = {0xff,0x75};
char push_8[2] = {0x6a,0x08};            
char _call = 0xe8;
char XP_SP3[0x16f] = {0x6a,0x44,0x68,0x68,0xa4,0x4e,0x80,0xe8,0x7e,0x07,0xf7,0xff,0x33,0xdb,\
0x89,0x5d,0xd8,0x8b,0x4d,0x14,0xe8,0x64,0x27,0xf7,0xff,0x83,0xf8,0xff,\
0x0f,0x84,0x89,0x17,0x08,0x00,0x64,0xa1,0x24,0x01,0x00,0x00,0x8b,0x48,0x44,\
0x89,0x4d,0xcc,0x8a,0x80,0x40,0x01,0x00,0x00,0x88,0x45,0xd4,0x84,0xc0,\
0x0f,0x84,0x86,0xcb,0x04,0x00,0x89,0x5d,0xfc,0x8b,0x7d,0x0c,0xa1,0xd4,0xfb,0x55,0x80,\
0x3b,0xf8,0x0f,0x83,0x63,0x17,0x08,0x00,0x8b,0x07,0x89,0x07,0x8b,0x75,0x10,\
0xa1,0xd4,0xfb,0x55,0x80,0x3b,0xf0,0x0f,0x83,0x56,0x17,0x08,0x00,0x8b,0x06,\
0x89,0x06,0x8b,0x5d,0x18,0xa1,0xd4,0xfb,0x55,0x80,0x3b,0xd8,0x0f,0x83,0x49,0x17,0x08,0x00,\
0x8b,0x03,0x89,0x03,0x8b,0x0f,0x89,0x4d,0xdc,0x8b,0x16,0x89,0x55,0xe0,\
0x83,0x4d,0xfc,0xff,0xa1,0xdc,0xfb,0x55,0x80,0x3b,0xc8,0x0f,0x87,0x5c,0x17,0x08,0x00,\
0x2b,0xc1,0x3b,0xc2,0x0f,0x82,0x5c,0x17,0x08,0x00,0x85,0xd2,0x0f,0x84,0x54,0x17,0x08,0x00,\
0x6a,0x00,0x8d,0x45,0xe4,0x50,0xff,0x75,0xd4,0xff,0x35,0x58,0x14,0x56,0x80,0x6a,0x08,\
0xff,0x75,0x08,0xe8,0x73,0x2e,0xff,0xff,0x85,0xc0,0x0f,0x8c,0x8e,0x00,0x00,0x00,\
0x8b,0x45,0xe4,0x39,0x45,0xcc,0x0f,0x85,0x9e,0xec,0x01,0x00,0x8d,0x45,0xc8,\
0x50,0xff,0x75,0x14,0x8d,0x45,0xe0,0x50,0x8d,0x45,0xdc,0x50,0xff,0x75,0xe4,\
0xe8,0x8d,0xfd,0xff,0xff,0x89,0x45,0xc4,0x83,0x7d,0xd8,0x00,0x0f,0x85,0x6c,0xec,0x01,0x00,\
0x8b,0x4d,0xe4,0xe8,0x9b,0x72,0xf6,0xff,0xc7,0x45,0xfc,0x01,0x00,0x00,0x00,\
0x80,0x7d,0xd4,0x00,0x74,0x33,0xa1,0xd4,0xfb,0x55,0x80,0x3b,0xf8,0x0f,0x83,0xeb,0x16,0x08,0x00,\
0x8b,0x07,0x89,0x07,0xa1,0xd4,0xfb,0x55,0x80,0x3b,0xf0,0x0f,0x83,0xe5,0x16,0x08,0x00,\
0x8b,0x06,0x89,0x06,0xa1,0xd4,0xfb,0x55,0x80,0x3b,0xd8,0x0f,0x83,0xdf,0x16,0x08,0x00,\
0x8b,0x03,0x89,0x03,0x8b,0x45,0xe0,0x89,0x06,0x8b,0x45,0xdc,0x89,0x07,0x8b,0x45,0xc8,\
0x89,0x03,0x83,0x4d,0xfc,0xff,0x8b,0x45,0xc4,0xe8,0x66,0x06,0xf7,0xff,0xc2,0x14,0x00};
typedef struct _C_ID
{
    _C_ID *_next;
    char *_def_sig;
    ULONG Size;
}C_ID,*PC_ID;
C_ID *InitC_ID(char* _sig,ULONG Size,C_ID *CallId);
C_ID *AddC_ID(char* _sig,ULONG Size,C_ID *CallId);
ULONG Find_CallSigChain(ULONG StartAddress,C_ID *CallId);
int Cycle = 0;
ULONG StartC_ID = 0;
void Find_Addr()
{
      ULONG StartAddress = 0;
      ULONG CallAddress = 0;
      C_ID *CallId = {0};
	  StartAddress = (ULONG)RtlAllocateHeap(RtlProcessHeap(),HEAP_ZERO_MEMORY|HEAP_GROWABLE,sizeof(XP_SP3));
      RtlCopyMemory((void*)StartAddress,(void*)&XP_SP3,sizeof(XP_SP3));
	  CallId = InitC_ID((char*)push_0,sizeof(push_0),CallId);
      CallId = AddC_ID((char*)push_dwds,sizeof(push_dwds),CallId);
      CallId = AddC_ID((char*)push_8,sizeof(push_8),CallId);
      CallId = AddC_ID((char*)_call,sizeof(_call),CallId);
      CallId = AddC_ID((char*)push_dwptr,sizeof(push_dwptr),CallId);
      CallId = AddC_ID((char*)_call,sizeof(_call),CallId);
      //StartAddress = Get NtProtectVirtualMemory Address;
      CallAddress = Find_CallSigChain(StartAddress,(C_ID*)StartC_ID);
}
C_ID *AddC_ID(char *_sig,ULONG Size,C_ID *CallId)
{
      if(Cycle == 0)
      {
      	  StartC_ID = (ULONG)RtlAllocateHeap(RtlProcessHeap(),HEAP_ZERO_MEMORY,sizeof(C_ID)); 
          CallId = (C_ID*)StartC_ID;
		  CallId->_def_sig = _sig;
      	  CallId->Size = Size;
		  Cycle++;
      	  return CallId;
      }
      else
      {
		  if(Size != 1)
		  {
			  CallId->_next =  (_C_ID*)RtlAllocateHeap(RtlProcessHeap(),HEAP_ZERO_MEMORY,sizeof(C_ID));
			  CallId = CallId->_next;
			  CallId->_def_sig = _sig;
			  CallId->Size = Size;
			  Cycle++;
			  return CallId;
		  }
		  else
		  {
			  CallId->_next = (C_ID*)RtlAllocateHeap(RtlProcessHeap(),HEAP_ZERO_MEMORY,sizeof(C_ID));
			  CallId = CallId->_next;
			  memset(&CallId->_def_sig,0xe8,1);
			  CallId->Size = Size;
			  Cycle++;
			  return CallId;
		  }
      }
}
C_ID *InitC_ID(char* _sig,ULONG Size,C_ID *CallId)
{
	return AddC_ID(_sig,Size,CallId);
}       	
ULONG Find_CallSigChain(ULONG StartAddress,C_ID *CallId)
{
	int fid = 0;
	ULONG CallAddr = 0;
CheckC_ID:
	if(CallId->_def_sig != 0)
	{
		do
     	{
			if(CallId->_def_sig == (char*)0xe8)
			{
				fid = memcmp((void*)StartAddress,(void*)&CallId->_def_sig,CallId->Size);
				StartAddress++;
            }
			else
            {
				fid = memcmp((void*)StartAddress,CallId->_def_sig,CallId->Size);		
				StartAddress++;
			}
		}while(fid != 0);
		if(CallId->_next == 0)
		{
			return *(ULONG*)StartAddress;
		}
		else
		{
			goto NextC_ID;
		}  
	}
    else
    {
		return 0;
	}
NextC_ID:
    if(CallId->_next != 0)
	{
		CallId = CallId->_next;
		goto CheckC_ID;
    }
	else
	{
		return 0;
	}
return 0;
}
 
my opcodes for MiProtectVirtualMemory are 0x8dfdffff..the address for this is actually 0x805743fb