随笔 - 37  文章 - 0  评论 - 150  阅读 - 29万

随笔分类 -  Win32

[Win32]防止套接字被继承
摘要:有一个网络应用程序,需要创建子进程,同时要将一个内核对象的句柄传递给子进程使用。句柄默认是不可继承的,为了达到这个目的,要在创建内核对象的时候指定其句柄是可继承的,然后在调用CreateProcess的时候将bInheritHandles参数设置为TRUE,像下面那样(以创建Mutex为例): SECURITY_ATTRIBUTES sa = { 0 };sa.nLength = sizeof(s... 阅读全文
posted @ 2012-03-20 19:47 Zplutor 阅读(2935) 评论(2) 推荐(1) 编辑
[Win32]IP数据报的首部如何定义
摘要:在进行网络编程时,可能需要直接操作原始的IP数据报,例如编写网络嗅探器。此时要定义一个表示IP数据报首部的结构体来获取首部中的各个信息,问题也随之而来:平时我们使用的数据都是BYTE、WORD或者DWORD,但IP数据报首部的有些字段并不按照字节、字或双字对齐,字段的长度也不是一字节、两字节或四字节,这种不一致的现象使得结构体的定义很有难度。我见过几种IP数据报首部结构体的定义,虽然方法各异,但都是大量使用union,将几个字段塞进一个BYTE或WORD中,在代码中还要通过移位、按位与等操作获取实际的字段。其实,只要理解数据在内存中是如何摆放的,以及利用好结构体定义的特性,可以最大限度地使结构 阅读全文
posted @ 2011-07-05 21:07 Zplutor 阅读(4007) 评论(0) 推荐(0) 编辑
[Win32]一个调试器的实现(十一)显示函数调用栈
摘要:本文讲解如何在调试器中显示函数调用栈,如下图所示:原理首先我们来看一下显示调用栈所依据的原理。每个线程都有一个栈结构,用来记录函数的调用过程,这个栈是由高地址向低地址增长的,即栈底的地址比栈顶的地址大。ESP寄存器的值是栈顶的地址,通过增加或减小ESP的值可以缩减或扩大栈的大小。上一篇文章已经简略地介绍过在调用函数时线程栈上会发生什么事情,现在我们再来详细地看看这个过程:①在栈上压入参数。②执行CALL指令,在栈上压入函数的返回地址。③压入EBP寄存器的值。④将ESP寄存器的值赋给EBP寄存器。⑤减小ESP寄存器的值,为局部变量分配空间。⑥执行函数代码。⑦将EBP寄存器的值赋给ESP寄存器,等 阅读全文
posted @ 2011-04-23 11:19 Zplutor 阅读(9890) 评论(13) 推荐(7) 编辑
[Win32]一个调试器的实现(十)显示变量
摘要:上回介绍了微软的符号模型,有了这个基础知识,这回我们向MiniDebugger中添加两个新功能,分别是显示变量列表和以指定类型显示内存内容。显示变量列表用于列出当前函数内的局部变量或者全局变量;以指定类型显示内存内容用于读取指定地址处的内存内容,然后将这些二进制数据按照类型的格式解析成可读的内容并显示出来。如下面的截图所示:使用lv命令显示局部变量时,每一列从左到右分别是:类型,名称,长度,地址,值。只有基本类型、枚举类型以及指针类型的变量才会显示它的值,对于数组类型和UDT类型的变量则不显示它的值。获取这些变量的值需要使用f命令,该命令遵守同样的显示规则。下面介绍这两个命令的实现方法。枚举全 阅读全文
posted @ 2011-04-22 18:44 Zplutor 阅读(7123) 评论(5) 推荐(3) 编辑
[Win32]一个调试器的实现(九)符号模型
摘要:在接下来的文章中会讲解如何在调试器中显示局部变量和全局变量的类型和值。实现这个功能一定要有调试符号的支持,因为调试符号记录了每个变量的名称,类型,地址,长度等信息。这不是一件轻松的事情,因为你首先要对符号模型有一定的了解。所以本文的主要目的就是介绍DbgHelp中的符号模型。符号模型这里所说的“符号模型”指的是各种符号之间的逻辑关系,虽然微软定义了各种不同格式的符号文件,但是它们使用的符号模型都是相同的。正因为如此,使用DbgHelp可以读取各种格式的符号文件,而且DIA文档中关于符号模型的那部分内容也适用于DbgHelp,正好弥补了DbgHelp文档中缺少的内容。遗憾的是,这部分内容非常少, 阅读全文
posted @ 2011-04-14 12:42 Zplutor 阅读(6295) 评论(4) 推荐(4) 编辑
[Win32]一个调试器的实现(八)单步执行
摘要:上回讲解了如何实现断点功能,这回讲解如何实现与断点紧密相关的单步执行功能。单步执行有三种类型:StepIn,StepOver和StepOut,它们的实现方式比较多样化,单独实现它们的话并不困难,但是将它们整合到一起就比较困难了,特别是加上断点功能之后,程序的逻辑更加难以理解。本文首先单独讲解每种单步执行的原理,最后讲解如何将它们整合到一起。这都是我个人的实现方法,大家可以用来参考。(注意:本文所讲的单步执行是源代码级别的,而不是指令级别的。)StepIn原理StepIn即逐条语句执行,遇到函数调用时进入函数内部。当用户对调试器下达StepIn命令时,调试器的实现方式如下:①通过调试符号获取当前 阅读全文
posted @ 2011-04-09 19:35 Zplutor 阅读(8094) 评论(1) 推荐(3) 编辑
[Win32]一个调试器的实现(七)断点
摘要:断点是最基本和最重要的调试技术之一,本文讲解了如何在调试器中实现断点功能。什么是断点在进行调试的时候,只有被调试进程暂停执行时调试器才可以对它执行操作,例如观察内存内容等。如果被调试进程不停下来的话,调试器是什么也做不了的。要使被调试进程停下来,除了几个在特定时刻才发生的调试事件外,唯一的途径就是引发异常。断点正是用来达到上述目的的异常,在第三篇文章的异常代码表中,有一种EXCEPTION_BREAKPOINT异常,它就是断点异常。虽然断点是一种异常,但并不意味着被调试进程发生了问题,它只是用来调试的一种手段,所以调试器应该将它和别的异常明显区分开来。实际上Windows对断点异常的处理也有一 阅读全文
posted @ 2011-04-02 23:10 Zplutor 阅读(10827) 评论(0) 推荐(3) 编辑
[Win32]一个调试器的实现(六)显示源代码
摘要:上一篇文章介绍了调试符号以及DbgHelp的加载和清理,这回我们使用它来实现一个显示源代码的功能。该功能的实际使用效果如下图所示:该功能不仅仅是显示源代码,还要显示每一行代码对应的地址。实现该功能大概需要进行以下的步骤:①获取下一条要执行的指令的地址。②通过调试符号获取该地址对应哪个源文件的哪一行。③对于其它的行,通过调试符号获取它对应的地址。第一步可以通过获取EIP寄存器的值来完成,相关的内容已经在第四篇文章中进行了讲解,这里不再重复。下面讲一下如何实现第二个和第三个步骤。获取源文件以及行号在调试符号中,记录了每一行源代码对应的地址。通过DbgHelp的SymGetLineFromAddr6 阅读全文
posted @ 2011-03-27 21:32 Zplutor 阅读(9139) 评论(4) 推荐(2) 编辑
[Win32]一个调试器的实现(五)调试符号
摘要:一个调试器应该可以跟踪被调试程序执行到了什么地方,显示下一条将要执行的语句,显示各个变量的值,设置断点,进行单步执行等等,这些功能都需要一个基础设施的支持,那就是调试符号。什么是调试符号我们知道,在exe、dll等可执行文件中保存的数据大部分都是二进制指令,CPU直接读取这些指令并执行。那么调试器是如何知道每条指令对应哪个源文件的哪一行代码呢?它又是如何知道每个变量和函数的名称,并显示变量的值呢?很显然,可执行文件的二进制数据中不可能包含这么多信息,这一切都是由调试符号来支持的。所谓符号,简单来说就是源代码中每个对象的名称。例如变量、函数、类型等,它们都有一个名称,以及其它的相关信息:变量有类 阅读全文
posted @ 2011-03-20 22:51 Zplutor 阅读(12780) 评论(8) 推荐(4) 编辑
[Win32]一个调试器的实现(四)读取寄存器和内存
摘要:在前几篇文章中,我实现的那个调试器只能被动接收调试事件并输出这些事件的信息。现在,我要将它修改成可以接收命令,并根据命令对被调试进程进行各种操作。首先从最基本的操作开始。获取寄存器的值每个线程都有一个上下文环境,它包含了有关线程的大部分信息,例如线程栈的地址,线程当前正在执行的指令地址等。上下文环境保存在寄存器中,系统进行线程调度的时候会发生上下文切换,实际上就是将一个线程的上下文环境保存到内存中,然后将另一个线程的上下文环境装入寄存器。获取某个线程的上下文环境需要使用GetThreadContext函数,该函数声明如下:1BOOLWINAPIGetThreadContext(2HANDLEh 阅读全文
posted @ 2011-03-13 21:57 Zplutor 阅读(11498) 评论(16) 推荐(4) 编辑
[Win32]一个调试器的实现(三)异常
摘要:这回接着处理上一篇文章留下的问题:如何处理EXCEPTION_DEBUG_EVENT这类调试事件。这类调试事件是调试器与被调试进程进行交互的最主要手段,在后面的文章中你会看到调试器如何使用它完成断点、单步执行等操作。所以,关于这类调试事件的处理很自由,调试器的作者可以根据需要进行不同的处理。但是,在对其进行处理之前必须要了解一些关于异常的知识,这也是本文的重点。(本文的内容参考了《软件调试》一书)异常的分类根据异常发生时是否可以恢复执行,可以将异常分为三种类型,分别是错误异常,陷阱异常以及中止异常。错误异常和陷阱异常一般都可以修复,并且在修复后程序可以恢复执行。两者的不同之处在于,错误异常恢复 阅读全文
posted @ 2011-03-08 22:39 Zplutor 阅读(18461) 评论(8) 推荐(3) 编辑
[Win32]一个调试器的实现(二)调试事件的处理
摘要:上一篇文章说到了调试循环的写法,这回讲一下调试器应该如何处理各种调试事件。RIP_EVENT关于这种调试事件的文档资料非常少,即使提到也只是用“系统错误”或者“内部错误”一笔带过。既然如此,我们也不需要对其进行什么处理,只要输出一条信息或者干脆忽略它即可。OUTPUT_DEBUG_STRING_EVENT当被调试进程调用OutputDebugString时就会引发该类调试事件,OUTPUT_DEBUG_STRING_INFO结构体描述了关于该事件的详细信息。在MSDN中,对该结构体各字段的解释是:lpDebugStringData字段是字符串在被调试进程的进程空间内的地址;nDebugStri 阅读全文
posted @ 2011-03-06 21:47 Zplutor 阅读(9925) 评论(2) 推荐(2) 编辑
[Win32]一个调试器的实现(一)调试事件与调试循环
摘要:前言程序员离不开调试器,它可以动态显示程序的执行过程,对于解决程序问题有极大的帮助。如果你和我一样对调试器的工作原理很感兴趣,那么这一系列文章很适合你,这些文章记录了我开发一个调试器雏形的过程,希望对你有帮助。或许我写的代码很拙劣,还请大家多多见谅!这个调试器使用Visual Studio 2010作为开发工具,是一个控制台程序。为了简化,一切输入输出都使用C++标准库的相关类,而且省略了很多错误检查和处理的过程。启动被调试程序要想对一个程序进行调试,首先要做的当然是启动这个程序,这要使用CreateProcess这个Windows API来完成。例如,下面的代码以记事本作为被调试程序:1#i 阅读全文
posted @ 2011-03-04 22:26 Zplutor 阅读(19238) 评论(4) 推荐(7) 编辑
[Win32]创建模态窗口
摘要:在Win32编程中,如果要显示一个模态窗口,一般是先创建对话框模板,然后使用DialogBox来显示对话框。这种做法很简单,但存在一个问题:对话框是以资源的形式保存在可执行文件中的,如果可执行文件没有进行加壳处理的话,任何人都可以通过ExeScope等资源修改工具修改对话框的内容,这对于含有版权信息的“关于”对话框来说是非常危险的,怀有不良目的的人只需进行简单的操作就可以将一个软件变成是自己的。保护软件的版权信息不被修改有很多种方法,在这里我想说的一种方法是用代码来创建“关于”对话框的内容,在运行时才创建这个对话框,而不是通过对话框模板早早就创建 阅读全文
posted @ 2011-02-20 14:05 Zplutor 阅读(7319) 评论(2) 推荐(0) 编辑

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示