CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  VB >  网络编程

关于web的系列问题 300分求助

楼主hebhd(汉德)2004-05-03 00:13:10 在 VB / 网络编程 提问

说的可能不太清楚,望高手给予指点  
  1.  
   
  http://freeqq2.qq.com/nom_reg.shtml  
   
  这个是申请QQ的地址,里有段代码  
   
  <script>document.write("<img   src='http://freeqq3.qq.com/getimage?",Math.random(),"'>")</script>  
   
  这段代码。也就是显示验证码的图片.  
   
  为了实现自动申请出现问题  
  1.如何将显示在   webbrowser   里的上面的图片存到程序当前目录下[注意:因为有cookies的设置。所以直接用downloadurl是肯定不可以啦]  
  2.如果清理cookies?  
  3.使用webbrowser占用内存极大。用inet   sockes   如何处理这种情况也就是怎么能知道在显示这个图片的时候设置的cookies是什么  
   
  我的目的只有一个自动申请QQ号.这里只作技术上交流.  
   
  附带一个问题:如何屏幕取词,查遍所有资料没有一个完整详细的解释。和可用代码  
  望指教!  
   
   
   
   
  问题点数:100、回复次数:8Top

1 楼online(龙卷风V4.0--决战江湖(MS MVP-VB))回复于 2004-05-03 00:29:08 得分 100

1.试试,直接保存页面  
  Private   Sub   brwSaveAs_Click()  
          On   Error   Resume   Next  
   
          Screen.MousePointer   =   vbHourglass  
          DoEvents  
          brwWeb1.ExecWB   OLECMDID_SAVEAS,   OLECMDEXECOPT_PROMPTUSER  
          If   Err.Number   <>   0   Then  
                  MsgBox   "无法另存新文件!"  
          End   If  
          Screen.MousePointer   =   vbDefault  
  End   Sub  
  Top

2 楼online(龙卷风V4.0--决战江湖(MS MVP-VB))回复于 2004-05-03 00:31:34 得分 0

2,3  
   
  The   following   code   can   be   used   to   query   and   delete   files   in   the   internet   cache   (including   cookies).   A   demonstration   routine   can   be   found   at   the   bottom   of   this   post.   Note,   the   enumerated   type   eCacheType   is   not   supported   in   Excel   97,   but   can   be   changed   to   a   list   of   Public   Constants   eg.   Public   Const   eNormal   =   &H1&.  
  Option   Explicit  
  '--------------------------Types,   consts   and   structures  
  Private   Const   ERROR_CACHE_FIND_FAIL   As   Long   =   0  
  Private   Const   ERROR_CACHE_FIND_SUCCESS   As   Long   =   1  
  Private   Const   ERROR_FILE_NOT_FOUND   As   Long   =   2  
  Private   Const   ERROR_ACCESS_DENIED   As   Long   =   5  
  Private   Const   ERROR_INSUFFICIENT_BUFFER   As   Long   =   122  
  Private   Const   MAX_CACHE_ENTRY_INFO_SIZE   As   Long   =   4096  
  Private   Const   LMEM_FIXED   As   Long   =   &H0  
  Private   Const   LMEM_ZEROINIT   As   Long   =   &H40  
  Public   Enum   eCacheType  
  eNormal   =   &H1&  
  eEdited   =   &H8&  
  eTrackOffline   =   &H10&  
  eTrackOnline   =   &H20&  
  eSticky   =   &H40&  
  eSparse   =   &H10000  
  eCookie   =   &H100000  
  eURLHistory   =   &H200000  
  eURLFindDefaultFilter   =   0&  
  End   Enum  
  Private   Type   FILETIME  
  dwLowDateTime   As   Long  
  dwHighDateTime   As   Long  
  End   Type  
  Private   Type   INTERNET_CACHE_ENTRY_INFO  
  dwStructSize   As   Long  
  lpszSourceUrlName   As   Long  
  lpszLocalFileName   As   Long  
  CacheEntryType     As   Long                   'Type   of   entry   returned  
  dwUseCount   As   Long  
  dwHitRate   As   Long  
  dwSizeLow   As   Long  
  dwSizeHigh   As   Long  
  LastModifiedTime   As   FILETIME  
  ExpireTime   As   FILETIME  
  LastAccessTime   As   FILETIME  
  LastSyncTime   As   FILETIME  
  lpHeaderInfo   As   Long  
  dwHeaderInfoSize   As   Long  
  lpszFileExtension   As   Long  
  dwExemptDelta     As   Long  
  End   Type  
  '--------------------------Internet   Cache   API  
  Private   Declare   Function   FindFirstUrlCacheEntry   Lib   "Wininet.dll"   Alias   "FindFirstUrlCacheEntryA"   (ByVal   lpszUrlSearchPattern   As   String,   lpFirstCacheEntryInfo   As   Any,   lpdwFirstCacheEntryInfoBufferSize   As   Long)   As   Long  
  Private   Declare   Function   FindNextUrlCacheEntry   Lib   "Wininet.dll"   Alias   "FindNextUrlCacheEntryA"   (ByVal   hEnumHandle   As   Long,   lpNextCacheEntryInfo   As   Any,   lpdwNextCacheEntryInfoBufferSize   As   Long)   As   Long  
  Private   Declare   Function   FindCloseUrlCache   Lib   "Wininet.dll"   (ByVal   hEnumHandle   As   Long)   As   Long  
  Private   Declare   Function   DeleteUrlCacheEntry   Lib   "Wininet.dll"   Alias   "DeleteUrlCacheEntryA"   (ByVal   lpszUrlName   As   String)   As   Long  
  '--------------------------Memory   API  
  Private   Declare   Function   LocalAlloc   Lib   "kernel32"   (ByVal   uFlags   As   Long,   ByVal   uBytes   As   Long)   As   Long  
  Private   Declare   Function   LocalFree   Lib   "kernel32"   (ByVal   hMem   As   Long)   As   Long  
  Private   Declare   Sub   CopyMemory   Lib   "kernel32"   Alias   "RtlMoveMemory"   (pDest   As   Any,   pSource   As   Any,   ByVal   dwLength   As   Long)  
  Private   Declare   Function   lstrcpyA   Lib   "kernel32"   (ByVal   RetVal   As   String,   ByVal   Ptr   As   Long)   As   Long  
  Private   Declare   Function   lstrlenA   Lib   "kernel32"   (ByVal   Ptr   As   Any)   As   Long  
  'Purpose           :     Deletes   the   specified   internet   cache   file  
  'Inputs             :     sCacheFile                             The   name   of   the   cache   file  
  'Outputs           :     Returns   True   on   success.  
  'Author             :     Andrew   Baker  
  'Date                 :     03/08/2000   19:14  
  'Notes               :  
  'Revisions       :  
  Function   InternetDeleteCache(sCacheFile   As   String)   As   Boolean  
  InternetDeleteCache   =   CBool(DeleteUrlCacheEntry(sCacheFile))  
  End   Function  
  'Purpose           :     Returns   an   array   of   files   stored   in   the   internet   cache  
  'Inputs             :     eFilterType                           An   enum   which   filters   the   files   returned   by   their   type  
  'Outputs           :     A   one   dimensional,   one   based,   string   array   containing   the   names   of   the   files  
  'Author             :     Andrew   Baker  
  'Date                 :     03/08/2000   19:14  
  'Notes               :  
  'Revisions       :  
  Function   InternetCacheList(Optional   eFilterType   As   eCacheType   =   eNormal)   As   Variant  
  Dim   ICEI   As   INTERNET_CACHE_ENTRY_INFO  
  Dim   lhFile   As   Long,   lBufferSize   As   Long,   lptrBuffer   As   Long  
  Dim   sCacheFile   As   String  
  Dim   asURLs()   As   String,   lNumEntries   As   Long  
  'Determine   required   buffer   size  
  lBufferSize   =   0  
  lhFile   =   FindFirstUrlCacheEntry(0&,   ByVal   0&,   lBufferSize)  
  If   (lhFile   =   ERROR_CACHE_FIND_FAIL)   And   (Err.LastDllError   =   ERROR_INSUFFICIENT_BUFFER)   Then  
  'Allocate   memory   for   ICEI   structure  
  lptrBuffer   =   LocalAlloc(LMEM_FIXED,   lBufferSize)  
  If   lptrBuffer   Then  
  'Set   a   Long   pointer   to   the   memory   location  
  CopyMemory   ByVal   lptrBuffer,   lBufferSize,   4  
  'Call   first   find   API   passing   it   the   pointer   to   the   allocated   memory  
  lhFile   =   FindFirstUrlCacheEntry(vbNullString,   ByVal   lptrBuffer,   lBufferSize)                 '1   =   success  
  If   lhFile   <>   ERROR_CACHE_FIND_FAIL   Then  
  'Loop   through   the   cache  
  Do  
  'Copy   data   back   to   structure  
  CopyMemory   ICEI,   ByVal   lptrBuffer,   Len(ICEI)  
  If   ICEI.CacheEntryType   And   eFilterType   Then  
  sCacheFile   =   StrFromPtrA(ICEI.lpszSourceUrlName)  
  lNumEntries   =   lNumEntries   +   1  
  If   lNumEntries   =   1   Then  
  ReDim   asURLs(1   To   1)  
  Else  
  ReDim   Preserve   asURLs(1   To   lNumEntries)  
  End   If  
  asURLs(lNumEntries)   =   sCacheFile  
  End   If  
  'Free   memory   associated   with   the   last-retrieved   file  
  Call   LocalFree(lptrBuffer)  
  'Call   FindNextUrlCacheEntry   with   buffer   size   set   to   0.  
  'Call   will   fail   and   return   required   buffer   size.  
  lBufferSize   =   0  
  Call   FindNextUrlCacheEntry(lhFile,   ByVal   0&,   lBufferSize)  
  'Allocate   and   assign   the   memory   to   the   pointer  
  lptrBuffer   =   LocalAlloc(LMEM_FIXED,   lBufferSize)  
  CopyMemory   ByVal   lptrBuffer,   lBufferSize,   4&  
  Loop   While   FindNextUrlCacheEntry(lhFile,   ByVal   lptrBuffer,   lBufferSize)  
  End   If  
  End   If  
  End   If  
  'Free   memory  
  Call   LocalFree(lptrBuffer)  
  Call   FindCloseUrlCache(lhFile)  
  InternetCacheList   =   asURLs  
  End   Function  
  'Purpose           :     Converts   a   pointer   an   ansi   string   into   a   string.  
  'Inputs             :     lptrString                                     A   long   pointer   to   a   string   held   in   memory  
  'Outputs           :     The   string   held   at   the   specified   memory   address  
  'Author             :     Andrew   Baker  
  'Date                 :     03/08/2000   19:14  
  'Notes               :  
  'Revisions       :  
  Function   StrFromPtrA(ByVal   lptrString   As   Long)   As   String  
  'Create   buffer  
  StrFromPtrA   =   String$(lstrlenA(ByVal   lptrString),   0)  
  'Copy   memory  
  Call   lstrcpyA(ByVal   StrFromPtrA,   ByVal   lptrString)  
  End   Function  
  'Demonstration   routine  
  Sub   Test()  
  Dim   avURLs   As   Variant,   vThisValue   As   Variant  
  On   Error   Resume   Next  
  'Return   an   array   of   all   internet   cache   files  
  avURLs   =   InternetCacheList  
  For   Each   vThisValue   In   avURLs  
  'Print   files  
  Debug.Print   CStr(vThisValue)  
  Next  
  'Return   the   an   array   of   all   cookies  
  avURLs   =   InternetCacheList(eCookie)  
  If   MsgBox("Delete   cookies?",   vbQuestion   +   vbYesNo)   =   vbYes   Then  
  For   Each   vThisValue   In   avURLs  
  'Delete   cookies  
  InternetDeleteCache   CStr(vThisValue)  
  Debug.Print   "Deleted   "   &   vThisValue  
  Next  
  Else  
  For   Each   vThisValue   In   avURLs  
  'Print   cookie   files  
  Debug.Print   vThisValue  
  Next  
  End   If  
  End   SubTop

3 楼online(龙卷风V4.0--决战江湖(MS MVP-VB))回复于 2004-05-03 00:39:29 得分 0

屏幕抓字技术揭密    
  ----------深入WINDOWS内部探险手记    
   
  郑州   马飞涛    
   
  一   公开它!    
  四通利方和金山词霸的用户都曾见识过屏幕抓字技术,鼠标指哪就翻译哪个单    
  词,这个技术看似简单,其实在WINDOWS系统中实现却是非常复杂和有趣的。   经    
  过半年多的艰辛探索,笔者终于破解了其中的秘密,并在今天决定公开它,这个    
  人人   都曾见过但是却鲜有人知的秘密,这个只被几家软件公司垄断从未在公开的报刊   资   料披露过只言片语的秘密!    
  回想这半年多的探索,其中浸润了多少笔者的苦闷与欢乐,绝望与兴奋,挫   折    
  与收获,现在都终于有了结果:将屏幕抓字技术的秘密公开,献给孜孜不倦辛勤    
  工   作的程序员们。如果这样做能为国产软件事业的发展效微薄之力,对笔者来说,也   是一桩快事!    
   
  二   初识屏幕抓字    
   
  最初知道屏幕抓字,   是在购买了〖英汉通〗软件之后。   当时笔者还只是一   个    
  VISUAL   BASIC   的初学者,   对   WINDOWS   系统内部的知识了解并不多,   认为   在    
  WINDOWS系统中屏幕抓字的实现应该和DOS系统中的一样,调用一个DOS   中断取屏    
  幕   上的字符或直接读显示内存的内容就可以了。    
   
  三   看似很简单,其实不然    
   
  随着对WINDOWS系统的认识不断深入,才发现问题并不象想得那么简单。首先,    
  翻阅了WINODWS应用程序接口(API)中的上千个函数,并没有发现有一个现成的    
  类   似于getWordFromPoint()的函数;根据使用经验,经过判断发现屏幕抓字采用的   也   不是图像识别技术;翻阅了SDK的联机文档中没有,DDK的联机文档中也没有;显示   卡编程接口的资料则很难获得,有的也只是CGA到VGA显存的基本知识。回想当时   坐   在机子前,面对一屏屏的联机资料(如果是纸,将堆积如山),感觉就是在黑暗   中   的大海里航行,没有方向,没有灯光,但强烈的兴趣紧抓着我,一定要把这个谜   解   开。    
   
  四   选择合适的编程工具    
   
  突然又有了一些新的想法:    
  可否试着截获WINDOWS中关于字符的消息呢?    
  DC(设备描述表)到底是什么?    
  WINDOWS的TextOut函数是否将TEXT放在DC的某个单元中?    
  显然,用VISUAL   BASIC就力不从心了。在DOS中用TURBO   C编程笔者还算熟练    
  ,    
   
  因此先尝试用VISUAL   C++,但是奇慢的编译速度使人难以忍受,   高度抽象的类    
  让   人一头雾水,开发商务软件可能还行,但开发这样一个深入WINDOWS   内部的系统     件,望着一堆缠绕不清的类和消息,真有点牛刀宰鸡、刺刀耕田的感觉。    
  最后选择了DELPHI,第一印象是编译速度真快,在我的祖父型386   机子上   编    
  译一个WINDOWS程序,速度和用TURBO   C的速度感觉差不多,真让人兴奋得爱不释手。   随着不断使用,发觉DELPHI真是一个好的快速开发工具,(快速并不意味着简单   粗   糙,而是和WINDOWS系统有混然一体良好接口的表现)让初学者也很容易上手。   调   用各种WINDOWS   函数(包括很多未公开的函数)都非常直接迅速,用它来作开发   工   具,大有刺刀见红、一剑封喉的痛快感觉。    
   
  五   山穷水尽疑无路    
   
  随着对WINDOWS系统了解的深入,我逐渐明白了在向屏幕输出文字时,WINDO    
  WS   系统仅仅只是对某个应用程序发送WM_PAINT消息,告诉该应用程序窗口用户区已   经    
  “无效”而需要重画。具体的“绘制”工作(选择字体,颜色,文字)由应用程    
  序   完成。   应用程序在处理WM_PAINT消息时,调用BeginPaint和EndPaint来获得和释放   设   备描述表,调用DrawText、ExtTextOut、   TextOut等函数在设备描述表中“绘制   ”   文字。   应用程序“绘制”文字,   就象学生(应用程序)奉命(获得   WM_PAINT消息   )   用老师(WINDOWS)提供的画笔(DrawText   ExtTextOut   TextOut等)   在黑板上画   画   一样,虽然大家能看到画的是什么字,但是画笔作为绘图工具并不知道画的是什   么。    
   
  老师(WINDOWS)不知道学生(应用程序)到底用什么字体,颜色,画哪些文字。    
   
       总之   ,WINDOWS并不知道应用程序“绘制”的是什么。“文字”对   WINDO    
  WS    
   
  来说只是画笔留在黑板(屏幕)上的粉笔印,只是绘画的痕迹。“文字”只存在    
  于    
   
  应用程序的模块中,对WINDOWS系统是“不可见”的。    
  到处走投无路,真想掂5000块钱,跑到“英汉通”公司买回这个秘密。仔细    
  一    
   
  想,钱太少,就是多掂10倍,人家也不一定说。    
   
  六   柳暗花明又一村    
   
  经过再三考虑,我联想到在DOS系统中编程,会采取改变中断向量地址,   设    
  置    
   
  新的中断向量的技术:如果系统调用这个中断,就会先进入新的中断服务程序,    
  然    
   
  后再调用原来的中断服务程序。    
  那末,在WINDOWS系统中也采取这种技术,使系统如果调用某个函数,   先进    
  入    
   
  一个跟踪函数,取得原函数的参数,再调用原来的函数。听起来是否象病毒传染    
  和    
   
  发作?其实很多程序都采用过类似技术。大学毕业设计声卡时我就用过。    
  至此,   我认识到应该放弃常规的思路,   采取一些技巧,   截获   TextOut    
  、    
   
  ExtTextOut等函数,使之转向我的跟踪函数,在此查看应用程序(学生)的堆栈    
  中    
   
  传递给画笔(TextOut、ExtTextOut等函数)的参数,   从而获得应用程序要在屏    
  幕    
   
  上写的“文字”。    
   
  七 “   屏幕抓字”的实现    
   
  1   用SetWindowsHookEx()安装鼠标钩子MouseProc;    
  2   在屏幕上移动鼠标时,系统就会调用鼠标钩子MouseProc;    
  3   进入MouseProc,获得鼠标的坐标(x,y),    
  设置对TextOut()、ExtTextOut()等的跟踪程序,    
  用invalidateRect()告诉系统该点(x,y)“失效”;    
  4    
  系统发出WM_PAINT消息,指示该点(x,y)处的应用程序重绘“失效”的区域。    
  5   负责绘制该点()的应用程序在受到   WM_PAINT   消息后,   就有机会调用    
   
  TextOut()、   ExtTextOut()等函数。    
  6   调用的函数被拦截进入跟踪程序:设置好了的跟踪程序截获了该次调用,    
  从    
   
  应用程序的堆栈中取出   该点(x,y)“文字”的指针;    
  7   从应用程序的数据段中将“文字”指针的内容取出,即完成了一次“屏幕    
  抓    
   
  字”;    
  8   退出跟踪程序,返回到鼠标钩子MouseProc;    
  9   在MouseProc中解除对TextOut()   ExtTextOut()的跟踪;    
  10   退出MouseProc鼠标钩子程序,控制权交给系统。    
  11   在屏幕上移动鼠标,开始下一次“屏幕抓字”,返回步骤2。    
   
  八   前景展望    
  掌握了“屏幕抓字”的技术秘密,稍加改变,我们就可对WINDOWS   系统中    
  的    
   
  任意一个函数调用进行动态地拦截、跟踪、修改和恢复,就可让WINDOWS   系统中    
  的    
   
  任意一个函数按我们的设想工作,就可构造自己的外挂汉字平台,设计改变字体    
  的    
   
  放大镜、改变颜色的变色镜,保护视力的软件视保屏等等。    
   
  九   后记    
   
  希望此文能抛砖引玉,为大家编程时能找到捷径,开拓出新的思路;    
  对拦截、跟踪感兴趣的朋友也请来信交流切磋,如需DLL   或“抓字”的源    
  代   码,敬请    
  与   mafeitao@371.net   联系;Top

4 楼hebhd(汉德)回复于 2004-05-03 01:13:12 得分 0

第一篇。不知道你试过没有。根本不保存那个验证码的图片  
  第二篇。因为代码太乱。没有看懂是什么意思  
  第三篇。有比你贴的更好的。不过是C++的。我不知道怎么转vb还没有详细分析  
  Top

5 楼hebhd(汉德)回复于 2004-05-03 01:17:05 得分 0

第三篇的详细内容引自下面的网址  
  http://www.ccrun.com/doc/go.asp?id=139  
  C++的。我一时没有具体分析。是不是可以用vb实现.不过写的确实不错由于太长了。我分两篇回复。有能力的朋友帮帮忙改成vb的  
   
   
    文档标题:鼠标屏幕取词技术的原理和实现    
  关   键   字:鼠标屏幕取词,钩子,setwindowshookex    
  本文章自   2002-11-1   添加到   C++   Builder   研究   网站以来,已被阅读   1323   次。    
   
  --------------------------------------------------------------------------------  
     
  鼠标屏幕取词技术的原理和实现  
  作者:   白瑜   ,如转载请保证本文档的完整性,并注明出处。  
  欢迎光临   C++   Builder   研究,http://www.ccrun.com/doc/go.asp?id=139  
        “鼠标屏幕取词”技术是在电子字典中得到广泛地应用的,如四通利方和金山词霸等软件,这个技术看似简单,其实在windows系统中实现却是非常复杂的,总的来说有两种实现方式:  
          第一种:采用截获对部分gdi的api调用来实现,如textout,textouta等。  
          第二种:对每个设备上下文(dc)做一分copy,并跟踪所有修改上下文(dc)的操作。              
          第二种方法更强大,但兼容性不好,而第一种方法使用的截获windowsapi的调用,这项技术的强大可能远远超出了您的想象,毫不夸张的说,利用windowsapi拦截技术,你可以改造整个操作系统,事实上很多外挂式windows中文平台就是这么实现的!而这项技术也正是这篇文章的主题。  
          截windowsapi的调用,具体的说来也可以分为两种方法:  
          第一种方法通过直接改写winapi   在内存中的映像,嵌入汇编代码,使之被调用时跳转到指定的地址运行来截获;第二种方法则改写iat(import   address   table输入地址表),重定向winapi函数的调用来实现对winapi的截获。  
          第一种方法的实现较为繁琐,而且在win95、98下面更有难度,这是因为虽然微软说win16的api只是为了兼容性才保留下来,程序员应该尽可能地调用32位的api,实际上根本就不是这样!win   9x内部的大部分32位api经过变换调用了同名的16位api,也就是说我们需要在拦截的函数中嵌入16位汇编代码!  
          我们将要介绍的是第二种拦截方法,这种方法在win95、98和nt下面运行都比较稳定,兼容性较好。由于需要用到关于windows虚拟内存的管理、打破进程边界墙、向应用程序的进程空间中注入代码、pe(portable   executable)文件格式和iat(输入地址表)等较底层的知识,所以我们先对涉及到的这些知识大概地做一个介绍,最后会给出拦截部分的关键代码。  
          先说windows虚拟内存的管理。windows9x给每一个进程分配了4gb的地址空间,对于nt来说,这个数字是2gb,系统保留了2gb到   4gb之间的地址空间禁止进程访问,而在win9x中,2gb到4gb这部分虚拟地址空间实际上是由所有的win32进程所共享的,这部分地址空间加载了共享win32   dll、内存映射文件和vxd、内存管理器和文件系统码,win9x中这部分对于每一个进程都是可见的,这也是win9x操作系统不够健壮的原因。win9x中为16位操作系统保留了0到4mb的地址空间,而在4mb到2gb之间也就是win32进程私有的地址空间,由于   每个进程的地址空间都是相对独立的,也就是说,如果程序想截获其它进程中的api调用,就必须打破进程边界墙,向其它的进程中注入截获api调用的代码,这项工作我们交给钩子函数(setwindowshookex)来完成,关于如何创建一个包含系统钩子的动态链接库,《电脑高手杂志》在第?期已经有过专题介绍了,这里就不赘述了。所有系统钩子的函数必须要在动态库里,这样的话,当进程隐式或显式调用一个动态库里的函数时,系统会把这个动态库映射到这个进程的虚拟地址空间里,这使得dll成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈,也就是说动态链接库中的代码被钩子函数注入了其它gui进程的地址空间(非gui进程,钩子函数就无能为力了),当包含钩子的dll注入其它进程后,就可以取得映射到这个进程虚拟内存里的各个模块(exe和dll)的基地址,如:hmodule   hmodule=getmodulehandle(“mypro.exe”);在mfc程序中,我们可以用afxgetinstancehandle()函数来得到模块的基地址。exe和dll被映射到虚拟内存空间的什么地方是由它们的基地址决定的。它们的基地址是在链接时由链接器决定的。当你新建一个win32工程时,vc++链接器使用缺省的基地址0x00400000。可以通过链接器的base选项改变模块的基地址。exe通常被映射到虚拟内存的0x00400000处,dll也随之有不同的基地址,通常被映射到不同进程的相同的虚拟地址空间处。  
      系统将exe和dll原封不动映射到虚拟内存空间中,它们在内存中的结构与磁盘上的静态文件结构是一样的。即pe   (portable   executable)   文件格式。我们得到了进程模块的基地址以后,就可以根据pe文件的格式穷举这个模块的image_import_descriptor数组,看看进程空间中是否引入了我们需要截获的函数所在的动态链接库,比如需要截获“textouta”,就必须检查“gdi32.dll”是否被引入了。说到这里,我们有必要介绍一下pe文件的格式,如右图,这是pe文件格式的大致框图,最前面是文件头,我们不必理会,从pe   file   optional   header后面开始,就是文件中各个段的说明,说明后面才是真正的段数据,而实际上我们关心的只有一个段,那就是“.idata”段,这个段中包含了所有的引入函数信息,还有iat(import   address   table)的rva(relative   virtual   address)地址。  
        说到这里,截获windowsapi的整个原理就要真相大白了。实际上所有进程对给定的api函数的调用总是通过pe文件的一个地方来转移的,这就是一个该模块(可以是exe或dll)的“.idata”段中的iat输入地址表(import   address   table)。在那里有所有本模块调用的其它dll的函数名及地址。对其它dll的函数调用实际上只是跳转到输入地址表,由输入地址表再跳转到dll真正的函数入口。  
   
        具体来说,我们将通过image_import_descriptor数组来访问“.idata”段中引入的dll的信息,然后通过image_thunk_data数组来针对一个被引入的dll访问该dll中被引入的每个函数的信息,找到我们需要截获的函数的跳转地址,然后改成我们自己的函数的地址……具体的做法在后面的关键代码中会有详细的讲解。  
     
     
   
  Top

6 楼hebhd(汉德)回复于 2004-05-03 01:20:10 得分 0

讲了这么多原理,现在让我们回到“鼠标屏幕取词”的专题上来。除了api函数的截获,要实现“鼠标屏幕取词”,还需要做一些其它的工作,简单的说来,可以把一个完整的取词过程归纳成以下几个步骤:  
  1.   安装鼠标钩子,通过钩子函数获得鼠标消息。  
      使用到的api函数:setwindowshookex  
  2.   得到鼠标的当前位置,向鼠标下的窗口发重画消息,让它调用系统函数重画窗口。  
      使用到的api函数:windowfrompoint,screentoclient,invalidaterect  
  3.   截获对系统函数的调用,取得参数,也就是我们要取的词。  
        对于大多数的windows应用程序来说,如果要取词,我们需要截获的是“gdi32.dll”中的“textouta”函数。  
  我们先仿照textouta函数写一个自己的mytextouta函数,如:  
  bool   winapi   mytextouta(hdc   hdc,   int   nxstart,   int   nystart,   lpcstr   lpszstring,int   cbstring)  
  {  
                //   这里进行输出lpszstring的处理  
              //   然后调用正版的textouta函数  
  }  
        把这个函数放在安装了钩子的动态连接库中,然后调用我们最后给出的hookimportfunction函数来截获进程对textouta函数的调用,跳转到我们的mytextouta函数,完成对输出字符串的捕捉。hookimportfunction的用法:  
   
  hookfuncdesc   hd;  
  proc                   porigfuns;  
  hd.szfunc="textouta";  
  hd.pproc=(proc)mytextouta;  
  hookimportfunction   (afxgetinstancehandle(),"gdi32.dll",&hd,porigfuns);  
  下面给出了hookimportfunction的源代码,相信详尽的注释一定不会让您觉得理解截获到底是怎么实现的很难,ok,let’s   go:  
   
  /////////////////////////////////////////////   begin   ///////////////////////////////////////////////////////////////  
  #include   <crtdbg.h>  
   
  //   这里定义了一个产生指针的宏  
  #define   makeptr(cast,   ptr,   addvalue)   (cast)((dword)(ptr)+(dword)(addvalue))  
   
  //   定义了hookfuncdesc结构,我们用这个结构作为参数传给hookimportfunction函数  
  typedef   struct   tag_hookfuncdesc  
  {  
      lpcstr   szfunc;   //   the   name   of   the   function   to   hook.  
      proc   pproc;         //   the   procedure   to   blast   in.  
  }   hookfuncdesc   ,   *   lphookfuncdesc;  
   
  //   这个函数监测当前系统是否是windownt  
  bool   isnt();  
   
  //   这个函数得到hmodule   --   即我们需要截获的函数所在的dll模块的引入描述符(import   descriptor)  
  pimage_import_descriptor   getnamedimportdescriptor(hmodule   hmodule,   lpcstr   szimportmodule);  
   
  //   我们的主函数  
  bool   hookimportfunction(hmodule   hmodule,   lpcstr   szimportmodule,    
                                                    lphookfuncdesc   pahookfunc,   proc*   paorigfuncs)  
  {  
  ///////////////////////   下面的代码检测参数的有效性   ////////////////////////////  
  _assert(szimportmodule);  
  _assert(!isbadreadptr(pahookfunc,   sizeof(hookfuncdesc)));  
  #ifdef   _debug  
  if   (paorigfuncs)   _assert(!isbadwriteptr(paorigfuncs,   sizeof(proc)));  
  _assert(pahookfunc.szfunc);  
  _assert(*pahookfunc.szfunc   !=   '\0');  
                  _assert(!isbadcodeptr(pahookfunc.pproc));  
  #endif  
  if   ((szimportmodule   ==   null)   ||   (isbadreadptr(pahookfunc,   sizeof(hookfuncdesc))))  
  {  
      _assert(false);  
      setlasterrorex(error_invalid_parameter,   sle_error);  
      return   false;  
  }  
  //////////////////////////////////////////////////////////////////////////////  
   
  //   监测当前模块是否是在2gb虚拟内存空间之上  
  //   这部分的地址内存是属于win32进程共享的  
  if   (!isnt()   &&   ((dword)hmodule   >=   0x80000000))  
  {  
      _assert(false);  
      setlasterrorex(error_invalid_handle,   sle_error);  
      return   false;  
  }  
            //   清零  
  if   (paorigfuncs)   memset(paorigfuncs,   null,   sizeof(proc));    
   
  //   调用getnamedimportdescriptor()函数,来得到hmodule   --   即我们需要  
  //   截获的函数所在的dll模块的引入描述符(import   descriptor)  
  pimage_import_descriptor   pimportdesc   =   getnamedimportdescriptor(hmodule,   szimportmodule);  
  if   (pimportdesc   ==   null)  
  return   false;   //   若为空,则模块未被当前进程所引入  
   
  //     从dll模块中得到原始的thunk信息,因为pimportdesc->firstthunk数组中的原始信息已经  
  //     在应用程序引入该dll时覆盖上了所有的引入信息,所以我们需要通过取得pimportdesc->originalfirstthunk  
  //     指针来访问引入函数名等信息  
  pimage_thunk_data   porigthunk   =   makeptr(pimage_thunk_data,   hmodule,    
                                                                                                pimportdesc->originalfirstthunk);  
   
  //     从pimportdesc->firstthunk得到image_thunk_data数组的指针,由于这里在dll被引入时已经填充了  
  //     所有的引入信息,所以真正的截获实际上正是在这里进行的  
  pimage_thunk_data   prealthunk   =   makeptr(pimage_thunk_data,   hmodule,   pimportdesc->firstthunk);  
   
  //     穷举image_thunk_data数组,寻找我们需要截获的函数,这是最关键的部分!  
  while   (porigthunk->u1.function)  
  {  
      //   只寻找那些按函数名而不是序号引入的函数  
      if   (image_ordinal_flag   !=   (porigthunk->u1.ordinal   &   image_ordinal_flag))  
      {  
        //   得到引入函数的函数名  
        pimage_import_by_name   pbyname   =   makeptr(pimage_import_by_name,   hmodule,  
                                porigthunk->u1.addressofdata);  
   
        //   如果函数名以null开始,跳过,继续下一个函数        
        if   ('\0'   ==   pbyname->name[0])  
          continue;  
   
        //   bdohook用来检查是否截获成功  
        bool   bdohook   =   false;  
   
        //   检查是否当前函数是我们需要截获的函数  
        if   ((pahookfunc.szfunc[0]   ==   pbyname->name[0])   &&  
          (strcmpi(pahookfunc.szfunc,   (char*)pbyname->name)   ==   0))  
        {  
          //   找到了!  
          if   (pahookfunc.pproc)  
          bdohook   =   true;  
        }  
        if   (bdohook)  
        {  
          //   我们已经找到了所要截获的函数,那么就开始动手吧  
          //   首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取  
          memory_basic_information   mbi_thunk;  
          virtualquery(prealthunk,   &mbi_thunk,   sizeof(memory_basic_information));  
          _assert(virtualprotect(mbi_thunk.baseaddress,   mbi_thunk.regionsize,    
                                                  page_readwrite,   &mbi_thunk.protect));  
   
          //   保存我们所要截获的函数的正确跳转地址  
          if   (paorigfuncs)  
              paorigfuncs   =   (proc)prealthunk->u1.function;  
   
          //   将image_thunk_data数组中的函数跳转地址改写为我们自己的函数地址!  
          //   以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用  
          prealthunk->u1.function   =   (pdword)pahookfunc.pproc;  
   
          //   操作完毕!将这一块虚拟内存改回原来的保护状态  
          dword   dwoldprotect;  
          _assert(virtualprotect(mbi_thunk.baseaddress,   mbi_thunk.regionsize,    
                                                  mbi_thunk.protect,   &dwoldprotect));  
          setlasterror(error_success);  
          return   true;  
        }  
      }  
      //   访问image_thunk_data数组中的下一个元素  
      porigthunk++;  
      prealthunk++;  
  }  
  return   true;  
  }  
   
  //   getnamedimportdescriptor函数的实现  
  Top

7 楼BlueBeer(1win)回复于 2004-05-03 01:27:41 得分 0

楼主的问题我也关注一段时间了,就是怎么把所谓验证码或附加码的图片转换成文字,我想你的程序下一步也要用到这个,如果有答案,还请不吝赐教啊Top

8 楼hebhd(汉德)回复于 2004-05-04 02:11:43 得分 0

图片转成文字需要分析对方验证码的规率。  
  因为现在的验证码不过是字母加数字。还没有到汉字的地步。如果改成汉字的时候估计就没折了。Top

相关问题

  • MQ系列。。。
  • 菜鸟系列
  • top系列
  • top系列
  • 放分系列-2
  • 放分系列-3
  • 放分系列-6
  • 放分系列-7
  • 放分系列-8
  • 放分系列-9

关键词

  • c++
  • c++ builder
  • win32
  • win95
  • 函数
  • 应用程序
  • 鼠标
  • 屏幕
  • 系统
  • 内存

得分解答快速导航

  • 帖主:hebhd
  • online

相关链接

  • Visual Basic类图书
  • Visual Basic类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo