呵呵,我这刚好有,给你转贴一个吧。相关的我还有。Windows 95/98下屏幕抓词的原理和实现方法夏庆德 朱 虹摘 要 本文介绍了Windows 95/98下屏幕抓词的原理,对其如何获得鼠标位置的字符串,从代码拦截、鼠标HOOK、屏幕刷新等方面进行了讨论。 最后提到了涉及屏幕抓词的其它一些问题。
关键词 代码拦截,鼠标HOOK,屏幕刷新1 屏幕抓词  屏幕抓词(或者叫动态翻译)是指随着鼠标的移动,软件能够随时获知屏幕上鼠标位置的单词或汉字,并翻译出来提示用户。它对於上网浏览、在线阅读外文文章等很有帮助作用,因此许多词典软件都提供了屏幕抓词功能。
  屏幕抓词的关键是如何获得鼠标位置的字符串,Windows的动态链接和消息响应机制为之提供了实现途径。 概括地说,主要通过下面的几个步骤来取得屏幕上鼠标位置的字符串:
  . 代码拦截:Windows以DLL方式提供系统服务,可以方便地获取Windows字符输出API的地址,修改其入口代码,拦截应用程序对它们的调用。  .  鼠标HOOK:安装WH—MOUSEPROC类型的全局鼠标HOOK过程,监视鼠标在整个屏幕上的移动。
  .   屏幕刷新:使鼠标周围一块区域无效,并强制鼠标位置的窗口刷新屏幕输出。窗口过程响应WM—NCPAINT和WM—PAINT消息,调用ExtTextOut/TextOut等字符输出API更新无效区域里面的字符串。这些调用被我们截获,从堆栈里取得窗口过程传给字符API的参数,如字符串地址、长度、输出坐标、HDC、裁剪区等信息。
2 Windows 95/98的字符输出方法  Windows95/98不是一个纯32位的操作系统,它从16位操作系统发展而来,为了保持兼容,其内部仍然是32位和16位代码的混合体。系统通过gdi.exe 、user.exe和krnl386.exe提供16位API,供16位程序调用;通过gdi32.dll、user32.dll和kernel32.dll提归结如下:图1 Windows 95/98的字符输出机制  .  16位程序通过16位gdi.exe的ExtTextOut/TextOut函数输出字符;
  .  32位程序通过gdi32.dll的ExtTextOutA/TextOutA输出ANSI格式的字符,通过ExtTextOutW/TextOutW输出UNICODE格式的字符;
  .  32位的ExtTextOutA/TextOutA转换到16位的ExtTextOut/TextOut,完成ANSI格式字符的输出;
  .  32位的ExtTextOutW/TextOutW转换到16位gdi.exe的两个未公开API,完成UNICODE格式字符的输出。为方便叙述,本文对这两个未公开API称为ExtTextOut16W和TextOut16W。
  因此,只要拦截四个16位函数:TextOut、ExtTextOut、TextOut16W和ExtTextOut16W,就能截获32位和16位应用程序的所有字符串输出。 
3 拦截字符输出API3.1 代码拦截的基本思路  为了实现对ExtTextOut/TextOut等API的拦截,需要在函数入口放入一条动态生成的“JMP<替代函数>”指令,JMP的操作数是我们提供的一个拦截替代函数的地址。当该API被调用时,JMP指令首先执行,跳转到替代函数。替代函数负责从堆栈中获取参数,计算字符串坐标,分出鼠标位置的单词等工作。执行完成后,替代函数再调用原来的被拦截函数,完成正常的字符输出,然后返回。 图2表明了应用程序对TextOut的正常调用流程和TextOut被拦截后的流程。
a)① 程序调用TextOut;
② 从TextOut返回程序。① 程序调用TextOut(其入口已经被修改);
② 转入拦截替代函数myTextOut;
③ 从myTextOut调用原来的TextOut;
④ 从TextOut返回myTextOut;
⑤ 从myTextOut返回程序。图2 对TextOut的正常调用流程   和TextOut被拦截后的流程3.2 提供拦截替代函数  拦截替代函数插入被拦截API的流程中执行,需要有相同的参数和返回值原型。以对TextOut的拦截为例,下面是替代函数myTextOut的伪代码:
BOOL myTextOut(HDC hdc,int x,int y,LPSTR lpstr,int cbstr)

DoSpy(hDC,x ,y,lpstr,cbstr);
//保存参数,作抓词的所有工作
RestoreCode();//恢复TextOut入口原来的指令
TextOut(hDC,x,y,lpstr,cbstr);//调用原来的API 
SpyCode();//再次放入JMP指令
return TRUE;

  函数首先调用DoSpy()来作抓词的具体工作,然后RestoreCode()函数恢复被拦截函数入口的代码,再调用TextOut()执行正常的字符输出,接下来SpyCode()在被拦截函数入口再次放入JMP指令,最后返回调用进程。 
3.3 获取被拦截API的动态链接地址  TextOut和ExtTextOut的地址可以通过GetProcAddress取得,而TextOut16W和ExtTextOut16W既未公开于文档,也没有用字符串或序号从gdi.exe中引出,无法使用GetProcAddress取得它们的地址。下面讨论如何解决这个问题。
  第一种方法:用softICE可以跟踪发现,ExtTextOut16W位于公开函数GetTextMetrics 入口的偏移20H处,TextOut16W位于GetTextMetrics的偏移7CH处。所以可以先取得GetTextMetrics的地址,再分别在加上20H和7CH,就是ExtTextOutW和TextOutW的地址。 
  第二种方法:从指令里面析出地址。
  Windows 95/98维持一个DWORD类型的数组,称为32位-16位替换表,表中每个元素存放了一个Win32 API对应的16位API的段:偏移地址。需要转入16位运行的Win32API使用不同的索引来从该表格里面取目的地址。ExtTextOutW和TextOutW分别使用索引B2H和30H,取表中相应元素作为ExtTextOut16W和TextOut16W的地址。取得这个数组的起始位置,根据索引号即可找到16位函数的地址。由于这个数组是一个重定位项,在内存的地址不固定,所以需要从指令流里面动态析出它的地址。
3.4 动态生成JMP指令   动态生成的JMP指令占用5个字节,保存在一个数组里面。以生成跳转到TextOut的替代函数myTextOut的JMP指令为例:
BYTE ins[5]; //保存JMP指令
ins[0] = 0xea; //操作码:1 byte
*(WORD *)(ins+1) = FP—OFF(myTextOut);
 //操作数:2byte的偏移
*(WORD *)(ins+3) = FP—SEG(myTextOut);
 //操作数:2byte的段
3.5 修改被拦截函数的入口  Windows运行在保护模式下,16位进程采用了段保护机制,代码段描述符的属性被标记为只读。如果直接向被拦截函数的入口写入JMP指令,会引起CPU保护错误,因此在修改代码前要采用下面的方法绕过段保护机制:
  .  获取GDI代码段的基地址和界限;
  .  用当前DS复制一个新的段选择子,该选择子的描述符具有可读写的属性;
  .  将复制得到的选择子的基地址和界限设置为GDI代码段的基地址和界限;
  .  用新的选择子作为段,同被拦截API的偏移组合成一个新的地址。
  这样就获得了一个指向被拦截代码的可写指针。先保存5字节内容,再将数组ins[]复制到该地址,即完成对TextOut等API的拦截修改。 
4 使用HOOK监视鼠标移动  安装一个WH—MOUSEPROC类型的全局HOOK可以监视鼠标在全屏幕的移动。每当有鼠标事件产生,HOOK过程被调用,它判断出鼠标移动了后,就向主窗口发送消息,通知主窗口鼠标位置发生了变化。
  主窗口收到消息后,设置定时器,监视鼠标在某一位置停留时间的长短。如果鼠标停留超过设定的时间,才启动抓词功能,否则抓词功能保持禁止状态。这样可以减少代码拦截对系统性能的影响。
  全局HOOK过程需要放入DLL里面。
5 刷新屏幕输出  预先创建一个小的工具窗口,当鼠标停留在某个位置超过设定时间后,使工具窗口在鼠标位置上显示一下,然后隐含掉,这样就会在目标窗口——鼠标位置的窗口产生无效区域。然后调用UpdateWindow强制目标窗口刷新屏幕输出。在响应WM—PAINT /WM—NCPAINT中,目标窗口对字符输出API的调用将被我们截获和处理,完成一次抓词过程。
6 其它  本文所介绍的Windows 95/98环境下屏幕抓词的原理和取得鼠标位置字符串的实现方法。对于进一步的探索,笔者提出下面的几点看法:
  .  只有通过响应WM—PAINT /WM—NCPAINT消息输出的字符串才会被捕捉到;
  .  有些软件(例如Internet Explorer)在刷新屏幕时,为了消除闪烁,不直接把字符串输出到屏幕DC,而是创建一个兼容的内存DC,先将字符串写到内存DC,再复制到屏幕上去。由于内存DC坐标和屏幕DC坐标的不同,不能直接依赖内存DC的坐标来计算字符串的屏幕位置;
  .  本文讨论的方法不适用于Windows NT下的抓词。Windows NT的系统功能完全由32位代码提供,NT下的抓词需要拦截Win32 API。其实现机制同在Windows 95/98下也不一样。在NT里,KERNEL、USER、GDI模块位於进程的私有地址空间内,所以需要使用HOOK来将拦截替代函数动态映射到不同的被拦截进程的地址空间里面。而且由于控制台窗口禁止大多数HOOK,还需要创建远程线程来获取控制台窗口的字符输出。
 

解决方案 »

  1.   

    方法1。必须写DLL工程,而且该DLL必须能够映象到系统进程空间即2G以上,取修改系统的DLL
    方法2。写DLL用setwindowhook映象到被截取的进程空间,把调用API该为调用自己的函数
      

  2.   

    我Kao,回答N次了,代码都有了,不搜索先?关键字:屏幕取词,金山词霸,APIHOOK
      

  3.   

    to: Kingron
    资料到有不少,代码还没挖掘到,你有代码(Delphi)的话就贴出来,分全给你!
      

  4.   

    看贴:
    http://expert.csdn.net/Topic/6650.shtm
    http://expert.csdn.net/Topic/4221.shtm
    http://expert.csdn.net/Topic/5276.shtm
    http://expert.csdn.net/Topic/2002.shtm
    http://expert.csdn.net/Topic/7028.shtm
      
      

  5.   

      “金山词霸”屏幕取词技术揭密
                “金山词霸”屏幕取词技术揭密(讨论稿)            主题    屏幕取词技术系列讲座(一)
              作者      亦东
              很多人对这个问题感兴趣。
              原因是这项技术让人感觉很神奇,也很有商业价值。
              现在词典市场金山词霸占了绝对优势,所以再做字典也没什么前途了。我就是这么认为的,所以我虽然掌握了这项技术,却没去做字典软件。只做了一个和词霸相似的软件自己用,本来想拿出来做共享软件,但我的词库是“偷”来的,而且词汇不多,所以也就算了,词库太小,只能取词有什么用呢?而且词霸有共享版的。
              但既然很多人想了解这项技术,我也不会保留。我准备分多次讲述这项技术的所有细节。
              大约每周一两次。想知道的人就常常来看看吧!
              一.基础知识
              首先想编这种程序需要一些基础知识。
              会用Vc++,包括16/32位。
              精通Windows API特别是GDI,KERNEL部分。
              懂汇编语言,会用softice调试程序,因为这种程序最好用softice调试。
              二.基本原理
              在Window 3.x时代,windows系统提供的字符输出函数只有很少的几个。
              TextOut
              ExtTextOut
              DrawText
              ......
              其中DrawText最终是用ExtTextOut实现的。
              所以Windows的所有字符输出都是由调用TextOut和ExtTextOut实现的。因此,如果你可以修改这两个函数的入口,让程序先调用你自己的一个函数再调用系统的字符输出,你就可以得到Windows所有输出的字符了。
              到了Windows95时代,原理基本没变,但是95比3.x要复杂。开始的时候,一些在windows3.x下编写的取词软件仍然可以是使用。但是后来出了个IE4,结果很多词典软件就因为不支持IE4而被淘汰了,但同时也给一些软件创造了机会,如金山词霸。其实IE4的问题并不复杂,只不过它的输出的是unicode字符,是用TextOutW和ExtTextOutW输出的。知道了这一点,只要也截取就可以了。不过实现方法复杂一点,以后会有详细讲解。现在又出了个IE5,结果词霸也不好用了,微软真是#^@#$%$*&^&#@#@..........
              我研究后找到了一种解决办法,但还有些问题,有时会取错,正在继续研究,希望大家共同探讨。
              另外还有WindowsNT,原理也是一样,只是实现方法和95下完全不同。
              三.技术要点
              要实现取词,主要要解决以下技术问题。
              1.截取API入口,获得API的参数。
              2.安全地潜入Windows内部,良好地兼容Windows的各个版本
              3.计算鼠标所在的单词和字母。
              4.如果你在Window95下,做32位程序,还涉及Windows32/16混合编程的技术。
              今天先到这里吧!最好准备一份softice for 95/98和金山词霸,让我们先来分析一下别人是怎么做的。
              欢迎与我联系
              E-Mail:[email protected]
              Guest    1999-04-30 16:00:48
              请问用VC自己的DEBUGGER不行吗?为什么要用SOFTICE? 我没用过SOFTICE,它有什么特别之处吗?
              葫芦    1999-04-30 19:15:03
              本人对这个问题也有兴趣,以前研究过16位版本截获TextOut和ExtTextOut的过程;
              但对金山词霸,用Softice跟踪,发现SetWindowsHookEx在程序装载时就安装了鼠标钩子,暂停取字/恢复取字只是设置的内部变量,但本人发现金山词霸并没有象16位版本那样修改TextOut和ExtTextOut。
              苍蝇 (555021552)    1999-05-02 08:56:57
              有哪位大虾愿意先介绍一下SOFTICE?
              蟑螂    1999-05-04 13:58:22
              把金山词霸的cjktl95.dll用tdump分析可以看到它根本用的不是hook,而是用了一些kernel32.dll中的Win32 SDK里没有包含的函数,使用这些函数来替换改写原先的几个GDI函数。看来是Win95未公开的一些东西。有些人知道,为什么不肯说出来呢?未必见得多么高深!
              葫芦    1999-05-05 23:28:07
              你可能没有研究过它的目标代码,怎么能断言没有使用hook呢? 其实金山词霸一运行就安装了鼠标钩子。
              亦东    1999-05-07 09:52:42
              未必见得多么高深?
              你知道有些人是怎么知道这些Win95未公开的东西的吗?你不会是以为微软偷偷告诉他们的吧?其实他们大多和我一样是用softice自己跟踪Win95跟出来的。
              还有你从cjktl95.dll里tdump出的未公开函数和hook无关,那是做别的用的。
              setwindowshook在user里
              亦东    1999-05-10 16:16:14
              从cjktl95.dll里tdump出的未公开函数和32位和16位之间的互调有关。
              主题    屏幕取词技术系列讲座(二)
              作者      亦东
              很抱歉让大家久等了!
              我看了一些人的回帖,发现很多人对取词的原理还是不太清楚。
              首先我来解释一下hook问题。词霸中的确用到了hook,而且他用了两种hook其中一种是Windows标准hook,通过SetWindowHook安装一个回调函数,它安装了一个鼠标hook,是为了可以及时响应鼠标的消息用的和取词没太大关系。
              另一种钩子是API钩子,这才是取词的核心技术所在。他在TextOut等函数的开头写了一个jmp语句,跳转到自己的代码里。
              你用softice看不到这个跳转语句是因为它只在取词的一瞬间才存在,平时是没有的。
              你可以在TextOut开头设一个读写断点
              bpm textout
              再取词,就会找到词霸用来写钩子的代码了。
              /**********************************
              所以我在次强调,想学这种技术一定要懂汇编语言和熟练使用softice.
              **********************************/
              至于从cjktl95中dump出来的未公开函数是和Windows32/16混合编程有关的,以后我会提到他们。
              我先来讲述取词的过程,
              0 判断鼠标是否在一个地方停留了一段时间
              1 取得鼠标当前位置
              2 以鼠标位置为中心生成一个矩形
              3 挂上API钩子
              4 让这个矩形产生重画消息
              5 在钩子里等输出字符
              6 计算鼠标在哪个单词上面,把这个单词保存下来
              7 如果得到单词则摘掉API钩子,在一段时间后,无论是否得到单词都摘掉API钩子
              8 用单词查词库,显示解释框。
              很多步骤实现起来都有一些难度,所以在中国可以做一个完善的取词词典的人屈指可数。
              其中0,1,2,7,8比较简单就不提了。
              先说如何挂钩子:
              所谓钩子其实就是在WindowsAPI入口写一个JMP XXXX:XXXX语句,跳转到自己的代码里。
              步骤如下:
              1.取得Windows API入口,用GetProcAddress实现
              2.保存API入口的前五个字节,因为JMP是0xEA,地址是4个字节
              3.写入跳转语句
              这步最复杂
              Windows的代码段本来是不可以写的,但是Microsoft给自己留了个后门。
              有一个未公开函数是AllocCsToDsAlias,
              UINT WINAPI ALLOCCSTODSALIAS(UINT);
              你可以取到这个函数的入口,把API的代码段的选择符(要是不知道什么是选择符,就先去学学保护模式编程吧)传给他,他会返回一个可写的数据段选择符。这个选择符用完要释放的。用新选择符和API入口的偏移量合成一个指针就可以写windows的代码段了。
              这就是取词技术的最核心的东东,不止取词,连外挂中文平台全屏汉化都是使用的这种技术。现在知道为什么这么简单的几句话却很少知道了吧?因为太多的产品使用他,太多的公司靠他赚钱了。
              这些公司和产品有:中文之星,四通利方,南极星,金山词霸,实达铭泰的东方快车,roboword,译典通,即时汉化专家等等等等。还有至少20多家小公司。他们的具体实现虽然不同,但大致原理是相同的。
              我这些都是随手写的,也没有提纲之类的东西,以后如果有机会我会整理一下,大家先凑合着看吧!xixi...
              葫芦    1999-05-06 14:52:30
              你说的这个技术是16位的,至少金山词霸III没有采用16位的AllocCsToDsAlias函数,也根本没有修改TextOut开始的语句为JMP        XXXXXXXX。softice本人非常精通,是绝对不会错的!
              葫芦    1999-05-06 15:38:40
              谁假冒吾名,坏吾名声?!本人在此郑重宣布,以上贴子非本人所发!
              经过跟踪分析,金山词霸III确实修改了TextOut的入口为转跳到自身代码的JMP XXXXXXXX语句,只是修改没有调用AllocCsToDsAlias,也不是在取字时才去修改,而是常常修改(估计是在Timer中进行的)。
              亦东    1999-05-06 17:25:23
              我说过词霸里用AllocCsToDsAlias了吗?
              我是说AllocCsToDsAlias,的确可以用,但词霸里是用DPMI的Int 31做的,其实本质是一样的,你用softice跟一下就知道了
              bpint 31 设一个中断断点。
              实际上我至少有五种方法写Windows代码段
              我介绍使用AllocCsToDsAlias是因为这种方法最简单,其他方法要麻烦得多。
              词霸用int 31来做是出于兼容性的考虑,
              AllocCsToDsAlias毕竟不是公开函数,但DPMI却是标准。
              词霸在你鼠标在某一点停留超过200ms时就会取词,所以他有一个定时器,会经常修改API入口。
              看来“假”葫芦只是自以为非常精通softice.
              mao    1999-05-06 19:29:28
              在微软的MSDN中有一个程序,包含了全部的Source code, 名字好象叫"Inject" 或 stealth什么的,忘了。提供了一个很完善的hook任何一个windows函数的功能。对win16完全适用,在win95下也有用,但NT下不行。
              建议大家去找找这个例子看看会很有帮助。
              此外有本清华出的微软的Advanced Windows也介绍了具体的方法。
              建议亦东干脆把source code给open出来,让有兴趣的朋友用起来更方便,把取词技术可发展的应用发扬光大!
              亦东    1999-05-07 09:40:56
              我不主张“把取词技术可发展的应用发扬光大”,这也是我掌握了这项技术一年多才公开它的原因。我公开它并不是想让大家都来做字典软件,相反我希望不要再有人做字典了,现在做字典的人已经太多了。看到某种软件有利可图,大家就一哄而上,这种恶性竞争对中国软件业的发展是极其有害的。我公开他的目的是希望提高大家的编程水平。你会发现在研究这项技术的过程中你的编程水平和对Windows的理解程度会有质的飞跃,我本人就从中获益匪浅。
              MSDN中是有这样的代码。
              甚至有一个叫ProcHook.Dll,提供SetProcAddress之类的函数,但是没有源码。源码在1994年的 MSJ 上很难弄到的。
              源码我会分几次公开,每次会有详细的说明。
              想要源码的人,准备一份VC++1.52或Borland C++,最好还有softice,下次我会给出一段代码,教你如何修改Windows的代码。
              老冒 (555036)    1999-05-07 11:56:46
              如果认为屏幕取词的应用就是做字典,就大错特错了。其实关于拦劫windows api的东东早就在93年的Undocument Windows上公开过了。
              其实Adobe的Adobe Type Manager在Windows 3.0的时代就通过这种办法实现了漂亮的字体. (现在有TTF不需要ATM了)
              MSDN上的那个东东是有全部source和sample, 我抓下来编译过。是1996年夏天的一张MSDN Level 2光碟上的,现在也不知搁哪里了,有兴趣的朋友自己找去吧。
              还是open 完整的source好,很多朋友其实只要用这项技术,并不太想知道细节,不是吗.
              亦东    1999-05-07 13:28:19
              这种技术不是做字典全屏汉化就是外挂语言平台,自从王志东使用它以来,就没用来编过其他软件,也许有但我不知道。
              原来有那么多书和其他资料上都有这种技术的资料还有例子,到是我孤陋寡闻了,以为大家都不知道,在这里给大家讲一些众所周知的东西。回去我要好好研究一下,看看Rasir        Dex的词霸是从那里抄的。
              我不知道某项技术中细节是不是重要,如果很多人只想用而不想自己编,那么楼下那50多个回帖是怎么回是?
              老冒    1999-05-07 13:54:18
              呵呵,你可千万要坚持把讲座做下去,否则那50多个回应的哥们企不要把我给痛扁了...:)
              俺已两年多不碰底层技术的,这方面很落后啦...俺可应付不了这么多热切的求知朋友,亦东要顶住呵!
              欢迎和俺多多交流探导!
              P.S. 亦东大侠目前何方高就? 正在忙什么项目?交流交流
              亦东    1999-05-07 17:46:06
              没什么正经事做,到处瞎混呢!
              葫芦    1999-05-08 21:50:29
              我对此持否定观点,不要自作聪明,以为AllocCsToDsAlias就是能用的,其实AllocCsToDsAlias只是16位的Windows用的函数,32位的Win95程序不能使用此函数,不信你在VC        5.0或6.0中可以试试。
              另外,int 31h也不是说能用就能拿来用的,在Windows 3.x下使用是没有问题的(本人还有这方面的文章发表),但在Win95下随意使用会产生GP错,主要原因是32位并不支持DPMI直接调用,不知亦东先生对此有没有研究,就在此发表诸多理论!本人就先请问:32位程序如何调用16位函数或动态库你懂不懂?
              葫芦    1999-05-09 02:39:10
              上面的这个帖子并没有攻击谁的意思,只是希望大家探讨问题都要本着认真的态度,不要不懂装懂,至少有一点大家要清楚:32位的程序根本不能使用 int        31h,调用16位的动态库Kernel中的AllocCsToDsAlias也并不是件简单的事。
              nn_zdm (555031742)    1999-05-09 16:35:35
              使用hook函数,可用的功能并非只是做字典全屏汉化和外挂语言平台。使用hook可以调试程序,就象你们说的softice其本身也是使用了hook函数。
              nn_zdm (555031742)    1999-05-09 16:42:05
              另外hook函数还可以使用在游戏修改工具中,本人就开发过此类工具。《整人专家》估计也是使用这种方法。当然还有另外两种方法。
              亦东    1999-05-10 16:10:59
              你们说的都有道理。
              但hook有两种,一种是Windows标准钩子,通过SetWindowshook挂。
              另一种是非标准的,通过在API入口写JMP XXXXXXXX来实现的。
              softice的钩子更高级,他都挂到VXD上了。
              从32为代码调用16位DLL碰巧我会。
              打倒米D国主义!!!
              瓜果    1999-05-10 17:07:00
              谁知道在哪能搞到SOFTICE,我以前从未用过它!
              葫芦    1999-05-10 21:39:46
              愿继续拜读你以后的讲座。
              SOFTICE吗?光盘上很多,有for DOS, for Windows95, for Windows NT 各个版本。
              孙玮 (555031339)    1999-05-11 11:08:35
              能否将 si for NT 上传到 10.82.46.33
              (使用 ftp) user: haotao
              pass: haotao123
              tommy    1999-05-11 11:34:11
              http://www.swww.com.cn/htm/down/others/main.html 可以下载
              亦东    1999-05-11 14:01:19
              最近忙于反美,暂时没时间再写了,过些时间才行,下次我会给出源码。
              最新消息,美国海军被黑了。
              http://www.nctsw.navy.mil/
              打倒米D国主义!!!
              黄金狮子    1999-05-12 13:19:32
              我对各位大虾的讨论深感兴趣。
              有几个问题想请教:
              1.AllocCsToDsAlias 在32-bit下调用是否采用Thunk?
              2.32-bit 下是否有类似function?
              3.Jeffrey Richter的"Advanced Windows"里Remote Thread 的Thread Stack来远程注入DLL函数,因此不需上述Function.
              4.我有MSJ 1994-1的ProcHook.dll的source code,不知用于WinNT需如何改动.
              5.总而言之,有无WinNT下hook API的source code,请告知.
              (我还有Softice 3.24 for Win95, 3.25 for WinNT.)
              --这个主题很好
              鼹鼠    1999-05-14 09:41:20
              请大虾给我发一份MSJ 1994-1的ProcHool.dll的source code, 我现在急需这方面的资料。谢谢!!
              Email Address: [email protected]
              下面是一个Australia人的API hook软件,    它是基于VxD技术。
              Molten    Home Page:
              http://ourworld.compuserve.com/homepages/molten
              黄金狮子    1999-05-14 14:34:54
              在Win95和NT上,可通过WriteProcessMemory()直接写Code Segment.(原来以为"advanced        Windows" 调CreateRemoteThread(),是因为WriteProcessMemory()只能写代码段和堆栈段)
              阿涛    1999-05-14 19:45:05
              如何亦东老兄要分步公布是PROCHOOK的代码就不必了,这个程序的代码很容易搞到,只须到MSJ的站点上查一下就可找到。
              亦东    1999-05-14 21:44:39
              大家到msj的大海里去捞针好了。
              在95你WriteProcessMemory 写kernel user gdi试试,一定失败。
              调CreateRemoteThread并不是为了写代码段,有别的用途,是为了在其他进程里分配内存。回去再好好看看“advanced Windows"        最好用一个程序试试,你就明白了。
              其实在NT4.0调CreateRemoteThread是没必要的,这是为了兼容NT3.51.
              nn_zdm (555031742)    1999-05-18 13:57:48
              利用CreateRemoteThread()函数,在WinNT4.0中使用很有用,它是在winNT中闯过进程边界的三种办法之一,在WinNT中,使用它可以进行远程调试,及修改他人代码.
              nn_zdm (555031742)    1999-05-18 14:07:17
              在winNT中用WriteProcessMemory()写code
              代码是可以的,win95没试过,但MSDN上说是可以的.不过,可能没什么用,因为CreateRemoteThread()函数只在winNT中有用.
              如:
              WriteProcessMemory(...,"LoadLibrary(...,"mydll.dll",..).
              CreateRemoteThread(...)
              nn_zdm (555031742)    1999-05-18 14:14:19
              上面写漏了,应是
              WriteProcessMemory(...,"LoadLibrary(...,"mydll.dll",..).        ");
              CreateRemoteThread(...) ;      主题    关于屏幕取词的讨论(三)
              作者      亦东
              让大家久等,很抱歉,前些时候工作忙硬盘又坏了,太不幸了。
              这回来点真格的。
              咱们以截取TextOut为例。
              下面是代码:
              //截取TextOut
              typedef UINT (WINAPI* ALLOCCSTODSALIAS)(UINT);
              ALLOCCSTODSALIAS AllocCsToDsAlias;
              BYTE NewValue[5];//保存新的入口代码
              BYTE OldValue[5];//API原来的入口代码
              unsigned char * Address=NULL;//可写的API入口地址
              UINT DsSelector=NULL;//指向API入口的可写的选择符
              WORD OffSetEntry=NULL;//API的偏移量
              BOOL bHookAlready = FALSE; //是否挂钩子的标志
              BOOL InitHook()
              {
              HMODULE hKernel,hGdi;
              hKernel = GetModuleHandle("Kernel");
              if(hKernel==NULL)
              return FALSE;
              AllocCsToDsAlias = (ALLOCCSTODSALIAS)GetProcAddress(hKernel,"AllocCsToDsAlias");//这是未公开的API所以要这样取地址
              if(AllocCsToDsAlias==NULL)
              return FALSE;
              hGdi = GetModuleHandle("Gdi");
              if(hmGdi==NULL)
              return FALSE;
              FARPROC Entry = GetProcAddress(hGdi,"TextOut");
              if(Entry==NULL)
              return FALSE;
              OffSetEntry = (WORD)(FP_OFF(Entry));//取得API代码段的选择符
              DsSelector = AllocCsToDsAlias(FP_SEG(Entry));//分配一个等同的可写的选择符
              Address = (unsigned char*)MK_FP(DsSelector,OffSetEntry);//合成地址
              NewValue[0]=0xEA;
              *((DWORD*)(NewValue+1)) = (DWORD)MyTextOut;
              OldValue[0]=Address[0];
              *((DWORD*)(OldValue+1)) = *((DWORD*)(Address+1));
              }
              BOOL ClearHook()
              {
              if(bHookAlready)
              HookOff();
              FreeSelector(DsSelector);
              }
              BOOL HookOn()
              {
              if(!bHookAlready){
              for(int i=0;i<5;i++){
              Address[i]=NewValue[i];
              }
              bHookAlready=TRUE;
              }
              }
              BOOL HookOff()
              {
              if(bHookAlready){
              for(int i=0;i<5;i++){
              Address[i]=OldValue[i];
              }
              bHookAlready=FALSE;
              }
              }
              //钩子函数,一定要和API有相同的参数和声明
              BOOL WINAPI MyTextOut(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,UINT        cbString)
              {
              BOOL ret;
              HookOff();
              ret = TextOut(hdc,nXStart,nYStart,lpszString,cbString);//调原来的TextOut
              HookOn();
              return ret;
              }
              上面的代码是一个最简单的挂API钩子的例子,我要提醒大家的是,这段代码是我凭记忆写的,我以前的代码丢了,我没有编译测试过
              因为我没有VC++1.52.所以代码可能会有错。
              建议使用Borland c++,按16位编译。
              如果用VC++1.52,则要改个选项
              在VC++1.52的Option里,有个内存模式的设置,选大模式,和"DS!=SS DS Load on Function entry.",切记,否则会系统崩溃。
              有什么不明白的可以给我写信
              [email protected]
              Guest    1999-05-21 22:20:47
              你这是16为的地址存取模式吧
              你看这个MK_FP,win32不用了,
              而且GetProcAddress(hKernel,"AllocCsToDsAlias")
              这个API有用吗?
              sorry
              Guest    1999-05-21 22:31:47
              亦东,想请教一个问题,
              win32下,每个process有
              自己的地址空间,process
              A得到process B 的一个窗口C的handle,这个
              handle的值 等于process B自己得到的window C 的handle值 吗?
              我想应该不相等,但系统是如何转换的呢?(比如process A 向
              window C 发消息,系统如何
              知道process A 里的handle 和process B 里的
              handle 都是指的window C)
              . 是不是用duplicatehandle()?
              (声明,我是真的不知道)
              亦东    1999-05-21 22:54:48
              这段代码就是十六位的。
              你用Win32根本就不能编译。
              32位没有AllocCsToDsAlias,因为在32位里不能写系统代码段(其实有办法,不是这样,不过比较麻烦)。
              系统代码都在0x80000000以上,都是只读的。
              所以要截WinAPI只能用16位的代码。
              每个Process有自己的地址空间没错,但Window的句柄是共享的,同一个窗口在任何进程里的句柄都是一样的。
              你可以在自己的进程里向任何窗口发消息。
              Window的句柄很多,有的是共享的有的不是,
              我也不知道那里有说明,一般是凭经验或试试看。
              GUEST    1999-05-22 20:51:51
              如果 window handle 换成
              moudle handle呢?我
              用moudlefirst,moudlenext遍历
              得到的某个moudle 的句柄,
              在任何一个process 中得到的
              这个moudle handle 都是一样的值吗。(这个handle 和进程地址空间无关吗?)。
              thx
              亦东    1999-05-23 22:31:59
              绝对有关
              在Win32里module handle就是模块的起始地址。
              说起来比较复杂
              在95和NT里有些不同
              在Win32里,每个模块(DLL,EXE)有一个ImageBase,这个数存放在DLL和EXE的文件头里。每个模块通常是不一样的。当Windows加载这个模块时优先考虑把模块放到Imagebase指定的地址,但有时会出现两个模块的地址重叠会有冲突,Windows会把模块移到与Imagebase最近的地址。所以Imagebase相同的模块在不同进程可能会在不同的地址上。这个地址就是module        handle.Imagebase是可以在编译时指定的。
              你用moudlefirst,moudlenext遍历得到的module handle是和进程有关的。
              比如:你编了一个Imagebase为0x10000000的DLL A,进程A调用这个DLL A,在进程A里这个DLL被加载到地址0x10000000处,他的module        handle为0x10000000,进程B也调用这个DLL A,但是进程B还调用另外一个DLL B,这另外的DLL B也是Imagebase为0x10000000的而且先加载,这是进程B的这个DLL        A可能就被加载到0x13000000了,DLL A在进程B里的module handle 就是0x13000000了。
              在95下,模块是共享的,也就是Windows只加载一份模块到内存,所有用到这个模块的进程都映射同一个模块,也就是说在95里每个模块在物理内存里只有一份。NT则不同,他为每个进程都加载一份模块。所以NT比95需要的内存多。所以在NT里不但在不同进程里的Module        handle可能不同,连物理地址都是不同的。
      
    --------------------------------------------------------------------------------