摘要:
也许读者会注意到,端口寄存器的变量使用了volatile 修饰符,这是因为C语言在编译的时候会进行某种优化来提高效率,比如下面这段代码int i = 1;int a = i;int b = i;对于编译器来说,处理a=i 的时候,是先把i的内容放入寄存器中,然后把寄存器的内容付值给a, 当处理b = i的时候,编译器发现在这中间并没有其它代码,也就是认为i的内容不会发生变化,因此不需要再一次从i中读取内容,而是直接把刚才放入寄存器里的内容再付值给b, 这对一般的程序是没有任何问题的,而且提高了效率。但是存在一些编译器不知道的原因,让i 的值产生了变化,那么就在b=i的时候,b得到值并不是i真正 阅读全文
摘要:
操作系统:windows XP调试器通过CreateProcess传入带有DEBUG_PROCESS和DEBUG_ONLY_THIS_PROCESS的dwCreationFlags创建被调试进程。这种情况下,进程创建的早期(执行NtCreateProcess或NtCreateProcessEx之前),调用DbgUiConnectToDbg()使调用线程和调试子系统建立连接。DbgUiConnectToDbg()内部调用ZwCreateDebugObject创建一个DEBUG_OBJECT内核对象,并将其句柄保存在当前线程环境块(TEB)的的DbgSsReserved[1]中。调试进程与被调试进 阅读全文
摘要:
就是缺页中断的处理。在虚拟内存二级映射表PTE中相应位置为0,说明对应虚拟内存需要文件(非swap文件)支持。windows在对应地址所属的管理虚拟内存的数据结构中取出相应文件句柄和偏移,并将该页面读入物理内存。同时修改二级映射表。文件相对应也有一个二级映射表与物理内存产生联系。对于没有指定文件句柄情况,windows只是简单的使用swap文件。 阅读全文
摘要:
注意返回时得使用iretd。通过sidt取得idtr,找到里面的基址和limit。遍历所有的表项,找到一个p位没有置位的,添加一个调用门。和使用call gate没什么大差别。看了下,我机器里的第一个空白项是0x20,就懒得写和ring3通信的东西了。ring3:#include int main(){__asm int 0x20return 1;}ring0:#include #pragma pack(1)typedef struct _IDTR{USHORT limit;ULONG base;}IDTR, *PIDTR;typedef struct _IDT_ENTRY{USH... 阅读全文
摘要:
要注意gdt的第一项是0,不能使用。然后看gdt中那一项的p位没有置位,再添加一个调用门描述符。描述符的offset指向需要被ring3程序调用的ring0函数地址。DPL为3。当然selector权限也需要是3。描述符中的selector应是0x8,说明是ring0下code段。驱动通过DeviceIoControl传递给ring3程序调用门的selector,当然也可以通过文件注册表之类的。不过这里我有点不解,使用了调用门之后,system("pause");就不起作用了。。有知道的请说一声。由于调用门是段间转移,所以用ret返回是错误的,会蓝屏。得用retf。至于怎么 阅读全文
摘要:
先用随便哪个PE文件信息查看工具查看驱动加载的基址,一般来说是0x10000,当然你也可以用IDA看。然后用IDA打开驱动,看DriverEntry的偏移,然后用这个偏移减去基址,得到a。用windbg的时候,下断点bu xxxx(模块名)+a。比方说,TesSafe.sys中基址为0x01001000,DriverEntry偏移为0x01001005,偏移就是5,可以下断点 bu TesSafe+5。就可以动态调试了。 阅读全文
摘要:
通常我们所知IoCallDriver是把irp传递给下一层设备,传递到底是什么意思呢?IoCallDriver中实际调用了IopfCallDriver,其代码如下:NTSTATUSFORCEINLINEIopfCallDriver(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)/*++Routine Description:This routine is invoked to pass an I/O Request Packet (IRP) to anotherdriver at its dispatch routine.Arguments:De 阅读全文
摘要:
欢玩玩二进制技巧挺好的,也确实有助于对实现干的那些事的理解。但须注意,莫走入歧途与其只关注某几种特定的二进制布局,等在认识达到一定程度后,回归到标准学习、ABI等规范的学习上去,这才能从更高层面认识一些问题(研究100种情况下的编译器实现,也不代表第101种情况一定被涵盖在这其中)有些东西,只是“规定”,了解到就行了,没有什么神奇的原理性内容(换言之,规定成其他方式一样可行),兴趣盎然本身就体现出对这一问题认识不足别拘泥于VC的x86实现(即便是x86架构,intel64/amd64上的实现也将有显著不同,更别说其他架构(ARM)了),应适度探究。 阅读全文
摘要:
IoAttachDeviceToDeviceStack将Source Device附加到Target Device上。打开windbgkd> u IoAttachDeviceToDeviceStack l 10nt!IoAttachDeviceToDeviceStack:804f1aac 8bff mov edi,edi804f1aae 55 push ebp804f1aaf 8bec mov ebp,esp804f1ab1 6a00 push 0804f1ab3 ff750... 阅读全文
摘要:
前言经常有人说iostream的速度慢,IO流比stdio的慢多了。但是有人测试过的,iostream的速度是超过stdio的。测试结果/* C */#include int main(){FILE* stream;size_t num;size_t sum = 0;size_t i = 0;stream = fopen("random.data", "r");while(fscanf(stream, "%u", &num) != EOF){sum += num;}fclose(stream);printf("%u\ 阅读全文
摘要:
windows驱动开发中,感觉很多小问题都会导致一些比较麻烦的错误,很多不良习惯都可能会导致系统崩溃。原因是对内核原理的理解太欠缺了,因为驱动运行在RING0优先级,开发的时候必须相当注意细节,不然调试的时候会很麻烦(有些时候Dump文件分析出来是错误的)。原来我一直奇怪写驱动程序问什么要把有些例程放到非分页内存中,今天算是豁然开朗。只怪原来看内核原理的时候没太仔细。具体原因是这样的:因为windows的缺页中断处理程序是运行在DISPATCH_LEVEL的级别的。而我的驱动某些例程一般是等于DISPATCH_LEVEL这个中断级别。也就是说。。如果我把我的代码放到分页内存中。。那操作系统很可 阅读全文
摘要:
是任意形式的递归,是化解的一般式。主题所谓的“递归调用化解为栈处理”,意思是,将递归函数调用化解为“一个由stack_push stack_pop stack_top等函数调用组成的循环式子”。这里的 stack_push, stack_pop, stack_top是指,程序员自己实现的一个ADT(Abstract Data Type)中的函数操作接口,这个ADT叫做栈。要知道,在C语言中,函数调用链本身就是栈处理的,处理C语言中函数调用链的是进程栈/线程栈,进程栈/线程栈是一个C语言程序运行环境的必备部件。将递归调用化解为栈处理的意义在于,大多数计算机系统,对进程栈/线程栈的大小都是有限制的 阅读全文
摘要:
[ISO C11 Clause 3]对象(object):执行环境中数据存储的一块区域,它的内容可以用来表示值。-注释:对象可以具有特定的类型。--值(value):确定类型的对象的内容的确切含义。--访问(access):读取或修改一个对象的值。-注释1:如果只适用其中一种含义,则直接用“读取”或“修改”。-注释2:“修改”包含新值和先前存储的旧的值相同的情况。-注释3:未被求值的表达式不访问对象。--行为(behavior):外部的表现或动作。--未定义行为(undefined behavior):通过使用不可移植、错误的程序构造或错误的数据导致的ISO C没有任何要求的行为。--未确定行 阅读全文
摘要:
作者:@幻の上帝1 前置条件语文其实挺重要,这个没问题,但容易被忽视。当然,如果不是经常要折腾文档,要求不高;但起码要能说清楚话。数学重要,主要是广度,作为快速学习相关领域知识的基础。深度上面可深可浅,若只是学习语言,初中水平的基础足够。(不过要用标准库的complex什么的当然不止了。)而大部分人... 阅读全文
摘要:
对于初学者而言,一般意义上,程序错误可以分为两类,逻辑错误和非逻辑错误。前者是指,程序可以通过编译或链接但运行时不符合预期结果,后者是程序不能通过编译或链接。乍一看这样的分类非常清楚。不过,当引入语言标准对程序行为的规范时,事情变得复杂了。例如, ISO C/C++ 中,引起 undefined behavior (未定义行为)的如果是错误,属于以上分类中的哪一种错误——即,引起 undefined behavior 的程序是否需要保证编译或链接的成功?事实上,这一点在 ISO C 和 ISO C++ 中有微妙不同。首先,摘录和undefined behavior相关的关键术语定义如下:ISO 阅读全文
摘要:
栈比堆快的原因有一个很重要的原因就是栈页不会被从内存中换出,就这么简单。 阅读全文
摘要:
首先明确几个概念:字符串:形式语言理论研究的基本对象之一,是字符的有限序列。以下引用中文喂鸡“字符串”:设∑是叫做字母表的非空有限集合。∑的元素叫做“符号”或“字符”。在∑上的字符串(或字)是来自∑的任何有限序列。例如,如果∑ = {0, 1},则0101是在∑之上的字符串。字符串的长度是在字符串中字符的数目(序列的长度),它可以是任何非负整数。“空串”是在∑上的唯一的长度为0的字符串,并被指示为ε或λ。注意,这里的长度的概念是足够清晰的。以下引用中文喂鸡“字符串->字符串数据类型”:字符串长度尽管形式字符串可以有任意(但有限)的长度,实际语言的字符串的长度经常被限制到一个人工极大值。一 阅读全文
摘要:
摘要 本文综述面向对象,尤其是面向对象编程的基本概念和一些其它编程范型的比较,并指出了现有初学者的一些常见误区。I.面向对象(Object-Oriented, OO)综述 公认的面向对象是一种“思想”,更精确地说是一种方法学(methodology)。面 向对象编程(OOP)、面向对象分析(OOA)、面向对象设计(OOD)等范畴是对此的衍生。容易理解,OOP指使用OO的方法进行编程;OOA和OOD 分别指使用OO的方法进行系统分析与设计(可以合称OOAD),是OO方法学在软件工程上的应用。对于使用OO方法学的软件开发,OOP是基础也是具有更 强的普遍性(即便使用OO方法,也并非所有的软件都.. 阅读全文
摘要:
原文:blog.llvm.org/2011/05/what-every-c-programmer-should-know.html人们偶尔会问为什么LLVM的汇编代码有时会在优化器打开时产生SIGTRAP信号。经过深入研究,他们发现Clang生成了“ud2”指令(假设x86代码)——和__built... 阅读全文
摘要:
前言:__cdecl:C/C++函数默认调用约定,参数依次从右向左传递,并压入堆栈,最后由调用函数清空堆栈,这种方式适用于传递参数个数可变的被调用函数,只有被调用函数才知道它传递了多少个参数给被调用函数,比如printf();__stdcall:参数由右向左传递,并压入堆栈,由被调用函数清空堆栈,当函数有可变参数个数时,函数调用约定自动转换成__cdecl调用约定;__thiscall:C++非静态成员函数默认调用约定,不能使用个数可变参数,调用非静态成员函数时,this指针直接保存在ecx寄存器中,不入栈,其他方面同__stdcall;__fastcall:凡是接口函数都必须指明其调用规范, 阅读全文