Monday, August 8, 2011

Using C# and Netbios-NS to get Information about a remote computer

Using C# and Netbios-NS to get Information about a remote computer

Last time I posted something regarding Converting IP Addresses to Decimal and Looping an IP Address Range The next step is to do something with those remote IP Addresses. The first thing that we can play with is to get some information from a remote host using Netbios Name Service.

Some of the information that we can get using the class below are

1. Mac Address
2. Netbios Name (Computer Name)
3. Netbios Group (Workgroup name, Domain Name)
4. Netbios Username

Below is the initial helper class I coded

Sample Usage

NBNS nbnsPacket = new NBNS();
NBNSData nbnsData = new NBNSData();
nbnsData = nbnsPacket.SendNBNSPacket("192.168.50.200",137);
MessageBox.Show(nbnsData.NetbiosUser);

Class Definition

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace NetworkLib
{
// Coded by: Humprey E: Cogay
// Date: February 2011
// Use: Low Level Netbios Over TCP Packet
public class NBNSData
{
public string MacAddress { get; set; }
public string NetbiosUser { get; set; }
public string NetbiosComputer { get; set; }
public string NetbiosGroup { get; set; }
}

public class NBNS
{

//Recieves an IP address and any available port to listen on
public NBNSData SendNBNSPacket(string strIPCur, int intPortNum)
{
//IPAddress in
IPAddress server = IPAddress.Parse(strIPCur);

//NBNS Data
NBNSData nbnsData = new NBNSData();

//Declare MAC Address
string strMAC = "";
string strNetbiosComputer = "";
string strNetbiosGroup = "";
string strNetbiosUser = "";

Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

System.Net.IPEndPoint ipEndPT = new System.Net.IPEndPoint(IPAddress.Parse(strIPCur), 137);
System.Net.EndPoint endPT = (System.Net.EndPoint)ipEndPT;

System.Net.IPEndPoint inIPEndPT = new System.Net.IPEndPoint(IPAddress.Parse(strIPCur), intPortNum);
System.Net.EndPoint inEndPT = (System.Net.EndPoint)inIPEndPT;

soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 50);
soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 50);

//Datagram declaration expected to receive from host
byte[] dataIn = new byte[4096];


int intTries = 0;

bool bolResponded = false;

do
{
soc.SendTo(NBQuery(), endPT);
try
{
//Get data from host
soc.ReceiveFrom(dataIn, ref inEndPT);
bolResponded = true;
}
catch (SocketException se)
{
intTries++;
if (se.ErrorCode == 10060)
{
//handleTimed out
}
}
}
while ((!bolResponded) && intTries < 1);

if (bolResponded)
{
//parse the MAC Address from the data received from host
strMAC = getMAC(dataIn);
strNetbiosComputer = getNebiosComputer(dataIn);
strNetbiosGroup = getNebiosGroup(dataIn);
strNetbiosUser = getRemoteMachineNameTable(dataIn).Count.ToString();
}
else
{
strMAC = "Host Unreachable";
}

nbnsData.MacAddress = strMAC;
nbnsData.NetbiosComputer = strNetbiosComputer;
nbnsData.NetbiosGroup = strNetbiosGroup;
nbnsData.NetbiosUser = strNetbiosUser;
return nbnsData;
}

//NBNS Request Packet Contents
private byte[] NBQuery()
{

byte[] bdata = new byte[50]{ 0x80, 0xff, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x43, 0x4B,
0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41,
0x00, 0x00, 0x21, 0x00, 0x01};

return bdata;
}


//Parse the Packet sent by the host and get the value @byt 56
private string getNebiosComputer(byte[] dtResponse)
{
string strNetbiosComputer = "";

int intStart = (int)dtResponse[56];

int intOffset = 57;
for (int x = 0; x < 15; x++)
{
strNetbiosComputer += Convert.ToChar(dtResponse[intOffset + x]);
}
return strNetbiosComputer;
}

private List getRemoteMachineNameTable(byte[] dtResponse)
{
Int32 strNoOfRemoteMachineName = 0;
String CurrentName = "";
List RemoteMachineNames = new List();

//Get no of names in the Response Packet (position 56 of response Packet)
strNoOfRemoteMachineName = Convert.ToInt32(dtResponse[56]);

for (int remoteNameCounter = 0; remoteNameCounter <= strNoOfRemoteMachineName - 1; remoteNameCounter++)
{
CurrentName = "";
//Get first 15 characters after position 56
for (int x = 1; x <= 15; x++)
{
//18 characters per name,
byte newByte = dtResponse[x + (56 + remoteNameCounter * 18)];

//checked if printable chars 0x21 to 0x7E
//0x20 = space
//0x7F = Delete
//TRAP GROUP NAMES - Must have a 1E NetBios Suffix
if (newByte > 0x19 && newByte < 0x7E)
CurrentName += Convert.ToChar(newByte);
else
CurrentName += " ";
}

//HEC Notes
//NAME_FLAGS = Bytes 17 and 18 Definition
//Taken from http://www.faqs.org/rfcs/rfc1002.html
//
//RESERVED 7-15 Reserved for future use. Must be zero (0).
//PRM 6 Permanent Name Flag. If one (1) then entry
// is for the permanent node name. Flag is zero
// (0) for all other names.
//ACT 5 Active Name Flag. All entries have this flag
// set to one (1).
//CNF 4 Conflict Flag. If one (1) then name on this
// node is in conflict.
//DRG 3 Deregister Flag. If one (1) then this name
// is in the process of being deleted.
//ONT 1,2 Owner Node Type:
// 00 = B node
// 01 = P node
// 10 = M node
// 11 = Reserved for future use
//G 0 Group Name Flag.
// If one (1) then the name is a GROUP NetBIOS
// name.
// If zero (0) then it is a UNIQUE NetBIOS name.

RemoteMachineNames.Add(CurrentName + String.Format("{0:X2}", dtResponse[16 + (56 + remoteNameCounter * 18)]) + Convert.ToString(dtResponse[17 + (56 + remoteNameCounter * 18)], 2).PadLeft(8, '0'));
}

return RemoteMachineNames;
}

private string getNebiosGroup(byte[] dtResponse)
{
String netbiosGroupName = "";
foreach (string tmpString in getRemoteMachineNameTable(dtResponse))
{
if (tmpString.Substring(15, 2) == "1E" || tmpString.Substring(17, 1) == "1")
{
netbiosGroupName = tmpString.Substring(0, 15);
break;
}

}

return netbiosGroupName;
}

private string getMAC(byte[] dtResponse)
{
string strMac = "";
//intStart reads the value @ byte 56 which contains the
//no of names in the Response Packet
int intStart = (int)dtResponse[56];

//1 name contains 16 bytes followed by 2 bytes name flag = 18 Bytes
int intOffset = 56 + intStart * 18 + 1;

for (int x = 0; x < 6; x++)
{
strMac += String.Format("{0:X2}", dtResponse[intOffset + x]) + ":";
}

strMac = strMac.Remove(strMac.Length - 1, 1);
return strMac;
}

}
}

3 comments:

  1. I am trying to retrive the macaddress of the modem from the data recieved by my computer on 137 port. But, the resolving of MAC logic is wrong.

    ReplyDelete
  2. the way to get computer name is wrong. the computer is in remote machine name table.

    ReplyDelete