/*++ Copyright (c) 1990 Microsoft Corporation Module Name: smbkd.c Abstract: Smb kd extension (To be finished) Author: Jiandong Ruan Notes: Revision History: 12-Mar-2001 jruan --*/ #include #include #define KDEXTMODE #define KDEXT_64BIT #include #include #include #include #include #include #include #include #include "winsock2.h" #include "winsock.h" #include #include "../inc/ip6util.h" #include "../sys/drv/precomp.h" #define PRINTF 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; DECLARE_API(dumpcfg) { ULONG64 SmbDeviceAddr, SmbServerAddr; ULONG64 ConfigPtr; ULONG TcpCfgOffset; SYM_DUMP_PARAM SymDump = { 0 }; CHAR *cfg_sym = "smb!SmbCfg"; CHAR *dns_sym = "smb!Dns"; CHAR *smbdev_sym = "smb!_SMB_DEVICE"; CHAR *smbsrv_sym = "smb!_SMB_CLIENT_ELEMENT"; CHAR *tcp_sym = "smb!_SMB_TCP_INFO"; PRINTF ("dt %s\n", cfg_sym); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = cfg_sym; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); PRINTF ("dt %s\n", dns_sym); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = dns_sym; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); ConfigPtr = GetExpression(cfg_sym); InitTypeRead(ConfigPtr, smb!SMBCONFIG); SmbDeviceAddr = ReadField(SmbDeviceObject); PRINTF ("dt %s %16.16I64x\n", smbdev_sym, SmbDeviceAddr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = smbdev_sym; SymDump.addr = SmbDeviceAddr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); PRINTF ("\n************ TCP Configuration ****************\n"); if (GetFieldOffset("smb!_SMB_DEVICE", (LPSTR)"Tcp4", &TcpCfgOffset)) { PRINTF ("Cannot find the offset of smb!_SMB_CONNECT!TraceRcv\n"); return; } PRINTF ("Dump IPv4 TCP configuration: dt %s %16.16I64x\n", tcp_sym, SmbDeviceAddr + TcpCfgOffset); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = tcp_sym; SymDump.addr = SmbDeviceAddr + TcpCfgOffset; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); if (GetFieldOffset("smb!_SMB_DEVICE", (LPSTR)"Tcp6", &TcpCfgOffset)) { PRINTF ("Cannot find the offset of smb!_SMB_CONNECT!TraceRcv\n"); return; } PRINTF ("Dump IPv6 TCP configuration: dt %s %16.16I64x\n", tcp_sym, SmbDeviceAddr + TcpCfgOffset); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = tcp_sym; SymDump.addr = SmbDeviceAddr + TcpCfgOffset; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); InitTypeRead(SmbDeviceAddr, smb!_SMB_DEVICE); SmbServerAddr = ReadField(SmbServer); if (SmbServerAddr) { PRINTF ("\n************ Smb Server Client Element ****************\n"); PRINTF ("dt %s %16.16I64x\n", smbsrv_sym, SmbServerAddr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = smbsrv_sym; SymDump.addr = SmbServerAddr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); } } __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 MAX_LIST_ELEMENTS 4096 LPSTR Extensions[] = { "SMB6 debugger extensions", 0 }; LPSTR LibCommands[] = { "help -- print out these messages", "tracercv -- dump the trace log for TDI receive handler", "srvmap -- dump IPv6-NetBIOS name mapping (only for SRV)", "dumpcfg -- dump smb common global information", "clients -- dump the client list", "client -- dump a client", "interface -- dump a interface", 0 }; DECLARE_API(help) { 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; } 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 MIN(x,y) ((x) < (y) ? (x) : (y)) DECLARE_API(interface) { CHAR *smbsrv_sym = "smb!SMB_TCP_DEVICE"; SYM_DUMP_PARAM SymDump = { 0 }; ULONG64 addr; addr = GetExpression(args); PRINTF ("****** dt %s %16.16I64x\n", smbsrv_sym, addr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = smbsrv_sym; SymDump.addr = addr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); PRINTF("\n"); } DECLARE_API(tracercv) { ULONG64 addr; ULONG tag, head, i; ULONG traceoffset; SMB_TRACE_RCV traces; CHAR fn[512]; if (*args == 0) { PRINTF ("tracercv connect_object\n"); return; } addr = GetExpression(args); if (0 == addr) { PRINTF ("tracercv connect_object\n"); return; } InitTypeRead(addr, smb!_SMB_CONNECT); tag = (ULONG)ReadField(Tag); if (tag != TAG_CONNECT_OBJECT) { PRINTF ("Incorrect tag: 0x%08lx\n", tag); return; } #if 0 if (GetFieldOffset("smb!_SMB_CONNECT", (LPSTR)"TraceRcv", &traceoffset)) { PRINTF ("Cannot find the offset of smb!_SMB_CONNECT!TraceRcv\n"); return; } #endif if (GetFieldData(addr, "smb!_SMB_CONNECT", "TraceRcv", sizeof(SMB_TRACE_RCV), &traces)) { PRINTF ("Cannot find the smb!_SMB_CONNECT!TraceRcv\n"); return; } head = ((traces.Head + 1) % SMB_MAX_TRACE_SIZE); for (i = head; i < SMB_MAX_TRACE_SIZE; i++) { if (traces.Locations[i].id) { break; } } for (; i < SMB_MAX_TRACE_SIZE; i++) { if (traces.Locations[i].id == 0) { PRINTF ("Invalid trace Id: index=%3d, line=%d\n", i, traces.Locations[i].ln); continue; } PRINTF ("%3d: Id=0x%08lx at line %d\n", i - head + 1, traces.Locations[i].id, traces.Locations[i].ln); } for (i = 0; i < head; i++) { if (traces.Locations[i].id == 0) { PRINTF ("Invalid trace Id: index=%3d, line=%d\n", i, traces.Locations[i].ln); continue; } PRINTF ("%3d: Id=0x%08lx at line %d\n", SMB_MAX_TRACE_SIZE - head + i + 1, traces.Locations[i].id, traces.Locations[i].ln); } } BOOL clientlist_callback(ULONG64 addr, const int *bkt) { static ULONG addr_offset = (ULONG)(-1); CHAR *smbsrv_sym = "smb!_SMB_CLIENT_ELEMENT"; SYM_DUMP_PARAM SymDump = { 0 }; if (addr_offset == (ULONG)(-1)) { if (GetFieldOffset(smbsrv_sym, (LPSTR)"Linkage", &addr_offset)) { PRINTF ("Please fix your symbols\n"); return FALSE; } } addr -= addr_offset; PRINTF ("****** dt %s %16.16I64x\n", smbsrv_sym, addr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = smbsrv_sym; SymDump.addr = addr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); PRINTF("\n"); return TRUE; } DECLARE_API(clients) { ULONG64 ConfigPtr = 0, SmbDeviceAddr = 0; ULONG ClientListOffset; CHAR *cfg_sym = "smb!SmbCfg"; ConfigPtr = GetExpression(cfg_sym); InitTypeRead(ConfigPtr, smb!SMBCONFIG); SmbDeviceAddr = ReadField(SmbDeviceObject); if (GetFieldOffset("smb!_SMB_DEVICE", (LPSTR)"ClientList", &ClientListOffset)) { PRINTF ("Cannot find the offset of smb!_SMB_CONNECT!TraceRcv\n"); return; } PRINTF ("Dump client list\n"); ListForEach(SmbDeviceAddr + ClientListOffset, -1, NULL, (LIST_FOR_EACH_CALLBACK)clientlist_callback); } BOOL connect_callback(ULONG64 addr, const int *bkt) { static ULONG addr_offset = (ULONG)(-1); CHAR *cnt_sym = "smb!_SMB_CONNECT"; SYM_DUMP_PARAM SymDump = { 0 }; if (addr_offset == (ULONG)(-1)) { if (GetFieldOffset(cnt_sym, (LPSTR)"Linkage", &addr_offset)) { PRINTF ("Please fix your symbols\n"); return FALSE; } } addr -= addr_offset; PRINTF ("****** dt %s %16.16I64x\n", cnt_sym, addr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = cnt_sym; SymDump.addr = addr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); PRINTF("\n"); return TRUE; } DECLARE_API(client) { ULONG64 addr; ULONG addr_offset, assoc_offset, active_offset; CHAR *smbsrv_sym = "smb!_SMB_CLIENT_ELEMENT"; if (*args == 0) { PRINTF ("tracercv connect_object\n"); return; } if (GetFieldOffset(smbsrv_sym, (LPSTR)"Linkage", &addr_offset)) { PRINTF ("Please fix your symbols\n"); return; } if (GetFieldOffset(smbsrv_sym, (LPSTR)"AssociatedConnection", &assoc_offset)) { PRINTF ("Please fix your symbols\n"); return; } if (GetFieldOffset(smbsrv_sym, (LPSTR)"ActiveConnection", &active_offset)) { PRINTF ("Please fix your symbols\n"); return; } addr = GetExpression(args); clientlist_callback(addr + addr_offset, NULL); PRINTF ("Dump associated connections\n"); ListForEach(addr + assoc_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)connect_callback); PRINTF ("Dump Active connections\n"); ListForEach(addr + active_offset, -1, NULL, (LIST_FOR_EACH_CALLBACK)connect_callback); } BOOL srvmap_callback(ULONG64 addr, const int *bkt) { static ULONG addr_offset = (ULONG)(-1); struct sockaddr_in6 addr_in6 = { 0 }; LONG RefCount; DWORD SerialNumber, dwError; CHAR host[64]; if (addr_offset == (ULONG)(-1)) { if (GetFieldOffset("smb!SMB_IPV6_NETBIOS", (LPSTR)"Linkage", &addr_offset)) { PRINTF ("Please fix your symbols\n"); return FALSE; } } addr -= addr_offset; if (InitTypeRead(addr, smb!SMB_IPV6_NETBIOS)) { PRINTF ("Please fix your symbols\n"); return FALSE; } RefCount = (LONG)ReadField(RefCount); SerialNumber = (DWORD)ReadField(Serial); if (GetFieldData(addr, "smb!SMB_IPV6_NETBIOS", "IpAddress", 16, &addr_in6.sin6_addr)) { PRINTF ("Please fix your symbols\n"); return FALSE; } addr_in6.sin6_family = AF_INET6; dwError = inet_ntoa6(host, sizeof(host), (PSMB_IP6_ADDRESS)&addr_in6.sin6_addr); if (dwError == 0) { return FALSE; } PRINTF ("%03d\t< %16.16I64x > *SMBSER%08x | %-40s | %02d\n", *bkt, addr, SerialNumber, host, RefCount); return TRUE; } DECLARE_API(srvmap) { ULONG64 addr = 0; ULONG64 hashtbl_addr = 0; ULONG64 buckets_addr = 0; ULONG64 sizeof_list = 0; int i, bucket_number = 0; SYM_DUMP_PARAM SymDump = { 0 }; CHAR *mapping_sym = "smb!SmbIPv6Mapping"; CHAR *hash_sym = "smb!SMB_HASH_TABLE"; addr = GetExpression(mapping_sym); if (0 == addr) { PRINTF ("Please fix your symbols\n"); return; } // // dump the mapping structure // PRINTF ("dt %s\n", mapping_sym); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = mapping_sym; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); // // dump the hash table // InitTypeRead(addr, smb!SMB_IPV6_NETBIOS_TABLE); hashtbl_addr = ReadField(HashTable); if (0 == hashtbl_addr) { PRINTF ("Please fix your symbols\n"); return; } if (GetFieldOffset(hash_sym, (LPSTR)"Buckets", (LONG*)&buckets_addr)) { PRINTF ("Please fix your symbols\n"); return; } buckets_addr += hashtbl_addr; PRINTF ("dt %s %16.16I64x\n", hash_sym, hashtbl_addr); SymDump.size = sizeof(SYM_DUMP_PARAM); SymDump.sName = hash_sym; SymDump.addr = hashtbl_addr; Ioctl(IG_DUMP_SYMBOL_INFO, &SymDump, SymDump.size); InitTypeRead(hashtbl_addr, smb!SMB_HASH_TABLE); bucket_number = (int)ReadField(NumberOfBuckets); if (0 >= bucket_number) { PRINTF ("Please fix your symbols\n"); return; } // // dump each bucket // sizeof_list = GetTypeSize ("LIST_ENTRY"); if (0 == sizeof_list) { PRINTF ("Please fix your symbols\n"); return; } PRINTF ("[Bkt#]\t< Address > < Name > | IPv6 Address | RefC\n"); PRINTF ("================================================================================================\n"); for (i = 0; i < bucket_number; i++) { ListForEach(buckets_addr + i * sizeof_list, -1, &i, (LIST_FOR_EACH_CALLBACK)srvmap_callback); } } // // Standard Functions // DllInit( HANDLE hModule, DWORD dwReason, DWORD dwReserved ) { WSADATA wsaData; switch (dwReason) { case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: WSAStartup(MAKEWORD(2, 0), &wsaData); break; case DLL_PROCESS_ATTACH: WSACleanup(); break; } return TRUE; } VOID WinDbgExtensionDllInit( PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion ) { ExtensionApis = *lpExtensionApis; SavedMajorVersion = MajorVersion; SavedMinorVersion = MinorVersion; ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE; return; } VOID CheckVersion(VOID) { return; } LPEXT_API_VERSION ExtensionApiVersion( VOID ) { return &ApiVersion; }