为了给本系列文章一个具体的实例,笔者编写了"网络黑手"这样一个免费软件。它是一种融合了目前许多类似工具软件功能的具有超强攻击/侦听能力的流氓软件,并可能将成为又一个臭名昭著的破坏性工具,它的功能包括:
1. 检测本地网络适配器列表并选择一个工作适配器;
2. 检测局域网内指定IP范围内所有节点的IP地址、MAC地址信息,并列表显示; 3. 监听局域网上某节点的所有收发信息;
4. 剪断局域网上某机器与网关的联络,从而让其不能上网;
5. 不停向局域网内某台主机发送ARP报文,让其不断提示"IP冲突",烦恼不已。
如果你所在的局域网内有人使用此软件攻击你的计算机,你将变得痛苦不堪。所以,笔者不得不声明的是编写本软件的目的不在于要荼毒生灵、贻害人间,而仅仅是为了本系列教程教学和广大读者掌握黑客攻防技术的需要。任何个人或组织使用本软件进行破坏行为,都应受到道德的谴责或可能的法律制裁。
尽管如此,为了防范于未然,笔者在研制"网络黑手"这一毒药的同时,也精心研制了其相应的解药――"网络黑手终结者",这一软件也是免费的。在你的网络内,如果有谁使用了"网络黑手",你将可以用"网络黑手终结者"直接终结之!
点击此处下载网络黑手;
网络黑手程序的运行最好先安装winpcap,请在此地址下载:http://www.winpcap.org/。
1、网络黑手的实现
网络黑手0.1版(限于时间的原因,在本教程中我们给出的仅仅是一个教学版本,所以版本号仅为0.1),其界面如下:
界面的左上角用于设置监控的目标范围(IP地址,如192.168.1.1~192.168.1.254,只能输入与本机处于同一子网的IP地址)、选择本地网卡(对于安装了多块网卡的用户),按钮"开始"用于启动监控和其他操作,启动成功后"开始"按钮会变为"停止"。
界面的左下角列出活动的与本机处于同一子网机器的主机名、IP地址、MAC地址,在相应的主机上双击"Sniffer"和"ARP欺骗"项目可以启动和停止对该主机的嗅探和ARP欺骗(会切断该机的外网出口)。
与之对应的数据结构为:
typedef struct tagHostList { unsigned long ip; char mac[6]; bool sniffer; bool arpCheat; bool ipConflict; } HostList; | 界面的右边即为监控到报文的源IP地址、目的IP地址、协议、源端口号、目的端口号以及报文的长度,而表格的最后一行将对应显示相关IP报文的数据。为了简化软件的设计和减少程序对内存的占用,在Sniffer时,实际缓存的数据包MAX_PACKET最大为30,超过的会自动被覆盖。
与之对应的数据结构为:
typedef struct tagPacketList { unsigned long srcIp; unsigned long desIp; unsigned char protocol; unsigned long srcPort; unsigned long desPort; unsigned long len; char data[256]; }PacketList; | 我们需要在对话框的初始化函数中构造上述界面中的表格项目,相关源代码如下:
BOOL CNetHackerDlg::OnInitDialog() { CDialog::OnInitDialog(); // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } }
// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here int i=0; //…
m_hostList.Create(CRect(12,115,435,466),this, 1000,WS_BORDER |WS_VISIBLE |WS_VSCROLL|WS_CHILD); m_hostList.SetScrollRange(1,0,351); m_hostList.EnableScrollBar(ESB_ENABLE_BOTH);
m_hostList.SetCols (5); m_hostList.SetRows (256); for (i = 0; i < 256; i ++) { m_hostList.SetRowHeight (i, 13); for(int j =0;j<5;j++) { m_hostList.SetAlignment(i,j,DT_CENTER); } }
m_hostList.SetColWidth (0, 100); m_hostList.SetColWidth (1, 130); m_hostList.SetColWidth (2, 50); m_hostList.SetColWidth (3, 55); m_hostList.SetColWidth (4, 70);
m_hostList.SetText (0,0,"IP地址"); m_hostList.SetText (0,1,"MAC地址"); m_hostList.SetText (0,2,"Sniffer"); m_hostList.SetText (0,3,"ARP欺骗"); m_hostList.SetText (0,4,"报告IP冲突");
m_packetList.Create(CRect(444,26,768,466),this, 1000); m_packetList.SetCols (6); m_packetList.SetRows (31); for (i = 0; i < 30; i ++) { m_packetList.SetRowHeight (i, 13); for(int j =0;j<6;j++) { m_packetList.SetAlignment(i,j,DT_CENTER); } } m_packetList.SetRowHeight (i, 47);
m_packetList.SetColWidth (0, 75); m_packetList.SetColWidth (1, 75); m_packetList.SetColWidth (2, 32); m_packetList.SetColWidth (3, 45); m_packetList.SetColWidth (4, 55); m_packetList.SetColWidth (5, 40); m_packetList.SetText (0,0,"源IP"); m_packetList.SetText (0,1,"目的IP"); m_packetList.SetText (0,2,"协议"); m_packetList.SetText (0,3,"源端口"); m_packetList.SetText (0,4,"目的端口"); m_packetList.SetText (0,5,"长度"); m_packetList.JoinCells (30,0,30,5);
mailDlg = this; return TRUE; // return TRUE unless you set the focus to a control } | 右边表格中最后的一行是多列合并的结果,完成此合并的代码为:
int XTable::JoinCells (int startRow, int startCol, int endRow, int endCol) { if (startRow < 0 || startRow >= rows) return -1; if (endRow < 0 || startRow >= rows) return -1;
if (startCol < 0 || startCol >= cols) return -1; if (endCol < 0 || endCol >= cols) return -1;
if (startRow > endRow || startCol > endCol) return -1;
for (int i = startRow; i <= endRow; i++) { for (int j = startCol; j <=endCol; j++) { cells [i * cols + j].SetSpan(0,0); } } cells [startRow * cols + startCol].SetSpan(endRow - startRow+1, endCol - startCol+1); return 0; } | 其"反函数"为:
int XTable::UnjoinCells (int row, int col) { if (row < 0 || row >= this->rows) return -1; if (col < 0 || col >= this->cols) return -1;
if (cells [row * cols + col].rowSpan <= 1 && cells [row * cols + col].colSpan <= 1 ) return -1;
for (int i = row; i <= row + cells [row * cols + col].rowSpan; i++) { for (int j = col; j <= cells [row * cols + col].colSpan; j++) { cells[i*cols+j] = defaultCell; cells [i * cols + j].SetSpan(1,1); } } return 0; } | 程序中的IDC_ADAPTERLIST_COMBO控件用于提供用户选择本地适配器,获得本地适配器列表的代码如下(也处于对话框的初始化函数中):
char errbuf[PCAP_ERRBUF_SIZE]; /* 取得列表 */ if (pcap_findalldevs(&alldevs, errbuf) == - 1) { AfxMessageBox("获得网卡列表失败!\n"); GetDlgItem(IDC_STARTSTOP_BUTTON)->EnableWindow(FALSE); }
/* 输出列表 */ for (d = alldevs; d; d = d->next) { CString str(d->name); if (str.Find("\\Device\\NPF_Generic", 0) == - 1) m_adapterList.AddString(str); } | 给监控IP地址范围内的主机发送ARP请求包并获取反馈,即可获得监控范围内活动机器的IP地址和MAC地址,以进行进一步地管理。
发送ARP请求的函数代码:
void SendArpReq(unsigned long srcIp,unsigned long desIp,UCHAR * srcMac) { char sendbuf[1024]; ETHDR eth; ARPHDR arp;
memcpy(eth.eh_src,mmac,6); eth.eh_type=htons(ETH_ARP);
arp.arp_hdr=htons(ARP_HARDWARE); arp.arp_pro=htons(ETH_IP); arp.arp_hln=6; arp.arp_pln=4; arp.arp_opt=htons(ARP_REQUEST); arp.arp_spa=htonl(srcIp); arp.arp_tpa=htonl(desIp); memcpy(arp.arp_sha,srcMac,6);
for(int i=0;i<6;i++) { eth.eh_dst[i]=0xff; arp.arp_tha[i]=0x00; }
memset(sendbuf,0,sizeof(sendbuf)); memcpy(sendbuf,ð,sizeof(eth)); memcpy(sendbuf+sizeof(eth),&arp,sizeof(arp));
PacketInitPacket(lppackets,sendbuf,sizeof(eth)+sizeof(arp)); if(PacketSendPacket(lpadapter,lppackets,TRUE)==FALSE) { AfxMessageBox("PacketSendPacket in SendArpReq Error"); } } | 双击表格中控制Sniffer、ARP欺骗和IP地址重复的栏目,需要变换其中的显示内容,要么从"ON"到"OFF",要么从"OFF"到"ON"(当然,主机数据结构中的控制属性也要随之而改变),相关的代码为:
void XTable::OnLButtonDblClk(UINT nFlags, CPoint point) { HitTest(point, focusRow, focusCol);
SetFocus(); CString str = GetText(focusRow, focusCol); if (str == "ON") { SetText(focusRow, focusCol, "OFF"); switch (focusCol) { case 2: oldHostList[focusRow - 1+nVWndPos / 13].sniffer = 0; break; case 3: oldHostList[focusRow - 1+nVWndPos / 13].arpCheat = 0; break; case 4: oldHostList[focusRow - 1+nVWndPos / 13].ipConflict = 0; break; default: break; } } else if (str == "OFF") { SetText(focusRow, focusCol, "ON"); switch (focusCol) { case 2: oldHostList[focusRow - 1+nVWndPos / 13].sniffer = 1; break; case 3: oldHostList[focusRow - 1+nVWndPos / 13].arpCheat = 1; break; case 4: oldHostList[focusRow - 1+nVWndPos / 13].ipConflict = 1; break; default: break; } } Invalidate(); CWnd::OnLButtonDblClk(nFlags, point); } | 上述代码中的HitTest()调用比较关键,用于获得当前选中的行和列,我们来看看相关的代码:
bool XTable::HitTest(CPoint point, int &row, int &col) { for (int i = 0; i < rows; i++) { for (int j = 0; j < rows; j++) { RECT rect = GetRect(i, j); if (rect.top <= point.y && rect.bottom > point.y && rect.left <= point.x && rect.right > point.x) { row = i; col = j; return true; } } } return false; } | 在表格的某一格处于焦点时,我们应给其画一个矩形边框:
int XTable::Draw(CDC* pDC) { //… if (focusRow < rows && focusCol < cols) //** { RECT rect = GetRect (focusRow, focusCol); GetCells (focusRow, focusCol)->DrawHitBorder(pDC, rect, RGB(0xb0, 0xb0, 0xb0)); } return 0; }
int XCell::DrawHitBorder (CDC* pDC, RECT rect, COLORREF color) { CPen pen (PS_SOLID, 2, color); CPen* oldPen = pDC->SelectObject(&pen); pDC->MoveTo (rect.left, rect.top); pDC->LineTo (rect.right, rect.top); pDC->LineTo (rect.right, rect.bottom); pDC->LineTo (rect.left, rect.bottom); pDC->LineTo (rect.left, rect.top); pDC->SelectObject(oldPen); return 0; } | 获得IP地址监控范围内主机列表的方法如下:
m_fromip.GetAddress(fromip); m_toip.GetAddress(toip);
rthread = CreateThread(NULL, 0, sniff, 0, 0, 0); Sleep(100); //保证sniff线程已经稳定运行 SendArpReq(1, myip, mmac); while (1) { if (!(!mmac[0] && !mmac[1] && !mmac[2] && !mmac[3])) break; Sleep(100); }
for (unsigned long i = fromip; i < myip; i++) { SendArpReq(myip, i, mmac); }
for (i = myip + 1; i <= toip; i++) { SendArpReq(myip, i, mmac); }
Sleep(1000);
for (i = 0; i < currentHstIndex; i++) { HOSTENT *tmpHostent; tmpHostent = gethostbyaddr((char*)(&(hostList[i].ip)), 16, AF_INET); if (tmpHostent) m_hostList.SetText(i + 1, 0, tmpHostent->h_name); m_hostList.SetText(i + 1, 1, inet_ntoa(*(struct in_addr*)(&(hostList[i].ip)))) ; m_hostList.SetText(i + 1, 3, "OFF"); CString str; str.Format("%02x-%02x-%02x-%02x-%02x-%02x", hostList[i].mac[0], hostList[i].mac[1], hostList[i].mac[2], hostList[i].mac[3], hostList[i].mac[4], hostList[i].mac[5]); m_hostList.SetText(i + 1, 2, str); m_hostList.SetText(i + 1, 4, "OFF"); m_hostList.SetText(i + 1, 5, "OFF"); }
m_hostList.Invalidate(); | 上述代码的思路是给fromip~min(myip-1,toip),myip+1~toip范围内的主机发送ARP请求报文并监控其ARP回复,从而获得其IP与MAC的对应关系。当然,它首先用了同样的原理来获取本机的MAC地址。 分页: [1] [2] [3]
(编辑:网站学习网)
|
|
|
|