在OS下写一个访问底层的程序

前言

我们知道,在UEFI Shell下,可以随意读写底层的寄存器,但是对OS来说是行不通的!因为基于安全性考虑,目前的OS都对上层的应用程序做了限制,所以上层是无法直接访问底层的。如果要进行访问,必须要经过一个中间层(驱动),这篇文章记录在Windows和Linux中,如何编写一个可以访问底层寄存器的程序。

既然访问底层需要驱动,那么是不是要自己写一个驱动呢?当然不是,这里不讨论驱动开发,而且开发驱动不是三言两语说得清的。

Windows

Windows系统微软在WinXP后加了RING级别限制,普通应用程序访问底层必须经过驱动,除非使用OS提供的API。

访问底层无非就是IO或memory操作,网络上有几个免费的驱动做好了这些接口。常见的有WinIO、Inpout32/Inpoutx64、Winring0等。前面两个没有驱动签名,只能在windows测试模式使用,而winring0是带签名的,所以可以直接拿来使用。

Winring0项目地址:https://github.com/QCute/WinRing0/releases

详细API的使用可仔细阅读manual.chm下面举一个读取CMOS数据的例子。

Step1,下载WinRing0_1_3_0.zip并解压。

Step2,使用VS新建一个名称为Cmos的C++空项目,并添加一个Main.cpp文件,注意一定要cpp后缀,winring0是c++写的,这样才能以C++方式编译,语法可以用C语言的。

Step3,复制解压出来的文件

1) 复制WinRing0_1_3_0\source\dll\OlsApi.h 至 Main.cpp同目录并添加到VS项目中

2) 复制WinRing0_1_3_0_\release\WinRing0x64.lib至 Main.cpp同目录

Step4,复制以下代码,VS设置编译成x64:

#include <windows.h>
#include <iostream>
#include "OlsApi.h"

using namespace std;

#pragma comment(lib, "WinRing0x64.lib")

int main(int argc, char ** argv)
{
    int Data[256];
    int Index;

    if (!InitializeOls()) {
        cout << "Init Error!" << endl;
        return 0;
    }

    for (Index = 0; Index <= 0xFF; Index++) {
        WriteIoPortByte(0x70, Index);
        Data[Index] = ReadIoPortByte(0x71);
    }

    for (Index = 0; Index <= 0xFF; Index++) {

        if (Index % 0x10 == 0 && Index > 0) {
            printf("\n\r");
        }

        printf("%02X ", Data[Index]);
    }

    return 0;
}

Step5,点击“生成”->生成Cmos。

Step6,找到生成的目录,管理员权限运行windows shell,运行Cmos.exe,会提示找不到WinRing0x64.dll。

Step7,将WinRing0_1_3_0_\release\WinRing0x64.dll和WinRing0_1_3_0_\release\WinRing0x64.sys复制到Cmos.exe目录下。

Step8,重做Step6,成功读取CMOS。

Linux

Linux下有两种方法可以访问,一是自己写驱动模块,二是通过操作OS下/dev/port或/dev/mem设备,这里记录的是第二种。Linux下的访问底层的方式与Windows有很大的差异,它是将底层数据映射到一个文件上的,读写端口就是读写文件,原理这里不多描述,有兴趣可网上搜索。

这里同样举一个读取CMOS的例子,没什么什么步骤,直接新建一个文件main.c并粘贴以下代码:

#include <stdint.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

static int fd;
bool port_dev_init(void)
{
    fd = open("/dev/port", O_RDWR);
    if (fd < 0) {
        return false;
    }  
    return true;
}
void port_dev_exit(void)
{
    close(fd);
}
uint8_t ioread8(uint16_t port)
{
    uint8_t buf[2] = { 0 };
    lseek(fd, port, SEEK_SET);
    read(fd, buf, 1);
    return buf[0];
}
void iowrite8(uint16_t port, uint8_t data)
{
    uint8_t buf[2] = { 0 };
    lseek(fd, port, SEEK_SET);
    buf[0] = data;
    write(fd, buf, 1);
}

int main(uint64_t argc, uint8_t **argv)
{
    uint8_t value;
    uint8_t index;

    if (!port_dev_init()) {
        printf("Init error!\n");
        return 0;
    }

    for (index = 0; index <= 0xFF; index++) {
    if (index % 0x10 == 0 && index > 0) {
        printf("\n\r");
    }
        iowrite8(0x70, index);
        value = ioread8(0x71);
    printf("%02X ", value);
    }
    port_dev_exit();

    return 0;
}

编译:gcc main.c -o main

运行:sudo ./main

附件

https://wwi.lanzoui.com/ik09Cm210af

版权声明:
作者:bin
链接:https://ay123.net/mystudy/945/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
海报
在OS下写一个访问底层的程序
前言 我们知道,在UEFI Shell下,可以随意读写底层的寄存器,但是对OS来说是行不通的!因为基于安全性考虑,目前的OS都对上层的应用程序做了限制,所以上层是……
<<上一篇
下一篇>>