内核关是最蛋疼的一关,需要配置DDK VM 之类的一些东西,调试过程中还很有可能各种蓝屏,而且我的机器也不给力,巨卡无比,所以调试过程中·也是各种阻碍各种死机。
内核关一:
题目给一个内核文件,要求调用此内核文件一个函数来读出密码的长度,其实用笔记本打开后可以看到密码,发现代码很短,挨个试一下,水水的解决了。
内核关二:
这题我纠结了很久,题目要求实现一个windows API HOOK,来隐藏进程。想要详细了解同学可以看这篇文章http://www.cnblogs.com/BoyXiao/archive/2011/09/05/2168115.html
先说一下原理,HOOK 分为 用户态也就是ring3 HOOK与内核态HOOK也就是Ring0 HOOK,这次要用到得是Ring0 HOOK中的SSDK HOOK,
SSDK 全程叫做 System Services Descriptor Table.俗称系统服务描述表,linux中也有一个类似的表叫做system_call_table,SSDK的作用是把Ring3的Win32 API和Ring0
的内核API联系起来。我们只需要修改SSDK数组中的函数地址使它指向我们自己定义的函数,便完成了HOOK。
先来说一下编程过程中用到的知识,
#pragma pack(1)
#pragma pack()
这两句是为了修改数据在内存中的对齐方式,不加也可以。
__declspec(dllimport) 声明了函数为导入函数,是ms自定义的宏,一般在dll文件中使用__declspec(dllexmport),在exe文件中使用__declspec(dllimport)
NTSYSAPI 的定义在winnt.h 中如下,NTSYSAPI这个宏最终还是归结到 __declspec(dllimport)这个宏上
#if (defined(_M_IX86) || defined(_M_IA64) || defined(_M_AMD64)) && !defined(MIDL_PASS)
#define DECLSPEC_IMPORT __declspec(dllimport)
#else
#define DECLSPEC_IMPORT
#endif
#if !defined(_NTSYSTEM_)
#define NTSYSAPI DECLSPEC_IMPORT
#define NTSYSCALLAPI DECLSPEC_IMPORT
#else
#if (defined(_M_IX86) || defined(_M_IA64) || defined(_M_AMD64)) && !defined(MIDL_PASS)
#define DECLSPEC_IMPORT __declspec(dllimport)
#else
#define DECLSPEC_IMPORT
#endif
NTAPI 的定义在winnt.h中
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define NTAPI __stdcall
#else
#define _cdecl
#define __cdecl
#define NTAPI
#endif
__stdcall是函数调用约定的一种,主要规定了参数入栈顺序,和堆栈由谁清理。
具体可以看百度百科http://baike.baidu.com/view/1276580.htm
NTSTATUS 在头文件NTSTATUS.h中,一般被定义成long型,用来返回函数执行中的状态。
在修改SSDT之前,需要去除SSDT的写保护,不然会出现访问无效内存之类的蓝屏,去除写保护只要修改控制寄存器CR0就可以了
CR0的16位是WP位,把它置0可以关闭写保护。代码很简单,只可以在RING0权限下运行。
__asm
{
cli ; //关中断
mov eax, cr0
and eax, ~0x10000 //and eax,0xfffeffff
mov cr0, eax
}
// 恢复写保护
__asm
{
mov eax, cr0
or eax, 0x10000
mov cr0, eax
sti ; //开中断
}
PULONG与PUCHAR的定义如下,应该也是微软弄得蛋疼东西
UCHAR == unsigned char,
PUCHAR == unsigned char *,
因为ZwQuerySysteminformation的汇编代码第一句是吧SSDT索引值传入寄存器,
mov eax,0xxxxxxxxxh 其中的立即数便是索引值
这段代码的机器码是5个字节,立即数占了4字节
所以先把函数地址转为char型,后移一个字节,再转成long型,便读取到索引值了·
*(PULONG)((PUCHAR)ZwQuerySystemInformation+1));
#include "ntddk.h"
#pragma pack(1) //修改数据在内存中的对齐方式
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t;
#pragma pack() //还原数据在内存中的对齐方式
unsigned long OldCr0;
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
typedef struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
}SYSTEM_PROCESSES,*PSYSTEM_PROCESSES;
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG SystemInformationCLass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
ZWQUERYSYSTEMINFORMATION OrgZwQuerySystemInformation;