今天我们一起来探索下如何实现ring3程序直接访问硬件。这部分内容跟windows保护模式中的I/O保护部分有直接的关系。
我们来看看Windows系统I/O访问保护的方法:
80386采用 I/O特权级IPOL 和 I/O许可位图 的方法来控制输入/输出,实现输入/输出保护.
I/O许可位图位于 任务状态段TSS中。 I/O特权级IPOL就是EFLAGS寄存器中IOPL位。
采用的保护规则 是:
(1)若CPL<=IOPL,则直接转步骤(8);
(2)取得I/O位图开始偏移;
(3)计算I/O地址对应位所在字节在I/O许可位图内的偏移;
(4)计算位偏移以形成屏蔽码值,即计算I/O地址对应位在字节中的第几位;
(5)把字节偏移加上位图开始偏移,再加1,所得值与TSS界限比较,若越界,则产生出错码为0的通用保护故障;
(6)若不越界,则从位图中读对应字节及下一个字节;
(7)把读出的两个字节与屏蔽码进行与运算,若结果不为0表示检查未通过,则产生出错码为0的通用保护故障;
(8)进行I/O访问。
其中windows中IOPL值是为0,从第一条规则我们可以了解到为什么ring0下可以直接访问I/O了,因为ring0中CPL = 0 ,完全满足第一条。而ring3下CPL = 3 ,第一条不能满足。
我们知道每个任务使用各自的EFLAGS值和拥有自己的TSS,所以每个任务可以有不同的IOPL。所以想在ring3下访问I/O,最简单的方法当然是修改当前进程IOPL的值为3了。
根据前面了解到 IPOL就是EFLAGS寄存器中IOPL位,所以我们尝试下修改eflags寄存器看看。如图:
我们写段代码看看:
#include "stdio.h"
int main(int argc, char* argv[])
{
_asm
{
pushfd
pop eax
or eax,0x3000 //设置iopl = 3
push eax
popfd
pushfd //看看修改后的效果
pop eax //eflags寄存器的值保存到eax中
}
return 0;
}
通过上面代码,我们发现不能直接修改eflags中iopl的值。呵呵,继续想办法吧。
每个Windows进程都有一个相对应的执行体进程(EPROCESS),EPROCESS不仅包括了进程的许多属性,还包扩了许多指向其他数据结构的指针,其中包含了大量有用的信息.
为了找出思路,我们还是先看看进程eprocess吧。
lkd> dt _eprocess
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE_X86
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B