<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cuile&#039;s Blog</title>
	<atom:link href="http://blog.cuile.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.cuile.com/blog</link>
	<description>瘦了就帅了</description>
	<lastBuildDate>Mon, 06 Sep 2010 16:11:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>MLDonkey命令手册</title>
		<link>http://blog.cuile.com/blog/archives/109</link>
		<comments>http://blog.cuile.com/blog/archives/109#comments</comments>
		<pubDate>Mon, 09 Aug 2010 03:17:16 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[使用技巧]]></category>
		<category><![CDATA[MLDonkey]]></category>
		<category><![CDATA[telnet]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=109</guid>
		<description><![CDATA[MLDonkey 以简单的命令为特色。大多数mldonkey的接口，例如telnet、web管理界面、其他gui的console标签（比如sancho），都提供了用命令控制mldonkey的方法。这些命令不但方便，有时候也是唯一的方法来控制一些mldonley的高级特性。 mldonkey有很多可用的命令，有些可能不为人知。这个手册旨在较详细地说明mldonkey中的常用命令的用法。 注：&#60;&#62; : 必要参数，[&#60;&#62;] : 可选参数，&#60;1 &#124; 2&#62; : 二选一的参数。提到的mldonkey选项见选项手册。 用户命令 1. auth &#60;用户名&#62; &#60;密码&#62; : 用户登录 2. useradd &#60;用户名&#62; &#60;密码&#62; [&#60;邮箱&#62;] : 添加新mldonkey用户/更改用户密码 3. userdel &#60;用户名&#62; : 删除一个mldonkey用户 4. users : 列出所有用户和用户组 5. whoami : 列出所有已登录用户 用户组命令 1. groupadd &#60;用户组名&#62; : 添加用户组 &#60;管理员&#62; 服务器命令 1. vm : 列出已连接服务器 2. vma : 列出所有已知服务器 [...]]]></description>
			<content:encoded><![CDATA[<p>MLDonkey 以简单的命令为特色。大多数mldonkey的接口，例如telnet、web管理界面、其他gui的console标签（比如sancho），都提供了用命令控制mldonkey的方法。这些命令不但方便，有时候也是唯一的方法来控制一些mldonley的高级特性。<br />
mldonkey有很多可用的命令，有些可能不为人知。这个手册旨在较详细地说明mldonkey中的常用命令的用法。<br />
注：&lt;&gt; : 必要参数，[&lt;&gt;] : 可选参数，&lt;1 | 2&gt; : 二选一的参数。提到的mldonkey选项见选项手册。</p>
<h1>用户命令</h1>
<p>1. auth &lt;用户名&gt; &lt;密码&gt; : 用户登录<br />
2. useradd &lt;用户名&gt; &lt;密码&gt; [&lt;邮箱&gt;] : 添加新mldonkey用户/更改用户密码<br />
3. userdel &lt;用户名&gt; : 删除一个mldonkey用户<br />
4. users : 列出所有用户和用户组<br />
5. whoami : 列出所有已登录用户</p>
<h1>用户组命令</h1>
<p>1. groupadd &lt;用户组名&gt; : 添加用户组 &lt;管理员&gt;</p>
<h1>服务器命令</h1>
<p>1. vm : 列出已连接服务器<br />
2. vma : 列出所有已知服务器<br />
3. n [&lt;端口&gt;] : 添加服务器<br />
4. server_banner : 打印编号为的服务器的旗帜（欢迎信息），其中由vm命令获得<br />
5. servers &lt;文件名&gt; : 从一个server.met文件中添加服务器<br />
6. c [] : 连接到更多服务器（或者连接到号服务器）<br />
7. x : 断开与号服务器的连接<br />
8. id : 列出本机在已连接服务器上的id<br />
9. preferred<br />
: 设置/取消为首选服务器<br />
10. bs [ ...] : 将所给ip加入服务器黑名单<br />
11. bp [ ...] : 将所给端口加入端口黑名单<br />
12. rem [ ...] : 从服务器列表移除指定服务器 (&#8216;all&#8217;清空服务器列表)<br />
13. remove_old_servers : 移除几天没有连接上的服务器</p>
<h1>搜索命令</h1>
<p>1. s [特殊搜索参数] &lt;查询内容&gt; : 在所有网络上搜索文件<br />
* 特殊搜索参数（SpecialSearchArgs）<br />
-minsize : 限制最小文件大小<br />
-maxsize : 限制最大文件大小<br />
-media : 限制文件类型<br />
-Video : 指定为视频文件<br />
-Audio : 指定为音频文件<br />
-format<br />
: 指定为特定格式 &lt;扩展名&gt;<br />
-title : 搜索标题(Mp3 tag搜索)<br />
-album : 搜索专辑(Mp3 tag搜索)<br />
-artist : 搜索艺术家(Mp3 tag搜索)<br />
-field<br />
-not : “非”条件搜索<br />
-and : “与”条件搜索<br />
-or : “或”条件搜索<br />
-without<br />
2. xs : 扩展搜索以获得更多的搜索结果（向一些低优先级的服务器发送查询请求）<br />
3. vs : 显示查询历史和结果统计<br />
4. vr : 查看某此查询的详细结果，其中num由vs获得<br />
5. view_custom_queries : 列出定义的自定义查询种类，如[Complex Search]，[MP3 Search]，[Movie Search]，[Album Search]等<br />
6. forget [ ...] : 丢弃指定编号搜索记录，num由vs获得</p>
<h1>好友命令</h1>
<p>1. friends : 列出所有好友的名称和好友编号<br />
2. files : 列出指定标号的好友的共享文件<br />
3. vfr : 列出所有好友的详细信息，friends命令的扩展，包括IP和积分等<br />
4. gfr : 请求指定编号好友的共享文件列表，以便用files命令查看<br />
5. friend_add : 添加指定编号客户端为好友，client_num可由downloaders和uploaders命令得到<br />
6. friend_remove : 移除指定编号好友 (编号all清空好友列表)<br />
7. message : 向指定编号客户端发送消息</p>
<h1>下载命令</h1>
<p>1. cancel : 取消指定编号的下载任务，用法同pause，另见confirm<br />
2. confirm : 确认取消下载任务，当使用cancel取消下载任务后，需要用 confirm yes确认取消<br />
3. d : 下载指定编号文件，编号可由s等搜索命令获得<br />
4. dllink : 下载以ed2k、sig2dat、BT种子等链接形式给出的文件，比如ed2k打头的ed2k文件hash<br />
5. dllinks : 下载指定文件中的所有url（允许有空行）<br />
6. dd : 下载一个已知大小和md4-hash码的文件<br />
7. http : 从一个http/ftp/ssh url下载文件（注：FTP尤其是SSH仍处于实验阶段）<br />
8. mirror : 给指定编号下载任务添加源（镜像），其中file_num由vd得到（这是迅雷的强项）<br />
9. merge : 这是条强大的命令。这条命令将不同协议（ed2k/BT/HTTP/FTP等）但文件相同的下载任务链接到一起（可以说是mirror的升级版），其中 file1是主文件，不能取消链接（注：这条命令仍处于实验阶段）<br />
10. force_download : 强制重新下载一个已经下载的文件。用法是，先用d/dd/dlink等命令下载文件，mldonkey会提示该文件已经下载，此时键入此命令<br />
11. vd [] : 不加参数将会列出所有处于下载队列中的下载任务信息，加上参数num则列出指定编号的下载任务<br />
12. pause : 暂停指定编号下载任务，all暂停所有任务，编号由vd获得<br />
13. resume : 恢复指定编号下载任务，用法同pause<br />
14. tracker [...] : 给指定编号的BT热任务添加tracker服务器<br />
15. priority [...] : 改变下载任务的优先级<br />
16. rename &#8220;&#8221; : 重命名一个已经完成下载的文件<br />
17. commit : 将完成下载的文件从download文件夹移动到income文件夹，文件夹的具体位置在download.ini中设置<br />
18. startbt : 开始一个BT下载任务</p>
<h1>上传命令</h1>
<p>1. compute_torrent : 为指定文件制作BT种子<br />
2. nu : 暂停上传m分钟。注：此命令受一个积分系统控制（credit system），没上传1分钟，得到1点积分（最大300）,每暂停上传1分钟消耗1点积分，所以每次暂停最多300分钟。<br />
3. reshare : 从共享目录更新共享文件列表。（现在mldonkey会自动监视文件变化，这条命令很少用了）<br />
4. reshare_torrents : 更新共享的种子列表<br />
5. seeded_torrents : 列出所有共享的种子<br />
6. shares : 列出所有共享目录<br />
7. unshare : 将指定目录从共享目录中移除</p>
<h1>全局控制命令</h1>
<p>1. version : 打印mldonkey的版本<br />
2. q : 退出当前的telnet会话<br />
3. save &lt;&#8221;options&#8221;|&#8221;sources&#8221;|&#8221;backup&#8221;&gt; : 保存当前的选项（通常不用手动执行这条命令，mldonkey会每save_options_delay秒自动保存<br />
4. kill : 保存配置文件并关闭mldonkey客户端<br />
5. ! : 远程执行shell命令，如： ! halt<br />
6. close_fds : 关闭所有文件，清除文件缓存，释放磁盘空间。<br />
7. close_all_sockets : 关闭所有打开的sockets。这条命令主要作用是mldonkey在IP改变后（动态IP）快速恢复正常工作，而不是等待连接超时。<br />
8. activity : 列出指定时间内的edonkey和overnet所有活动</p>
<h1>用户配置命令</h1>
<p>1. alias : 自定义命令，如： &#8220;alias ca cancel all&#8221;，使得 &#8220;ca&#8221; 等于&#8221;cancel all&#8221;<br />
2. ansi : 如果设置成true，命令行将采用彩色显示文字，但是有些命令行并不支持（如windows的comandline），这时就需要将其设置成false<br />
3. disable : 禁止指定编号的网络<br />
4. enable : 激活指定编号的网络<br />
5. html_mods : 切换web界面模式（两种）<br />
6. html_mods_style [<br />
] : 不加参数则列出所有可用的web颜色风格及编号，加上编号参数则选择指定web界面的颜色风格（切换颜色风格后web界面自动变回第一种模式，应该是个bug）<br />
7. html_theme : 选择web界面的主题<br />
8. import : 从指定目录导入edonkey官方客户端的下载任务<br />
9. port : 改变ed2k端口，默认是4662，改变在重启core后生效<br />
10. set : 设置某个选项的值<br />
11. share [] : 将指定目录以指定优先级共享，可选参数是共享策略。优先级越高，为此目录预留的上传槽越多。下面是预定义的共享策略：<br />
&#8220;all_files&#8221; : 共享所有文件，包括子目录（默认）<br />
&#8220;only_directory&#8221; : 共享所有文件，不包括子目录<br />
&#8220;incoming_files&#8221; : 设置目录为默认文件下载目录，共享文件不包括子目录<br />
&#8220;incoming_directories&#8221; : 设置目录为默认文件夹下载目录，例如多文件的BT任务。共享文件不包括子目录<br />
12. unalias : 删除由alias设置的自定义命令，如 : &#8220;unalias ca&#8221;<br />
13. urladd : 从url载入指定类型的文件，定义的kind如下<br />
donkey服务器列表<br />
增加rss同步频道. 其内容可由rss命令获得<br />
Setup changes of the day<br />
Information of the day in HTML format<br />
edonkey的文件注释列表<br />
Overnet网络结点列表<br />
Overnet网络结点<br />
kad网络结点<br />
IP to country mapping database<br />
IP过滤列表 (ipfilter and guardian v2格式)<br />
fasttrack结点列表<br />
14. urlremove : 从web_infos列表中移除url，web_infos列表由vwi命令查看<br />
15. vo : 列出关键选项的值，如上传/下载限制速度，昵称，端口等<br />
16. voo [] : 列出所有可用选项，可选参数正则式作匹配条件，如voo *ED2K, voo *port<br />
17. options [] : 不加参数列出所有选项分类，如Header, main, interface, ed2k等，option 分类名 则列出指定分类下的选项<br />
18. reset_md4 : 重置客户端的md4 hash（估计是被ban了才会用）</p>
<h1>Overnet 命令</h1>
<p>1. ov_boot : 添加一个overnet结点<br />
2. ov_boots : 列出所有overnet结点<br />
3. ov_dump_bucket : 废弃指定序号索引桶，索引桶序号由ov_store得到，见ov_store(This is for development)<br />
4. ov_dump_known_peers : dumps known_peers (This is for development)<br />
5. ov_link : 从overnet网络下载一个以fha链接给出的文件（就像edonkey的ed2k链接一样）<br />
6. ov_load : 从一个contact.dat文件中增加overnet结点<br />
7. ov_md4 : 得到客户端在Overnet网络中的md4 hash码<br />
8. ov_send_udp : 通过udp向ov网络中的指定客户端发送消息<br />
9. ov_store : 显示在本客户端上索引的关键字和文件（overnet是纯p2p的网络，没有服务器，所以每个客户端都要存储一笑部分网络信息）<br />
10. ov_view_stats_cmds : 显示overnet的状态（一堆正则式，调试用命令）<br />
11. ov_web : 用指定url的ocl（overnet contact list）文件初始化<br />
Kad(emlia)命令<br />
1. kad_boot : 添加一个kad结点<br />
2. kad_dump_bucket : 废弃指定序号索引桶，索引桶序号由ov_store得到 (This is for development)<br />
3. kad_dump_known_peers : dumps known_peers (This is for development)<br />
4. kad_link : 从kad网络下载一个以fha链接给出的文件<br />
5. kad_load : 从一个contact.dat文件中增加kad结点<br />
6. kad_md4 : 得到客户端在kad网络中的md4 hash码<br />
7. kad_send_udp : 通过udp向kad网络中的指定客户端发送消息(消息是16进制的)<br />
8. kad_store : 显示在本客户端上索引的关键字和文件(见ov_store)<br />
9. kad_view_stats_cmds : 显示Kad网络的状态<br />
10. kad_web : 用指定url的ocl文件初始化</p>
<h1>恢复命令</h1>
<p>1. import_temp : 从eDonkey / eMule / lMule临时文件目录导入未完成的下载，<br />
2. scan_temp : 列出临时目录下的文件<br />
3. recover_bytes [&lt;file2_num2&gt; ...] : 尝试修复指定的部分下载的文件（字节级别），未完成部分用非零字节填充（最好用verify_chunks进行校验），file_num由vd得到，见选项max_recover_gap。<br />
4. recover_temp : 从指定目录恢复未完成的下载。这个命令的作用是恢复那些文件信息丢失（files.ini）但是下载数据还在的下载任务，重建文件信息。并且只能恢复文件中已经完成的块(chunck)。<br />
5. verify_chunks : 按块(chunk)检查文件的正确性，num由vd获得</p>
<h1>状态及统计命令</h1>
<p>1. block_list : 列出被mldonkey阻止ip段，分成网络和本地两个列表<br />
2. buildinfo : 显示mldonkey核心的版本信息<br />
3. bw_stats : 显示上传/下载速度，共享文件数，上传槽/下载槽数<br />
4. cs : 显示按按ed2k客户端软件分类的ed2k上传/下载统计表<br />
5. csbt : 显示按BT客户端软件分类的BT上传/下载统计表<br />
6. csm : 显示按eMule MODs分类的ed2k上传/下载统计表(emule_mods_count = true)<br />
7. client_stats : 显示按按ed2k客户端软件分类的成功连接数/文件请求/上传/下载/阻止数统计<br />
8. client_stats_bt : 显示按按BT客户端软件分类的成功连接数/文件请求/上传/下载/阻止数统计<br />
9. diskinfo : 显示mldonkey磁盘信息，列出下载/共享/临时文件夹信息<br />
10. downloaders : 列出当前正在从哪些客户下载数据<br />
11. gdstats : 显示图形化的统计信息(只在web界面可用)<br />
12. kad_boots : 列出kad网络结点信息<br />
13. kad_buckets : 显示kad索引桶信息<br />
14. kad_stats : 显示kad网络状态<br />
15. links : 列出所有共享文件的ed2k链接<br />
16. ov_buckets : 显示Oernet索引桶信息<br />
17. ov_stats : 显示Overnet网络状态<br />
18. runinfo : 显示mldonkey的运行信息，包括用户/网络种/DNS/系统信息等<br />
19. sources : 显示下载文件的源的统计信息<br />
20. sysinfo : 列出mldonkey的core build, runtime, disk, Port信息，见buildinfo, runinfo, diskinfo和portinfo<br />
21. upstats : 上传统计信息，显示所有共享文件，并按请求数高低排序<br />
22. reset_stats : 重置此次会话的统计信息<br />
23. stats : 显示所有网络的传输状态<br />
24. torrents : 列出服务器上所有BT种子文件<br />
25. uploaders : 列出当前正在上传给哪些客户数据<br />
26. uptime : 核心运行时间统计<br />
27. vu : 显示当前的上传积分，关于上传积分见nu(上传命令)<br />
28. portinfo : 列出mldonkey的端口使用情况</p>
<h1>调试及测试命令</h1>
<p>这些命令可能会在没有通知的情况下被取消或改变. 使用的时候请注意 <img src='http://blog.cuile.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
1. block_test : 测试指定ip是否被阻止<br />
2. clear_log : 清空日志文件<br />
3. close_log : 停止核心向日志文件写入信息<br />
4. debug_client [ ...] : 记录指定客户端的行为到日志文件<br />
5. debug_disk : 显示磁盘信息，如debug_bug /<br />
6. debug_file : debug file state<br />
7. debug_fileinfo : 显示文件或文件夹信息，如debug_fileinfo /home<br />
8. debug_rlimit : debug command, god konws&#8230;<br />
9. debug_socks : for debugging only<br />
10. dump_heap : dump heap for debug<br />
11. dump_reliability : 列出用reliable_sources算法得到的可信任源及其ip<br />
12. log : 将当前的日志信息打印到终端中<br />
13. log_file : 将核心信息写入指定文件<br />
14. mem_stats : 列出详细的内存信息<br />
15. networks : 列出已经连接到的网络<br />
16. open_log : 激活日志记录<br />
17. test_recover : 显示指定文件中已经下载的段<br />
18. use_poll : 用poll() 代替select(), mldonkey应该使用poll()，因为它更高效，而且没有1024文件描述长度限制<br />
19. stdout<br />
: 恢复日志到标准输出流</p>
<h1>未分类命令</h1>
<p>1. vc : 查看客户端信息，num由downloaders和uploaders得到<br />
2. calendar_add &#8220;&#8221; : 添加命令到任务计划，此命令将被储存到download.ini，并且在每天的指定hour执行。如：calendar_add 8 &#8220;set max_upload_rate 10&#8243; 附download.ini的储存内容，可由vcal命令得到：calendar = [ ([0;1;...;6;], [0;1;...;23;], &#8220;command1&#8243; ); ([0;1;...;6;], [0;1;...;23;], &#8220;command2&#8243; ); &#8230; ]<br />
* 第一个参数是定义了一个星期内此命令在那些天被执行(Sunday=0, Monday=1, Tuesday=2, &#8230;, Saturday=6).<br />
* 第一个参数是定义了一天内此命令在那些小时被执行(in 24-hour format 0 &#8230; 24).<br />
* 第三个参数是要执行的命令<br />
3. vwi : 列出当前网络信息<br />
4. gdremove : 移除存储图形化统计信息的文件<br />
5. message_log : 显示已经记录到日志的消息（数秒内显示 ）<br />
6. preview : 预览指定文件，文件编号由vd得到<br />
7. reload_messages : 重新载入消息文件<br />
8. rm_old_torrents : 移除所有旧的BT种子文件<br />
9. rss : 列出所有订阅的rss种子，见urladd<br />
10. vcal : 打印计划的任务，见calendar_add命令</p>
<h1>旧版命令</h1>
<p>1. add_user : 改为useradd<br />
2. remove_user : 改为userdel<br />
3. add_url : 改为urladd<br />
4. commit_to : 已取消<br />
5. set_brothers : 已取消</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/109/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EasyHook中英文教程</title>
		<link>http://blog.cuile.com/blog/archives/98</link>
		<comments>http://blog.cuile.com/blog/archives/98#comments</comments>
		<pubDate>Wed, 04 Aug 2010 10:22:23 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[编程技术]]></category>
		<category><![CDATA[easyhook]]></category>
		<category><![CDATA[hook]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=98</guid>
		<description><![CDATA[从网上找到一篇easyhook的中英文教程，因为GOOGLE随时会被封赶紧记下来，以后慢慢翻译补全 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 1 Continuing Detours: the reinvention of Windows API Hooking 1继续截获:重新改造Windows API 挂钩 Microsoft® Detours latest release was in December 2006. Now times have changed and the NET Framework has become more and more popular. Besides the well known unmanaged code hooking, EasyHook provides a way to hook unmanaged code from a managed environment. [...]]]></description>
			<content:encoded><![CDATA[<p>从网上找到一篇easyhook的中英文教程，因为GOOGLE随时会被封赶紧记下来，以后慢慢翻译补全<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
1 Continuing Detours: the reinvention of Windows API Hooking<br />
1继续截获:重新改造Windows API 挂钩</p>
<p>Microsoft® Detours latest release was in December 2006. Now times have changed and the NET Framework has become more and more popular. Besides the well known unmanaged code hooking, EasyHook provides a way to hook unmanaged code from a managed environment. This implies several advantages:<br />
微软的Detours最新的版本是在2006年12月发布。而现在.Net框架越来越流行，除了大家知道的非托管理代码挂接，EasyHook提供一个从托管环境挂接非托管代码的方法。这意味着几个优点：</p>
<p>No resource or memory leaks are left in the target<br />
在目标中不会有资源和内存泄漏。</p>
<p>You can write pure managed hook handlers for unmanaged APIs<br />
你能够针对非托管API写纯粹的托管钩子句柄</p>
<p>All hooks are installed and automatically removed in a stable manner<br />
所有挂构的安装和自动移除通过稳定的方式。</p>
<p>You can use all the convenience managed code provides, like NET Remoting, WCF and WPF<br />
你可以使用所有托管代码的便利,像Net Rmoting, WCF 和 WPF。</p>
<p>You will be able to write injection libraries and host processes compiled for AnyCPU, which will allow you to inject your code into 32- and 64-Bit processes from 64- and 32-Bit processes by using the very same assembly in all cases.<br />
你可以为各种CPU写注入库和托管进程，你可以用相同的汇编将你的代码注入32和64位进程。</p>
<p>This way hooking has become a simple task and you can now write hooking applications like FileMon or RegMon with a few lines of code.</p>
<p>Further EasyHook 2.5 provides additional features like:</p>
<p>Experimental stealth injection for unmanaged code not raising attention of any current AV </p>
<p>32- and 64-Bit Kernel mode hooking support, since Windows XP. </p>
<p>A pure unmanaged hooking core which will improve performance, stability and compatibility. </p>
<p>A solid unmanaged API for writing hooking apps and libraries without the NET Framework </p>
<p>The unmanaged core does not require CRT bindings and thus will reduce deployment size about some megabytes. Also Windows 2000 SP4 and Windows Server 2008 SP1 can now be targeted with the same EasyHook binary. </p>
<p>Minimal software requirements for end-users to execute applications using EasyHook:</p>
<p>Windows 2000 SP4 or later </p>
<p>Microsoft NET Framework 2.0 Redistributable </p>
<p>Table of Content </p>
<p>1 Continuing Detours: the reinvention of Windows API Hooking</p>
<p>1.1 Security Advisor </p>
<p>1.2 A simple FileMon derivate </p>
<p>2 A deep look under the hook</p>
<p>2.1 Global Assembly Cache </p>
<p>2.2 Windows Defender </p>
<p>2.3 Injection – A burden made easy </p>
<p>2.3.1 Creating an already hooked process </p>
<p>2.4 The injected library entry point </p>
<p>2.4.1 The library constructor </p>
<p>2.4.2 The library Run-Method </p>
<p>2.5 Injection helper routines </p>
<p>2.6 How to install a hook </p>
<p>2.7 How to write a hook handler </p>
<p>2.8 Using Thread ACLs </p>
<p>2.9 Using handler utilities </p>
<p>2.10 The IPC helper API </p>
<p>2.11 Guidelines for stable hooking </p>
<p>2.12 A look into the future</p>
<p>ATTENTION</p>
<p>This Guide will cover the managed part of EasyHook only. Most things also apply to the unmanaged API. Refer to the “Unmanaged API Reference” for more information. The “Managed API Reference” also contains much additional information to the stuff covered here. </p>
<p>LICENSE CHANGE</p>
<p>EasyHook is now released under the Lesser GPL instead of the MIT License.</p>
<p>ProcessMonitor Screenshot</p>
<p>The following is a screenshot of my ProcessMonitor demo, shipping with the source code and the binary package: </p>
<p>It allows you to intercept CreateFile calls of any process currently running in your system.</p>
<p>1.1 Security Advisor </p>
<p>Unlike what some (commercial) hooking libraries out there are advertising to boost sales, user-mode hooking can NEVER be an option to apply additional security checks in any safe manner. If you only want to “sandbox” a dedicated process, you know well about, and the process in fact doesn’t know about EasyHook, this might succeed! But don’t ever attempt to write any security software based on user mode hooking. It won’t work, I promise you… This is also why EasyHook does not support a so called “System wide” injection, which in fact is just an illusion, because as I said, with user-mode hooks this will always be impossible. But if you want to keep this illusion you may stick with other (commercial) libraries attempting to do so…<br />
Since EasyHook 2.5, you are able to easily hook 32-Bit kernels. Even if EasyHook would allow hooking 64-Bit kernels, I don’t recommend this because then you would get trouble with PatchGuard. Bypassing PatchGuard is possible, at least these days, but the chance of BSODing your customer’s PCs is too big. You should consider purchasing the PatchGuard API which will allow you to write security apps based on kernel mode interceptions. Kernel mode hooking (or the PatchGuard API) is the only option to apply additional security checks. Since Windows Vista, also the Windows Filtering Platform and other Vista specific APIs will be helpful to write security software!</p>
<p>So what is user-mode hooking for? In general, user-mode hooking is intended for API monitoring, like Mark Russinovich’s ProcessMonitor (alias FileMon/RegMon), resource leak detection, various malware which doesn’t need to care about security issues, extending applications and libraries you don’t have the source code for (also cracks may fall in this category), adding a compatibility layer for existing applications to run on newer OSes, etc. </p>
<p>If anyone uses security in context of user-mode hooks, your alarm bells should ring!</p>
<p>1.2 A simple FileMon derivate<br />
1.2一个简单的文件监视程序</p>
<p>To prove that EasyHook really makes hooking simple, look at the following demo application, which will log all file accesses from a given process. We need a host process which injects the library and displays file accesses. It is possible to combine injection library and host process in one file as both are just threaded as valid NET assemblies, but I think to separate them is a more consistent approach. This demo will be used throughout the whole guide:<br />
为了证明EasyHook的确让挂接变得简单,看看下面的常规应用,它会将所有给定进程的文件获取全部记录下来.我们需要一个托管进程将库注入并显示文件访问信息.我们可能通过注入库和托管进程在一个文件中结合并作为有效的NET程序集,但我想还是把它们分开更协调一点，该演示会在整个指南中使用。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</pre></td><td class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">using</span> <span style="color: #008080;">System</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Collections.Generic</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Runtime.Remoting</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Text</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Runtime.InteropServices</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">EasyHook</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">namespace</span> FileMon
<span style="color: #000000;">&#123;</span>
<span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> FileMonInterface <span style="color: #008000;">:</span> MarshalByRefObject
<span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> IsInstalled<span style="color: #000000;">&#40;</span>Int32 InClientPID<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;文件访问监视器将被安装到目标 {0} 中.<span style="color: #008080; font-weight: bold;">\r</span><span style="color: #008080; font-weight: bold;">\n</span>&quot;</span>, InClientPID<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> OnCreateFile<span style="color: #000000;">&#40;</span>Int32 InClientPID, <span style="color: #FF0000;">String</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> InFileNames<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">for</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i <span style="color: #008000;">&lt;</span> InFileNames.<span style="color: #0000FF;">Length</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #000000;">&#123;</span>
        Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span>InFileNames<span style="color: #000000;">&#91;</span>i<span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> ReportException<span style="color: #000000;">&#40;</span>Exception InInfo<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;目标进程报告错误：<span style="color: #008080; font-weight: bold;">\r</span><span style="color: #008080; font-weight: bold;">\n</span>&quot;</span> <span style="color: #008000;">+</span> InInfo.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #000000;">&#125;</span>
  <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> Ping<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span>
<span style="color: #FF0000;">class</span> Program
<span style="color: #000000;">&#123;</span>
  <span style="color: #0600FF;">static</span> <span style="color: #FF0000;">String</span> ChannelName <span style="color: #008000;">=</span> null<span style="color: #008000;">;</span>
  <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">try</span>
      <span style="color: #000000;">&#123;</span>
        Config.<span style="color: #0000FF;">Register</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;文件访问监视类演示程序&quot;</span>, <span style="color: #666666;">&quot;FileMon.exe&quot;</span>, <span style="color: #666666;">&quot;FileMonInject.dll&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        RemoteHooking.<span style="color: #0000FF;">IpcCreateServer</span><span style="color: #000000;">&#40;</span><span style="color: #0600FF;">ref</span> ChannelName, WellKnownObjectMode.<span style="color: #0000FF;">SingleCall</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        RemoteHooking.<span style="color: #0000FF;">Inject</span><span style="color: #000000;">&#40;</span>Int32.<span style="color: #0000FF;">Parse</span><span style="color: #000000;">&#40;</span>args<span style="color: #000000;">&#91;</span><span style="color: #FF0000;">0</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span>, <span style="color: #666666;">&quot;FileMonInject.dll&quot;</span>, <span style="color: #666666;">&quot;FileMonInject.dll&quot;</span>, ChannelName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        Console.<span style="color: #0000FF;">ReadLine</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #000000;">&#125;</span>
    <span style="color: #0600FF;">catch</span><span style="color: #000000;">&#40;</span>Exception ExtInfo<span style="color: #000000;">&#41;</span>
      <span style="color: #000000;">&#123;</span>
        Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;当连接到目标时出现错误:<span style="color: #008080; font-weight: bold;">\r</span><span style="color: #008080; font-weight: bold;">\n</span>{0}&quot;</span>, ExtInfo.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></td></tr></table></div>

<p>The most complex part is the injected library which has to fulfill various requirements. We are hooking the CreateFile-API and redirecting all requests to our host process. The library will be unloaded if the host process is terminated:<br />
最复杂的部分是应用于各种需求的注入库。我们现在挂在CreateFile-API并重定向所有的请求到我们的托管进程。如果托管进程结束，库将卸载。
</pre>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
</pre></td><td class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">using</span> <span style="color: #008080;">System</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Collections.Generic</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Text</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Threading</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">System.Runtime.InteropServices</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">using</span> <span style="color: #008080;">EasyHook</span><span style="color: #008000;">;</span>
<span style="color: #0600FF;">namespace</span> FileMonInject
<span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">public</span> <span style="color: #FF0000;">class</span> Main <span style="color: #008000;">:</span> EasyHook.<span style="color: #0000FF;">IEntryPoint</span>
    <span style="color: #000000;">&#123;</span>
        FileMon.<span style="color: #0000FF;">FileMonInterface</span> Interface<span style="color: #008000;">;</span>
        LocalHook CreateFileHook<span style="color: #008000;">;</span>
        Stack Queue <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> Stack<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #0600FF;">public</span> Main<span style="color: #000000;">&#40;</span>RemoteHooking.<span style="color: #0000FF;">IContext</span> InContext, <span style="color: #FF0000;">String</span> InChannelName<span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #008080; font-style: italic;">// 连接到托管… </span>
            <span style="color: #FF0000;">Interface</span> <span style="color: #008000;">=</span> RemoteHooking.<span style="color: #0000FF;">IpcConnectClient</span><span style="color: #000000;">&#40;</span>InChannelName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
        <span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> Run<span style="color: #000000;">&#40;</span>RemoteHooking.<span style="color: #0000FF;">IContext</span> InContext, <span style="color: #FF0000;">String</span> InChannelName<span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #008080; font-style: italic;">// 按装挂钩… </span>
            <span style="color: #0600FF;">try</span>
            <span style="color: #000000;">&#123;</span>
                CreateFileHook <span style="color: #008000;">=</span> LocalHook.<span style="color: #0000FF;">Create</span><span style="color: #000000;">&#40;</span>LocalHook.<span style="color: #0000FF;">GetProcAddress</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;kernel32.dll&quot;</span>, <span style="color: #666666;">&quot;CreateFileW&quot;</span><span style="color: #000000;">&#41;</span>, <span style="color: #008000;">new</span> DCreateFile<span style="color: #000000;">&#40;</span>CreateFile_Hooked<span style="color: #000000;">&#41;</span>, <span style="color: #0600FF;">this</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                CreateFileHook.<span style="color: #0000FF;">ThreadACL</span>.<span style="color: #0000FF;">SetExclusiveACL</span><span style="color: #000000;">&#40;</span><span style="color: #008000;">new</span> Int32<span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> <span style="color: #000000;">&#123;</span> <span style="color: #FF0000;">0</span> <span style="color: #000000;">&#125;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #0600FF;">catch</span> <span style="color: #000000;">&#40;</span>Exception ExtInfo<span style="color: #000000;">&#41;</span>
            <span style="color: #000000;">&#123;</span>
                <span style="color: #FF0000;">Interface</span>.<span style="color: #0000FF;">ReportException</span><span style="color: #000000;">&#40;</span>ExtInfo<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                return<span style="color: #008000;">;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #FF0000;">Interface</span>.<span style="color: #0000FF;">IsInstalled</span><span style="color: #000000;">&#40;</span>RemoteHooking.<span style="color: #0000FF;">GetCurrentProcessId</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #008080; font-style: italic;">// 等待托管进程结束… </span>
            <span style="color: #0600FF;">try</span>
            <span style="color: #000000;">&#123;</span>
                <span style="color: #0600FF;">while</span> <span style="color: #000000;">&#40;</span><span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span>
                <span style="color: #000000;">&#123;</span>
                    Thread.<span style="color: #0000FF;">Sleep</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">500</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                    <span style="color: #008080; font-style: italic;">// 传送最新监视到的文件访问… </span>
                    <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Queue.<span style="color: #0000FF;">Count</span> <span style="color: #008000;">&gt;</span> <span style="color: #FF0000;">0</span><span style="color: #000000;">&#41;</span>
                    <span style="color: #000000;">&#123;</span>
                        <span style="color: #FF0000;">String</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> Package <span style="color: #008000;">=</span> null<span style="color: #008000;">;</span>
                        <span style="color: #0600FF;">lock</span> <span style="color: #000000;">&#40;</span>Queue<span style="color: #000000;">&#41;</span>
                        <span style="color: #000000;">&#123;</span>
                            Package <span style="color: #008000;">=</span> Queue.<span style="color: #0000FF;">ToArray</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                            Queue.<span style="color: #0000FF;">Clear</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                        <span style="color: #000000;">&#125;</span>
                        <span style="color: #FF0000;">Interface</span>.<span style="color: #0000FF;">OnCreateFile</span><span style="color: #000000;">&#40;</span>RemoteHooking.<span style="color: #0000FF;">GetCurrentProcessId</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, Package<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                    <span style="color: #000000;">&#125;</span>
                    <span style="color: #0600FF;">else</span>
                    <span style="color: #000000;">&#123;</span>
                        <span style="color: #FF0000;">Interface</span>.<span style="color: #0000FF;">Ping</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                    <span style="color: #000000;">&#125;</span>
                <span style="color: #000000;">&#125;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #0600FF;">catch</span>
            <span style="color: #000000;">&#123;</span>
                <span style="color: #008080; font-style: italic;">// NET Remoting在托管不可达时会触发异常 </span>
            <span style="color: #000000;">&#125;</span>
        <span style="color: #000000;">&#125;</span>
        <span style="color: #000000;">&#91;</span>UnmanagedFunctionPointer<span style="color: #000000;">&#40;</span>CallingConvention.<span style="color: #0000FF;">StdCall</span>, CharSet <span style="color: #008000;">=</span> CharSet.<span style="color: #0000FF;">Unicode</span>, SetLastError <span style="color: #008000;">=</span> <span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
        <span style="color: #FF0000;">delegate</span> IntPtr DCreateFile<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">String</span> InFileName, UInt32 InDesiredAccess, UInt32 InShareMode, IntPtr InSecurityAttributes, UInt32 InCreationDisposition, UInt32 InFlagsAndAttributes, IntPtr InTemplateFile<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008080; font-style: italic;">// 就使用P-Invoke执行获得从C#访问原始APIC# (这一步对 C++.NET来说没必要) </span>
        <span style="color: #000000;">&#91;</span>DllImport<span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;kernel32.dll&quot;</span>, CharSet <span style="color: #008000;">=</span> CharSet.<span style="color: #0000FF;">Unicode</span>, SetLastError <span style="color: #008000;">=</span> <span style="color: #0600FF;">true</span>, CallingConvention <span style="color: #008000;">=</span> CallingConvention.<span style="color: #0000FF;">StdCall</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span>
        <span style="color: #0600FF;">static</span> <span style="color: #0600FF;">extern</span> IntPtr CreateFile<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">String</span> InFileName, UInt32 InDesiredAccess, UInt32 InShareMode, IntPtr InSecurityAttributes, UInt32 InCreationDisposition, UInt32 InFlagsAndAttributes, IntPtr InTemplateFile<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008080; font-style: italic;">// 这里就是所有文件访问截取的地方! </span>
        <span style="color: #0600FF;">static</span> IntPtr CreateFile_Hooked<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">String</span> InFileName, UInt32 InDesiredAccess, UInt32 InShareMode, IntPtr InSecurityAttributes, UInt32 InCreationDisposition, UInt32 InFlagsAndAttributes, IntPtr InTemplateFile<span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
            <span style="color: #0600FF;">try</span>
            <span style="color: #000000;">&#123;</span>
                Main <span style="color: #0600FF;">This</span> <span style="color: #008000;">=</span> <span style="color: #000000;">&#40;</span>Main<span style="color: #000000;">&#41;</span>HookRuntimeInfo.<span style="color: #0000FF;">Callback</span><span style="color: #008000;">;</span>
                <span style="color: #0600FF;">lock</span> <span style="color: #000000;">&#40;</span><span style="color: #0600FF;">This</span>.<span style="color: #0000FF;">Queue</span><span style="color: #000000;">&#41;</span>
                <span style="color: #000000;">&#123;</span>
                    <span style="color: #0600FF;">This</span>.<span style="color: #0000FF;">Queue</span>.<span style="color: #0000FF;">Push</span><span style="color: #000000;">&#40;</span>InFileName<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
                <span style="color: #000000;">&#125;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #0600FF;">catch</span>
            <span style="color: #000000;">&#123;</span>
            <span style="color: #000000;">&#125;</span>
            <span style="color: #008080; font-style: italic;">// 调用原始的API… </span>
            <span style="color: #0600FF;">return</span> CreateFile<span style="color: #000000;">&#40;</span>InFileName, InDesiredAccess, InShareMode, InSecurityAttributes, InCreationDisposition, InFlagsAndAttributes, InTemplateFile<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #000000;">&#125;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></td></tr></table></div>

<p>Even if this might look strange, the next chapters will explain what is done there and why. You may start this application with a user defined target process ID as one and only parameter from command line. I recommend using the PID of “explorer.exe” because this will immediately produce output! Just browse your file system while running the FileMon utility:<br />
即使看上去挺奇怪，下一章将解释来龙去脉。你可以使用一自定义的进程ID启动该程序，只需要一个参数。我建议使用”exploerer.exe”进程，因为他很快就会有输出。只要在命令行上这样运行程序即可：<br />
Command line utility-> FileMon.exe %PID% </p>
<p>It is also possible to output the whole thing into a file what might provide more convenience:<br />
也可以这样输出放到一个文件中：<br />
Command line utility-> FileMon.exe %PID% > “C:\MyLog.txt” </p>
<p>2 A deep look under the hook<br />
深入查看挂钩</p>
<p>Now that you have seen the basic ideas of EasyHook and some sample code, we should start to discover what is really going on under the hood. In this chapter you will learn how to utilize most parts of the EasyHook API, injecting libraries into any process and hooking any API you want.<br />
现在你已经看到EasyHook的一些基本思想和一些示例代码,我们开始看看到底是怎么回事.这一章你会学到怎样用EasyHook API的主要部分，把库注入到任何进程和挂接任何你想要的API。<br />
2.1 Global Assembly Cache<br />
全局程序集缓存</p>
<p>Currently EasyHook is expecting every injected assembly including all of its dependencies in the Global Assembly Cache (GAC). This is because the CLR will only search for assemblies in directories relative to the current application base directory and the GAC and therefore a target process normally has no access to EasyHook or your injected library. EasyHook is using a reference counter to make sure that multiple installations of the same assemblies from different applications can be managed. The following will register all EasyHook components and the two user assemblies required for injection in the GAC. The first parameter is just an uninterpreted string which should describe what your service is doing. All further parameters are expected to be relative/absolute file paths referring to all assemblies that should be temporarily registered in GAC. Please note that only strongly named assemblies are accepted.<br />
当前 EasyHook是怀着每个注入程序集包括所有的组件都在全局程序集缓存中(GAC).这是因为CLR将只在与当前应用主目录相关的当前目录程序集和GAC中搜索程序集,而GAC因此一个目标进程通常不能在你注入库中访问EasyHook.EasyHook正使用引用计数确定同一程序集不同的应用能被管理和安装。以下将注册所有的EasyHook组件和两个所需注入的用户程序集到GAC中。首先暂时在GAC中注册。请注意，只有强命名应用才可以。<br />
Config.Register(</p>
<p>“文件访问监视类演示程序.”,</p>
<p>“FileMon.exe”,</p>
<p>“FileMonInject.dll”); </p>
<p>It is guaranteed that your libraries will be removed from GAC if the injecting process is being terminated in all common cases. Of course there are some rare exceptions, for example if you shutdown your PC by disconnecting the power cable. In such a case the assemblies will remain in the GAC, forever, which is no bad thing in end-user scenarios but truly during development. You may use the Gacutil.exe that ships with Visual Studio to remove all temporary GAC assemblies.<br />
当注入进程在所有普通情况下终止时保证你的库会从GAC中移除。当然会有很少的异常情况，例如，直接停电导致你的电脑关闭。这时程序集还会在GAC中，这在最终用户的情况下也不怎么糟，但在开发时不大好。你可以使用Visual Stuido的Gacutil.exe工具卸除所有临时的GAC程序集。<br />
Open the “Visual Studio Command Promt” as administrator.<br />
以管理员身份打开“Visual Studio 命令行工具”<br />
Run the command: gacutil /uf EasyHook<br />
运行命令:gacutil /uf EasyHook</p>
<p>Run additional commands for each of your assemblies that should be removed from the GAC…<br />
运行其它需要移徐出GAC程序集的命令。</p>
<p>2.2 Windows Defender<br />
Windows防火墙</p>
<p>Injection will sometimes make the Windows Defender complain. This does not only apply to EasyHook, but to every library using remote thread creation for injection:<br />
注入有时会导至Windows防火墙的警告。这不仅仅是对EasyHook，几乎使用远程线程注入的所有库都会这样：<br />
Windows Defender Real-Time Protection agent has detected changes.</p>
<p>Microsoft recommends you analyze the software that made these changes</p>
<p>for potential risks. You can use information about how these programs</p>
<p>operate to choose whether to allow them to run or remove them from your</p>
<p>computer. Allow changes only if you trust the program or the software</p>
<p>publisher. Windows Defender can’t undo changes that you allow.</p>
<p>For more information please see the following:</p>
<p>Not Applicable</p>
<p>Scan ID: {44726E79-4262-454E-AFED-51A30D34BF67}</p>
<p>User: Lynn-PC\Lynn</p>
<p>Name: Unknown</p>
<p>ID: </p>
<p>Severity ID: </p>
<p>Category ID: </p>
<p>Path Found: process:pid:864;service:EasyHook64Svc;file:D:\Projects\EasyHook 2.0.0.0\Debug\x64\EasyHook64Svc.exe</p>
<p>Alert Type: Unclassified software</p>
<p>Detection Type:</p>
<p>Such warnings are immediately followed by information pointing out that Windows Defender has prevented a malicious attempt. I think this will vanish if you sign all executable binaries of EasyHook with AuthentiCode. Such blocking only occurs when injecting into essential system services.</p>
<p>2.3 Injection – A burden made easy<br />
2.3注入-负担变得简单了</p>
<p>In general, library injection is one of the most complicated parts of any hooking library. But EasyHook goes further. It provides three layers of injection abstraction and your library is the fourth one. The first layer is pure, relocatable assembler code. It launches the second layer, an unmanaged C++ method. The assembler code itself is really stable. It provides extensive error information and is able to unload itself without leaving any resource leaks in the target. The C++ layer starts the managed injection loader and adjusts the target’s<br />
PATH variable by adding the injecting process’ application base directory as first entry. This way you will have access to any file you would also have access to from your injecting process. The managed injection loader uses NET Reflection and NET Remoting to provide extensive error reports in case of failure and to find a proper entry point in your injection library. It also cares about graceful hook removal and resource cleanup. It is supported to load the same library multiple times into the same target!<br />
一般来说，库注入时所有挂接库中最复杂的部分。但是EasyHook让他不一样了。它提供了注入抽像的三个层而你的库在第四个。第一层是纯的汇编代码。它运行第二层，非托管的C++方法。汇编代码本身相当稳定。它提供很多的错误信息并能够将自己在目标中卸除不会留下资源泄露。C++层开始管理注入装载器并调整目标路径变量，通过添加进程应用主目录作为第一个入口。这样你可能访问任何你被注入进程能够访问的任何文件。托管的注入装载器使用NET反射和Net Remoting进供很多的在出错时的错误报告并发现在你注入库中的正确的入口点。它还关注挂钩的移除和资源的清除。它支持将同一个库多次的装入到同一目标中！<br />
Another complex part is run on host side. It is supported to inject libraries into other terminal sessions, system services and even through WOW64 boundaries. To you, all cases seem the same. EasyHook will automatically select the right injection procedure. If EasyHook has succeeded injection, you can be 99% sure that your library has been successfully loaded and executed. If it fails you can be 99% sure that no resource leaks are left in the target and it remains in a stable, hookable state! Nearly all possible failures are being caught and it would be like a lottery win to see a target getting crashed by library injection!<br />
另一个复杂的疗分时在托管这边运行。它支持将库注入到其它终端会话，系统服务甚至WOW64边界。对你来说，所以有情况都是一样。EasyHook可以自动的选择正确的注入进程。如果EasyHook成功 注入，你可99%确定你的库成功装载并运行。如果失败，则99%确保隐定和不泄露。几乎所有可能的错误都能被捕捉到，如果注入失败那时您摸彩中奖了。</p>
<p>Please note that Windows Vista has advanced security for its subsystem services. They are running in a protected environment like the “Protected Media Path”. It is not possible to hook such services with EasyHook or any other user-mode library.<br />
The following shows the API method that we are talking about:<br />
RemoteHooking.Inject(</p>
<p>Int32.Parse(args[0]),</p>
<p>“FileMonInject.dll”, // 32-Bit version</p>
<p>“FileMonInject.dll”, // 64-Bit version</p>
<p>ChannelName); </p>
<p>The first four parameters are required. If you only want to hook either 32- or 64-Bit targets, you can set the unused path to null. You may either specify a file path that EasyHook will automatically translate to a full qualified assembly name or a partial assembly name like “FileMonInject, PublicKeyToken = 3287453648abcdef”. Currently there is only one injection option preventing EasyHook from attaching a debugger to the target but you should only set this option if the target does not like an attached debugger. EasyHook will detach it before injection is completed so in general there is nothing to worry about and it increases injection stability about magnitudes by using the target symbol addresses instead of assuming that the local ones remain valid in the target!</p>
<p>You can pass as many additional parameters as you like but be aware of that you shall only pass types that are accessible through GAC, otherwise the injected library is not able to deserialize the parameter list. In such a case the exception will be redirected to the host process and you may catch it with a try-catch statement around RemoteHooking.Inject. That’s one of the great advantages! </p>
<p>The injected library will automatically get access to all additional parameters you specify after the fourth one. This way you can easily pass channel names to the target so that your injected library is able to connect to your host.<br />
Attention</p>
<p>Keep in mind that the CLR will unload your library only if the target is being terminated. Even if EasyHook releases all associated resources much earlier, you won’t be able to change the injected DLL which implies that the corresponding GAC library is not updateable until the target is terminated. So if you need to change your injected library very frequently (during development) you should always terminate the target after each debugging session. This will ensure that no application depends on the library and it can be removed from the GAC.</p>
<p>2.3.1 Creating an already hooked process<br />
2.3.1创建一个已经存在的挂钩进程</p>
<p>Sometimes it is necessary to hook a process from the beginning. This is no big deal, just call<br />
RemoteHooking.CreateAndInject instead of Inject. This will execute your library main method before any other instruction. You can resume the newly created process by calling RemoteHooking.WakeUpProcess from your injected library Run method. This only makes sense in conjunction with CreateAndInject, otherwise it will do nothing.<br />
有时需要在进程开始时挂接。这没有什和大不了。不用注入调用RemoteHooking.CreateAndInject 即可。这会在其它指令前执行你的库主方法。你可继续通过调用 RemoteHooking.WakeUpProcess 最新创建的进程从你注入库运行方法中。这只在CreatAndJnject 连接时有意义，不然没什么用。<br />
2.4 The injected library entry point<br />
注入库入口点</p>
<p>All injected libraries have to export at least one public class implementing the<br />
EasyHook.IEntryPoint interface. The interface itself is empty but identifies your class as entry point. A class marked as entry point this way, is expected to export an instance constructor and a Run instance method having the signature “void Run(IContext, %ArgumentList%)” and “.ctor(IContext, %ArgumentList%)”. Please note that “%ArgumentList%” is a placeholder for additional parameters passed to RemoteHooking.Inject. The list is starting with the fifth parameter you passed to Inject and will be passed to both, the constructor and Run. The list is not passed as array but as expanded parameter list. For example if you called Inject(Target, Options, Path32, Path64, String, Int32, MemoryStream), then %ArgumentList% would be “String, Int32, MemoryStream” and your expected Run signature “void Run(IContext, String, Int32, MemoryStream)”. EasyHook enforces strict binding which means that the parameter list is not casted in any way. The types passed to Inject shall be exactly the same as in the Run signature. I hope this explains it.<br />
The next thing to mention is that you should avoid using static fields or properties. Only if you know for sure that it is not possible having two instances of your library in the same target simultaneously, you can safely use static variables!<br />
所有注入库都必须导出至少一个公共类执行 EasyHook.IEntryPoint 接口。该接口本身是空的但将把你的类确定为入口。 一个类通过这种方法标记为入口点，认为导出实例构造并有一个RUN实例方法有着签我 “void Run(IContext, %ArgumentList%)” 和 “.ctor(IContext, %ArgumentList%)”. 请注意 “%ArgumentList%” 是传入 RemoteHooking.Inject附加参数的占位符。列表开始于第五个参数传入到Inject 并传入到两者，构造函数和Run. 列表不是以数组而是以扩展参数列表传入。例如，你已调用 Inject(Target, Options, Path32, Path64, String, Int32, MemoryStream), 则 %ArgumentList% 将是 “String, Int32, MemoryStream” 并且你期待 Run 签名为 “void Run(IContext, String, Int32, MemoryStream)”. EasyHook 执行研究的绑定意味着参数列表没有在任何情况下封装。这个类型传到Inject将一模一样的传入Run签名。我希望这能解释。另一个需要提的事是你应该避免使用静态的字段和属性。只在你确保在你的库上不可能有两个相同目标同时存在实例，才可以安全使用静态变量。</p>
<p>2.4.1 The library constructor<br />
2.4.1 库构造器</p>
<p>The constructor is called immediately after EasyHook has gained control in the target process. You should only connect to your host and validate the parameters. At this point EasyHook already has a working connection to the host so all exceptions you are leaving unhandled, will automatically be redirected to the host process. A common constructor may look like this:<br />
构造器在EasyHook获得目标进程控制权时调用。你只能连接到你的托管并检验参数。这一点上EasyHook已经工作连接到托管，所以所有的异常都没有处理，并自动重定向到托管进程。一个普通的构造象这样：</p>
<p>public class Main : EasyHook.IEntryPoint<br />
{<br />
  FileMon.FileMonInterface Interface;<br />
  LocalHook CreateFileHook;<br />
  Stack Queue = new Stack();<br />
  public Main(RemoteHooking.IContext InContext, String InChannelName)<br />
  {<br />
    // 连接到托管…<br />
    Interface = RemoteHooking.IpcConnectClient(InChannelName);<br />
    // 检查连接…<br />
    Interface.Ping...<br />
  }<br />
}</p>
<p>2.4.2 The library Run-Method<br />
2.4.2 库的Run方法<br />
The Run method can be threaded as application entry point. If you return from it, your library will be unloaded. But this is not really true  . In fact your library stays alive until the CLR decides to unload it. This<br />
behavior might change in future EasyHook versions by utilizing the CLR Hosting API, but currently we simply don’t know about!<br />
Run方法能作为应用入口点线程。如果从它近回，库将卸除。但这不是这样。实际上，你的库会直到CLR决定卸除时才终止。这会在以后的版本中通过使用CLR托管API改烃，现在不要关心它就行了。 </p>
<p>In contrast to the constructor, your Run method has no exception redirection. If you leave any exception unhandled, it will just initiate the usual unload procedure. In debug versions of EasyHook, you will find such unhandled exceptions in event logs. You should install all hooks and notify your host about success, what might look like this:<br />
同构造器相比，你的RUN方法没有格外的重定向。如果你有没处理的异常，则会初始化通常的卸除进程。在EasyHook的调试版本，你会发现未处理的异常在事件日志中。你可以安装所有的挂钩并通知你的托管是否成功，看起来就象这样：</p>
<p>public void Run(RemoteHooking.IContext InContext, String InChannelName)<br />
{<br />
// 按装挂钩…<br />
  try<br />
    {<br />
      CreateFileHook = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"), new DCreateFile(CreateFile_Hooked), this);<br />
      CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });<br />
    }<br />
  catch(Exception ExtInfo)<br />
    {<br />
      Interface.ReportException(ExtInfo);<br />
      return;<br />
    }<br />
  Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());<br />
  // 等待托管进程结束…<br />
  try<br />
    {<br />
      while(true)<br />
        {<br />
          Thread.Sleep(500);<br />
          // 传送最新监视到的文件访问…<br />
          if(Queue.Count > 0)<br />
            {<br />
              String[] Package = null;<br />
              lock(Queue)<br />
              {<br />
                Package = Queue.ToArray();<br />
                Queue.Clear();<br />
              }<br />
              Interface.OnCreateFile(RemoteHooking.GetCurrentProcessId(), Package);<br />
            }<br />
          else<br />
            {<br />
              Interface.Ping();<br />
            }<br />
        }<br />
    }<br />
  catch<br />
  {<br />
    // NET Remoting在托管不可达时会触发异常<br />
  }<br />
}</p>
<p>The loop simply sends the currently queued files accesses to the host process. If the host process is being terminated, such attempts throw an exception which causes the CLR to return from the Run method and automatically unload your library!<br />
循环部分简单的发送当前排对文件访问到托管进程。如果托管进程结束，这个偿试会抛出异常将导至CLR从RUN方法返回并自动卸除你的库。</p>
<p>2.5 Injection helper routines</p>
<p>There are several methods that you will find useful when dealing with injection.<br />
在处理注入时有几个比较有用的方法。<br />
To query if the current user is administrator, you can use<br />
RemoteHooking.IsAdministrator. Please note that injection will fail in most cases if you don’t have admin privileges! Vista is using the UAC for evaluating to admin privileges and so you should read some MSDN articles about how to utilize it.<br />
查看肖前用户是不是系统管理员，可以使用<br />
RemoteHooking.IsAdministrator. 注意如果你没有管理权限，注入常常会失入。Vista使用UAC确定管理权限，所以你可以阅读MSDN看看怎么用。</p>
<p>If you already are admin, you may use the<br />
RemoteHooking.ExecuteAsService method to execute a given static method under system privileges without the need to start a service. This is potentially useful when enumerating running processes of all sessions or for any other information querying task, which might require highest privileges. Keep in mind that the static method will be executed within a system service. So any handle or other process related information will be invalid when transmitted back into your process. You should design such a method so that you retrieve all information and store it in a serializable, process independent form. This form shall be an object that is returned and this way sent back to your application by NET Remoting.<br />
如果你已经是管理员，可可以使用 RemoteHooking.ExecuteAsService 方法在系统权限下执行静态方法而不需要启动服务。这在其它信息查询任务中列举所有会活的运行进程会有用，这会需要较高的权限。记住静态方法可以作为系统服务执行。所以任何其它相关进程信息当传回你的进程时都有效。你可以设计这样的方法来获得所有的信息并存在序列化的进程独立的表单中。该表单会是一个对象返回，并通过Net Remoting发到您的应用中。</p>
<p>If you want to determine whether a target process is 64-Bit or not, you may use<br />
RemoteHooking.IsX64Process. But be aware of that you need PROCESS_QUERY_INFORMATION access to complete the call. It will also work on 32-Bit only Windows versions like Windows 2000, of course, by returning false in any case.<br />
Further there are<br />
RemoteHooking.GetCurrentProcessId and GetCurrentThreadId which might help to query the real native values in a pure managed environment! Managed thread IDs don’t necessarily map to native ones, when thinking about the coming NET 4.0.<br />
2.6 How to install a hook<br />
2.6如何安装挂钩</p>
<p>To install a hook you are required to pass at least two parameters. The first one is the entry point address you want to hook and the second one is the delegate where calls should be redirected to. The delegate shall have the </p>
<p>UnmanagedFunctionPointerAttribute and also the exact call signature as the corresponding P-Invoke implementation. The best way is to look for a well tested P-Invoke implementation already out in the net and just make a delegate out of it. The managed hook handler also has to match this signature what is automatically enforced by the compiler… A P-Invoke implementation with the DllImportAttribute may be used to call the original API within the handler which will be necessary in most cases. Don’t forget that most APIs are expected to SetLastError in case of failure. So you should set it to ERROR_ACCESS_DENIED or ERROR_INTERNAL_ERROR for example if your code does not want to execute the call. Otherwise external code might behave unexpected!<br />
A third parameter provides a way to associate an uninterpreted callback object with the hook. This is exactly the object accessible through<br />
HookRuntimeInfo.Callback later in the handler.<br />
要安装挂钩你需要传送至少两个参数。第一个你想挂接的入口地址而第二个是你想调用重定向的代理。代理需要有UnmanagedFunctionPointerAttribute 并要有正确的与相应P-Invode执行相对应的调用签名。最好的方法是找一个测试好的P-Invoke执行，而只是代理一下。托管的挂钩处理还有相应的自动的编译指定的签名…一个用 DllImportAttribute 执行可以在大多情况行用句柄调用原命名API。不要忘了很多API都在错误时需要SetLastError 。所你你应将它设为第三个参数提供一个解释回调挂钩的方法。这就是对象通过HookRuntimeInfo.Callback 在句柄中访问的地方。</p>
<p>To uninstall a hook just remove all references to the object obtained during creation. To prevent it from being uninstalled you have to keep the reference of course… This is always a delayed removal because you won’t know when a hook is finally removed and your handler is never called again. If you want to remove it immediately you have to call<br />
LocalHook.Dispose like known from dealing with unmanaged resources as file streams are.<br />
要卸载挂钩只要将所有创建对象的引用删除即可。当然，要不被卸除，只要保存这些引用即可…<br />
The following code snipped is an example of how to install a hook that is excluding the current thread from being intercepted:</p>
<p>CreateFileHook = LocalHook.Create(<br />
                   LocalHook.GetProcAddress(”kernel32.dll”, “CreateFileW”),<br />
                   new DCreateFile(CreateFile_Hooked),<br />
                   this);<br />
CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[] {0});</p>
<p>EasyHook also does provide a way to install pure unmanaged hooks using<br />
LocalHook.CreateUnmanaged. You may write them using C++.NET that allows you to combine managed and unmanaged code. But keep in mind that you won’t have access to the HookRuntimeInformation class. You would need to directly call the unmanaged API available since EasyHook 2.5, to access runtime information from unmanaged code.<br />
But, all protection mechanisms (see next paragraph) will still wrap around your unmanaged code. An empty unmanaged hook is about magnitudes faster than an empty managed one. If your handler once has gained execution, both are running with the same speed. The costly operation is the switch from unmanaged to managed environment and vice versa, which is not required when using pure unmanaged hooks! So your handler will be invoked in approx. 70 nanoseconds whereas a managed handler requires up to some microseconds… In some scenarios you will need this speed gain and this is why EasyHook offers it.</p>
<p>2.7 How to write a hook handler<br />
2.7怎样写一个挂钩处理</p>
<p>Until now there was nothing complicated and I hope you agree. But writing a hook handler is something very strange. EasyHook already does provide several mechanisms to make writing hook handlers much easier or let’s say possible at all:<br />
A Thread Deadlock Barrier (TDB) which will allow you and any subcalls to invoke the hooked API from within its handler again. Normally this would lead into a deadlock because the handler would invoke itself again and again. EasyHook will prevent such loops! This also provides the advantage that you don’t need to keep track of a clean entry point. </p>
<p>An OS loader lock protection which will prevent your handler from being executed in an OS loader lock and in case of managed handler code attempting so would crash the process! </p>
<p>A Thread ACL model allowing you to exclude well known dedicated threads, used to manage your hooking library (for example threads that are communicating with your host), from being intercepted. Refer to the chapter “Guidelines for stable hooking”, to learn about the differences and why the TDB is not enough! </p>
<p>A mechanism to provide hook specific callbacks through a static class named HookRuntimeInfo. This way you are able to access the library instance without using a static variable for example. </p>
<p>Additionally since EasyHook 2.5, you may generate call stack traces; determine the calling module, the handler return address, the address of this return address, etc. </p>
<p>Without some of the above mechanisms it would be simply impossible to use managed code as hook handler and this is what is unique to EasyHook. All of those mechanisms are very stable and heavily tested with hundred simultaneous threads executing hundred thousands of hooks (on a quad-core CPU). And the best thing is that all of them are also available in kernel-mode.</p>
<p>Using a hook handler you can simply provide your own implementation for the hooked API. But you should read and understand the related API documentation in detail, to provide the correct behavior for external code. If it is possible you should handle an interception as fast as possible and negotiate access or whatever within the injected library. Only in rare cases you should redirect calls to the host application in a synchronous manner as this will heavily slow down the hooked application; for example if an access negotiation can’t be completed with the knowledge of the library. In a real world application you should queue all requests and transmit them periodically as an array and not every single call. This can be done like it is shown in the FileMon demo.<br />
使用挂够处理你可以简单的为你挂接的API添加你自己的处理，但是你要详细理解和阅读相应的API文档。以提供外部代码正确的行为。</p>
<p>Keep in mind that if you are compiling for 64-Bit or AnyCPU, you have to use the right type replacements. For example<br />
HANDLE does NOT map to Int32, but to IntPtr. In case of 32-Bit this is not important but when switching to 64-Bit a handle is 64-Bit wide, like IntPtr. A DWORD in contrast will always be 32-Bit as its name implies.<br />
The following is an example hook handler as used in the FileMon demo:</p>
<p>// 这里就是所有文件访问截取的地方!<br />
static IntPtr CreateFile_Hooked(String InFileName, UInt32 InDesiredAccess, UInt32 InShareMode, IntPtr InSecurityAttributes, UInt32 InCreationDisposition, UInt32 InFlagsAndAttributes, IntPtr InTemplateFile)<br />
{<br />
  try<br />
    {<br />
      Main This = (Main)HookRuntimeInfo.Callback;<br />
      lock(This.Queue)<br />
      {<br />
        This.Queue.Push(InFileName);<br />
      }<br />
    }<br />
  catch<br />
  {<br />
  }<br />
// 调用原始的API…<br />
return CreateFile(InFileName, InDesiredAccess, InShareMode, InSecurityAttributes, InCreationDisposition, InFlagsAndAttributes, InTemplateFile);<br />
}</p>
<p>You may wonder about the queue limitation of 1000. The problem is that both demo applications were not designed to handle huge amounts of interceptions. I had Tortiose SVN installed and this caused my explorer to raise hundred thousands of pipe accesses. For my surprise, IPC and the injected library have no problems in dealing with that much data, but the ProcessMonitor blocked with 100% CPU usage while trying to add about 300.000 entries to the data grid. I suppose FileMon would react equally, because it will take a while to write 300.000 console lines. As the overall remote hooking mechanism seems to be stable even in such high performance scenarios, it just depends on your host application whether you can handle it or not. To keep things simple, both demos are NOT able to handle high-performance scenarios!<br />
Thus, if your host application is fast enough, you can safely remove the queue limitation.<br />
何能能奇怪对列限制为1000。这是因为演示不想处理大量的交互。</p>
<p>2.8 Using Thread ACLs</p>
<p>EasyHook manages a global<br />
ThreadACL and also an ACL for every hook. Further each ACL can either be inclusive or exclusive. This allows you to compose nearly any kind of access negotiation based on thread IDs without much effort. By default EasyHook sets an empty global exclusive ACL, which will grant access for all threads, and an empty inclusive local ACL for every hook, which will finally deny access for all threads. All hooks are installed virtually suspended meaning no threads will pass access negotiation. This is to prevent hook handler invocation before you are able to initialize possible structures, like ACLs for example. To enable a hook for all threads just set its local ACL to an empty exclusive one. To enable it for the current thread only, just set a local inclusive ACL with zero as one and only entry. A thread ID of zero will automatically be replaced by the current thread ID BEFORE the ACL is set (this is negotiation will later use your thread ID and doesn’t know anything about zero). The following is a pseudo-code of IsThreadIntercepted:</p>
<p>if(ACLContains(&#038;Unit.GlobalACL, CheckID))<br />
  {<br />
    if(ACLContains(LocalACL, CheckID))<br />
      {<br />
        if(LocalACL->IsExclusive)<br />
          return FALSE;<br />
      }<br />
    else<br />
      {<br />
        if(!LocalACL->IsExclusive)<br />
          return FALSE;<br />
      }<br />
    return !Unit.GlobalACL.IsExclusive;<br />
  }<br />
else<br />
  {<br />
    if(ACLContains(LocalACL, CheckID))<br />
      {<br />
        if(LocalACL->IsExclusive)<br />
          return FALSE;<br />
      }<br />
    else<br />
      {<br />
        if(!LocalACL->IsExclusive)<br />
          return FALSE;<br />
      }<br />
    return Unit.GlobalACL.IsExclusive;<br />
  }</p>
<p>The code does nothing more than computing an intersection of the thread ID sets represented by the global and local ACL. An ACL always describes a set of threads that will be intercepted. The fact that an ACL may be inclusive or exclusive has no impact on this computation. It is just a way for you to make it easier to define a set of threads. An exclusive ACL start with ALL threads and you can specify threads that should be removed from the set. An inclusive ACL start with an empty thread set and you may specify this set manually. </p>
<p>The method returns<br />
TRUE, if the intersection of the global and local set of intercepted threads contains the given thread ID, FALSE otherwise.</p>
<p>Just play around with them and use<br />
LocalHook.IsThreadIntercepted to check whether your ACLs will provide expected access negotiation. </p>
<p>2.9 Using handler utilities</p>
<p>EasyHook exposes some debugging routines which may be extended in future versions. They are statically available through the<br />
EasyHook.LocalHook class. Currently they solve the following issues which are common when writing hook handlers:<br />
Translate a thread handle back to its thread ID (requires the handle to have THREAD_QUERY_INFORMATION access). </p>
<p>Translate a process handle back to its process ID (requires the handle to have PROCESS_QUERY_INFORMATION access). </p>
<p>Query kernel object name for any given handle. This way you are able to convert a file handle obtained by CreateFile back to its file name. This will even work if the handle has no access to anything! </p>
<p>In contrast to EasyHook 2.0, the latest version does not require a debugger for any of the handler utilities. The only thing is that a debugger is still required to relocate RIP-relative addresses. By default a debugger is disabled. To get support for RIP relocation (which is in general not necessary for the Windows API), just call LocalHook.EnableRIPRelocation before hook installation. </p>
<p>Additionally EasyHook 2.5 exposes the<br />
HookRuntimeInformation class, which provides handler-specific support routines:<br />
Query ReturnAddress, query AddressOfReturnAddress, generate managed/unmanaged module stack backtrace, query calling managed/unmanaged module and the callback specified during hook creation. </p>
<p>Setup a proper stack frame to allow exception throwing and custom stack traces. EasyHook technically would make such a stack trace impossible, but since version 2.5 the stack image can be restored for a defined code section to get rid of this issue. </p>
<p>2.10 The IPC helper API</p>
<p>The core part of any target-host scenario is IPC. With NET remoting this has become really amazing. As you can see in the FileMon demo it is a thing of two lines to setup a stable, fast and secure IPC channel between the injected library and host. Of course this is only possible with the IPC helper routines exposed by EasyHook. Using the native<br />
IpcChannels the code blows up to three A4 pages which is still quiet small. The helper routines will take care of serialization setup and channel privileges so that you can even connect a system service with a normal user application running without admin privileges. It also offers to generate a random port name. This service should always be used because it is the only way to get a connection secure! If you want to provide your own name, you also have to specify proper well known SIDs, which are allowed to access the channel. You should always specify the built in admin group in this case, because all admin users could crash the whole system so you don’t have to worry about being exploited by an admin!</p>
<p>To create a server with a random port name, just call:</p>
<p>String ChannelName = null;<br />
RemoteHooking.IpcCreateServer(ref ChannelName,  WellKnownObjectMode.SingleCall);</p>
<p>Pass the generated port name to the client and call:<br />
FileMon.FileMonInterface Interface =  RemoteHooking.IpcConnectClient(InChannelName);</p>
<p>From now on you are able to call the server by using the client instance of the returned underlying<br />
MarshalByRefObject and those calls will be automatically redirected to the server. Isn’t that great?! But be aware of that this will only apply to instance members! Static members and fields will always be processed locally…</p>
<p>2.11 Guidelines for stable hooking</p>
<p>Even if EasyHook provides a new dimension of API hooking, there are still several things that you should know about, before starting to write your own handlers. The TDB will protect you from per thread deadlocks but during hooking you will often run into multi-thread deadlocks which are covered here.<br />
Scenario 1</p>
<p>Imagine you would rewrite the FileMon demo sending the intercepted call directly to the target, without going through any asynchronous queue. Even if this might look correct, because the TDB should take care of it, there is indeed a big bug in it. The issue is not within your code itself but within the code your code is calling. And that is nearly always the source of bugs in hook handlers. </p>
<p>The problem is within NET Remoting. You already established a connection before hook installation and this is why the above approach, directly sending the interceptions back to the host, might initially work. But from time to time the CLR will reconnect to the host using<br />
CreateFile. This wouldn’t be messy because the TDB would take care of it, but obviously NET Remoting does it in a queued worker item. This will call CreateFile in another thread while the intercepted one is waiting for it to complete. But because it is executed in another thread, it is also intercepted again. The CLR is still not connected and will start the whole procedure again and again until the worker item queue is full and no further threads are available. This is the time where the target will hang.</p>
<p>Of course I am only speculating because I don’t know about the internals of NET Remoting, but this deadlock will occur! Someone might say that a solution would be to call the original API before sending the interception back to the host and maybe it would be, but keep in mind how easy our hook handler was and this simple deadlock scenario can easily apply to any complex one which you can’t solve this way. It was just to show you the basic idea…<br />
Scenario 2</p>
<p>We now have learned and would never make the above mistake again, would we? Let’s say we are using a dedicated thread to send our queued interceptions to our host. The Stack class will usually be a good choice and to make our code thread safe, we are using a lock, which we are entering once to transmit the stack content and once to add a new interception from within our hook handler. </p>
<p>Now the following happens. To send the result back to our host, the dedicated thread might call CreateFile again while holding the lock. If NET Remoting would use the same thread to call this API, the recursive lock capabilities of Monitor::Enter and the TDB would do their part and prevent any deadlock. But sometimes NET Remoting will use another thread and as we are already holding the lock it could never enter it. Of course you can again solve this by just filling a temporary buffer in the lock and send the result back outside, like done in the FileMon demo.</p>
<p>A universal solution</p>
<p>What we have learned? Writing stable hook handlers is not only a matter of a good hooking library like EasyHook, but also a matter of experiences with windows API programming and issues that will show up in your own applications. Be careful when dealing with multi-thread code because the TDB won’t fully protect you in this case. Don’t call APIs or NET members which internally are using or waiting for other threads to complete. If you need to do this, use dedicated threads and exclude them from being intercepted. By the time you will write more and more stable hook handlers and don’t worry about the very beginnings where things will cause the targets to crash or hang. With EasyHook you got a great utility in your hands, the rest depends on you!</p>
<p>Another side-effect that you should know about occurs when dealing with NET Remoting, again, is that you are usually implementing the shared class in the host application. This will cause the CLR to load your host assembly and initialize all associated static variables in related classes. This is why you shouldn’t initialize any static variables in classes that are associated with ones used as remote interface.</p>
<p>2.12 A look into the future</p>
<p>With the latest version “EasyHook 2.5 Beta”, all desired features are currently implemented. If you miss anything, don’t hesitate to request a new feature. I plan a first release candidate during the next two months. Please report any bug you find, otherwise a stable release candidate is not possible!</p>
<p>Currently I am working on an OpenSource clone for the mentioned ProcessMonitor available at www.microsoft.com. Mine will only use user-mode hooks to accomplish its task and should be a good example of how to write hooking applications. I plan to publish it in late August 2008.<br />
I don’t have the time to test EasyHook all day long. I will always make sure that all shipped demos and test suites are working on all supported OS versions, but that is all I can do so far. Not only in case of OpenSource, is the customer the tester. But any bug you report will be fixed soon!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/98/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EasyHook一个全新的Hook库</title>
		<link>http://blog.cuile.com/blog/archives/95</link>
		<comments>http://blog.cuile.com/blog/archives/95#comments</comments>
		<pubDate>Wed, 04 Aug 2010 08:52:49 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[编程技术]]></category>
		<category><![CDATA[easyhook]]></category>
		<category><![CDATA[hook]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=95</guid>
		<description><![CDATA[这几天重新捡起Ｄetour来看，想写个Hook wininet的程序，不过没学过Ｃ++感觉很吃力，于是在网上找 没想到找到了EasyHook，一个可能使用C#的Hook库，真是太伟大了 先在这里记下来，回去好好研究一下，嘿嘿 http://easyhook.codeplex.com/releases/view/24401]]></description>
			<content:encoded><![CDATA[<p>这几天重新捡起Ｄetour来看，想写个Hook wininet的程序，不过没学过Ｃ++感觉很吃力，于是在网上找<br />
没想到找到了EasyHook，一个可能使用C#的Hook库，真是太伟大了<br />
先在这里记下来，回去好好研究一下，嘿嘿<br />
<a href="http://easyhook.codeplex.com/releases/view/24401">http://easyhook.codeplex.com/releases/view/24401</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>编译Detours</title>
		<link>http://blog.cuile.com/blog/archives/50</link>
		<comments>http://blog.cuile.com/blog/archives/50#comments</comments>
		<pubDate>Sat, 12 Jul 2008 07:06:58 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[编程技术]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Detours]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=50</guid>
		<description><![CDATA[一直在学着做HOOK,听说过微软自己的Detours非常好用,可一直不知道该怎么用!!! 可今天,就在今天,上网看到了篇好博文,终于知道可以编译来用了(看来不是我太笨了,不过话说回来,现在好多的文章,那怕是教程都是在抄老美的技术手册,罕有实用性的中文教材出现,可悲啊!) 言归正传,编译Detours其实非常非常的简单 先下载Detours,这个不用我多说了吧,网上一搜就有. 然后安装,这个就更不用我说了吧,Windows的安装一直都是傻瓜化的. 安装vs2005或vs2008,vs2005网上可以下到,就是比较大;vs2008微软提供了免费的版本. 安装Microsoft Platform SDK,这个非常重要啊,因为有Detours里的一些库文件的引用. 起动vs2005或vs2008的命令行,找到Detours安装目录的src文件夹. 运行nmake,就可以了,还真不是一般的简单啊(我居然一直搞不明白,哭死&#8230;&#8230;). 完成之后原来Detours的目录里用多出bin,lib,include这三个目录,要用的东西就在这里了,直接在程序里引用就可以了,呵呵 PS:可能会出一些错误,反正我是没碰到,非常顺利的就搞定了 在这里给出原文地址http://zhuaxia.com/pre_channel/4940069/?logId=190]]></description>
			<content:encoded><![CDATA[<p>一直在学着做HOOK,听说过微软自己的Detours非常好用,可一直不知道该怎么用!!!</p>
<p>可今天,就在今天,上网看到了篇好博文,终于知道可以编译来用了(看来不是我太笨了,不过话说回来,现在好多的文章,那怕是教程都是在抄老美的技术手册,罕有实用性的中文教材出现,可悲啊!)</p>
<p>言归正传,编译Detours其实非常非常的简单</p>
<ol>
<li>先下载Detours,这个不用我多说了吧,网上一搜就有.</li>
<li>然后安装,这个就更不用我说了吧,Windows的安装一直都是傻瓜化的.</li>
<li>安装vs2005或vs2008,vs2005网上可以下到,就是比较大;vs2008微软提供了免费的版本.</li>
<li>安装Microsoft Platform SDK,这个非常重要啊,因为有Detours里的一些库文件的引用.</li>
<li>起动vs2005或vs2008的命令行,找到Detours安装目录的src文件夹.</li>
<li>运行nmake,就可以了,还真不是一般的简单啊(我居然一直搞不明白,哭死&#8230;&#8230;).</li>
<li>完成之后原来Detours的目录里用多出bin,lib,include这三个目录,要用的东西就在这里了,直接在程序里引用就可以了,呵呵</li>
</ol>
<p>PS:可能会出一些错误,反正我是没碰到,非常顺利的就搞定了</p>
<p>在这里给出原文地址http://zhuaxia.com/pre_channel/4940069/?logId=190</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/50/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>人类可以经由改变态度进而改变自己的生命</title>
		<link>http://blog.cuile.com/blog/archives/23</link>
		<comments>http://blog.cuile.com/blog/archives/23#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:46:47 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=23</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/23/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在人生中，拥有了信誉，就如同沙漠中的行者有了取之不尽的水源。信誉加于谁的身上，谁就会像芝兰一样芬芳。信誉如金，它既是无形的力量同，也是无形的财富。</title>
		<link>http://blog.cuile.com/blog/archives/19</link>
		<comments>http://blog.cuile.com/blog/archives/19#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:12:39 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=19</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/19/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个乐观的人是当鞋子磨破的时候，反而觉得更“脚踏实地”</title>
		<link>http://blog.cuile.com/blog/archives/17</link>
		<comments>http://blog.cuile.com/blog/archives/17#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:07:48 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=17</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/17/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>人生本在得失之间，失去了不必惋惜，得到了一定要珍惜。</title>
		<link>http://blog.cuile.com/blog/archives/27</link>
		<comments>http://blog.cuile.com/blog/archives/27#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:04:29 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>
		<category><![CDATA[人生感悟]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=27</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/27/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>与人协作也就是认识别人的价值，借用别人的价值，哪怕是在最纯粹的理论研究领域，这一点很重要。牛顿就说，他是站在巨人的肩膀上。</title>
		<link>http://blog.cuile.com/blog/archives/29</link>
		<comments>http://blog.cuile.com/blog/archives/29#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:03:30 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>
		<category><![CDATA[人生感悟]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=29</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/29/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>面对机遇和挑战，唯有不找借口的人，才有可能成为事业的成功者。</title>
		<link>http://blog.cuile.com/blog/archives/31</link>
		<comments>http://blog.cuile.com/blog/archives/31#comments</comments>
		<pubDate>Fri, 12 Aug 2005 05:01:47 +0000</pubDate>
		<dc:creator>sniper</dc:creator>
				<category><![CDATA[铭言]]></category>
		<category><![CDATA[人生感悟]]></category>

		<guid isPermaLink="false">http://blog.cuile.com/blog/?p=31</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://blog.cuile.com/blog/archives/31/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
