开源项目之防火墙 tdifw

tdifw是windows防火墙软件(TDI层驱动过滤),负责监控网络监听与连接、以及过滤信息。

源码在src目录, 程序在Bin目录,执行根目录下的批处理文件也可以,
具体步骤如下: 
1. 运行install.bat 
2. 根据你机器的配置情况,编辑%SystemRoot%\system32\drivers\etc\tdifw.conf配置文件 
3. 重新启动计算机 

主程序源码是win32的,就9个目标文件,不包含驱动部分,项目如图:

开源项目之防火墙 tdifw_第1张图片

程序主要源码分析:

int main(int argc, char **argv)
{
    static SERVICE_TABLE_ENTRY dispatch_table[] = {
        {"tdifw", service_main},
        {NULL, NULL}
    };

	_LEAK_CHECK;

	//模拟参数
	argc = 3;
	argv[0]="tdifw";
	argv[1]="install";
	argv[2]="tdifw_drv.sys";

	if (argc >= 2) 
	{
		const char *param = argv[1];
		
		if (strcmp(param, "install") == 0) 
		{
			if (argc < 3) 
			{
				fprintf(stderr, "Use: tdifw install <config>\n");
				return -1;
			}
		
			//加载驱动服务
			install_service(argv[2]);
		
		} 
		else if (strcmp(param, "remove") == 0) 
		{
			//移除驱动服务
			remove_service();
		} else if (strcmp(param, "debug") == 0) 
		{

			if (argc < 3) 
			{
				fprintf(stderr, "Use: tdifw debug <config>\n");
				return -1;
			}

			if (start(argv[2])) 
			{
				printf("press enter to exit...\n");
				getchar();
				printf("exiting...\n");
				//停止 释放资源
				stop();
			}

		} else if (strcmp(param, "listen") == 0) 
		{		// tdifw specific
			//枚举监听
			enum_listen();
		} else if (strcmp(param, "conn") == 0)
		{		// tdifw specific
			//枚举连接
			enum_connect();
		} else 
		{
			fprintf(stderr, "Use: tdifw install|remove|debug|listen|conn\n");
		}
	}
	else 
	{
		g_console = FALSE;

		// 连接程序主线程到服务控制管理程序
		if (!StartServiceCtrlDispatcher(dispatch_table))
			winerr("main: StartServiceCtrlDispatcher");

	}

	return 0;
}

//获得驱动文件所在路径 则开启 否则退出
void install_service(const char *config)
{
	SC_HANDLE	schService;
	SC_HANDLE	schSCManager;

	CHAR szPath[MAX_PATH];

	//从注册表中获得信息
	AddEventSource("tdifw");

	if (GetModuleFileName(NULL, szPath, sizeof(szPath)) == 0) {
		winerr("install_service: GetModuleFileName");
		return;
	}

	//建立了一个连接到服务控制管理器,并打开指定的数据库。
	schSCManager = OpenSCManager(
						NULL,					// machine (NULL == local)
						NULL,					// database (NULL == default)
						SC_MANAGER_ALL_ACCESS);	// access required

	if (schSCManager != NULL) {

		//创建一个服务对象并且把它加入到服务管理数据库中
		schService = CreateService(
			schSCManager,				// SCManager database
			"tdifw",				    // name of service
			"TDI-based open source personal firewall",	// name to display
			SERVICE_ALL_ACCESS, 		// desired access
			SERVICE_WIN32_OWN_PROCESS,	// service type
			SERVICE_AUTO_START,		    // start type
			SERVICE_ERROR_NORMAL,		// error control type
			szPath, 					// service's binary
			NULL,						// no load ordering group
			NULL,						// no tag identifier
			NULL,						// dependencies
			NULL,						// LocalSystem account
			NULL);						// no password

		if (schService != NULL) {
			printf("tdifw service has been installed\n");

			if (!add_config_info(schService, config))
				fprintf(stderr, "Can't store config info! Service will use defaults.\n");

			CloseServiceHandle(schService);
		} else
			winerr("install_service: CreateService");

		CloseServiceHandle(schSCManager);
	}
	else
		winerr("install_service: OpenSCManager");
}

//移除服务 关闭驱动
void remove_service(void)
{
	SC_HANDLE	schService;
	SC_HANDLE	schSCManager;

	schSCManager = OpenSCManager(
						NULL,					// machine (NULL == local)
						NULL,					// database (NULL == default)
						SC_MANAGER_ALL_ACCESS); // access required
	
	if (schSCManager != NULL) {
		schService = OpenService(schSCManager, "tdifw", SERVICE_ALL_ACCESS);

		if (schService != NULL) {

			// try to stop the service
			if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) {
				printf("stopping...");
				Sleep(1000);

				while(QueryServiceStatus( schService, &ssStatus)) {
					if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
						printf(".");
						Sleep( 1000 );
					}
					else
						break;
				}

				printf("\n");

				if (ssStatus.dwCurrentState == SERVICE_STOPPED)
					printf("stopped\n");
				else
					printf("failed to stop\n");
			}

			// now remove the service
			if (DeleteService(schService))
				printf("service has been removed\n");
			else
				winerr("install_service: DeleteService");

			CloseServiceHandle(schService);
		}
		else
			winerr("install_service: OpenService");

		CloseServiceHandle(schSCManager);
	}
	else
		winerr("install_service: OpenSCManager");
}

// 从驱动程序中获得网络监听对象
void enum_listen(void)
{
	ULONG size;
	struct listen_nfo *ln = NULL;
	int i, n;

	// 从 psapi.dll 中获得链接EnumProcesses、EnumProcessModules、GetModuleFileNameExW函数地址
	link_psapi();

	/* connect with driver */
	
	g_device = CreateFile(g_nfo_device_name, GENERIC_READ | GENERIC_WRITE, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (g_device == INVALID_HANDLE_VALUE) {
		winerr(g_nfo_device_name);
		goto done;
	}

	/* get list of listening objects */

	size = sizeof(*ln) * 0x10000 * 3;	// this size is good enough :-)
	ln = (struct listen_nfo *)malloc(size);
	if (ln == NULL) {
		perror("malloc");
		goto done;
	}

	//与驱动交流 枚举监听操作 获取监听信息
	if (!DeviceIoControl(g_device, IOCTL_CMD_ENUM_LISTEN, NULL, 0,
		ln, size, &size, NULL)) {
		winerr("DeviceIoControl");
		goto done;
	}

	n = size / sizeof(*ln);

	// sort this list! 
	qsort(ln, n, sizeof(*ln), compare_ln);

	printf("IPProto\tAddress:Port\tProcess (pid)\n");
	printf("-------\t------------\t---------------------------------------------\n");

	//显示
	for (i = 0; i < n ; i++) {
		char *proto, pname[MAX_PATH];
		
		if (ln[i].ipproto == IPPROTO_TCP)
			proto = "TCP";
		else if (ln[i].ipproto == IPPROTO_UDP)
			proto = "UDP";
		else if (ln[i].ipproto == IPPROTO_IP)
			proto = "RawIP";
		else
			proto = "?";

		// resolve pid!
		if (!get_pname_by_pid(ln[i].pid, pname, sizeof(pname)))
			pname[0] = '\0';

		printf("%s\t%d.%d.%d.%d:%d\t%s (%d)\n",
			proto, PRINT_IP_ADDR(ln[i].addr), ntohs(ln[i].port), pname, ln[i].pid);
	}

done:
	free(ln);
	if (g_device != INVALID_HANDLE_VALUE)
		CloseHandle(g_device);
}

// 从驱动程序中获得网络连接信息
void enum_connect(void)
{
	ULONG size;
	struct tcp_conn_nfo *tn = NULL;
	int i, n;
	unsigned __int64 traffic[TRAFFIC_MAX];

	// 从 psapi.dll 中获得链接EnumProcesses、EnumProcessModules、GetModuleFileNameExW函数地址
	link_psapi();

	/* connect with driver */
	
	g_device = CreateFile(g_nfo_device_name, GENERIC_READ | GENERIC_WRITE, 
		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
	if (g_device == INVALID_HANDLE_VALUE) {
		winerr(g_nfo_device_name);
		goto done;
	}

	/* get list of listening objects */

	size = sizeof(*tn) * 0x10000 * 3;	// this size is good enough :-)
	tn = (struct tcp_conn_nfo *)malloc(size);
	if (tn == NULL) {
		perror("malloc");
		goto done;
	}

		//与驱动交流 枚举监听操作 获取连接信息
	if (!DeviceIoControl(g_device, IOCTL_CMD_ENUM_TCP_CONN, NULL, 0,
		tn, size, &size, NULL)) {
		winerr("DeviceIoControl");
		goto done;
	}

	n = size / sizeof(*tn);

	// sort this list!
	qsort(tn, n, sizeof(*tn), compare_tn);

	//顺序输出
	for (i = 0; i < n ; i++) {
		char pname[MAX_PATH];

		if (tn[i].state >= TCP_STATE_MAX)
			tn[i].state = 0;
		
		// resolve pid!
		if (!get_pname_by_pid(tn[i].pid, pname, sizeof(pname)))
			pname[0] = '\0';

		printf("%s\t%d.%d.%d.%d:%d\t%d.%d.%d.%d:%d\t%s (%d)\t%u/%u\n",
			g_tcp_states[tn[i].state],
			PRINT_IP_ADDR(tn[i].laddr), ntohs(tn[i].lport),
			PRINT_IP_ADDR(tn[i].raddr), ntohs(tn[i].rport),
			pname, tn[i].pid,
			tn[i].bytes_out, tn[i].bytes_in);
	}

	// output traffic counters
	get_traffic_stats(traffic);

	printf(
		"\n"
		"Traffic counters (out/in):\n"
		"    Total:   %I64u/%I64u\n"
		"    Counted: %I64u/%I64u\n",
		traffic[TRAFFIC_TOTAL_OUT], traffic[TRAFFIC_TOTAL_IN],
		traffic[TRAFFIC_COUNTED_OUT], traffic[TRAFFIC_COUNTED_IN]);

done:
	free(tn);
	if (g_device != INVALID_HANDLE_VALUE)
		CloseHandle(g_device);
}

以上是主要程序的源码,驱动部分共有32个目标文件,如图:

开源项目之防火墙 tdifw_第2张图片


/* 驱动入口 */
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
            IN PUNICODE_STRING theRegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
	int i;
	UNICODE_STRING name, linkname;

	//内存跟踪初始化	调用了KeInitializeSpinLock(&guard);
	memtrack_init();

	//初始化锁
	KeInitializeSpinLock(&g_traffic_guard);

#ifdef USE_TDI_HOOKING
	KdPrint(("[tdi_fw] WARNING! Using unstable working mode: TDI hooking!\n"));
#endif

	status = ot_init();
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: ot_init: 0x%x\n", status));
		goto done;
	}

	//过滤器初始化
	status = filter_init();
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: filter_init: 0x%x\n", status));
		goto done;
	}

	//连接状态初始化
	status = conn_state_init();
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: conn_state_init: 0x%x\n", status));
		goto done;
	}
	
	//分发函数
	for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
		theDriverObject->MajorFunction[i] = DeviceDispatch;

#if DBG
	// register UnLoad procedure
	theDriverObject->DriverUnload = OnUnload;
#endif

	/* create control device and symbolic link */

	RtlInitUnicodeString(&name, L"\\Device\\tdifw");

	status = IoCreateDevice(theDriverObject,
							0,
							&name,
							0,
							0,
							TRUE,		// exclusive!
							&g_devcontrol);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(control): 0x%x!\n", status));
		goto done;
	}

	RtlInitUnicodeString(&linkname, L"\\??\\tdifw");

	//创建了一个符号连接
	status = IoCreateSymbolicLink(&linkname, &name);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status));
		goto done;
	}

	RtlInitUnicodeString(&name, L"\\Device\\tdifw_nfo");

	//创建设备对象
	status = IoCreateDevice(theDriverObject,
							0,
							&name,
							0,
							0,
							FALSE,		// not exclusive!
							&g_devnfo);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(nfo): 0x%x!\n", status));
		goto done;
	}

	RtlInitUnicodeString(&linkname, L"\\??\\tdifw_nfo");

	//创建了一个符号连接
	status = IoCreateSymbolicLink(&linkname, &name);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status));
		goto done;
	}

#ifndef USE_TDI_HOOKING

	//绑定设备
	status = c_n_a_device(theDriverObject, &g_tcpfltobj, &g_tcpoldobj, L"\\Device\\Tcp");
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
		goto done;
	}

		//绑定设备
	status = c_n_a_device(theDriverObject, &g_udpfltobj, &g_udpoldobj, L"\\Device\\Udp");
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
		goto done;
	}

		//绑定设备
	status = c_n_a_device(theDriverObject, &g_ipfltobj, &g_ipoldobj, L"\\Device\\RawIp");
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
		goto done;
	}

#else	/* USE_TDI_HOOKING */

	/* get device objects for tcp/udp/ip */
	//获得tcp设备对象
	status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(tcp): 0x%x\n", status));
		goto done;
	}
	//获得Udp设备对象
	status = get_device_object(L"\\Device\\Udp", &g_udpfltobj);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(udp): 0x%x\n", status));
		goto done;
	}
	//获得RawIp设备对象
	status = get_device_object(L"\\Device\\RawIp", &g_ipfltobj);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: get_device_object(ip): 0x%x\n", status));
		goto done;
	}

	/* hook tcpip */
	//针对tcp下钩子
	status = hook_tcpip(&g_old_DriverObject, TRUE);
	if (status != STATUS_SUCCESS) {
		KdPrint(("[tdi_fw] DriverEntry: hook_driver: 0x%x\n", status));
		goto done;
	}
	g_hooked = TRUE;

#endif	/* USE_TDI_HOOKING */

	status = STATUS_SUCCESS;

done:
	if (status != STATUS_SUCCESS) {
		// cleanup
		OnUnload(theDriverObject);
	}

    return status;
}

针对tcp或udp、ip等设备对象时的操作,操作分两种:设备过滤模式 和 TDI Hook模式。源码如下:

		//TDI Hook过滤模式
		case IRP_MJ_CREATE:		/* create fileobject */
			
			result = tdi_create(irp, irps, &completion);

			status = tdi_dispatch_complete(DeviceObject, irp, result,
				completion.routine, completion.context);
			
			break;

		case IRP_MJ_DEVICE_CONTROL:
			
			KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_DEVICE_CONTROL, control 0x%x for 0x%08X\n",
				irps->Parameters.DeviceIoControl.IoControlCode, irps->FileObject));

			if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
				/*
				 * try to convert it to IRP_MJ_INTERNAL_DEVICE_CONTROL
				 * (works on PASSIVE_LEVEL only!)
				 */
				status = TdiMapUserRequest(DeviceObject, irp, irps);
			
			} else
				status = STATUS_NOT_IMPLEMENTED; // set fake status

			if (status != STATUS_SUCCESS) {
				void *buf = (irps->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) ?
					irps->Parameters.DeviceIoControl.Type3InputBuffer : NULL;

				// send IRP to original driver
				status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);

				if (buf != NULL && status == STATUS_SUCCESS) {

					g_TCPSendData = *(TCPSendData_t **)buf;

					KdPrint(("[tdi_fw] DeviceDispatch: IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER: TCPSendData = 0x%x\n",
						g_TCPSendData));

					*(TCPSendData_t **)buf = new_TCPSendData;
				}

				break;
			}

			// don't break! go to internal device control!
		
		case IRP_MJ_INTERNAL_DEVICE_CONTROL: {
			/*
			 * Analyze ioctl for TDI driver
			 */
			int i;

			for (i = 0; g_tdi_ioctls[i].MinorFunction != 0; i++)
				if (g_tdi_ioctls[i].MinorFunction == irps->MinorFunction) {
					
#if DBG
					// print description
					KdPrint(("[tdi_fw] DeviceDispatch: %s (0x%x) for 0x%x\n",
						g_tdi_ioctls[i].desc,
						irps->MinorFunction,
						irps->FileObject));
#endif

					if (g_tdi_ioctls[i].fn == NULL) {
						// send IRP to original driver
						status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,
							NULL, NULL);
						break;
					}

					// call dispatch function

					result = g_tdi_ioctls[i].fn(irp, irps, &completion);

					// complete request
					status = tdi_dispatch_complete(DeviceObject, irp, result,
						completion.routine, completion.context);

					break;
				}
	
			// if dispatch function hasn't been found
			if (g_tdi_ioctls[i].MinorFunction == 0) {
				// send IRP to original driver
				status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
			}

			break;
		}

		case IRP_MJ_CLEANUP:		/* cleanup fileobject */

			result = tdi_cleanup(irp, irps, &completion);

			status = tdi_dispatch_complete(DeviceObject, irp, result,
				completion.routine, completion.context);
			break;

		case IRP_MJ_CLOSE:
			KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_CLOSE fileobj 0x%x\n", irps->FileObject));

			// passthrough IRP
			status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,
				completion.routine, completion.context);

			break;

		//设备过滤操作模式
		if (irps->MajorFunction == IRP_MJ_CREATE) {

			// initialize for user-mode part (exclusive access - 1 user-mode logging part)
			filter_init_2();

			g_got_log = TRUE;

		} else if (irps->MajorFunction == IRP_MJ_CLOSE) {

			// cleanup for user-mode logging part
			filter_free_2();

			g_got_log = FALSE;

		} if (irps->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

			/*
			 * control request
			 */

			ULONG ioctl = irps->Parameters.DeviceIoControl.IoControlCode,
				len = irps->Parameters.DeviceIoControl.InputBufferLength,
				size = irps->Parameters.DeviceIoControl.OutputBufferLength;
			char *out_buf;

			if (IOCTL_TRANSFER_TYPE(ioctl) == METHOD_NEITHER) {
				// this type of transfer unsupported
				out_buf = NULL;
			} else
				out_buf = (char *)irp->AssociatedIrp.SystemBuffer;

			// process control request
			status = process_request(ioctl, out_buf, &len, size);

			irp->IoStatus.Information = len;

		}

		irp->IoStatus.Status = status;

		IoCompleteRequest(irp, IO_NO_INCREMENT);

开源项目之防火墙 tdifw_第3张图片


学习的目的是成熟!~

源码包下载



你可能感兴趣的:(开源项目之防火墙 tdifw)