・使い方
これでMSRのレジスタ0x2aが読み込まれる。
このサンプルはCPUがMSRに対応しているかどうか判断していない。CPUIDを実行することで判別してから実行することが好ましい。
・サンプル
これで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;
}







