返回列表 发帖

检测并禁用隐藏服务

隐藏服务的概念是由hxdef和rootkit这些后门工具提出的。这些后门工具通过挂钩系统本地调用来隐藏自己,原本通过调用WindowsAPI调用查看系统服务的企图都是徒劳的。所以这时的系统是不可靠的,不值得信任的。目前针对查找隐藏服务的工具已经有很多,比如IceSword,knlsc,FHS等等。虽然这些软件都是免费的,但是它们到目前为止都不是开源,所以将自己的实现版本展示出来,正如knlsc的作者所说的那样,这是一个简单的小程序。 Knlsc是通过将%SystemRoot%/System32/Config/System这个Hive文件转储出来,提取出ControlSet001/Services的子项再与RegEnumKeyEx的输出结果进行比对,发现若是在RegEnumKeyEx的输出结果中没有的子项就可以认为是一个隐藏的服务。当然knlsc还认为隐藏服务必须同时拥有ImagePath,Start,Type三个键值。据说knlsc运行时还将从资源段中放出一个驱动程序,但是估计这个驱动是假的。将knlsc托壳后用VC从资源段中导出的文件是一个没有EntryPoint但有MZ标志的驱动,没有办法进行反汇编。或许作者使用了SMC技术,放出资源文件后在进行修改,在执行文件中也有NtLoadDriver的调用片段,但是同一作者的knlps中的资源驱动却未作任何的处理。要实现检测隐藏服务的功能其实没有必要使用驱动程序,即使可以验证knlsc驱动的真实性。直接对Hive文件的转储也不是必须的,虽然这只要通过修改GaryNebbett的示例代码就可做到。 Hive文件的转储可以通过RegSaveKey函数来进行,rootkitrevealer就是使用这个API的扩充函数RegSaveKeyEx工作的,至少到目前为止还没有挂钩这类函数的后门,但是世上没有永远的安全,在理论上是可行的,可能不得不对该函数的输出文件进行处理,这将在一定程度上影响该函数的执行时间。使用该函数时还必须赋予调用进程以SE_BACKUP_NAME权限。 在实现中将“HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services"的子项都转储为Hive格式文件(使用DumpServiceInfo函数),存放在C:\tmp.hive,在C盘下不可有同名文件,否则会发生Dump错误。现在的问题是如何对Hive格式文件进行处理,在这一点上必须感谢PetterNordahl-Hagen所写的NTRegistryHiveaccesslibrary,它是TheOfflineNTPasswordEditor的一部分。本人的实现很大程度上就是参照他的程序,然而这个库工作在Linux环境,但是它向VC编译器移植的工作量是极少的,只需稍加修改。 1.将 #include 去掉 2.将程序中三处的 #defineD_OFFS(o)((void*)&(key->o)-(void*)hdesc->buffer-vofs) 改为 #defineD_OFFS(o)((int*)&(key->o)-(int*)hdesc->buffer-vofs) 因为在VC中无法打印void*类型,只得改为int* 。 3.将程序中唯一的一处使用snprintf函数该为_snprintf,即 snprintf(path,maxlen,"(...)%s",tmp);改为 _snprintf(ptth,maxlen,”(…)%s”,tmp); 4.添加两个VC不支持的函数来使编译通过 voidbzero(void*s,intn) { memset(s,0,n); } intstrncasecmp(constchar*s1,constchar*s2,size_tn) { return_stricmp(s1,s2); } 为了表示对PetterNordahl-Hagen的尊重,我不再修改他的库文件ntreg.c和ntreg.h(除了以上移植的需要),而是将所有需要重写和添加的函数放到KHS.C文件中,这样可以使原来的库文件保持其独立性。 由于在Petter库中openHive函数使用open和read函数来进行hive文件的读取,在VC条件下的read函数有一个问题,每当文件中存在一个0x1a的二进制数值时,read函数就会在那儿终止,这样就会导致hive文件无法完全导入。所以就使用了WindowsAPI重写openHive,命名为My_openHive。相应的还重写了closeHive,writeHive并加上了前缀My_。 随后GetPatterns函数将使用RegEnumKey枚举的服务键值名称保存在pattern的全局变量指针中,为以后的匹配作准备。ShowHideService函数是由nk_ls函数改写的,将由Hive文件导出的buffer中的服务名称与pattern[I]作比较,这个比较过程使用CompareHive函数。若比较结果为相同,CompareHive会将pattern[I]置为NULL,以提高匹配速度,或许有更好的匹配算法,但在这个小程序中也不使用了。若结果不同,则说明该服务是隐藏的,显示出该隐藏服务的名称,文件路径(ShowPathImage是由cat_vk改写的),启动类型和服务类型,并将该隐藏服务的启动类型改为SERVICE_DISABLED。如果存在隐藏服务并且禁止了该隐藏服务(仅在buffer中的修改),通过调用My_writeHive将修改过的hive的buffer保存在C:\tmp2.hiv文件中,此时提供用户一个选择“是否要禁用隐藏服务”,默认的选择是“否”,如果用户确实想要禁用,可输入“Yes”或“Y",接着使用RestoreServiceInfo函数将C:\tmp2.hiv文件导回原来的%SystemRoot%/System32/Config/System这个Hive文件中,这一步由系统自己来完成,值得一提的是Win32函数RegRestoreKey即使在dwFlags参数中使用了REG_FORCE_RESTORE(8),在第一次调用时往往会错误返回,一般在第二次调用就会成功,所以就使用了一个循环直到它成功后为止,并且调用它的进程需要有SE_RESTORE_NAME的权限。 至于让隐藏服务真正失去作用,仍然需要重新启动计算机之后。 下面给出KHS.C的完整源代码: /* *KHS.cpp-KillHideServicesv0.1 *Copyright(c)2005linux2linux. * *IttakesnotesfromknlscandFHS. *Thankyou,PetterNordahl-Hagen,foryour"NTRegistryHiveaccesslibrary" * *Freelydistributableinsourceorbinaryfornoncommercialpurposes. * *THISSOFTWAREISPROVIDEDBYPETTERNORDAHL-HAGEN`ASIS';';AND *ANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE *IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE *AREDISCLAIMED.INNOEVENTSHALLTHEAUTHORORCONTRIBUTORSBELIABLE *FORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIAL *DAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODS *ORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESSINTERRUPTION) *HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICT *LIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAY *OUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOF *SUCHDAMAGE. * */ #include"ntreg.h" #include char**pattern; intpattern_count; intnohideservice; intischange; externchar*val_types[REG_MAX+1]; structhive*My_openHive(char*filename,intmode); voidMy_closeHive(structhive*hdesc); intCompareHive(char*sample) { inti; for(i=0;i!=NULL) { if(strcmp(sample,pattern)==0) { free(pattern); pattern=NULL; return1; } } } return0; } //Becausereadcan';tworkwellinwindows. //whileitread0x1afromtheopenedfile,thefunctionreadwillstopthere. //Idon';tknowthereasonwhy,itworkwellinlinuxenvoriment. //readthedumpedhivefiletofillhivestruct. //returnthepoint structhive*My_openHive(char*filename,intmode) { HANDLEhFile; intszread; structhive*hdesc; intvofs; unsignedlongpofs; char*c; structhbin_page*p; structregf_header*hdr; intverbose=(mode&HMODE_VERBOSE); CREATE(hdesc,structhive,1); hdesc->filename=str_dup(filename); hdesc->state=0; hdesc->size=0; hdesc->buffer=NULL; hFile=CreateFile(hdesc->filename, GENERIC_READ,//openforreading 0,//donotshare NULL,//nosecurity OPEN_ALWAYS,//existingfileonly FILE_ATTRIBUTE_NORMAL,//normalfile NULL);//noattr.template if(hFile==INVALID_HANDLE_VALUE) { printf("Couldnotopenhivefile.");//processerror return0; } /*Readthewholefile*/ hdesc->size=GetFileSize(hFile,NULL); ALLOC(hdesc->buffer,1,hdesc->size); ReadFile(hFile,(void*)hdesc->buffer,hdesc->size,&szread,NULL); CloseHandle(hFile); if(szreadsize){ printf("Couldnotreadfile,got%dbyteswhileexpecting%d\n", szread,hdesc->size); My_closeHive(hdesc); return(NULL); } /*Nowrunthroughfile,tallyingallpages*/ /*NOTE/KLUDGE:Assumefirstpagestartsatoffset0x1000*/ pofs=0x1000; hdr=(structregf_header*)hdesc->buffer; if(hdr->id!=0x66676572){ printf("openHive(%s):Filedoesnotseemtobearegistryhive!\n",filename); return(hdesc); } for(c=hdr->name;*c&&(cname+64);c+=2)putchar(*c); hdesc->rootofs=hdr->ofs_rootkey+0x1000; while(pofssize){ #ifdefLOAD_DEBUG if(verbose)hexdump(hdesc->buffer,pofs,pofs+0x20,1); #endif p=(structhbin_page*)(hdesc->buffer+pofs); if(p->id!=0x6E696268){ printf("Pageat0x%lxisnot';hbin';,assumingfilecontainsgarbageatend",pofs); break; } hdesc->pages++; #ifdefLOAD_DEBUG if(verbose)printf("\n######Pageat0x%0lxhassize0x%0lx,nextat0x%0lx######\n",pofs,p->len_page,p->ofs_next); #endif if(p->ofs_next==0){ #ifdefLOAD_DEBUG if(verbose)printf("openhivedebug:bailingout..pagesizezero!\n"); #endif return(hdesc); } #if0 if(p->len_page!=p->ofs_next){ #ifdefLOAD_DEBUG if(verbose)printf("openhivedebug:len&ofsnotsame.HASTA!\n"); #endif exit(0); } #endif vofs=pofs+0x20;/*Skippageheader*/ #if1 while(vofs-pofsofs_next){ vofs+=parse_block(hdesc,vofs,verbose); } #endif pofs+=p->ofs_next; } return(hdesc); } voidMy_closeHive(structhive*hdesc) { FREE(hdesc->filename); FREE(hdesc->buffer); FREE(hdesc); } intMy_writeHive(structhive*hdesc) { HANDLEhFile; DWORDdwBytesWritten; hFile=CreateFile("C:\\tmp2.hiv", GENERIC_WRITE,//openforwriting 0,//donotshare NULL,//nosecurity CREATE_ALWAYS,//openorcreate FILE_ATTRIBUTE_NORMAL,//normalfile NULL); if(hFile==INVALID_HANDLE_VALUE) {printf("Can';topendumpfile"); return0; } WriteFile(hFile,hdesc->buffer,hdesc->size,&dwBytesWritten,NULL); if(dwBytesWritten!=hdesc->size) { printf("WriteHiveerror\n"); } CloseHandle(hFile); return0; } voidCleanPatterns() { inti; if(pattern!=NULL) { for(i=0;i!=NULL) free(pattern); } free(pattern); } } voidGetPatterns() { HANDLEhService; CHARachKey[MAX_PATH]; DWORDi; DWORDretCode; intNohide=1; DWORDSubKeyNum=0; pattern_count=0; if(RegOpenKeyEx( HKEY_LOCAL_MACHINE,//handletoopenkey "SYSTEM\\ControlSet001\\Services",//subkeyname NULL,//reserved KEY_ALL_ACCESS,//securityaccessmask &hService//handletoopenkey )!=ERROR_SUCCESS) { printf("sorry%d\n",GetLastError()); return; } RegQueryInfoKey(hService, NULL, NULL, NULL, &SubKeyNum, NULL, NULL, NULL, NULL, NULL, NULL, NULL); //Beforeitdon';tworkwell,becauseisetthewrongpremissionofHKEY //KEY_ALL_ACCESSisneeded if(SubKeyNum==0) { printf("SubKey';sNumberisNULL,it';stoostrange.\n"); return; } pattern=malloc(sizeof(char*)*SubKeyNum); for(i=0,retCode=ERROR_SUCCESS;retCode==ERROR_SUCCESS;i++) { retCode=RegEnumKey( hService,//handletokeytoquery i,//indexofsubkeytoquery achKey,//bufferforsubkeyname MAX_PATH//sizeofsubkeynamebuffer ); if(retCode==(DWORD)ERROR_SUCCESS) { //WhatiaddtogetpatternServicesTable. pattern[pattern_count]=strdup(achKey); pattern_count++; } } CloseHandle(hService); } voidShowPathImage(structhive*hdesc,intnkofs,char*path) { void*data; intlen,i,type; charstring[SZ_MAX+1]; type=get_val_type(hdesc,nkofs,path); if(type==-1){ printf("Nosuchvalue<%s>\n",path); return; } len=get_val_len(hdesc,nkofs,path); if(!len){ printf("Value<%s>haszerolength\n",path); return; } data=(void*)get_val_data(hdesc,nkofs,path,0); if(!data){ printf("Value<%s>referencesNULL-pointer(badboy!)\n",path); abort(); return; } switch(type){ caseREG_SZ: caseREG_EXPAND_SZ: caseREG_MULTI_SZ: cheap_uni2ascii(data,string,len); for(i=0;i<(len>>1)-1;i++){ if(string==0)string=';\n';; if(type==REG_SZ)break; } puts(string); break; caseREG_DWORD: printf("0x%08x",*(unsignedshort*)data); break; default: printf("Don';tknowhowtohandletypeyet!\n"); caseREG_BINARY: hexdump((char*)data,0,len,1); } } voidEnablePriv(LPCTSTRlpName) { HANDLEhToken; LUIDsedebugnameValue; TOKEN_PRIVILEGEStkp; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) {printf("openprocesserror\n"); return; } if(!LookupPrivilegeValue(NULL,lpName,&sedebugnameValue)){ printf("can';tfindprivilegeerror\n"); CloseHandle(hToken); return; } tkp.PrivilegeCount=1; tkp.Privileges[0].Luid=sedebugnameValue; tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,NULL)) { printf("adjusterror\n"); CloseHandle(hToken); } } intDumpServiceInfo() { HKEYhService; EnablePriv(SE_BACKUP_NAME); if(RegOpenKeyEx( HKEY_LOCAL_MACHINE,//handletoopenkey "SYSTEM\\ControlSet001\\Services",//subkeyname NULL,//reserved KEY_ALL_ACCESS,//securityaccessmask &hService//handletoopenkey )!=ERROR_SUCCESS) {printf("can';tgetkeyhandle\n"); return0; } if(RegSaveKey(hService,"C:\\tmp.hiv",NULL)!=ERROR_SUCCESS) { printf("Can';tdumpServiceinfo\n"); CloseHandle(hService); return0; } CloseHandle(hService); return1; } voidShowHideService(structhive*hdesc,char*path,intvofs,inttype) { structnk_key*key; intnkofs; structex_dataex; intcount=0,countri=0; //wHATIADD void*data; intnkofs_cat; intserviceno; serviceno=1; nkofs=trav_path(hdesc,vofs,path,0); if(!nkofs){ printf("nk_ls:Key<%s>notfound\n",path); abort(); return; } nkofs+=4; key=(structnk_key*)(hdesc->buffer+nkofs); if(key->id!=0x6b6e){ printf("Error:Nota';nk';node!\n"); debugit(hdesc->buffer,hdesc->size); } if(key->no_subkeys){ while((ex_next_n(hdesc,nkofs,&count,&countri,&ex)>0)){ if(!CompareHive(ex.name)) { nohideservice=0; if(!(serviceno-1)) printf("HideServiceList:\n"); printf("\n%d.------------------------------------------------------------\n",serviceno++); printf("HideService:%s\n",ex.name); nkofs_cat=trav_path(hdesc,vofs,ex.name,0); printf("ImagePath:"); ShowPathImage(hdesc,nkofs_cat+4,"ImagePath"); data=(void*)get_val_data(hdesc,nkofs_cat+4,"Start",0); if(data!=NULL) { printf("StartType:"); switch(*(unsignedshort*)data) { case0: printf("SERVICE_BOOT_START"); break; case1: printf("SERVICE_SYSTEM_START"); break; case2: printf("SERVICE_AUTO_START"); break; case3: printf("SERVICE_DEMAND_START"); break; case4: printf("SERVICE_DISABLED"); break; default: printf("UNKOWNSTARTTYPE"); } //disabletheservice if(*(unsignedshort*)data!=4) { printf("(WillbesettoDisabled)"); put_dword(hdesc,nkofs_cat+4,"Start",4); ischange=1; } printf("\n"); } data=(void*)get_val_data(hdesc,nkofs_cat+4,"Type",0); printf("ServiceType:"); if(data!=NULL) { if(*(unsignedshort*)data&1) printf("SERVICE_KERNEL_DRIVER"); if(*(unsignedshort*)data&2) printf("SERVICE_FILE_SYSTEM_DRIVER"); if(*(unsignedshort*)data&8) printf("SERVICE_RECOGNIZER_DRIVER"); if(*(unsignedshort*)data&16) printf("SERVICE_WIN32_OWN_PROCESS"); if(*(unsignedshort*)data&32) printf("SERVICE_WIN32_SHARE_PROCESS"); if(*(unsignedshort*)data&256) printf("SERVICE_INTERACTIVE_PROCESS"); printf("\n"); } } FREE(ex.name); } } if(nohideservice) printf("Therearenohideservices.\n"); else printf("\nTotalHideServicesis%d\n\n",serviceno-1); } intRestoreServiceInfo() { HKEYhService; LONGtmp; EnablePriv(SE_RESTORE_NAME); if(RegOpenKeyEx( HKEY_LOCAL_MACHINE,//handletoopenkey "SYSTEM\\ControlSet001\\Services",//subkeyname NULL,//reserved KEY_ALL_ACCESS,//securityaccessmask &hService//handletoopenkey )!=ERROR_SUCCESS) { printf("Can';topenServicekey\n"); return0; } //ThefirsttimetoRestorealwaysfailevenyousettheForceflag //Thesecondtimewillsuccess. for(;;) { if((tmp=RegRestoreKey(hService,"C:\\tmp2.hiv",8))==ERROR_SUCCESS) { break; } } CloseHandle(hService); return1; } intmain(intargc,char*argv[]) { structhive*pHive; charc; nohideservice=1; ischange=0; printf("KHS-killhideservices0.1bylinux2linux,2005/5/26.\n"); printf("TakenotesfromknlscandFHS.\n\n"); if(!DumpServiceInfo()) return0; pHive=My_openHive("C:\\tmp.hiv",HMODE_RW); if(pHive==NULL) { printf("OpenHivefail\n"); return0; } GetPatterns(); ShowHideService(pHive,"",pHive->rootofs+4,0); CleanPatterns(); if(!nohideservice&&ischange) { My_writeHive(pHive); printf("DoyouwantDisablethehideServices(Yes/No)?[No]:"); c=getchar(); if((c==';Y';)||c==';y';) { if(RestoreServiceInfo()) printf("SuccessRestore\n"); } else {printf("QuitwithoutRestore.\n"); } DeleteFile("C:\\tmp2.hiv"); } DeleteFile("C:\\tmp.hiv"); My_closeHive(pHive); return0; } 参考资源 1.TheOfflineNTPasswordEditor 源程序 -PetterNordahl-Hagen http://home.eunet.no/~pnordahl/ntpasswd/ 2.<>-GaryNebbett 3.Knlsc,FHS,IceSword使用说明

返回列表 回复 发帖