修改寄存器绕过保护

为了安全起见,Windows XP及其以后的系统将一些重要的内存页设置为只读属性,这样就算有权力访问该表也不能随意对其修改,例如SSDT、IDT等。但这种方法很容易被绕过,我们只要将这些部分修改为可写属性就可以了,不过当我们的事情做完后记得把它们恢复为只读属性,不然会造成一些很难预料到的后果。

  cr0是系统内的控制寄存器之一。控制寄存器是一些特殊的寄存器,它们可以控制CPU的一些重要特性。

  控制寄存器最初出现于低级的286处理器中,以前称之为机器状态字(machine status word),在386以后它们被重命名为控制寄存器(control register)。

  cr0寄存器直到486的处理器版本才被加入了“写保护”(Write Protect,WP)位,WP位控制是否允许处理器向标记为只读属性的内存页写入数据。

  WP位0:禁用写保护的功能

  WP位1:开启写保护的功能

cr0的第16位是WP位,只要将这一位置0就可以禁用写保护,置1则可将其恢复。

禁用写保护的操作步骤:

1 shl 16(1左移16位)//结果:10000000000000000

对结果取反 not (1 shl 16)//结果:FFFEFFFF=01111111111111111

对cr0的值进行“逻辑与”运算:and cr0,  01111111111111111 //即将第17位置0,其余位不变

启用写保护的操作步骤:

直接对CR0的值进行“逻辑或”运算:or cr0,10000000000000000//即将第17位置1,其余位不变

禁用和启用写保护的内联汇编代码如下所示:

// 关闭写保护
__asm
{
    cli ;//将处理器标志寄存器的中断标志位清0,不允许中断
    mov eax, cr0
    and  eax, ~0x10000
    mov cr0, eax
}

// 恢复写保护
__asm
{
    mov  eax, cr0
    or     eax, 0x10000
    mov  cr0, eax
    sti ;//将处理器标志寄存器的中断标志置1,允许中断
}

注意:cli和sti都是特权指令,必须在ring0才能使用的。

核心代码如下:

PJMPCODE pCurAddr;//指向SSDT表中"当前地址"的指针
JMPCODE oleCode;//用来保存前5字节,以便恢复

//驱动程序的入口函数
#pragma INITCODE//将DriverEntry设在分页内存中,当驱动加载成功,此函数在内存中移除。
extern "C" NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
    ULONG curAddr,oldAddr;
    JMPCODE jmpCode;

    // __asm int 3;//断点
    DbgPrint("驱动加载成功……\n");
    curAddr = Get_NTCurAddr();
    oldAddr = Get_NTOldAddr();
    if (curAddr!=oldAddr)
    {
        //保存前5字节
        pCurAddr=(PJMPCODE)curAddr;//初始化指针
        oleCode.jmpStyle=pCurAddr->jmpStyle;//跳转方式的机器码(1字节)
        oleCode.jmpAddr=pCurAddr->jmpAddr;//跳转的目的地址机器码(4字节)

        jmpCode.jmpStyle = 0xE9;//近跳转
        jmpCode.jmpAddr = oldAddr-curAddr-5;

        DbgPrint("要写入的地址:%X",jmpCode.jmpAddr);
        //写入JMP指令
        //关闭写保护
        _asm
        {
            cli ;//将处理器标志寄存器的中断标志位清0,不允许中断
            mov eax, cr0
            and  eax, ~0x10000
            mov cr0, eax
        }

        pCurAddr->jmpStyle=0xE9;//近跳转
        pCurAddr->jmpAddr=jmpCode.jmpAddr;//要跳转到的地址
        // 恢复写保护
        _asm
        {
            mov  eax, cr0
            or     eax, 0x10000
            mov  cr0, eax
            sti ;//将处理器标志寄存器的中断标志置1,允许中断
        }
        DbgPrint("NtOpenProcess被Hook了");
    }
    CreateMyDevice(pDriverObject);//创建设备
    pDriverObject->DriverUnload = DDK_UnLoad;
    return STATUS_SUCCESS;
}

//卸载例程
void DDK_UnLoad(IN PDRIVER_OBJECT pDriverObject)
{
    //关闭写保护
    _asm
    {
        cli ;//将处理器标志寄存器的中断标志位清0,不允许中断
        mov eax, cr0
        and  eax, ~0x10000
        mov cr0, eax
    }
    pCurAddr->jmpStyle=oleCode.jmpStyle;//近跳转
    pCurAddr->jmpAddr=oleCode.jmpAddr;//要跳转到的地址
    // 恢复写保护
    _asm
    {
        mov  eax, cr0
        or     eax,0x10000
        mov  cr0, eax
        sti ;//将处理器标志寄存器的中断标志置1,允许中断
    }
    DbgPrint("驱动卸载成功……\n");
}
时间: 2024-10-13 19:30:12

修改寄存器绕过保护的相关文章

IAA32过程调用寄存器的保护规则

由于操作系统中的共享性质,所以,寄存器也就成为了各个进程或者过程共享资源的一种.那么发生过程 调用的时候,如果调用者要用到一个寄存器里面的值,但是这个寄存器的内容很可能在被调用者运行过程中修改,那么我们就要在被调用过程执行之前,对该寄存器里面的内容进行保护,以至于不会出错,寄存器的保护规则也是因为程序的不可再现性而存在的. 在IA32上,实行了一个统一的寄存器保护规则.首先,我们要看一下,计算机中有多少个比较重要的寄存器 (偷偷懒我就不写寄存器前面的百分号了O(∩_∩)O) eax 这个寄存器属

寄存器的保护与恢复与相关子程序的书写

子程序为了完成一些功能,通常要使用一些寄存器来存放内容,有时候还要使用一些存储单元来存放内容,也就是说,在子程序运行时通常会破坏一些寄存器原有的内容,如果不采取措施,在调用子程序之后,主程序就无法在使用存放在这些寄存器或者存储单元的原有内容了,这常常会导致主程序错误,为此,要对有关的寄存器或存储单元进行保护和恢复 寄存器的保护和恢复的方法有两种 [1]把需要保护的寄存器的内容,在主程序中压入堆栈和弹出堆栈,这种方法的优点是在每次调用子程序的时候,只要把主程序所关心的寄存器压入堆栈即可,但是缺点是

通过修改CR0寄存器绕过SSDT驱动保护

为了安全起见,Windows XP及其以后的系统将一些重要的内存页设置为只读属性,这样就算有权力访问该表也不能随意对其修改,例如SSDT.IDT等.但这种方法很容易被绕过,我们只要将这些部分修改为可写属性就可以了,不过当我们的事情做完后记得把它们恢复为只读属性,不然会造成一些很难预料到的后果. cr0是系统内的控制寄存器之一.控制寄存器是一些特殊的寄存器,它们可以控制CPU的一些重要特性. 控制寄存器最初出现于低级的286处理器中,以前称之为机器状态字(machine status word),

Python批量修改寄存器的值

在写代码过程中,我们修改代码中寄存器的值,但是有时寄存器的数据较多,手动修改容易出现错误而且花费的时间长 这是一段寄存器的配置值: 0x00, 0x34  0x35, 0x25  0x10, 0xd4  0xf5, 0xa5  0x00, 0x34  0x3a, 0xff  0x00, 0x00  0x34, 0x25 这是要修改代码的值:  {Data, 0x21, 0x23},  {Data, 0x34, 0x23},  {Data, 0xd1, 0x2a},  {Data, 0xe1, 0

汇编函数 哪些寄存器在使用时需要保护和恢复现场

在写汇编函数时,总感觉在哪些寄存器该保护哪些不需要保护的问题上比较模糊,要是保护所有使用到的寄存器感觉比较死板也不符合规则,所以就去网上搜了搜.找到了一些规则,我觉得这是一个规则问题,大家都遵守的话就可以相互复用函数了,当然这个规则也是有一定道理的. 1.你自己的函数在操作改变edi esi ebx ebp esp这几个寄存器的值时,你必须先保存这几个寄存器原先的值,并在函数返回之前恢复上述这几个寄存器原先的值.2.你的函数在调用外部的函数时,edi esi ebx ebp esp这几个寄存器不

修改Android手机内核,绕过反调试

0x1.手机设备环境 Model number: Nexus 5 OS Version: Android 4.4.4 KTU84P Kernel Version: 3.4.0-gd59db4e 0x2.Android内核提取 查找Android设备的boot分区文件.高通芯片的设备可以通过下面的命令进行查找. cd /home/androidcode/AndroidDevlop/modifyNexus5Boot adb shell ls -al /dev/block/platform/msm_s

干货!linux密码的破解与保护

找回root口令: 遇到密码丢失的情况,如果只是普通用户的密码丢失,那么可以让管理员重新设定密码.但是如果管理员用户的密码丢失,那该如何解决? 在 Linux环境中root 密码忘记还是可以救回来的!只要能够进入并且挂载 / , 然后重新设定一下root的密码,就救回来啦!这是因为开机流程中,若强制进入runlevel 1 时, 默认是不需要密码即可取得一个 root 的 shell 来救援的.详细过程如下: 1. 重新启动! 2. 在开机按任意键进入 grub 选单 根据提示,键入a 进入以下

ASM:《X86汇编语言-从实模式到保护模式》第12章:存储器的保护

12章其实是11章的拓展,代码基本不变,就是在保护模式下展开讨论. ★PART1:存储器的保护机制 1. 修改段寄存器的保护 当执行把段选择子传到段寄存器的选择器部分的时候,处理器固件在完成传送之前,要检查和确认选择子是正确的,并且该选择子选择的描述符也是正确的.假如索引号是正确的,也就是说明索引号8+7要小于等于边界.如果超过边界,那么处理器就会终止处理,产生异常中断13,同时段寄存器的原值保持不变. 同时处理器还要对描述符的类别进行检查,如果描述符的类别进行确认,举个例子来说,如果描述符的类

若水软件论坛过游戏驱动保护视频教程

课程分四个大章节:?1.初级篇,2.中级篇,3.进阶篇,4.高级篇 初级篇1.VS2003/2008/VC6.0编译驱动A.VS2003驱动编译环境配置B.VS2003集成环境下编译一个简单的驱动2.创建一个卸载例程A.认识PDRIVER_OBJECT结构B.卸载例程回调函数构建C.查看卸载例程调试信息3.添加设备例程A.认识驱动对象DRIVER_OBJECTB.认识设备对象DEVICE_OBJECTC.添加创建设备的例程D.用工具查看驱动及驱动设备4.添加删除设备例程A.删除符号链接B.删除设