摘要:
共享的内核空间:用户空间是各个进程隔离的,但是内核空间是共享的。就是说,每个进程看到的高2GB空间范围内的数据,都应该是一样的。如果成功修改了高2GB范围内的代码,让硬盘驱动返回失败,那么所有进程都无法读取硬盘。内核空间是受到硬件保护的,比如X86下R0层的代码才可以访问内核空间。普通应用程序编译后都允许在Ring3层,R3层代码要调用R0层功能,一般都通过OS提供的一个入口(该入口中调用sysenter指令)来实现。所以编写的内核模块,是运行在内核空间中,称为OS的一个模块,最终被所有需要该模块提供功能的应用程序或OS本身调用。内核模块位于内核空间,而内核空间又被所有进程共享。因此,内核模块 阅读全文
摘要:
这两天一直在查一个Bug,图方便,直接通过Windbg Release调试。问题出现在一个很奇怪的地方,线程栈似乎被破坏,但是始终查不到原因。后来同事帮忙,VS Debug一下就把问题定位了,出在一个动态库导出函数的调用约定不一致。定义为_stdcall,调用处声明为C调用约定了。Release确实忽略了一些边界的检查,如果Release不能再现,或者思路不清的。别忘了使用Debug版。 阅读全文
摘要:
驱动模型区分:WDM 必须满足n种被要求的特性(如电源管理,即插即用);如果没有这些功能,则统一称为NT式驱动;如果调用了WDF的内核API,则称为WDF驱动。本书关注于通用的内核程序开发,不是针对某种硬件。例如,文件系统驱动,存储设备驱动,网络驱动。不是为了驱动某个硬件,而是在通用的windows上实现某种功能。开发环境的搭建:下载WDK,编译调试。无需VS,VS只是方便工程管理和编码。因为不是应用程序,所以所有win32API都不能使用。部分C Runtime函数也不能使用,但文档中说明的函数则可以使用。简单代码示例:#include <ntddk.h> // 提供一个Unlo 阅读全文
摘要:
Base64是MIME邮件中常用的编码方式之一。它的主要思想是将输入的字符串或数据编码成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}这64个可打印字符的串,故称为“Base64”。Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。举个例子:转换前aaaaaabbccccddddeef 阅读全文
摘要:
The WTSQueryUserToken function obtains the primary access token of the logged-on user specified by the session ID. To call this function successfully, the calling application must be running within the context of theLocalSystem account and have the SE_TCB_NAME privilege.MSDN明确指出调用该函数必须使用LocalSystem账 阅读全文
摘要:
参见MSDN中的一段:The FD_WRITE network event is handled slightly differently. An FD_WRITE network event is recorded when a socket is first connected with connect/ WSAConnect or accepted with accept/ WSAAccept, and then after a send fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an 阅读全文
摘要:
std::wstring string2wstring(std::string str){ std::wstring result; int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0); wchar_t* buffer = new wchar_t[len + 1]; MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len); buffer[len] = L'\0'; re... 阅读全文
摘要:
template <typename T> class CDestructor; template <typename T1, typename T2> class CDestructor<T1 (*)(T2)> //模板特化,这里类型 T 特化为一个函数指针 T1(*)(T2),改函数参数一个为T2,返回类型为T1 { public: typedef T1 (*FuncPtr)(T2); CDestructor(FuncPtr fp, T2 param):m_ptr(fp), m_param(param) {}; ... 阅读全文
摘要:
__cdecl与__stdcall这两种调用约定之间的主要差别在于由谁来执行对参数的清理工作。如果是__cdecl,那么主调函数将负责执行清理工作,如果是__stdcall那被调函数将负责执行清理。通常,我们倾向于使用__stdcall,它能够减少生成代码的规模。因为不需要每次调用时,都在返回后对esp进行操作,比如add esp, 0Ch.(抵消三个参数的大小)__cdecl存在的意义是?支持变长数量的参数。调用约定参数传递栈的清理工作函数名修饰stdcall右到左被调函数函数名字前加"_",并且在后面增加'@'以及栈空间所需要的字节数cdecl右到左主调 阅读全文
摘要:
__w64 int*这个类型有些奇怪,64位上大小显示为8,但是作为指针类型,两个变量进行算术运算时,得出的值并不正确。比如__w64 int* p1 = 0x00000090;__w64 int* p2 = 0x000000a0;long = p1-p2; //long的值为4实际应该为16/8 = 2;还是我理解错了??改用 PULONG_PTR一切正常#if defined(_WIN64)typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;#elsetypedef _W64 unsigned long ULONG_PTR, *PULONG_P. 阅读全文