首页
社区
课程
招聘
[原创]小菜也学内核笔记---前提知识
发表于: 2009-11-26 16:34 8971

[原创]小菜也学内核笔记---前提知识

2009-11-26 16:34
8971

数据类型
c语言的定义 DDK中的定义
void         VOID   无类型
char         CHAR   字符 8位
short        SHORT  短整型
long         LONG   长整型
wchar_t      WCHAR  宽字符 16位
char*        PCHAR  字符指针 char *p; char c; p=&c;=>p是指向字符的地址
wchar_t      PWCHAR 宽字符指针

#define VOID void
typedef char CHAR;
typedef short SHORT;
typedef long LONG;
typedef wchar_t WCHAR;
typedef unsigned short WCHAR;
typedef WCHAR *PWCHAR;
typedef WCHAR *LPWCH, *PWCH;
typedef CONST WCHAR *LPCWCH, *PCWCH;
typedef WCHAR *NWPSTR;
typedef WCHAR *LPWSTR, *PWSTR;
typedef CONST WCHAR *LPCWSTR, *PCWSTR;
typedef CHAR *PCHAR;
typedef CHAR *LPCH, *PCH;
typedef CONST CHAR *LPCCH, *PCCH;
typedef CHAR *NPSTR;
typedef CHAR *LPSTR, *PSTR;
typedef CONST CHAR *LPCSTR, *PCSTR;

DDK新加一种64位长整型整数,无符号形式,0到2^64-1 用LONGLONG表示
LONGLONG test=100i64  后面加上i64结尾
另一种64位整数表示 LARGE_INTEGER数据结构
typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    };
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER;

返回状态值
typedef LONG NTSTATUS;
定义新类型NTSTATUS 其实就是LONG型。
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
查看函数的返回状态是否成功
NTSTATUS status;
status=MyFun(...);
if (NT_SUCCESS(status))
{
//函数执行成功
}
//  Values are 32 bit values layed out as follows:
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +---+-+-+-----------------------+-------------------------------+
//  |Sev|C|R|     Facility          |               Code            |
//  +---+-+-+-----------------------+-------------------------------+
//      Sev - is the severity code
//          00 - Success
//          01 - Informational
//          10 - Warning
//          11 - Error
//      C - is the Customer code flag
//      R - is a reserved bit
//      Facility - is the facility code
//      Code - is the facility's status code
// Define the facility codes

使用宏注意的地方
用各种流程控制语句时,不要省略{}
if (a>b){大括号不要省去}

ASCII字符串与宽字符串
char型字符串,它是指向一个char数组的指针,每个char型变量大小为一个字节,以0标志字符串结束。
wchar_t型宽字符串[UNICODE],它是指向一个wchar_t数组指针,wchar_t字符大小为两个字节,以0标志字符串结束。

ANSI
char * str="0123";
str指针指向的内容是30 31 32 33 00
UNICODE
wchar_t * str=L"0123";//使用L,编译器会自动生成所需要的宽字符
str指针指向的内容是3000 3100 3200 3300 0000
打印字符串KdPrint(与printf差不多)
CHAR *string="zerostudy";
KdPrint("%s\n",string); //小写s
WCHAR *string=L"zerostudy";
KdPrint("%S\n",string);//大写%S

DDK定义的字符串
/////////////////////////////////////////
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef QUAD UQUAD;
/////////////////////////////////////////
typedef struct _STRING {
    USHORT Length;//字符长度,STRING字符串不以0标志结束。
    USHORT MaximumLength;//整个字符串缓冲区的最大长度
    PCHAR Buffer;//缓冲区的指针
} STRING;
typedef STRING *PSTRING;
typedef STRING ANSI_STRING;
typedef PSTRING PANSI_STRING;

typedef struct _UNICODE_STRING {
    USHORT Length;//字符长度,单位字节,如果N个字符,那么Length=N*2
    USHORT MaximumLength;//整个字符串缓冲区的最大长度,单位字节。
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
    PWSTR  Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
打印log
ANSI_STRING ansistring
KdPrint("%Z\n",&ansistring);
UNICODE_STRING unistring;
KdPrint("%wZ\n",&unistring);
初始化ANSI_STRING
VOID
  RtlInitAnsiString(
    IN OUT PANSI_STRING  DestinationString,//要初始化的字符串
    IN PCSZ  SourceString//字符串的内容
    );
Parameters
DestinationString
Points to the buffer for a counted ANSI string to be initialized.
SourceString
Points to a zero-terminated string with which to initialize the counted string.
Include
wdm.h or ntddk.h
初始化UNICODE_STRING
VOID
  RtlInitUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  SourceString
    );
Parameters
DestinationString
Points to the buffer for a counted Unicode string to be initialized.
SourceString
Points to a zero-terminated Unicode string with which to initialize the counted string.
Include
wdm.h or ntddk.h
使用方法
ANSI_STING ansistring;
CHAR * string1="my first";=>char *
RtlInitAnsiString(&ansistring,string1);
将ansistring中的Buffer指针等于string1的指针[指向同一个地址]
这样初始化用完后不城要清理内存,但是改了string1的话那么ansistring也会改变
ANSI_STRING ansistring;
CHAR * string1="study driver  ^_^!";//若是在C++中CHAR * a="af";是会变成const char* a="af";修改a[0]会出错
//因为在C++中"asdf"是属于const char*
//可以char a[]="asdf";定义一个数组刚,可以放下字符串常量大小,这样就可以更改
RtlInitAnsiString(&ansistring,string1);
KdPrint(("ansistring1:%Z\n",&ansistring));//打印出string1
ULONG slen=strlen(string1);// [wcslen计算宽字符长度 wcslen(L"asdf哈哈"); 这样a这些都会按16位存放]
for (ULONG i=0;i<slen;i++)
{
  if (string1[i]>='a') && (string1[i]<='z'))
       {
         string1[i]=string1[i]-32;
       }
}
KdPrint(("ansistring:%Z\n",&ansistring));

另一种是申请内存初始化,不用时要释放。//自己申请的要自己释放
#define BUFFER_SIZE 1024
UNICODE_STRING unicodestring={0};//初始化结构成员为0
unicodestring.MaximuLength=BUFFER_SIZE;//设置缓冲区大小
unicodestring.Buffer=(PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);//分配内存
WCHAR * widestring=L"study driver";
unicodestring.Length=2*wcslen(widestring); //设置字符长度[是以字符为单位的] 宽字符[16位]所以要*2
ASSERT(unicodestring.MaximumLength>=unicodestring.Length);
RtlCopyMemory(Unicodestring.Buffer,widestring,unicodestring.Length);//复制内存
unicodestring.Length=2*wcslen(widestring);
KdPrint(("unicodestring:%wZ\n",&unicodestring));
ExFreePool(unicodestring.Buffer);//清理内存
unicodestring.Buffer=NULL;
unicodestring.Length=unicodestring.MaximumLength=0;
//RtlFreeAnsiString与RtlFreeUnicodeString两个函数内部调用ExFreePool回收内存

ANSI_STRING字符串复制函数
RtlCopyString copies a source string to a destination string.
VOID
  RtlCopyString(
    IN OUT PSTRING  DestinationString,
    IN PSTRING  SourceString  OPTIONAL
    );
Parameters
DestinationString
Points to the destination string buffer.
SourceString
Points to the source string buffer.
Include
wdm.h or ntddk.h

UNICODE_STRING字符串复制函数

RtlCopyUnicodeString copies a source string to a destination string.
VOID
  RtlCopyUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString
    );
Parameters
DestinationString
Points to the destination string buffer.
SourceString
Points to the source string buffer.
Include
wdm.h or ntddk.h

RtlCopyUnicodeString函数演示

UNICODE_STRING sourceunicode;
RtlInitUnicodeString(&sourceunicode,L"study driver");//初始化
UNICODE_STRING destinationunicode={0};//结构初始化
destinationunicode.Buffer=(PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
destinationunicode.MaximumLength=BUFFER_SIZE;
RtlCopyUnicodeString(&destinationunicode,&sourceunicode);//把源地址的字符串复制到目的地址
KdPrint(("sourceunicode:%wZ\n",&sourceunicode));
KdPrint(("sourceunicode:%wZ\n",&destinationunicode));
//清除destinationunicode
RtlFreeUnicodeString(&destinationunicode);

ANSI_STRING字符串比较
RtlCompareString
RtlCompareString compares two counted strings.
LONG
  RtlCompareString(
    IN PSTRING  String1,
    IN PSTRING  String2,
    BOOLEAN  CaseInSensitive
    );
Parameters
String1
Points to the first string.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison. //若是TRUE则忽略大小写
Return Value
RtlCompareString returns a signed value that gives the results of the comparison:
Zero
String1 equals String2. //返回0则相等
< Zero
String1 is less than String2. //小于0则第一个参数小于第二个参数
> Zero
String1 is greater than String2. //大于0则第一个参数大于第二个参数

UNICODE_STRING字符串比较
RtlCompareUnicodeString
RtlCompareUnicodeString compares two Unicode strings.
LONG
  RtlCompareUnicodeString(
    IN PUNICODE_STRING  String1,
    IN PUNICODE_STRING  String2,
    IN BOOLEAN  CaseInSensitive
    );
Parameters
String1
Points to the first string.
String2
Points to the second string.
CaseInSensitive
If TRUE, case should be ignored when doing the comparison.
Include
wdm.h or ntddk.h
Return Value
RtlCompareUnicodeString returns a signed value that gives the results of the comparison:
Zero
String1 equals String2.
< Zero
String1 is less than String2.
> Zero
String1 is greater than String2.

RtlEqualString 与RtlEqualUnicodeString 返回非零表示相等,零表示不相等

字符串转化成大写
RtlUpperString
RtlUpperString copies the given SourceString to the DestinationString buffer, converting it to

uppercase.把源字符串copy到目的字符串的buffer中,并转换为大写
VOID
  RtlUpperString(
    IN OUT PSTRING  DestinationString,
    IN PSTRING  SourceString
    );
Parameters
DestinationString
Points to the buffer for the converted destination string.
SourceString
Points to the source string to be converted to uppercase.
Include
ntddk.h
Comments
The MaximumLength and Buffer fields of DestinationString are not modified by this routine.
The number of bytes copied from SourceString is either the Length of SourceString or the MaximumLength

of DestinationString, whichever is smaller.
Callers of RtlUpperString must be running at IRQL PASSIVE_LEVEL.//必须运行在PASSIVE级

RtlUpcaseUnicodeString
RtlUpcaseUnicodeString converts a copy of the source string to upper case and writes the converted

string in the destination buffer.
NTSTATUS
  RtlUpcaseUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString  OPTIONAL,
    IN PCUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString //是否为目的字符串分配内存
    );//源与目的可以是同一个字符串
Parameters
DestinationString
Points to a caller-allocated buffer for the converted Unicode string or is NULL if

AllocateDestinationString is set to TRUE.
SourceString
Points to the source Unicode string to be converted to upper case.
AllocateDestinationString
TRUE if RtlUpcaseUnicodeString is to allocate the buffer space for the DestinationString. If it does,

the buffer must be deallocated by calling RtlFreeUnicodeString.
Include
ntddk.h
Return Value
If the operation succeeds, RtlUpcaseUnicodeString returns STATUS_SUCCESS. Otherwise, no storage was

allocated, and no conversion was done.
Comments
Callers of RtlUpcaseUnicodeString must be running at IRQL PASSIVE_LEVEL.
///////////////////////
UNICODE_STRING unicodestring;
RtlInitUnicodeString(&unicodestring,L"study driver");
RtlUpcaseUnicodeString(&unicodestring,&unicodestring,FALSE);
///////////////////////

UNICODE_STRING字符串与整数相互转换

RtlUnicodeStringToInteger
RtlUnicodeStringToInteger converts a Unicode string representation of an integer into its integer

equivalent.
NTSTATUS
  RtlUnicodeStringToInteger(
    IN PUNICODE_STRING  String,
    IN ULONG  Base  OPTIONAL,
    OUT PULONG  Value
    );
Parameters
String
Points to the Unicode string to be converted to its integer equivalent.
Base
An optional argument that indicates the base of the number expressed as a Unicode string.
//转换的数进制 2/8/10/16
Value
Points to caller supplied storage of type ULONG. RtlUnicodeStringToInteger returns the integer

conversion results in Value.
Include
wdm.h or ntddk.h

Return Value
If the conversion is successful, RtlUnicodeStringToInteger returns STATUS_SUCCESS and Value is set to

the integer equivalent of the Unicode string. Otherwise, the Value is set to 0, and

RtlUnicodeStringToInteger returns STATUS_INVALID_PARAMETER.

If the first character of the string is a "–", the sign of the output Value is negative, otherwise if

the first character is a "+" or there is no sign character, the sign of Value is positive.
//如果字符第一个字符是 - 那么输出的值是负的,反之是正的。

整数转换成UNICODE_STRING字符串
RtlIntegerToUnicodeString
RtlIntegerToUnicodeString converts an unsigned integer value to a NULL-terminated string of one or more

Unicode characters in the specified base.

NTSTATUS
  RtlIntegerToUnicodeString(
    IN ULONG  Value,
    IN ULONG  Base  OPTIONAL,
    IN OUT PUNICODE_STRING  String
    );
Parameters
Value
Identifies an unsigned integer of type ULONG.
Base
Optional. If not zero, this must be 2, 8, 10, or 16, to specify that the returned string should

represent the integer as a binary, octal, decimal, or hexadecimal number. If zero, the integer is

represented as a decimal number.-
String
Points to a buffer large enough to contain the Unicode string.
Include
wdm.h or ntddk.h

Return Value
If RtlIntegerToUnicodeString succeeds, it returns STATUS_SUCCESS. Otherwise, it can return

STATUS_INVALID_PARAMETER if Base is not 0, 2, 8, 10, or 16, or STATUS_BUFFER_OVERFLOW if an internal

buffer overflow occurs.

转换演示
        //(1)字符串转换成数字
        //初始化UnicodeString1
        UNICODE_STRING UnicodeString1;
        RtlInitUnicodeString(&UnicodeString1,L"-100");

        ULONG lNumber;
        NTSTATUS nStatus = RtlUnicodeStringToInteger(&UnicodeString1,10,&lNumber);
        if ( NT_SUCCESS(nStatus))
        {
                KdPrint(("Conver to integer succussfully!\n"));
                KdPrint(("Result:%d\n",lNumber));
        }else
        {
                KdPrint(("Conver to integer unsuccessfully!\n"));
        }

        //(2)数字转换成字符串
        //初始化UnicodeString2
        UNICODE_STRING UnicodeString2={0};
        UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
        UnicodeString2.MaximumLength = BUFFER_SIZE;
        nStatus = RtlIntegerToUnicodeString(200,10,&UnicodeString2);

        if ( NT_SUCCESS(nStatus))
        {
                KdPrint(("Conver to string succussfully!\n"));
                KdPrint(("Result:%wZ\n",&UnicodeString2));
        }else
        {
                KdPrint(("Conver to string unsuccessfully!\n"));
        }

        //销毁UnicodeString2
        //注意!!UnicodeString1不用销毁
        RtlFreeUnicodeString(&UnicodeString2);

////////////////////////////////////////////////////////////////////
RtlUnicodeStringToAnsiString
RtlUnicodeStringToAnsiString converts a given Unicode string into an ANSI string.
NTSTATUS
  RtlUnicodeStringToAnsiString(
    IN OUT PANSI_STRING  DestinationString,
    IN PUNICODE_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

RtlAnsiStringToUnicodeString
RtlAnsiStringToUnicodeString converts the given ANSI source string into a Unicode string.
NTSTATUS
  RtlAnsiStringToUnicodeString(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PANSI_STRING  SourceString,
    IN BOOLEAN  AllocateDestinationString
    );

////////////////////////////////////////////////////////////////////
        //(1)将UNICODE_STRING字符串转换成ANSI_STRING字符串
        //初始化UnicodeString1
        UNICODE_STRING UnicodeString1;
        RtlInitUnicodeString(&UnicodeString1,L"Hello World");

        ANSI_STRING AnsiString1;
        NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString1,&UnicodeString1,TRUE);
       
        if ( NT_SUCCESS(nStatus))
        {
                KdPrint(("Conver succussfully!\n"));
                KdPrint(("Result:%Z\n",&AnsiString1));
        }else
        {
                KdPrint(("Conver unsuccessfully!\n"));
        }

        //销毁AnsiString1
        RtlFreeAnsiString(&AnsiString1);

        //(2)将ANSI_STRING字符串转换成UNICODE_STRING字符串
        //初始化AnsiString2
        ANSI_STRING AnsiString2;
        RtlInitString(&AnsiString2,"Hello World");

        UNICODE_STRING UnicodeString2;
        nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2,&AnsiString2,TRUE);
       
        if ( NT_SUCCESS(nStatus))
        {
                KdPrint(("Conver succussfully!\n"));
                KdPrint(("Result:%wZ\n",&UnicodeString2));
        }else
        {
                KdPrint(("Conver unsuccessfully!\n"));
        }

        //销毁UnicodeString2
        RtlFreeUnicodeString(&UnicodeString2);

///////////////////////////////////////////////////////////////////////////////////

CPU表
全局描述符表 Global Descriptor Table , GDT 用于映射地址
本地描述符表 Local Descriptor Table , LDT 用于映射地址
页目录 Page Directory 用于映射地址
中断描述符表 Interrupt Descriptor Table , IDT 用于寻找中断处理程序

OS表
系统服务调度表 System Service Dispatch Table ,SSDT ,Windows OS用于处理系统调用
///////////////////////////////////////////////////////////////////////////////////
一个地址空间是否可以被写入,可以被多少优先级的代码写入,是不是允许执行等涉及保护,涉及属性和保护模式下段

的其他参数,要表示的信息太多了,要用64位长的数据才能表示。我们把这64位的属性数据叫做段描述符(Segment

Descriptor)。
80386中引入了两个新的寄存器来管理段描述符表。一个是48位的全局描述符表寄存器GDTR,一个是16位的局部描述符

表寄存器LDTR。

GDTR[全局描述符表寄存器48位]
    GDTR指向的描述符表为全局描述符表GDT ,Global Descriptor Table。
    它包含系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符及各

任务的LDT段等;全局描述符表只有一个。
    GDT不为系统提供任何安全能力。

LDTR[局部描述符表寄存器16位]
    LDTR则指向局部描述符表LDT(Local Descriptor Table)。80386处理器设计成每个任务都有一个独立的LDT。
    它包含有每个任务私有的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调

用门描述符等。

CS,DS...段寄存器中的信息不再是段地址了,而是段选择器(Segment Selector)。可以通过它在段描述符表中“选择

”一个项目以得到段的全部信息
    16位的段选择器中只有高13位表示索引值。剩下的3个数据位中,第0,1位表示程序的当前优先级RPL;第2位TI位

用来表示在段描述符的位置;TI=0表示在GDT中,TI=1表示在LDT中。

xxxx:yyyyyyyy格式表示一个虚拟地址,经过段选择器及局部描述符表从全局描述符表得到段的起始地址。

地址转换
test dd 100 ;若test的rva值是2000,imagebast是400000,则物理地址是402000处
...
mov eax,test ;读入到eax中的值是存在物理地址上的值
|
|___________>页表转换------------->2000_______>402000----------->eax|402000


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (11)
雪    币: 50
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这也叫笔记。。这能叫教程了。。。。。
2009-11-26 16:37
0
雪    币: 202
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
抄下来的,打算打印出来看,
2009-11-26 16:38
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
4
很初级的笔记~一步步来吧
2009-11-26 17:45
0
雪    币: 411
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持一下,LZ辛苦
2009-11-26 17:53
0
雪    币: 254
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我到现在还搞不清楚几个门描述符,

到底现在用的WINXP有没用到TSS。

有没有任务切换,进程切换和任务切换啥区别,靠
2009-11-26 22:44
0
雪    币: 38
活跃值: (11)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
不错,顶一下,楼主很有心也很细心,我也初学,以后多交流。。。。
2009-11-27 10:02
0
雪    币: 103
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
wchar_t      PWCHAR 宽字符指针  这里就出错了
2009-11-29 19:23
0
雪    币: 269
活跃值: (25)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
9
任务切换是硬件的,xp不用,进程切换是操作系统处理的
2009-11-29 20:44
0
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
不错,顶一下,,我初学,楼主很有心也很细心
2009-11-30 00:29
0
雪    币: 428
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
也在学习。。
2010-3-29 19:39
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
好教材,不知有没更详细的
2010-4-9 11:48
0
游客
登录 | 注册 方可回帖
返回
//