-
-
[原创]建立自己的“SSDT”
-
发表于:
2010-1-15 17:18
7464
-
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
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)