MSRの読み込み(Win9x)

 ・使い方

 これでMSRのレジスタ0x2aが読み込まれる。
 このサンプルはCPUがMSRに対応しているかどうか判断していない。CPUIDを実行することで判別してから実行することが好ましい。

#include "Msr.h"

void	OnButton1() 
{
	DWORD	dwEAX;
	DWORD	dwEDX;
	CMsr	cMsr;
	CString	str;

	cMsr.ReadMSR(0x2a,&dwEAX,&dwEDX);

	str.Format("%X %X",dwEAX,dwEDX)
	AfxMessageBox(str);
}


 ・サンプル
class CMsr  
{
	#pragma pack(1)

	struct GDT_DESCRIPTOR
	{
		WORD Limit_0_15;
		WORD Base_0_15;
		BYTE Base_16_23;
		BYTE Type         : 4;
		BYTE System       : 1;
		BYTE DPL          : 2;
		BYTE Present      : 1;
		BYTE Limit_16_19  : 4;
		BYTE Available    : 1;
		BYTE Reserved     : 1;
		BYTE D_B          : 1;
		BYTE Granularity  : 1;
		BYTE Base_24_31;
	};

	struct CALLGATE_DESCRIPTOR
	{
		WORD Offset_0_15;
		WORD Selector;
		WORD ParamCount   : 5;
		WORD Unused       : 3;
		WORD Type         : 4;
		WORD System       : 1;
		WORD DPL          : 2;
		WORD Present      : 1;
		WORD Offset_16_31;
	};

	struct GDTR
	{
		WORD wGDTLimit;
		DWORD dwGDTBase;
	};
	#pragma pack()

	static	void	_RdMsr();

	bool	CallRing0(PVOID pvRing0FuncAddr, DWORD* lpdwEAX, DWORD* lpdwEBX, DWORD* lpdwECX, DWORD* lpdwEDX);

public:
	CMsr();
	virtual ~CMsr();

	bool  ReadMSR(DWORD dwAddr, DWORD* lpdwEAX, DWORD* lpdwEDX);

};





CMsr::CMsr()
{
}

CMsr::~CMsr()
{
}


//
//	ECXにrdmsrの読み出しレジスタ
//	EAX、EDXにDWORDへのポインタを入れる
//
//		EAXとEDXの値がそれぞれ[EAX]と[EDX]に返る
//
//
__declspec(naked) void CMsr::_RdMsr()
{
	_asm
	{
		push	eax
		push	edx
		mov		eax, dword ptr [ecx]
		mov		ecx, eax
		rdmsr
		pop		ebx
		mov		[ebx], edx
		pop		ebx
		mov		[ebx], eax
		retf
	}
}


//		for Windows9X
//
// ring 3モードからのring 0コード呼び出し
//
bool	CMsr::CallRing0(PVOID pvRing0FuncAddr, DWORD* lpdwEAX, DWORD* lpdwEBX, DWORD* lpdwECX, DWORD* lpdwEDX)
{

	GDT_DESCRIPTOR*		pGDTDescriptor;
	GDTR				gdtr;
	WORD				wGDTIndex;

	_asm	sgdt	[gdtr]		//Store Global/Interrupt Descriptor Table Register
	pGDTDescriptor = (GDT_DESCRIPTOR*)(gdtr.dwGDTBase + 8);	// Skip the null descriptor

	// Search for a free GDT descriptor
	for (wGDTIndex = 1; wGDTIndex < (gdtr.wGDTLimit / 8); wGDTIndex++)
	{
		if (pGDTDescriptor->Type == 0 && pGDTDescriptor->System == 0 && pGDTDescriptor->DPL == 0 && pGDTDescriptor->Present == 0)
		{
			// Typeなどが0のdescriptorを使用する。
			// selecter=0x28というのがring 0モードに対応する。
			// これで0~4GBまでの物理メモリにアクセスできる

			WORD					CallgateAddr[3];
			CALLGATE_DESCRIPTOR*	pCallgate;

			pCallgate =	(CALLGATE_DESCRIPTOR *) pGDTDescriptor;
			pCallgate->Offset_0_15 = LOWORD(pvRing0FuncAddr);
			pCallgate->Selector = 0x28;
			pCallgate->ParamCount =	0;
			pCallgate->Unused = 0;
			pCallgate->Type = 0xc;
			pCallgate->System = 0;
			pCallgate->DPL = 3;
			pCallgate->Present = 1;
			pCallgate->Offset_16_31 = HIWORD(pvRing0FuncAddr);

			// Prepare the far call parameters
			CallgateAddr[0] = 0x0;
			CallgateAddr[1] = 0x0;
			CallgateAddr[2] = (wGDTIndex << 3) | 3;

			_asm	mov		eax, [lpdwEAX]				// 引数を渡す
			_asm	mov		ebx, [lpdwEBX]				// 引数を渡す
			_asm	mov		ecx, [lpdwECX]				// 引数を渡す
			_asm	mov		edx, [lpdwEDX]				// 引数を渡す
			_asm	call	fword ptr [CallgateAddr]	// ring0の呼び出し

			memset(pGDTDescriptor, 0, 8);		//GDT descriptorの開放

			return true;
		}
		pGDTDescriptor++; 	// Advance to the next GDT descriptor
	}

	return false;
}

//		for Windows9X
//
//			MSR(Model Specific Registers)の読み出し
//
bool  CMsr::ReadMSR(DWORD dwAddr, DWORD* lpdwEAX, DWORD* lpdwEDX)
{
	bool	ret;

	DWORD	dwEAX;
	DWORD	dwEBX;
	DWORD	dwECX;
	DWORD	dwEDX;

	dwECX = dwAddr;
	ret = CallRing0((PVOID)_RdMsr, &dwEAX, &dwEBX, &dwECX, &dwEDX);

	*lpdwEAX = dwEAX;
	*lpdwEDX = dwEDX;

	return	ret;
}

カテゴリー「VC++ TIPS」 のエントリー