You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1082 lines
31 KiB
1082 lines
31 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
netbtkd.c
|
|
|
|
Abstract:
|
|
|
|
NETBT kd extension
|
|
|
|
Author:
|
|
|
|
Jiandong Ruan July 2000
|
|
|
|
Notes:
|
|
This version is totally rewritten to support 32-bit and 64-bit debug by using
|
|
new features of WINDBG
|
|
|
|
Revision History:
|
|
|
|
11-Jul-2000 jruan Support both 32-bit and 64-bit.
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
|
|
#define KDEXTMODE
|
|
#define KDEXT_64BIT
|
|
|
|
#include <nturtl.h>
|
|
#include <ntverp.h>
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <wdbgexts.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <..\..\inc\types.h>
|
|
|
|
#define PRINTF dprintf
|
|
#define ERROR dprintf
|
|
|
|
EXT_API_VERSION ApiVersion = {
|
|
(VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff),
|
|
EXT_API_VERSION_NUMBER64, 0
|
|
};
|
|
WINDBG_EXTENSION_APIS ExtensionApis;
|
|
USHORT SavedMajorVersion;
|
|
USHORT SavedMinorVersion;
|
|
BOOLEAN ChkTarget;
|
|
ULONG64 ConfigPtr;
|
|
|
|
static char* inet_addr(ULONG ip, char* addr);
|
|
|
|
DECLARE_API(init)
|
|
{
|
|
ReloadSymbols("netbt.sys");
|
|
|
|
if (*args) {
|
|
ConfigPtr = GetExpression(args);
|
|
} else {
|
|
ConfigPtr = GetExpression("netbt!NbtConfig");
|
|
}
|
|
if (ConfigPtr == 0) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
__inline
|
|
ULONG
|
|
read_list_entry(
|
|
ULONG64 addr,
|
|
PLIST_ENTRY64 List
|
|
)
|
|
{
|
|
if (InitTypeRead(addr, LIST_ENTRY)) {
|
|
return 1;
|
|
}
|
|
List->Flink = ReadField(Flink);
|
|
List->Blink = ReadField(Blink);
|
|
return 0;
|
|
}
|
|
|
|
#define READLISTENTRY read_list_entry
|
|
|
|
/*++
|
|
Call callback for each entry in the list
|
|
--*/
|
|
typedef BOOL (*LIST_FOR_EACH_CALLBACK)(ULONG64 address, PVOID);
|
|
int
|
|
ListForEach(ULONG64 address, int maximum, PVOID pContext, LIST_FOR_EACH_CALLBACK callback)
|
|
{
|
|
LIST_ENTRY64 list;
|
|
int i;
|
|
|
|
if (READLISTENTRY(address, &list)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", address);
|
|
return (-1);
|
|
}
|
|
if (list.Flink == address) {
|
|
return (-1);
|
|
}
|
|
|
|
if (maximum < 0) {
|
|
maximum = 1000000;
|
|
}
|
|
for (i = 0; i < maximum && (list.Flink != address); i++) {
|
|
/*
|
|
* Allow user to break us.
|
|
*/
|
|
if (CheckControlC()) {
|
|
break;
|
|
}
|
|
callback(list.Flink, pContext);
|
|
if (READLISTENTRY(list.Flink, &list)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", list.Flink);
|
|
return (-1);
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
#define NL 1
|
|
#define NONL 0
|
|
|
|
#define MAX_LIST_ELEMENTS 4096
|
|
|
|
#define DEFAULT_UNICODE_DATA_LENGTH 4096
|
|
USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH;
|
|
WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH];
|
|
WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
|
|
|
|
#define DEFAULT_ANSI_DATA_LENGTH 4096
|
|
USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH;
|
|
CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH];
|
|
CHAR *s_pAnsiStringData = s_AnsiStringData;
|
|
|
|
LPSTR Extensions[] = {
|
|
"Netbt debugger extensions",
|
|
0
|
|
};
|
|
|
|
LPSTR LibCommands[] = {
|
|
"help -- print out these messages",
|
|
"init <nbtconfig address> -- Reload symbols for NETBT.SYS",
|
|
"\tinit get the address of netbt!nbtconfig which will be used by other netbt kdext commands.",
|
|
"\tIn case that the symbol table cannot be loaded, you can manually set the address.",
|
|
"\tExamples:",
|
|
"\t\tinit --- reload symbols and automatically find the address of netbt!nbtconfig",
|
|
"\t\tinit 0xfac30548 --- Force 0xfac30548 to be the address of netbt!nbtconfig",
|
|
"dump -- is no longer supported. Please use 'dt <type> <addr>' instead",
|
|
"\tFor example 'dt netbt!tDEVICECONTEXT 0x98765432'",
|
|
"devices -- list all devices",
|
|
"dev <devobj> -- dump a device",
|
|
"connections -- list all connections",
|
|
"cache [Local|Remote]",
|
|
"localname <tNAMEADDR> Display the connections associated with a local name",
|
|
"verifyll <ListHead> [<Verify>]",
|
|
"sessionhdr <session header> Dump the session HDR",
|
|
"nbtworkitems Dump netbt workitems",
|
|
0
|
|
};
|
|
|
|
BOOL
|
|
help(void)
|
|
{
|
|
int i;
|
|
|
|
for( i=0; Extensions[i]; i++ )
|
|
PRINTF( " %s\n", Extensions[i] );
|
|
|
|
for( i=0; LibCommands[i]; i++ )
|
|
PRINTF( " %s\n", LibCommands[i] );
|
|
return TRUE;
|
|
}
|
|
|
|
DECLARE_API(version)
|
|
{
|
|
#if DBG
|
|
PCHAR DebuggerType = "Checked";
|
|
#else
|
|
PCHAR DebuggerType = "Free";
|
|
#endif
|
|
|
|
PRINTF ( "NETBT: %s extension dll (build %d) debugging %s kernel (build %d)\n",
|
|
DebuggerType,
|
|
VER_PRODUCTBUILD,
|
|
SavedMajorVersion == 0x0c ? "Checked" : "Free",
|
|
SavedMinorVersion
|
|
);
|
|
}
|
|
|
|
#define NAME_DELIMITER '@'
|
|
#define NAME_DELIMITERS "@ "
|
|
#define INVALID_INDEX 0xffffffff
|
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
|
|
|
void
|
|
dump_device(ULONG64 addr)
|
|
{
|
|
ULONG linkage_offset = 0;
|
|
ULONG tag;
|
|
ULONG ip, subnet_mask, assigned_ip, name_server1, name_server2;
|
|
UCHAR mac[6];
|
|
|
|
if (GetFieldOffset("netbt!tDEVICECONTEXT", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
|
|
InitTypeRead(addr, netbt!tDEVICECONTEXT);
|
|
tag = (ULONG)ReadField(Verify);
|
|
if (tag != NBT_VERIFY_DEVCONTEXT && tag != NBT_VERIFY_DEVCONTEXT_DOWN) {
|
|
addr -= linkage_offset;
|
|
InitTypeRead(addr, netbt!tDEVICECONTEXT);
|
|
tag = (ULONG)ReadField(Verify);
|
|
if (tag != NBT_VERIFY_DEVCONTEXT && tag != NBT_VERIFY_DEVCONTEXT_DOWN) {
|
|
PRINTF ("Tag not found. %I64lx may not be a valid NETBT device\n", addr + linkage_offset);
|
|
return;
|
|
}
|
|
}
|
|
|
|
PRINTF ("+++++++++++++++ tDEVICECONTEXT @ %I64lx (%s) ++++++++++++++++\n",
|
|
addr, (tag == NBT_VERIFY_DEVCONTEXT)? "Active": "Down");
|
|
ip = (ULONG)ReadField(IpAddress);
|
|
assigned_ip = (ULONG)ReadField(AssignedIpAddress);
|
|
subnet_mask = (ULONG)ReadField(SubnetMask);
|
|
GetFieldData(addr, "netbt!tDEVICECONTEXT", "MacAddress", 6, mac);
|
|
PRINTF (" IP Address: %s\n", inet_addr(ip, NULL));
|
|
PRINTF ("IP Interface Flag: %I64lx\n", ReadField(IpInterfaceFlags));
|
|
PRINTF (" MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
PRINTF (" subnet: %s\n", inet_addr(subnet_mask & ip, NULL));
|
|
if (ip != assigned_ip) {
|
|
PRINTF (" Assigned Address: %s\n", inet_addr(assigned_ip, NULL));
|
|
}
|
|
PRINTF (" subnet mask: %s\n", inet_addr(subnet_mask, NULL));
|
|
PRINTF ("broadcast address: %s\n", inet_addr((ULONG)ReadField(BroadcastAddress), NULL));
|
|
PRINTF (" network mask: %s\n", inet_addr((ULONG)ReadField(NetMask), NULL));
|
|
name_server1 = (ULONG)ReadField(lNameServerAddress);
|
|
name_server2 = (ULONG)ReadField(lBackupServer);
|
|
if (name_server1 == 0) {
|
|
PRINTF (" WINS: <not configured>\n");
|
|
} else if (name_server2 == 0) {
|
|
PRINTF (" WINS: %s\n", inet_addr(name_server1, NULL));
|
|
} else {
|
|
if (ReadField(SwitchedToBackup)) {
|
|
PRINTF (" Primary WINS: %s\n", inet_addr(name_server2, NULL));
|
|
PRINTF (" Secondary WINS: %s (in use)\n", inet_addr(name_server1, NULL));
|
|
} else {
|
|
PRINTF (" Primary WINS: %s (in use)\n", inet_addr(name_server1, NULL));
|
|
PRINTF (" Secondary WINS: %s\n", inet_addr(name_server2, NULL));
|
|
}
|
|
}
|
|
if (ReadField(WinsIsDown)) {
|
|
PRINTF ("************* WINS(s) ARE DOWN ***************\n");
|
|
}
|
|
PRINTF (" pFileObject: %I64lx (type netbt!tFILE_OBJECTS)\n", ReadField(pFileObjects));
|
|
PRINTF ("TCP Session: HANDLE=%I64lx DeviceObject=%I64lx FileObject=%I64lx\n",
|
|
ReadField(hSession), ReadField(pSessionDeviceObject), ReadField(pSessionFileObject));
|
|
PRINTF ("TCP Control: HANDLE=%I64lx DeviceObject=%I64lx FileObject=%I64lx\n",
|
|
ReadField(hControl), ReadField(pControlDeviceObject), ReadField(pControlFileObject));
|
|
|
|
PRINTF ("\n");
|
|
}
|
|
|
|
/*++
|
|
Dump a NETBT device
|
|
--*/
|
|
DECLARE_API (dev)
|
|
{
|
|
if (*args == 0) {
|
|
return;
|
|
}
|
|
dump_device(GetExpression(args));
|
|
}
|
|
|
|
/*++
|
|
Dump all NETBT devices
|
|
--*/
|
|
DECLARE_API (devices)
|
|
{
|
|
ULONG64 NbtSmbDevice;
|
|
ULONG Offset;
|
|
USHORT AdapterCounter;
|
|
int num;
|
|
|
|
GetFieldValue(ConfigPtr, "netbt!tNBTCONFIG", "AdapterCount", AdapterCounter);
|
|
|
|
/*
|
|
* SMB device
|
|
*/
|
|
NbtSmbDevice = GetExpression("netbt!pNbtSmbDevice");
|
|
ReadPtr(NbtSmbDevice, &NbtSmbDevice);
|
|
PRINTF( "Dumping SMB device\n");
|
|
dump_device(NbtSmbDevice);
|
|
|
|
/*
|
|
* dump device list
|
|
*/
|
|
if (GetFieldOffset("netbt!tNBTCONFIG", (LPSTR)"DeviceContexts", &Offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
|
|
num = ListForEach(ConfigPtr + Offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)dump_device);
|
|
PRINTF ("Total devices = %d (include SMB device)\n", num + 1);
|
|
|
|
/*
|
|
* Check consistency
|
|
*/
|
|
if (num != AdapterCounter) {
|
|
PRINTF ("Inconsistent!!! Number of devices = %d in NbtConfig.AdapterCount\n", AdapterCounter);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of listening request
|
|
*/
|
|
BOOL
|
|
listen_callback(ULONG64 addr, PVOID pContext)
|
|
{
|
|
ULONG irp_offset;
|
|
ULONG linkage_offset;
|
|
ULONG64 irp_addr;
|
|
|
|
if (GetFieldOffset("netbt!tLISTENREQUESTS", (LPSTR)"pIrp", &irp_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
if (GetFieldOffset("netbt!tLISTENREQUESTS", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
addr -= linkage_offset;
|
|
if (ReadPtr(addr+irp_offset, &irp_addr)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
PRINTF ("\t\t ** pListen@<%I64lx> ==> pIrp = %I64lx\n", addr, irp_addr);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of connection element
|
|
*/
|
|
BOOL
|
|
connect_callback(ULONG64 addr, PVOID pContext)
|
|
{
|
|
ULONG linkage_offset;
|
|
UCHAR name[NETBIOS_NAME_SIZE];
|
|
|
|
if (GetFieldOffset("netbt!tCONNECTELE", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
addr -= linkage_offset;
|
|
|
|
if (GetFieldData(addr, "netbt!tCONNECTELE", "RemoteName", NETBIOS_NAME_SIZE, name)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
PRINTF ("\t\t ** Connection@<%I64lx> ==> <%-15.15s:%x>\n", addr, name, name[15]&0xff);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of client element
|
|
*/
|
|
BOOL
|
|
client_callback(ULONG64 addr, PVOID pContext)
|
|
{
|
|
ULONG connect_offset;
|
|
ULONG listen_offset;
|
|
ULONG active_connect_offset;
|
|
ULONG linkage_offset, tag;
|
|
UCHAR name[NETBIOS_NAME_SIZE];
|
|
|
|
if (GetFieldOffset("netbt!tCLIENTELE", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
addr -= linkage_offset;
|
|
if (InitTypeRead(addr, netbt!tCLIENTELE)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
tag = (ULONG)ReadField(Verify);
|
|
if (tag == NBT_VERIFY_CLIENT) {
|
|
PRINTF ("\tActive ");
|
|
} else if (tag == NBT_VERIFY_CLIENT_DOWN) {
|
|
PRINTF ("\tClosed ");
|
|
} else {
|
|
PRINTF ("\tClient @ %I64lx: bad client tag: %lx\n", addr, tag);
|
|
return FALSE;
|
|
}
|
|
if (GetFieldData(addr, "netbt!tCLIENTELE", "EndpointName", NETBIOS_NAME_SIZE, name)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
PRINTF ("Client@<%I64lx> ==> pDevice = %I64lx\tEndpoint=<%-15.15s:%x>\n",
|
|
addr, ReadField(pDeviceContext), name, name[15]);
|
|
|
|
/*
|
|
* dump the connection associated with the client element
|
|
*/
|
|
PRINTF ("\t\t(ConnectHead):\n");
|
|
if (GetFieldOffset("netbt!tCLIENTELE", (LPSTR)"ConnectHead", &connect_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
ListForEach(addr + connect_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)connect_callback);
|
|
|
|
PRINTF ("\t\t(ConnectActive)\n");
|
|
if (GetFieldOffset("netbt!tCLIENTELE", (LPSTR)"ConnectActive", &active_connect_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
ListForEach(addr + active_connect_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)connect_callback);
|
|
|
|
PRINTF ("\t\t(ListenHead):\n");
|
|
if (GetFieldOffset("netbt!tCLIENTELE", (LPSTR)"ListenHead", &listen_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
ListForEach(addr + listen_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)listen_callback);
|
|
|
|
PRINTF ("\n");
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of address element
|
|
*/
|
|
BOOL
|
|
addresses_callback(ULONG64 addr, PVOID pContext)
|
|
{
|
|
UCHAR name[NETBIOS_NAME_SIZE];
|
|
ULONG64 NameAddr;
|
|
ULONG tag, linkage_offset, client_offset;
|
|
|
|
if (GetFieldOffset("netbt!tADDRESSELE", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT: %d of %s\n", __LINE__, __FILE__);
|
|
return FALSE;
|
|
}
|
|
addr -= linkage_offset;
|
|
|
|
if (InitTypeRead(addr, netbt!tADDRESSELE)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT: %I64lx\n", addr);
|
|
return FALSE;
|
|
}
|
|
tag = (ULONG)ReadField(Verify);
|
|
|
|
/*
|
|
* Check tag
|
|
*/
|
|
if (tag != NBT_VERIFY_ADDRESS) {
|
|
PRINTF ("ERROR: incorrect tag <%4.4s>. %lx is properly not a address element\n", tag, addr);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Print out the address element
|
|
*/
|
|
NameAddr = ReadField(pNameAddr);
|
|
if (GetFieldData(NameAddr, "netbt!tNAMEADDR", "Name", NETBIOS_NAME_SIZE, name)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT: pNameAddr=%I64lx\n", NameAddr);
|
|
return FALSE;
|
|
}
|
|
PRINTF ("Address@<%I64lx> ==> <%-15.15s:%x>\n", addr, name, name[15]);
|
|
|
|
/*
|
|
* dump the client element associated with the address element
|
|
*/
|
|
if (GetFieldOffset("netbt!tADDRESSELE", (LPSTR)"ClientHead", &client_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT: %I64lx\n", addr);
|
|
return FALSE;
|
|
}
|
|
ListForEach(addr + client_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)client_callback);
|
|
return TRUE;
|
|
}
|
|
|
|
DECLARE_API(connections)
|
|
{
|
|
ULONG Offset;
|
|
|
|
if (GetFieldOffset("netbt!tNBTCONFIG", (LPSTR)"AddressHead", &Offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
|
|
PRINTF ("Dumping information on all NetBT conections ...\n");
|
|
ListForEach(ConfigPtr + Offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)addresses_callback);
|
|
PRINTF( "---------------- End of Connections ----------------\n");
|
|
}
|
|
|
|
char* inet_addr(ULONG ip, char* addr)
|
|
{
|
|
static char my_addr[16];
|
|
|
|
if (addr == NULL) {
|
|
addr = my_addr;
|
|
}
|
|
sprintf (addr, "%d.%d.%d.%d",
|
|
(ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
|
|
return addr;
|
|
}
|
|
|
|
WCHAR*
|
|
GetUnicodeString(ULONG64 addr)
|
|
{
|
|
USHORT length;
|
|
ULONG readed_bytes;
|
|
ULONG64 buffer = 0;
|
|
WCHAR *p;
|
|
|
|
InitTypeRead(addr, netbt!UNICODE_STRING);
|
|
length = (USHORT)ReadField(Length);
|
|
buffer = ReadField(Buffer);
|
|
if (buffer == 0 || length == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
p = (WCHAR*)LocalAlloc(LMEM_FIXED, length + sizeof(WCHAR));
|
|
if (p == NULL) {
|
|
return NULL;
|
|
}
|
|
ReadMemory(buffer, (PVOID)p, length, &readed_bytes);
|
|
if ((USHORT)readed_bytes != length) {
|
|
LocalFree(p);
|
|
return NULL;
|
|
}
|
|
p[length/sizeof(WCHAR)] = L'\0';
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of cache entries
|
|
*/
|
|
BOOL
|
|
cache_callback(ULONG64 addr, const int *bkt)
|
|
{
|
|
static ULONG addr_offset = (ULONG)(-1);
|
|
static ULONG fqdn_offset = (ULONG)(-1);
|
|
ULONG Verify;
|
|
UCHAR name[NETBIOS_NAME_SIZE];
|
|
ULONG ip, refcnt, state, ttl;
|
|
WCHAR *fqdn = NULL;
|
|
|
|
if (addr_offset == (ULONG)(-1)) {
|
|
if (GetFieldOffset("netbt!tNAMEADDR", (LPSTR)"Linkage", &addr_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
addr_offset = (ULONG)(-1);
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (fqdn_offset == (ULONG)(-1)) {
|
|
if (GetFieldOffset("netbt!tNAMEADDR", (LPSTR)"FQDN", &fqdn_offset)) {
|
|
fqdn_offset = (ULONG)(-1);
|
|
}
|
|
}
|
|
|
|
addr -= addr_offset;
|
|
if (InitTypeRead(addr, netbt!tNAMEADDR)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
Verify = (ULONG)ReadField(Verify);
|
|
if (Verify != LOCAL_NAME && Verify != REMOTE_NAME) {
|
|
PRINTF ("ERROR: bad name cache entry @ %I64x tag %lx!\n", addr, Verify);
|
|
return FALSE;
|
|
}
|
|
ip = (ULONG)ReadField(IpAddress);
|
|
refcnt = (ULONG)ReadField(RefCount);
|
|
state = (ULONG)ReadField(NameTypeState);
|
|
ttl = (ULONG)ReadField(Ttl);
|
|
if (GetFieldData(addr, "netbt!tNAMEADDR", "Name", NETBIOS_NAME_SIZE, name)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (fqdn_offset != (ULONG)(-1)) {
|
|
fqdn = GetUnicodeString(addr + fqdn_offset);
|
|
}
|
|
PRINTF ("[%d]\t<%16.16I64lx> => <%-15.15s:%2x> | %-15.15s | %d | %8x | %9d\n",
|
|
*bkt, addr, name, name[15], inet_addr(ip, NULL), refcnt, state, ttl);
|
|
if (fqdn != NULL) {
|
|
PRINTF("\t\t%ws\n", fqdn);
|
|
LocalFree(fqdn);
|
|
fqdn = NULL;
|
|
}
|
|
PRINTF("\t\tName State:");
|
|
if (state & NAMETYPE_QUICK) {
|
|
PRINTF(" QUICK");
|
|
}
|
|
if (state & NAMETYPE_UNIQUE) {
|
|
PRINTF(" UNIQUE");
|
|
}
|
|
if (state & NAMETYPE_GROUP) {
|
|
PRINTF(" GROUP");
|
|
}
|
|
if (state & NAMETYPE_INET_GROUP) {
|
|
PRINTF(" INET_GROUP");
|
|
}
|
|
if (state & STATE_RESOLVED) {
|
|
PRINTF(" RESOLVED");
|
|
}
|
|
if (state & STATE_RELEASED) {
|
|
PRINTF(" RELEASED");
|
|
}
|
|
if (state & STATE_CONFLICT) {
|
|
PRINTF(" CONFLICT");
|
|
}
|
|
if (state & STATE_RESOLVING) {
|
|
PRINTF(" RESOLVING");
|
|
}
|
|
if (state & REFRESH_FAILED) {
|
|
PRINTF(" REFRESH_FAILED");
|
|
}
|
|
if (state & PRELOADED) {
|
|
PRINTF(" PRELOADED");
|
|
}
|
|
PRINTF("\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
dump_cache(ULONG64 addr)
|
|
{
|
|
LONG bucket_number;
|
|
int i;
|
|
static ULONG buckets_offset = (ULONG)(-1);
|
|
static ULONG sizeof_list;
|
|
|
|
if (buckets_offset == (ULONG)(-1)) {
|
|
if (GetFieldOffset("netbt!tHASHTABLE", (LPSTR)"Bucket", &buckets_offset)) {
|
|
PRINTF ("\nError -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
sizeof_list = GetTypeSize ("LIST_ENTRY");
|
|
}
|
|
if (InitTypeRead(addr, netbt!tHASHTABLE)) {
|
|
PRINTF ("\nError -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
bucket_number = (ULONG) ReadField(lNumBuckets);
|
|
|
|
PRINTF (" %d buckets\n", bucket_number);
|
|
PRINTF ("[Bkt#]\t< Address > => <Name > | IpAddr | RefC | State | Ttl\n");
|
|
for (i=0; i < bucket_number; i++) {
|
|
ListForEach(addr + buckets_offset + i * sizeof_list, -1, &i, (LIST_FOR_EACH_CALLBACK)cache_callback);
|
|
}
|
|
PRINTF ("-----------------------------------------------------------------------------------\n");
|
|
}
|
|
|
|
DECLARE_API (cache)
|
|
{
|
|
ULONG64 local_addr, remote_addr;
|
|
|
|
if (InitTypeRead(ConfigPtr, netbt!tNBTCONFIG)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
local_addr = ReadField(pLocalHashTbl);
|
|
remote_addr = ReadField(pRemoteHashTbl);
|
|
|
|
if (_stricmp(args, "local") == 0) {
|
|
PRINTF ("Dumping local cache %I64lx", local_addr);
|
|
dump_cache (local_addr);
|
|
} else if (_stricmp(args, "remote") == 0) {
|
|
PRINTF ("Dumping remote cache %I64lx", remote_addr);
|
|
dump_cache (remote_addr);
|
|
} else {
|
|
PRINTF ("Dumping local cache %I64lx", local_addr);
|
|
dump_cache (local_addr);
|
|
PRINTF ("Dumping remote cache %I64lx", remote_addr);
|
|
dump_cache (remote_addr);
|
|
}
|
|
PRINTF( "---------------- Cache ----------------\n");
|
|
return;
|
|
}
|
|
|
|
DECLARE_API (localname)
|
|
{
|
|
ULONG linkage_offset;
|
|
ULONG32 tag;
|
|
ULONG64 addr;
|
|
|
|
if (*args == 0) {
|
|
PRINTF ("Usage: localname pointer\n");
|
|
return;
|
|
}
|
|
|
|
addr = GetExpression(args);
|
|
if (GetFieldValue(addr, "netbt!tNAMEADDR", "Verify", tag)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
if (tag == REMOTE_NAME) {
|
|
PRINTF ("%I64x is a remote name. Please use a local name.\n", addr);
|
|
return;
|
|
}
|
|
if (tag == LOCAL_NAME) {
|
|
ULONG addr_offset;
|
|
|
|
/*
|
|
* GetFieldValue won't do signextended for 32-bit. Use ReadPtr
|
|
*/
|
|
if (GetFieldOffset("netbt!tNAMEADDR", (LPSTR)"pAddressEle", &addr_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
if (ReadPtr(addr + addr_offset, &addr)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
}
|
|
if (GetFieldValue(addr, "netbt!tADDRESSELE", "Verify", tag)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
if (tag != NBT_VERIFY_ADDRESS) {
|
|
PRINTF ("%I64x is not a local name. Please use a local name.\n", addr);
|
|
return;
|
|
}
|
|
if (GetFieldOffset("netbt!tADDRESSELE", (LPSTR)"Linkage", &linkage_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
addresses_callback(addr - linkage_offset, NULL);
|
|
}
|
|
|
|
ULONG
|
|
dump_field_callback(PFIELD_INFO pField, PVOID context)
|
|
{
|
|
PRINTF ("%s, %s, %I64lx\n", pField->fName, pField->printName, pField->address);
|
|
return 0;
|
|
}
|
|
|
|
DECLARE_API(dump)
|
|
{
|
|
PRINTF ("dump is no longer supported because 'dt type address' is better\n");
|
|
PRINTF ("\tFor example 'dt netbt!tDEVICECONTEXT 0x98765432'\n");
|
|
}
|
|
|
|
/*
|
|
* read in a list entry and a ULONG following that list entry.
|
|
*/
|
|
__inline ULONG
|
|
read_list_verify(
|
|
ULONG64 addr,
|
|
PLIST_ENTRY64 List,
|
|
ULONG *verify
|
|
)
|
|
{
|
|
static ULONG list_size = 0;
|
|
ULONG64 a;
|
|
|
|
if (list_size == 0) {
|
|
list_size = GetTypeSize("LIST_ENTRY");
|
|
}
|
|
if (InitTypeRead(addr, LIST_ENTRY)) {
|
|
return 1;
|
|
}
|
|
List->Flink = ReadField(Flink);
|
|
List->Blink = ReadField(Blink);
|
|
if (GetFieldData(addr+list_size, "ULONG", NULL, sizeof(ULONG64), &a)) {
|
|
return 1;
|
|
}
|
|
*verify = (ULONG)a;
|
|
return 0;
|
|
}
|
|
|
|
DECLARE_API(verifyll)
|
|
{
|
|
LIST_ENTRY64 list;
|
|
ULONG64 pHead, pCurrentEntry, pNextEntry, pPreviousEntry;
|
|
ULONG VerifyRead, VerifyIn = 0;
|
|
ULONG Count = 0;
|
|
BOOL fVerifyIn = FALSE;
|
|
BOOL fListCorrupt = FALSE;
|
|
|
|
PRINTF ("Verifying Linked list ...\n");
|
|
|
|
if (!args || !(*args)) {
|
|
PRINTF ("Usage: !NetbtKd.VerifyLL <ListHead>\n");
|
|
return;
|
|
} else {
|
|
//
|
|
// args = "<pHead> [<Verify>]"
|
|
//
|
|
LPSTR lpVerify;
|
|
|
|
while (*args == ' ') {
|
|
args++;
|
|
}
|
|
lpVerify = strpbrk(args, NAME_DELIMITERS);
|
|
|
|
pHead = GetExpression (args);
|
|
if (lpVerify) {
|
|
VerifyIn = (ULONG)GetExpression (lpVerify);
|
|
fVerifyIn = TRUE;
|
|
}
|
|
}
|
|
|
|
PRINTF ("** ListHead@<%I64lx>, fVerifyIn=<%x>, VerifyIn=<%x>:\n\n", pHead, fVerifyIn, VerifyIn);
|
|
PRINTF ("Verifying Flinks ...");
|
|
|
|
// Read in the data for the first FLink in the list!
|
|
pPreviousEntry = pHead;
|
|
if (READLISTENTRY(pHead, &list)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pHead);
|
|
return;
|
|
}
|
|
pCurrentEntry = list.Flink;
|
|
if (read_list_verify(pCurrentEntry, &list, &VerifyRead)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pCurrentEntry);
|
|
return;
|
|
}
|
|
pNextEntry = list.Flink;
|
|
|
|
while ((pCurrentEntry != pHead) && (++Count < MAX_LIST_ELEMENTS)) {
|
|
if (CheckControlC()) {
|
|
break;
|
|
}
|
|
if ((fVerifyIn) && (VerifyRead != VerifyIn)) {
|
|
PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far\n"
|
|
"\tPrevious=<%I64lx>, Current=<%I64lx>, Next=<%I64lx>\n",
|
|
Count, pPreviousEntry, pCurrentEntry, pNextEntry);
|
|
fListCorrupt = TRUE;
|
|
break;
|
|
}
|
|
pPreviousEntry = pCurrentEntry;
|
|
pCurrentEntry = pNextEntry;
|
|
if (read_list_verify(pCurrentEntry, &list, &VerifyRead)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pCurrentEntry);
|
|
return;
|
|
}
|
|
pNextEntry = list.Flink;
|
|
}
|
|
|
|
if (!fListCorrupt) {
|
|
PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count);
|
|
}
|
|
|
|
PRINTF ("Verifying Blinks ...");
|
|
Count = 0;
|
|
fListCorrupt = FALSE;
|
|
// Read in the data for the first BLink in the list!
|
|
pPreviousEntry = pHead;
|
|
if (READLISTENTRY(pHead, &list)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pHead);
|
|
return;
|
|
}
|
|
pCurrentEntry = list.Blink;
|
|
if (read_list_verify(pCurrentEntry, &list, &VerifyRead)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pCurrentEntry);
|
|
return;
|
|
}
|
|
pNextEntry = list.Blink;
|
|
|
|
while ((pCurrentEntry != pHead) && (++Count < MAX_LIST_ELEMENTS)) {
|
|
if (CheckControlC()) {
|
|
break;
|
|
}
|
|
if ((fVerifyIn) && (VerifyRead != VerifyIn)) {
|
|
PRINTF ("Verify FAILURE:\n\t<%d> Elements Read so far\n"
|
|
"\tPrevious=<%I64lx>, Current=<%I64lx>, Next=<%I64lx>\n",
|
|
Count, pPreviousEntry, pCurrentEntry, pNextEntry);
|
|
fListCorrupt = TRUE;
|
|
break;
|
|
}
|
|
pPreviousEntry = pCurrentEntry;
|
|
pCurrentEntry = pNextEntry;
|
|
if (read_list_verify(pCurrentEntry, &list, &VerifyRead)) {
|
|
PRINTF ("Failed to read memory 0x%I64lx\n", pCurrentEntry);
|
|
return;
|
|
}
|
|
pNextEntry = list.Blink;
|
|
}
|
|
|
|
if (!fListCorrupt) {
|
|
PRINTF ("SUCCESS: %s<%d> Elements!\n", (pCurrentEntry==pHead? "":"> "), Count);
|
|
}
|
|
|
|
PRINTF( "---------------- Verify LinkedList ----------------\n");
|
|
|
|
return;
|
|
}
|
|
|
|
DECLARE_API(sessionhdr)
|
|
{
|
|
tSESSIONHDR Hdr;
|
|
char called_name[34];
|
|
char callee_name[34];
|
|
ULONG64 addr;
|
|
ULONG Size;
|
|
int i;
|
|
|
|
if (!args || !(*args)) {
|
|
PRINTF ("Usage: !NetbtKd.sessionhdr hdr\n");
|
|
return;
|
|
}
|
|
|
|
addr = GetExpression(args);
|
|
if (addr == 0) {
|
|
return;
|
|
}
|
|
|
|
ReadMemory(addr, &Hdr, sizeof(Hdr), &Size);
|
|
ReadMemory(addr + sizeof(Hdr), called_name, sizeof(called_name), &Size);
|
|
ReadMemory(addr + sizeof(Hdr)+sizeof(called_name), callee_name, sizeof(callee_name), &Size);
|
|
|
|
if (called_name[0] != 32 || callee_name[0] != 32) {
|
|
PRINTF ("Error -- invalid called/callee name length called=%d, callee=%d\n",
|
|
(unsigned)called_name[0], (unsigned)callee_name[0]);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
called_name[i + 1] = ((called_name[i*2+1] - 'A') << 4) | (called_name[i*2+2] - 'A');
|
|
callee_name[i + 1] = ((callee_name[i*2+1] - 'A') << 4) | (callee_name[i*2+2] - 'A');
|
|
}
|
|
called_name[i + 1] = 0;
|
|
callee_name[i + 1] = 0;
|
|
|
|
PRINTF ("called name=%15.15s<%02x>\n", called_name+1, (unsigned)called_name[16]);
|
|
PRINTF ("callee name=%15.15s<%02x>\n", callee_name+1, (unsigned)callee_name[16]);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* call back function for dumping a list of workitem entries
|
|
*/
|
|
BOOL
|
|
workitem_callback(ULONG64 addr, const int *bkt)
|
|
{
|
|
static ULONG WorkerRtn_offset = (ULONG)(-1);
|
|
static ULONG addr_offset = (ULONG)(-1);
|
|
ULONG64 WorkerRoutine = 0;
|
|
ULONG64 pTracker = 0;
|
|
ULONG64 pDeviceContext = 0;
|
|
ULONG64 ClientCompletion = 0;
|
|
ULONG64 ClientContext = 0;
|
|
UCHAR ucSymbols[128];
|
|
ULONG64 uDisplacement = 0;
|
|
|
|
if (addr_offset == (ULONG)(-1)) {
|
|
if (GetFieldOffset("netbt!NBT_WORK_ITEM_CONTEXT", (LPSTR)"Linkage", &addr_offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
addr_offset = (ULONG)(-1);
|
|
return FALSE;
|
|
}
|
|
}
|
|
if (WorkerRtn_offset == (ULONG)(-1)) {
|
|
if (GetFieldOffset("netbt!NBT_WORK_ITEM_CONTEXT", (LPSTR)"WorkerRoutine", &WorkerRtn_offset)) {
|
|
WorkerRtn_offset = (ULONG)(-1);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
addr -= addr_offset;
|
|
if (InitTypeRead(addr, netbt!NBT_WORK_ITEM_CONTEXT)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return FALSE;
|
|
}
|
|
|
|
WorkerRoutine = ReadField(WorkerRoutine);
|
|
ClientCompletion = ReadField(ClientCompletion);
|
|
ClientContext = ReadField(pClientContext);
|
|
pTracker = ReadField(pTracker);
|
|
pDeviceContext = ReadField(pDeviceContext);
|
|
|
|
if (0 == WorkerRoutine) {
|
|
strcpy(ucSymbols, "null");
|
|
} else {
|
|
GetSymbol(WorkerRoutine, ucSymbols, &uDisplacement);
|
|
}
|
|
|
|
PRINTF ("%16.16I64lx : %s", addr, ucSymbols);
|
|
|
|
if (pTracker) {
|
|
PRINTF(" pTracker= %16.16I64lx", pTracker);
|
|
}
|
|
|
|
if (pDeviceContext) {
|
|
PRINTF(" pDeviceContext= %16.16I64lx", pDeviceContext);
|
|
}
|
|
|
|
if (0 != ClientCompletion) {
|
|
GetSymbol(WorkerRoutine, ucSymbols, &uDisplacement);
|
|
PRINTF (" pClientCompletion= %s", ucSymbols);
|
|
}
|
|
|
|
if (0 != ClientContext) {
|
|
PRINTF (" ClientContext= %16.16I64lx", ClientContext);
|
|
}
|
|
|
|
PRINTF("\n");
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DECLARE_API(nbtworkitems)
|
|
{
|
|
ULONG Offset = 0;
|
|
|
|
if (GetFieldOffset("netbt!tNBTCONFIG", (LPSTR)"WorkerQList", &Offset)) {
|
|
PRINTF ("Error -- please fix symbol path for NETBT\n");
|
|
return;
|
|
}
|
|
|
|
ListForEach(ConfigPtr + Offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)workitem_callback);
|
|
}
|
|
|
|
//
|
|
// Standard Functions
|
|
//
|
|
DllInit(
|
|
HANDLE hModule,
|
|
DWORD dwReason,
|
|
DWORD dwReserved
|
|
)
|
|
{
|
|
switch (dwReason) {
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
WinDbgExtensionDllInit(
|
|
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
|
USHORT MajorVersion,
|
|
USHORT MinorVersion
|
|
)
|
|
{
|
|
ExtensionApis = *lpExtensionApis;
|
|
|
|
SavedMajorVersion = MajorVersion;
|
|
SavedMinorVersion = MinorVersion;
|
|
ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
|
|
|
|
init(0, 0, 0, 0, "");
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
CheckVersion(VOID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LPEXT_API_VERSION
|
|
ExtensionApiVersion(
|
|
VOID
|
|
)
|
|
{
|
|
return &ApiVersion;
|
|
}
|