金山词霸”屏幕取词技术揭密  
                            “金山词霸”屏幕取词技术揭密(讨论稿)                           主题           屏幕取词技术系列讲座(一)  
                        作者             亦东  
                        很多人对这个问题感兴趣。  
                        原因是这项技术让人感觉很神奇,也很有商业价值。  
                        现在词典市场金山词霸占了绝对优势,所以再做字典也没什么前途了。我就是这么认为的,所以我虽然掌握了这项技术,却没去做字典软件。只做了一个和词霸相似的软件自己用,本来想拿出来做共享软件,但我的词库是“偷”来的,而且词汇不多,所以也就算了,词库太小,只能取词有什么用呢?而且词霸有共享版的。  
                        但既然很多人想了解这项技术,我也不会保留。我准备分多次讲述这项技术的所有细节。  
                        大约每周一两次。想知道的人就常常来看看吧!  
                        一.基础知识  
                        首先想编这种程序需要一些基础知识。  
                        会用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:yeedong@163.net  
                        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:   yanshg@263.net  
                        下面是一个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.",切记,否则会系统崩溃。  
                        有什么不明白的可以给我写信  
                        yeedong@163.net  
                        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可能不同,连物理地址都是不同的。  
posted on 2009-07-26 01:41  yxbsmx  阅读(805)  评论(0编辑  收藏  举报