/*++ 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 #include #define KDEXTMODE #define KDEXT_64BIT #include #include #include #include #include #include #include #include #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 -- 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 ' instead", "\tFor example 'dt netbt!tDEVICECONTEXT 0x98765432'", "devices -- list all devices", "dev -- dump a device", "connections -- list all connections", "cache [Local|Remote]", "localname Display the connections associated with a local name", "verifyll []", "sessionhdr Dump the session HDR", 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: \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 > => | 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 \n"); return; } else { // // args = " []" // 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; } // // 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; }