SSDT、ShadowSSDT、HOOK、InlineHook,都被大侠们玩腻了。发出来总是收到各种鄙视……

         最近仔细看了看WRK系统调用部分,发现还挺有意思,想出了个自己增加系统服务的方法,虽然没什么技术含量、可能暂时也找不到使用价值,但也放出来和大家分享一下,高手就不用使劲鄙视了。

先看看效果吧。

R3调用代码:

__declspec(naked) void SysEnter(){

    __asm {

        mov edx, esp

        _emit 0x0f      //sysenter

        _emit 0x34

    }

}


int main(int argc, char** arv)

{

    __asm{

        pushad

        mov eax, 0x2000     //第2张表,第0项服务

        call SysEnter

        popad

    }

    return 0;

}

这段代码模拟了ntdll的系统调用,不过我们的服务号是0x2000,在正常的系统中是没有这么大的服务号的。而现在这个这个服务的效果是在WinDbg中的打印“you are in MyServiceRoutine!!!!!!!!!!!!!”这样一行字符串。


这是怎么做到的呢?首先我们要了解一下WINNT的系统调用。

1. R3下的程序执行到sysenter指令时会转入R0的KiFastCallEntry函数。这时eax指向的是系统调用的服务编号,edx指向当前的用户态堆栈栈顶(通过edx我们可以找到系统调用的各参数)。

2. KiFastCallEntry中会进行TrapFrame等数据结构的初始化、用户态参数复制到内核栈等操作,不过这都不是重点(有兴趣请参照WRK,这里还有我的一个简单分析http://hi.baidu.com/index09/blog/item/729b1130b743e792a8018e72.html)

3. eax & 0xF000获得表号A、eax & 0x0FFF 获得服务号B

4. 当前线程的KTHREAD结构的0x0e0 偏移处有个叫ServiceTable的字段,指向的是当前系统的服务表。

这张表就是我们所熟悉的KeServiceDescriptorTable(对于普通线程)或KeServiceDescriptorTableShadow(对于GUI线程)。


这两张表的结构如下

typedef struct _ServiceTable{

    PULONG serviceEntry;

    ULONG zero;

    PULONG numberOfService;

    PUCHAR paramTable;

}ServiceTable, *PServiceTable;


typedef struct _ServiceDescriptorTable{

    ServiceTable Ssdt;

    ServiceTable Shadow;

    ServiceTable unused01;

    ServiceTable unused02;

}ServiceDescriptorTable, *PServiceDescriptorTable;


具体细节要是不明白的话请先学习一下SSDT HOOK~~


5. 第3步计算出的表号A便是ServiceDescriptorTable的索引。获得ServiceTable

6. 根据第三步计算出的服务号B调用ServiceTable中对应的系统函数~~

7. 完成调用返回用户态等。


我难看出windows的ServiceDescriptorTable对应了4个表,可是当前的版本只用的其中两个。也就是说系统调用号0x2000一下的才是有效的。

如果我们把两个没使用的ServiceTable填上会怎么样了?

哈哈,这样我们就可以制造自己的“系统调用”啦~~。

这里要注意因为ServiceTable有两张KeServiceDescriptorTable和KeServiceDescriptorTableShadow,对应了不同种类的线程,所以在填写新调用时两张表都要更新哟~~


简单说一下R0驱动的思路:

1. 获取KeServiceDescriptorTable和KeServiceDescriptorTableShadow地址,有很多种方式。我用的是遍历eprocess的方法可能通用性不佳.

2. 申请并填写如下结构

typedef struct _MyService{

ULONG service[10];      //我们的服务例程号

UCHAR args[10];         //参数大小

}MyService, *PMyService;

这个结构能容纳10个增的系统调用。当然例子里只用了一个。

3. KeServiceDescriptorTable. unused01. serviceEntry = PMyService.service;

KeServiceDescriptorTable. unused01. zero = 0;

KeServiceDescriptorTable. unused01. numberOfService = 1;//因为我只新增了一个调用

KeServiceDescriptorTable. unused01. serviceEntry = PMyService.args;


大功告成~~ 有兴趣的朋友可以下载附件编译一下看看实际效果~~ bin文件下是已经编译好的sys和exe。exe使用vs2008编译的,运行不了请下载运行库 ok~~

希望能和大家多交流
http://hi.baidu.com/index09

上传的附件 InsertSSDT.rar

  • 标 题:答复
  • 作 者:cvcvxk
  • 时 间:2010-01-15 17:30:12

其实没有那么复杂,大可以自己扩充原有的表~~

另外那个unused的表在某些系统上指向Shadow~~