| 发表于:2007-07-28 11:27:533楼 得分:0 |
看完下面的文字 ,再确定你的 递归函数没写错 就应该ok了.. 天气热,,不多说了..粘贴了.. ------------------------------------------------------------------------------------ 网络共享资源也是按树状组织的,非叶节点称为容器(container),对容器需要进一步搜索直到到达叶子节点为止,叶子节点才是共享资源的根路径。共享资源一般分成两种:共享打印设备和共享文件夹。对于网络共享文件的搜索,采用wnetopenenum和wnetenumresource(由 mpr.dll导出)进行递归枚举。其函数原型及参数含义请参阅msdn,使用如下代码enumshare.cpp将显示所有的网络驱动器共享文件夹的路径: #include #include #pragma comment(lib, "mpr.lib ") int enum_netshare(lpnetresource lpnr); void __cdecl main(int argc,char *argv[]) { enum_netshare(0); } int enum_netshare(lpnetresource lpnr) { dword r, renum,usage; handle henum; dword cbbuffer = 16384; dword centries = -1; lpnetresource lpnrlocal; // netresource数组结构的指针 dword i; r = wnetopenenum(resource_globalnet, // 范围:所有网络资源 resourcetype_disk,// 类型:仅枚举可存储介质 resourceusage_all,// 使用状态:所有 lpnr, // 初次调用时为null &henum); // 成功后返回的网络资源句柄 if (r != no_error) { printf( "wnetopenenum error....\n "); return false; } lpnrlocal = (lpnetresource) malloc(cbbuffer); if (lpnrlocal == null) return false; do { zeromemory(lpnrlocal, cbbuffer); renum = wnetenumresource(henum, ¢ries, // 返回尽可能多的结果 lpnrlocal, // lpnetresource &cbbuffer); // buffer大小 if (renum == no_error) { for(i = 0; i < centries; i++) { usage = lpnrlocal.dwusage; if(usage & resourceusage_container) { if(!enum_netshare(&lpnrlocal)) printf( "errors detected in enum process...\n "); }else{ // 这里病毒可调用遍历函数遍历该共享文件夹下的所有文件 // enum_path(lpnrlocal.lpremotename); printf( "find %s --> %s\n ",lpnrlocal.lplocalname, lpnrlocal.lpremotename); } } }else if (renum != error_no_more_items) { printf( "wnetenumresource error...\n "); break; } }while(renum != error_no_more_items); free((void*)lpnrlocal); r = wnetcloseenum(henum); if(r != no_error) { printf( "wnetcloseenum error....\n "); return false; } return true; } 遍历开始时wnetopenenum第4形参为0,在发现共享容器进行递归调用时候,该参数将为共享容器的netresource结构指针。从 netresource结构中可以找到我们感兴趣的lpremotename,该指针不为0则表示是有效的共享容器或共享文件夹。 typedef struct _netresource { dword dwscope; dword dwtype; dword dwdisplaytype; dword dwusage; lptstr lplocalname; lptstr lpremotename; lptstr lpcomment; lptstr lpprovider; } netresource; 在解决了起始目录的问题之后,就可以从这些起始目录开始使用findfirstfile和findnextfile开始遍历其下以及其子目录下的所有文件和目录了,遍历方法可采用深度优先或广度优先搜索算法,较常用的还是深度优先算法。具体实现方式可采用递归搜索或非递归搜索两种实现方式。递归搜索需要占用栈空间,有可能造成栈空间耗竭而产生异常,不过在现实应用中这种情况很少出现,而非递归搜索则不存在此问题,但代码实现略复杂。在现实应用中,应用最多的还是递归遍历搜索。搜索时,可指定findfirstfile的第一形参为*.*以搜索所有文件,根据搜索结果win32_find_data结构的 dwfileattributes成员判断是否为目录,若为目录则需要继续遍历该子目录,根据win32_find_data的cfilename中的文件名成员判断是否具有要感染的文件后缀以采取修改感染动作,以下代码实现了递归搜索某个目录及其下所有子目录的功能: void enum_path(char *cpath){ win32_find_data wfd; handle hfd; char cdir[max_path]; char subdir[max_path]; int r; getcurrentdirectory(max_path,cdir); setcurrentdirectory(cpath); hfd = findfirstfile( "*.* ",&wfd); if(hfd!=invalid_handle_value) { do{ if(wfd.dwfileattributes & file_attribute_directory) { if(wfd.cfilename[0] != '. ') { //合成完整路径名 sprintf(subdir, "%s\\%s ",cpath,wfd.cfilename); //递归枚举子目录 enum_path(subdir); } }else{ printf( "%s\\%s\n ",cpath,wfd.cfilename); // 病毒可根据后缀名判断是否要感染相应的文件 } }while(r=findnextfile(hfd,&wfd),r!=0); } setcurrentdirectory(cdir); } 短短20多行c代码就实现了文件遍历的功能,win32 api的强大功能不仅为开发者提供了便利,同时也为病毒敞开了方便之门。用汇编实现则稍微复杂一些,感兴趣的读者可参阅elkern中的 enum_path部分,原理是一样的,限于篇幅这里不再给出相应的汇编代码。 非递归搜索不使用堆栈存储相关的信息,而使用显式分配的链表或栈等结构存储相关的信息,应用一个迭代循环完成递归遍历同样的功能,下面是使用链表以栈方式处理子目录列表的一个简单实现: void nr_enum_path(char *cpath){ list dir_list; string cdir,subdir; win32_find_data wfd; handle hfd; int r; dir_list.push_back(string(cpath)); while(dir_list.size()) { cdir = dir_list.back(); dir_list.pop_back(); setcurrentdirectory(cdir.c_str()); hfd = findfirstfile( "*.* ",&wfd); if(hfd!=invalid_handle_value) { do{ if(wfd.dwfileattributes & file_attribute_directory) { if(wfd.cfilename[0] != '. ') { //合成完整路径名 subdir=cdir+ "\\ "+wfd.cfilename; cout < < "push subdir: " < < //递归枚举子目录 dir_list.push_back(string(subdir)); } }else{ printf( "%s\\%s\n ",cpath,wfd.cfilename); // 病毒可根据后缀名判断是否要感染相应的文件 } }while(r=findnextfile(hfd,&wfd),r!=0); } }//end while } | | |
|