Daniel Plohmann avatar Daniel Plohmann committed fbb539b

Added filter functionality to Function Inspection

Comments (0)

Files changed (8)

idascope/core/DocumentationHelper.py

 
     def _getColorsForGroup(self, target_group, config):
         for group in config["semantic_groups"]:
-            if group["name"] == target_group:
+            if group["tag"] == target_group:
                 return (group["base_color"], group["highlight_color"])
         print "[-] Failed to get colors for group \"%s\" - you might want to check your semantics file." % target_group
         return (self.default_base_color, self.default_highlight_color)

idascope/core/SemanticIdentifier.py

 
 from IdaProxy import IdaProxy
 from idascope.core.structures.FunctionContext import FunctionContext
+from idascope.core.structures.FunctionContextFilter import FunctionContextFilter
 from idascope.core.structures.CallContext import CallContext
 from idascope.core.structures.ParameterContext import ParameterContext
 
         self.time = time
         self.ida_proxy = IdaProxy()
         self.FunctionContext = FunctionContext
+        self.FunctionContextFilter = FunctionContextFilter
         self.CallContext = CallContext
         self.ParameterContext = ParameterContext
         self.renaming_seperator = "_"
         time_before = self.time.time()
         self.last_scan_result = {}
         for semantic_tag in self.semantic_definitions:
-            semantic_group_tag = semantic_tag["tag"]
             for api_name in semantic_tag["api_names"]:
                 api_address = self.ida_proxy.LocByName(api_name)
                 for ref in self._getAllRefsTo(api_address):
                     call_ctx.called_function_name = api_name
                     call_ctx.address_of_call = ref
                     call_ctx.called_address = api_address
-                    call_ctx.tag = semantic_group_tag
+                    call_ctx.tag = semantic_tag["tag"]
+                    call_ctx.group = semantic_tag["group"]
                     call_ctx.parameter_contexts = self._resolveApiCall(call_ctx)
                     function_ctx.call_contexts.append(call_ctx)
         print ("  [\\] Analysis took %3.2f seconds." % (self.time.time() - time_before))
                 number_of_functions += 1
         return number_of_functions
 
+    def calculateNumberOfTaggedFunctions(self):
+        """
+        Calculate the number of functions in all segments that have been tagged.
+        @return: (int) the number of functions found.
+        """
+        return len(self.getFunctionAddresses(self.createFunctionContextFilter()))
+
     def getFunctionAddresses(self, context_filter):
         """
         Get all function address that have been covered by the last scanning.
         @type tag_only: bool
         @return: (list of int) The addresses of covered functions.
         """
-        if context_filter.display_tag_only and context_filter.display_dummy_only:
-            return [addr for addr in self.last_scan_result.keys() if self.last_scan_result[addr].has_dummy_name and \
-                self.last_scan_result[addr].has_tags]
-        elif context_filter.display_tag_only:
-            return [addr for addr in self.last_scan_result.keys() if self.last_scan_result[addr].has_tags]
-        elif context_filter.display_dummy_only:
-            return [addr for addr in self.last_scan_result.keys() if self.last_scan_result[addr].has_dummy_name]
-        else:
-            return self.last_scan_result.keys()
-        return []
+        all_addresses = self.last_scan_result.keys()
+        filtered_addresses = []
+        if context_filter.display_all:
+            filtered_addresses = all_addresses
+        elif context_filter.display_tags:
+            for address in all_addresses:
+                enabled_tags = [tag[0] for tag in context_filter.enabled_tags]
+                if len(set(self.last_scan_result[address].getTags()) & set(enabled_tags)) > 0:
+                    filtered_addresses.append(address)
+        elif context_filter.display_groups:
+            for address in all_addresses:
+                enabled_groups = [group[0] for group in context_filter.enabled_groups]
+                if len(set(self.last_scan_result[address].getGroups()) & set(enabled_groups)) > 0:
+                    filtered_addresses.append(address)
+        # filter additionals
+        if context_filter.isDisplayTagOnly():
+            filtered_addresses = [addr for addr in filtered_addresses if self.last_scan_result[addr].has_tags]
+        if context_filter.isDisplayDummyOnly():
+            filtered_addresses = [addr for addr in filtered_addresses if self.last_scan_result[addr].has_dummy_name]
+        return filtered_addresses
 
     def getTags(self):
         """
                     tags.append(call_ctx.tag)
         return tags
 
+    def getGroups(self):
+        """
+        Get all the groups that have been covered by tags in the last scanning.
+        @return (list of str) The groups found.
+        """
+        tag_to_group_mapping = self._createTagToGroupMapping()
+        groups = []
+        for function_address in self.last_scan_result.keys():
+            for call_ctx in self.last_scan_result[function_address].call_contexts:
+                if tag_to_group_mapping[call_ctx.tag] not in groups:
+                    groups.append(tag_to_group_mapping[call_ctx.tag])
+        return groups
+
+    def _createTagToGroupMapping(self):
+        mapping = {}
+        for definition in self.semantic_definitions:
+            mapping[definition["tag"]] = definition["group"]
+        return mapping
+
     def getTagsForFunctionAddress(self, address):
         """
         Get all tags found for the function containing the queried address.
                     tags.append(call_ctx.tag)
         return tags
 
-    def getTagCountForFunctionAddress(self, tag, address):
+    def getFieldCountForFunctionAddress(self, query, address):
         """
-        Get the number of occurrences for a certain tag for the function containing the queried address.
-        @param tag: a tag as included in semantic definitions
-        @type tag: str
+        Get the number of occurrences for a certain field for the function containing the queried address.
+        @param query: a tuple (type, name), where type is additional, tag, or group and name the field being queried.
+        @type query: tuple
         @param address: address in the target function
         @type address: int
         @return: (int) The number of occurrences for this tag in the function
         """
         function_address = self.getFunctionAddressForAddress(address)
-        tag_count = 0
-        if tag in self.getTagsForFunctionAddress(function_address):
-            for call_ctx in self.last_scan_result[function_address].call_contexts:
-                if call_ctx.tag == tag:
-                    tag_count += 1
-        return tag_count
+        return self.last_scan_result[function_address].getCountForField(query)
 
     def getTaggedApisForFunctionAddress(self, address):
         """
                     unexplored.update(new_functions)
         return graph
 
+    def createFunctionContextFilter(self):
+        """
+        Create a function filter, containing only those tags/groups that have been identified within the last scan.
+        """
+        context_filter = self.FunctionContextFilter()
+        context_filter.tags = sorted([(tag, tag, tag) for tag in self.getTags()])
+        context_filter.enabled_tags = context_filter.tags
+        context_filter.groups = sorted([(group, group, group) for group in self.getGroups()])
+        context_filter.enabled_groups = context_filter.groups
+        return context_filter
+
     def getLastScanResult(self):
         """
         Get the last scan result as retrieved by I{scanByReferences}.

idascope/core/structures/FunctionContext.py

         self.calls_from = set()
         self.call_contexts = []
 
-    def __str__(self):
+    def getTags(self):
         """
-        Convenience function.
-        @return: a nice string representation for this object
+        Get all semantic tags covered by this function.
         """
-        return "0x%x %s [%d ins, %d blocks, %d calls, xrefs in/out: %d/%d]" % (self.function_address, \
-            self.function_name, self.number_of_instructions, self.number_of_basic_blocks, len(self.call_contexts), \
-            self.number_of_xrefs_to, self.number_of_xrefs_from)
+        tags = []
+        for call_ctx in self.call_contexts:
+            if call_ctx.tag != "" and call_ctx.tag not in tags:
+                tags.append(call_ctx.tag)
+        return tags
+
+    def getGroups(self):
+        """
+        Get all semantic groups covered by this function.
+        """
+        groups = []
+        for call_ctx in self.call_contexts:
+            if call_ctx.group != "" and call_ctx.group not in groups:
+                groups.append(call_ctx.group)
+        return groups
+
+    def getCountForField(self, query):
+        if query[0] == "additional":
+            return self.getCountForAdditional(query[1])
+        if query[0] == "tag":
+            return self.getCountForTag(query[1])
+        if query[0] == "group":
+            return self.getCountForGroup(query[1])
+
+    def getCountForTag(self, tag):
+        tag_count = 0
+        for call_ctx in self.call_contexts:
+            if call_ctx.tag == tag:
+                tag_count += 1
+        return tag_count
+
+    def getCountForGroup(self, group):
+        group_count = 0
+        for call_ctx in self.call_contexts:
+            if call_ctx.group == group:
+                group_count += 1
+        return group_count
+
+    def getCountForAdditional(self, additional):
+        if additional == "num_blocks":
+            return self.number_of_basic_blocks
+        elif additional == "num_ins":
+            return self.number_of_instructions
+        elif additional == "xrefs_out":
+            return self.number_of_xrefs_from
+        elif additional == "xrefs_in":
+            return self.number_of_xrefs_to
+        else:
+            print "[!] FunctionContext.getCountForAdditional(): Invalid query -> %s" % additional
+            return 0
 
     def getAllTaggedAddresses(self):
         """
             if call_ctx.tag != "":
                 tagged_addresses[call_ctx.address_of_call] = call_ctx.tag
         return tagged_addresses
+
+    def __str__(self):
+        """
+        Convenience function.
+        @return: a nice string representation for this object
+        """
+        return "0x%x %s [%d ins, %d blocks, %d calls, xrefs in/out: %d/%d]" % (self.function_address, \
+            self.function_name, self.number_of_instructions, self.number_of_basic_blocks, len(self.call_contexts), \
+            self.number_of_xrefs_to, self.number_of_xrefs_from)

idascope/core/structures/FunctionContextFilter.py

     def __init__(self):
         self.display_tags = True
         self.display_groups = False
-        self.display_tag_only = True
-        self.display_dummy_only = False
+        self.display_all = False
+        # tags, groups, additionals are 3-tuples of the form: (id, heading, description)
+        # tuples having an id starting with an underscore are not displayed in result tables.
+        self.tags = []
+        self.groups = []
         self.enabled_tags = []
         self.enabled_groups = []
-        self.enabled_additions = []
+        self.additionals = [("_dummy_only", "Dummy Names", "Dummy names only"), \
+            ("_tagged_only", "Tagged only", "Tagged functions only"), \
+            ("num_blocks", "Blocks", "Number of Basic Blocks"), \
+            ("num_ins", "Ins", "Number of Instructions"), \
+            ("xrefs_in", "Xrefs IN", "Incoming cross-references"), \
+            ("xrefs_out", "Xrefs OUT", "Outgoing cross-references")]
+        self.enabled_additionals = []
 
-    def setGroupDisplay(self):
-        self.display_tags = False
-        self.display_groups = True
+    def generateColumnHeadings(self):
+        headings = []
+        for additional in self.enabled_additionals:
+            if not additional[0].startswith("_"):
+                headings.append(additional[1])
+        if self.display_tags:
+            for tag in self.enabled_tags:
+                headings.append(tag[1])
+        if self.display_groups:
+            for group in self.enabled_groups:
+                headings.append(group[1])
+        return headings
 
-    def setTagDisplay(self):
-        self.display_tags = True
-        self.display_groups = False
+    def getQueryForHeading(self, heading):
+        for tag in self.tags:
+            if tag[1] == heading:
+                return ("tag", tag[0])
+        for group in self.groups:
+            if group[1] == heading:
+                return ("group", group[0])
+        for additional in self.additionals:
+            if additional[1] == heading:
+                return ("additional", additional[0])
+
+    def isDisplayTagOnly(self):
+        return ("_tagged_only", "Tagged only", "Tagged functions only") in self.enabled_additionals
+
+    def isDisplayDummyOnly(self):
+        return ("_dummy_only", "Dummy Names", "Dummy names only") in self.enabled_additionals
+
+    def __str__(self):
+        return "Tags: %s, Groups: %s\nTags: %s\nEnabled: %s\nGroups: %s\nEnabled: %s" % \
+            (self.display_tags, self.display_groups, \
+            self.tags, \
+            self.enabled_tags, \
+            self.groups, \
+            self.enabled_groups)

idascope/data/semantics.json

     "default_base_color": "0xB3DfFF",
     "default_highlight_color": "0x33A7FF",
     "semantic_groups": [{
-        "name": "CFG",
+        "tag": "CFG",
+        "name": "Configuration",
         "base_color": "0xB3B3FF",
         "highlight_color": "0x333377"
     }, {
-        "name": "FILE",
+        "tag": "FILE",
+        "name": "File interaction",
         "base_color": "0xB3DFFF",
         "highlight_color": "0x33A7FF"
     }, {
-        "name": "MEM",
+        "tag": "MEM",
+        "name": "Memory",
         "base_color": "0xB3FFFF",
         "highlight_color": "0x33FFFF"
     }, {
-        "name": "CRYPT",
+        "tag": "CRYPT",
+        "name": "Cryptography",
         "base_color": "0x26BD32",
         "highlight_color": "0x84BD89"
     }, {
-        "name": "NET",
+        "tag": "NET",
+        "name": "Network",
         "base_color": "0xC1A687",
         "highlight_color": "0xC17927"
     }, {
-        "name": "EXEC",
+        "tag": "EXEC",
+        "name": "Execution",
         "base_color": "0xB47E9E",
         "highlight_color": "0xB4247A"
     }],
     "semantic_definitions": [{
         "tag": "Reg",
+        "name": "Registry",
         "group": "CFG",
         "api_names": ["RegCloseKey", "RegConnectRegistryA", "RegConnectRegistryW", "RegCreateKeyA", "RegCreateKeyExA", "RegCreateKeyExW", "RegCreateKeyW", "RegDeleteKeyA", "RegDeleteKeyW", "RegDeleteValueA", "RegDeleteValueW", "RegDisablePredefinedCache", "RegDisablePredefinedCacheEx", "RegEnumKeyA", "RegEnumKeyExA", "RegEnumKeyExW", "RegEnumKeyW", "RegEnumValueA", "RegEnumValueW", "RegFlushKey", "RegGetKeySecurity", "RegLoadKeyA", "RegLoadKeyW", "RegNotifyChangeKeyValue", "RegOpenCurrentUser", "RegOpenKeyA", "RegOpenKeyExA", "RegOpenKeyExW", "RegOpenKeyW", "RegOpenUserClassesRoot", "RegOverridePredefKey", "RegQueryInfoKeyA", "RegQueryInfoKeyW", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW", "RegQueryValueA", "RegQueryValueExA", "RegQueryValueExW", "RegQueryValueW", "RegReplaceKeyA", "RegReplaceKeyW", "RegRestoreKeyA", "RegRestoreKeyW", "RegSaveKeyA", "RegSaveKeyExA", "RegSaveKeyExW", "RegSaveKeyW", "RegSetKeySecurity", "RegSetValueA", "RegSetValueExA", "RegSetValueExW", "RegSetValueW", "RegUnLoadKeyA", "RegUnLoadKeyW", "SHDeleteEmptyKeyA", "SHDeleteEmptyKeyW", "SHDeleteKeyA", "SHDeleteKeyW", "SHOpenRegStream2A", "SHOpenRegStream2W", "SHOpenRegStreamA", "SHOpenRegStreamW", "SHQueryInfoKeyA", "SHQueryInfoKeyW", "SHQueryValueExA", "SHQueryValueExW", "SHRegCloseUSKey", "SHRegCreateUSKeyA", "SHRegCreateUSKeyW", "SHRegDeleteEmptyUSKeyA", "SHRegDeleteEmptyUSKeyW", "SHRegDeleteUSValueA", "SHRegDeleteUSValueW", "SHRegDuplicateHKey", "SHRegEnumUSKeyA", "SHRegEnumUSKeyW", "SHRegEnumUSValueA", "SHRegEnumUSValueW", "SHRegGetBoolUSValueA", "SHRegGetBoolUSValueW", "SHRegGetPathA", "SHRegGetPathW", "SHRegGetUSValueA", "SHRegGetUSValueW", "SHRegGetValueA", "SHRegGetValueW", "SHRegOpenUSKeyA", "SHRegOpenUSKeyW", "SHRegQueryInfoUSKeyA", "SHRegQueryInfoUSKeyW", "SHRegQueryUSValueA", "SHRegQueryUSValueW", "SHRegSetPathA", "SHRegSetPathW", "SHRegSetUSValueA", "SHRegSetUSValueW", "SHRegWriteUSValueA", "SHRegWriteUSValueW", "SHDeleteOrphanKeyA", "SHDeleteOrphanKeyW", "SHDeleteValueA", "SHDeleteValueW", "SHEnumKeyExA", "SHEnumKeyExW", "SHEnumValueA", "SHEnumValueW", "SHGetValueA", "SHGetValueW", "SHOpenRegStream2A", "SHOpenRegStream2W", "SHOpenRegStreamA", "SHOpenRegStreamW", "SHQueryInfoKeyA", "SHQueryInfoKeyW", "SHQueryValueExA", "SHQueryValueExW", "SHRegCloseUSKey", "SHRegCreateUSKeyA", "SHRegCreateUSKeyW", "SHRegDeleteEmptyUSKeyA", "SHRegDeleteEmptyUSKeyW", "SHRegDeleteUSValueA", "SHRegDeleteUSValueW", "SHRegDuplicateHKey", "SHRegEnumUSKeyA", "SHRegEnumUSKeyW", "SHRegEnumUSValueA", "SHRegEnumUSValueW", "SHRegGetBoolUSValueA", "SHRegGetBoolUSValueW", "SHRegGetPathA", "SHRegGetPathW", "SHRegGetUSValueA", "SHRegGetUSValueW", "SHRegGetValueA", "SHRegGetValueW", "SHRegOpenUSKeyA", "SHRegOpenUSKeyW", "SHRegQueryInfoUSKeyA", "SHRegQueryInfoUSKeyW", "SHRegQueryUSValueA", "SHRegQueryUSValueW", "SHRegSetPathA", "SHRegSetPathW", "SHRegSetUSValueA", "SHRegSetUSValueW", "SHRegWriteUSValueA", "SHRegWriteUSValueW"]
     }, {
         "tag": "Ws2",
+        "name": "Ws2_32",
         "group": "NET",
         "api_names": ["FreeAddrInfoW", "GetAddrInfoW", "GetNameInfoW", "WEP", "WPUCompleteOverlappedRequest", "WSAAccept", "WSAAddressToStringA", "WSAAddressToStringW", "WSAAsyncGetHostByAddr", "WSAAsyncGetHostByName", "WSAAsyncGetProtoByName", "WSAAsyncGetProtoByNumber", "WSAAsyncGetServByName", "WSAAsyncGetServByPort", "WSAAsyncSelect", "WSACancelAsyncRequest", "WSACancelBlockingCall", "WSACleanup", "WSACloseEvent", "WSAConnect", "WSACreateEvent", "WSADuplicateSocketA", "WSADuplicateSocketW", "WSAEnumNameSpaceProvidersA", "WSAEnumNameSpaceProvidersW", "WSAEnumNetworkEvents", "WSAEnumProtocolsA", "WSAEnumProtocolsW", "WSAEventSelect", "WSAGetLastError", "WSAGetOverlappedResult", "WSAGetQOSByName", "WSAGetServiceClassInfoA", "WSAGetServiceClassInfoW", "WSAGetServiceClassNameByClassIdA", "WSAGetServiceClassNameByClassIdW", "WSAHtonl", "WSAHtons", "WSAInstallServiceClassA", "WSAInstallServiceClassW", "WSAIoctl", "WSAIsBlocking", "WSAJoinLeaf", "WSALookupServiceBeginA", "WSALookupServiceBeginW", "WSALookupServiceEnd", "WSALookupServiceNextA", "WSALookupServiceNextW", "WSANSPIoctl", "WSANtohl", "WSANtohs", "WSAProviderConfigChange", "WSARecv", "WSARecvDisconnect", "WSARecvFrom", "WSARemoveServiceClass", "WSAResetEvent", "WSASend", "WSASendDisconnect", "WSASendTo", "WSASetBlockingHook", "WSASetEvent", "WSASetLastError", "WSASetServiceA", "WSASetServiceW", "WSASocketA", "WSASocketW", "WSAStartup", "WSAStringToAddressA", "WSAStringToAddressW", "WSAUnhookBlockingHook", "WSAWaitForMultipleEvents", "WSApSetPostRoutine", "WSCDeinstallProvider", "WSCEnableNSProvider", "WSCEnumProtocols", "WSCGetProviderPath", "WSCInstallNameSpace", "WSCInstallProvider", "WSCUnInstallNameSpace", "WSCUpdateProvider", "WSCWriteNameSpaceOrder", "WSCWriteProviderOrder", "__WSAFDIsSet", "accept", "bind", "closesocket", "connect", "freeaddrinfo", "getaddrinfo", "gethostbyaddr", "gethostbyname", "gethostname", "getnameinfo", "getpeername", "getprotobyname", "getprotobynumber", "getservbyname", "getservbyport", "getsockname", "getsockopt", "htonl", "htons", "inet_addr", "inet_ntoa", "ioctlsocket", "listen", "ntohl", "ntohs", "recv", "recvfrom", "select", "send", "sendto", "setsockopt", "shutdown", "socket"]
     }, {
         "tag": "WINet",
+        "name": "WinInet",
         "group": "NET",
         "api_names": ["CreateMD5SSOHash", "DetectAutoProxyUrl", "DllInstall", "ForceNexusLookup", "ForceNexusLookupExW", "InternetAlgIdToStringA", "InternetAlgIdToStringW", "InternetAttemptConnect", "InternetAutodial", "InternetAutodialCallback", "InternetAutodialHangup", "InternetCanonicalizeUrlA", "InternetCanonicalizeUrlW", "InternetCheckConnectionA", "InternetCheckConnectionW", "InternetClearAllPerSiteCookieDecisions", "InternetCloseHandle", "InternetCombineUrlA", "InternetCombineUrlW", "InternetConfirmZoneCrossing", "InternetConfirmZoneCrossingA", "InternetConfirmZoneCrossingW", "InternetConnectA", "InternetConnectW", "InternetCrackUrlA", "InternetCrackUrlW", "InternetCreateUrlA", "InternetCreateUrlW", "InternetDial", "InternetDialA", "InternetDialW", "InternetEnumPerSiteCookieDecisionA", "InternetEnumPerSiteCookieDecisionW", "InternetErrorDlg", "InternetFindNextFileA", "InternetFindNextFileW", "InternetFortezzaCommand", "InternetGetCertByURL", "InternetGetCertByURLA", "InternetGetConnectedState", "InternetGetConnectedStateEx", "InternetGetConnectedStateExA", "InternetGetConnectedStateExW", "InternetGetCookieA", "InternetGetCookieExA", "InternetGetCookieExW", "InternetGetCookieW", "InternetGetLastResponseInfoA", "InternetGetLastResponseInfoW", "InternetGetPerSiteCookieDecisionA", "InternetGetPerSiteCookieDecisionW", "InternetGoOnline", "InternetGoOnlineA", "InternetGoOnlineW", "InternetHangUp", "InternetInitializeAutoProxyDll", "InternetLockRequestFile", "InternetOpenA", "InternetOpenUrlA", "InternetOpenUrlW", "InternetOpenW", "InternetQueryDataAvailable", "InternetQueryFortezzaStatus", "InternetQueryOptionA", "InternetQueryOptionW", "InternetReadFile", "InternetReadFileExA", "InternetReadFileExW", "InternetSecurityProtocolToStringA", "InternetSecurityProtocolToStringW", "InternetSetCookieA", "InternetSetCookieExA", "InternetSetCookieExW", "InternetSetCookieW", "InternetSetDialState", "InternetSetDialStateA", "InternetSetDialStateW", "InternetSetFilePointer", "InternetSetOptionA", "InternetSetOptionExA", "InternetSetOptionExW", "InternetSetOptionW", "InternetSetPerSiteCookieDecisionA", "InternetSetPerSiteCookieDecisionW", "InternetSetStatusCallback", "InternetSetStatusCallbackA", "InternetSetStatusCallbackW", "InternetShowSecurityInfoByURL", "InternetShowSecurityInfoByURLA", "InternetShowSecurityInfoByURLW", "InternetTimeFromSystemTime", "InternetTimeFromSystemTimeA", "InternetTimeFromSystemTimeW", "InternetTimeToSystemTime", "InternetTimeToSystemTimeA", "InternetTimeToSystemTimeW", "InternetUnlockRequestFile", "InternetWriteFile", "InternetWriteFileExA", "InternetWriteFileExW", "IsHostInProxyBypassList", "ParseX509EncodedCertificateForListBoxEntry", "PrivacyGetZonePreferenceW", "PrivacySetZonePreferenceW", "ResumeSuspendedDownload", "ShowCertificate", "ShowClientAuthCerts", "ShowSecurityInfo", "ShowX509EncodedCertificate", "UrlZonesDetach", "_GetFileExtensionFromUrl"]
     }, {
         "tag": "Cach",
+        "name": "Internet Cache",
         "group": "NET",
         "api_names": ["CommitUrlCacheEntryA", "CommitUrlCacheEntryW", "CreateUrlCacheContainerA", "CreateUrlCacheContainerW", "CreateUrlCacheEntryA", "CreateUrlCacheEntryW", "CreateUrlCacheGroup", "DeleteIE3Cache", "DeleteUrlCacheContainerA", "DeleteUrlCacheContainerW", "DeleteUrlCacheEntry", "DeleteUrlCacheEntryA", "DeleteUrlCacheEntryW", "DeleteUrlCacheGroup", "FindCloseUrlCache", "FindFirstUrlCacheContainerA", "FindFirstUrlCacheContainerW", "FindFirstUrlCacheEntryA", "FindFirstUrlCacheEntryExA", "FindFirstUrlCacheEntryExW", "FindFirstUrlCacheEntryW", "FindFirstUrlCacheGroup", "FindNextUrlCacheContainerA", "FindNextUrlCacheContainerW", "FindNextUrlCacheEntryA", "FindNextUrlCacheEntryExA", "FindNextUrlCacheEntryExW", "FindNextUrlCacheEntryW", "FindNextUrlCacheGroup", "FreeUrlCacheSpaceA", "FreeUrlCacheSpaceW", "GetUrlCacheConfigInfoA", "GetUrlCacheConfigInfoW", "GetUrlCacheEntryInfoA", "GetUrlCacheEntryInfoExA", "GetUrlCacheEntryInfoExW", "GetUrlCacheEntryInfoW", "GetUrlCacheGroupAttributeA", "GetUrlCacheGroupAttributeW", "GetUrlCacheHeaderData", "IncrementUrlCacheHeaderData", "IsUrlCacheEntryExpiredA", "IsUrlCacheEntryExpiredW", "LoadUrlCacheContent", "ReadUrlCacheEntryStream", "RegisterUrlCacheNotification", "RetrieveUrlCacheEntryFileA", "RetrieveUrlCacheEntryFileW", "RetrieveUrlCacheEntryStreamA", "RetrieveUrlCacheEntryStreamW", "RunOnceUrlCache", "SetUrlCacheConfigInfoA", "SetUrlCacheConfigInfoW", "SetUrlCacheEntryGroup", "SetUrlCacheEntryGroupA", "SetUrlCacheEntryGroupW", "SetUrlCacheEntryInfoA", "SetUrlCacheEntryInfoW", "SetUrlCacheGroupAttributeA", "SetUrlCacheGroupAttributeW", "SetUrlCacheHeaderData", "UnlockUrlCacheEntryFile", "UnlockUrlCacheEntryFileA", "UnlockUrlCacheEntryFileW", "UnlockUrlCacheEntryStream", "UpdateUrlCacheContentPath"]
     }, {
         "tag": "Ftp",
+        "name": "Ftp",
         "group": "NET",
         "api_names": ["FtpCommandA", "FtpCommandW", "FtpCreateDirectoryA", "FtpCreateDirectoryW", "FtpDeleteFileA", "FtpDeleteFileW", "FtpFindFirstFileA", "FtpFindFirstFileW", "FtpGetCurrentDirectoryA", "FtpGetCurrentDirectoryW", "FtpGetFileA", "FtpGetFileEx", "FtpGetFileSize", "FtpGetFileW", "FtpOpenFileA", "FtpOpenFileW", "FtpPutFileA", "FtpPutFileEx", "FtpPutFileW", "FtpRemoveDirectoryA", "FtpRemoveDirectoryW", "FtpRenameFileA", "FtpRenameFileW", "FtpSetCurrentDirectoryA", "FtpSetCurrentDirectoryW"]
     }, {
         "tag": "Gopher",
+        "name": "Gopher",
         "group": "NET",
         "api_names": ["GopherCreateLocatorA", "GopherCreateLocatorW", "GopherFindFirstFileA", "GopherFindFirstFileW", "GopherGetAttributeA", "GopherGetAttributeW", "GopherGetLocatorTypeA", "GopherGetLocatorTypeW", "GopherOpenFileA", "GopherOpenFileW"]
     }, {
         "tag": "Url",
+        "name": "Url handling",
         "group": "NET",
         "api_names": ["UrlApplySchemeA", "UrlApplySchemeW", "UrlCanonicalizeA", "UrlCanonicalizeW", "UrlCombineA", "UrlCombineW", "UrlCompareA", "UrlCompareW", "UrlCreateFromPathA", "UrlCreateFromPathW", "UrlEscapeA", "UrlEscapeW", "UrlGetLocationA", "UrlGetLocationW", "UrlGetPartA", "UrlGetPartW", "UrlHashA", "UrlHashW", "UrlIsA", "UrlIsNoHistoryA", "UrlIsNoHistoryW", "UrlIsOpaqueA", "UrlIsOpaqueW", "UrlIsW", "UrlUnescapeA", "UrlUnescapeW"]
     }, {
         "tag": "Dir",
+        "name": "Directory",
         "group": "FILE",
         "api_names": ["CreateDirectoryA", "CreateDirectoryExA", "CreateDirectoryExW", "CreateDirectoryW", "GetCurrentDirectoryA", "GetCurrentDirectoryW", "GetDllDirectoryA", "GetDllDirectoryW", "GetSystemDirectoryA", "GetSystemDirectoryW", "GetSystemWindowsDirectoryA", "GetSystemWindowsDirectoryW", "GetSystemWow64DirectoryA", "GetSystemWow64DirectoryW", "GetVDMCurrentDirectories", "GetWindowsDirectoryA", "GetWindowsDirectoryW", "ReadDirectoryChangesW", "RemoveDirectoryA", "RemoveDirectoryW", "SetCurrentDirectoryA", "SetCurrentDirectoryW", "SetDllDirectoryA", "SetDllDirectoryW", "SetVDMCurrentDirectories", "SHCreateDirectory", "SHCreateDirectoryExA", "SHCreateDirectoryExW"]
     }, {
         "tag": "Mutx",
+        "name": "Mutex",
         "group": "EXEC",
         "api_names": ["CreateMutexA", "CreateMutexW", "OpenMutexA", "OpenMutexW", "ReleaseMutex"]
     }, {
         "tag": "Pipe",
+        "name": "Pipe",
         "group": "FILE",
         "api_names": ["CallNamedPipeA", "CallNamedPipeW", "ConnectNamedPipe", "CreateNamedPipeA", "CreateNamedPipeW", "CreatePipe", "DisconnectNamedPipe", "GetNamedPipeHandleStateA", "GetNamedPipeHandleStateW", "GetNamedPipeInfo", "PeekNamedPipe", "SetNamedPipeHandleState", "TransactNamedPipe", "WaitNamedPipeA", "WaitNamedPipeW"]
     }, {
         "tag": "Http",
+        "name": "Http",
         "group": "NET",
         "api_names": ["HttpAddRequestHeadersA", "HttpAddRequestHeadersW", "HttpCheckDavCompliance", "HttpEndRequestA", "HttpEndRequestW", "HttpOpenRequestA", "HttpOpenRequestW", "HttpQueryInfoA", "HttpQueryInfoW", "HttpSendRequestA", "HttpSendRequestExA", "HttpSendRequestExW", "HttpSendRequestW"]
     }, {
         "tag": "Enum",
+        "name": "Process / Thread enumeration",
         "group": "EXEC",
         "api_names": ["CreateToolhelp32Snapshot", "Process32First", "Process32FirstW", "Process32Next", "Process32NextW"]
     }, {
         "tag": "Hash",
+        "name": "Hashing",
         "group": "CRYPT",
         "api_names": ["CryptCreateHash", "CryptDestroyHash", "CryptDuplicateHash", "CryptGetHashParam", "CryptHashData", "CryptHashSessionKey", "CryptSetHashParam", "CryptSignHashA", "CryptSignHashW", "FreeEncryptionCertificateHashList"]
     }, {
         "tag": "Crypt",
+        "name": "Cryptography",
         "group": "CRYPT",
         "api_names": ["CryptAcquireContextA", "CryptAcquireContextW", "CryptContextAddRef", "CryptDecrypt", "CryptDeriveKey", "CryptDestroyKey", "CryptDuplicateKey", "CryptEncrypt", "CryptEnumProviderTypesA", "CryptEnumProviderTypesW", "CryptEnumProvidersA", "CryptEnumProvidersW", "CryptExportKey", "CryptGenKey", "CryptGenRandom", "CryptGetDefaultProviderA", "CryptGetDefaultProviderW", "CryptGetKeyParam", "CryptGetProvParam", "CryptGetUserKey", "CryptImportKey", "CryptReleaseContext", "CryptSetKeyParam", "CryptSetProvParam", "CryptSetProviderA", "CryptSetProviderExA", "CryptSetProviderExW", "CryptSetProviderW", "CryptVerifySignatureA", "CryptVerifySignatureW", "DecryptFileA", "DecryptFileW", "EncryptFileA", "EncryptFileW", "EncryptedFileKeyInfo", "EncryptionDisable", "WriteEncryptedFileRaw", "OpenEncryptedFileRawA", "OpenEncryptedFileRawW", "DuplicateEncryptionInfoFile", "SetUserFileEncryptionKey", "ReadEncryptedFileRaw", "RemoveUsersFromEncryptedFile", "FileEncryptionStatusA", "FileEncryptionStatusW", "FreeEncryptedFileKeyInfo", "CloseEncryptedFileRaw", "AddUsersToEncryptedFile", "QueryRecoveryAgentsOnEncryptedFile", "QueryUsersOnEncryptedFile", "ChainWlxLogoffEvent", "CryptAcquireContextU", "CryptBinaryToStringA", "CryptBinaryToStringW", "CryptCloseAsyncHandle", "CryptCreateAsyncHandle", "CryptDecodeMessage", "CryptDecodeObject", "CryptDecodeObjectEx", "CryptDecryptAndVerifyMessageSignature", "CryptDecryptMessage", "CryptEncodeObject", "CryptEncodeObjectEx", "CryptEncryptMessage", "CryptEnumKeyIdentifierProperties", "CryptEnumOIDFunction", "CryptEnumOIDInfo", "CryptEnumProvidersU", "CryptExportPKCS8", "CryptExportPublicKeyInfo", "CryptExportPublicKeyInfoEx", "CryptFindLocalizedName", "CryptFindOIDInfo", "CryptFormatObject", "CryptFreeOIDFunctionAddress", "CryptGetAsyncParam", "CryptGetDefaultOIDDllList", "CryptGetDefaultOIDFunctionAddress", "CryptGetKeyIdentifierProperty", "CryptGetMessageCertificates", "CryptGetMessageSignerCount", "CryptGetOIDFunctionAddress", "CryptGetOIDFunctionValue", "CryptHashCertificate", "CryptHashMessage", "CryptHashPublicKeyInfo", "CryptHashToBeSigned", "CryptImportPKCS8", "CryptImportPublicKeyInfo", "CryptImportPublicKeyInfoEx", "CryptInitOIDFunctionSet", "CryptInstallDefaultContext", "CryptInstallOIDFunctionAddress", "CryptLoadSip", "CryptMemAlloc", "CryptMemFree", "CryptMemRealloc", "CryptMsgCalculateEncodedLength", "CryptMsgClose", "CryptMsgControl", "CryptMsgCountersign", "CryptMsgCountersignEncoded", "CryptMsgDuplicate", "CryptMsgEncodeAndSignCTL", "CryptMsgGetAndVerifySigner", "CryptMsgGetParam", "CryptMsgOpenToDecode", "CryptMsgOpenToEncode", "CryptMsgSignCTL", "CryptMsgUpdate", "CryptMsgVerifyCountersignatureEncoded", "CryptMsgVerifyCountersignatureEncodedEx", "CryptProtectData", "CryptQueryObject", "CryptRegisterDefaultOIDFunction", "CryptRegisterOIDFunction", "CryptRegisterOIDInfo", "CryptSIPAddProvider", "CryptSIPCreateIndirectData", "CryptSIPGetSignedDataMsg", "CryptSIPLoad", "CryptSIPPutSignedDataMsg", "CryptSIPRemoveProvider", "CryptSIPRemoveSignedDataMsg", "CryptSIPRetrieveSubjectGuid", "CryptSIPRetrieveSubjectGuidForCatalogFile", "CryptSIPVerifyIndirectData", "CryptSetAsyncParam", "CryptSetKeyIdentifierProperty", "CryptSetOIDFunctionValue", "CryptSetProviderU", "CryptSignAndEncodeCertificate", "CryptSignAndEncryptMessage", "CryptSignCertificate", "CryptSignHashU", "CryptSignMessage", "CryptSignMessageWithKey", "CryptStringToBinaryA", "CryptStringToBinaryW", "CryptUninstallDefaultContext", "CryptUnprotectData", "CryptUnregisterDefaultOIDFunction", "CryptUnregisterOIDFunction", "CryptUnregisterOIDInfo", "CryptVerifyCertificateSignature", "CryptVerifyCertificateSignatureEx", "CryptVerifyDetachedMessageHash", "CryptVerifyDetachedMessageSignature", "CryptVerifyMessageHash", "CryptVerifyMessageSignature", "CryptVerifyMessageSignatureWithKey", "CryptVerifySignatureU", "I_CertProtectFunction", "I_CertSrvProtectFunction", "I_CertSyncStore", "I_CertUpdateStore", "I_CryptAddRefLruEntry", "I_CryptAddSmartCardCertToStore", "I_CryptAllocTls", "I_CryptCreateLruCache", "I_CryptCreateLruEntry", "I_CryptDetachTls", "I_CryptDisableLruOfEntries", "I_CryptEnableLruOfEntries", "I_CryptEnumMatchingLruEntries", "I_CryptFindLruEntry", "I_CryptFindLruEntryData", "I_CryptFindSmartCardCertInStore", "I_CryptFlushLruCache", "I_CryptFreeLruCache", "I_CryptFreeTls", "I_CryptGetAsn1Decoder", "I_CryptGetAsn1Encoder", "I_CryptGetDefaultCryptProv", "I_CryptGetDefaultCryptProvForEncrypt", "I_CryptGetFileVersion", "I_CryptGetLruEntryData", "I_CryptGetLruEntryIdentifier", "I_CryptGetOssGlobal", "I_CryptGetTls", "I_CryptInsertLruEntry", "I_CryptInstallAsn1Module", "I_CryptInstallOssGlobal", "I_CryptReadTrustedPublisherDWORDValueFromRegistry", "I_CryptRegisterSmartCardStore", "I_CryptReleaseLruEntry", "I_CryptRemoveLruEntry", "I_CryptSetTls", "I_CryptTouchLruEntry", "I_CryptUninstallAsn1Module", "I_CryptUninstallOssGlobal", "I_CryptUnregisterSmartCardStore", "I_CryptWalkAllLruCacheEntries"]
     }, {
         "tag": "Serv",
+        "name": "System services",
         "group": "EXEC",
         "api_names": ["ChangeServiceConfig2A", "ChangeServiceConfig2W", "ChangeServiceConfigA", "ChangeServiceConfigW", "CloseServiceHandle", "ControlService", "CreateServiceA", "CreateServiceW", "DeleteService", "EnumDependentServicesA", "EnumDependentServicesW", "EnumServiceGroupW", "EnumServicesStatusA", "EnumServicesStatusExA", "EnumServicesStatusExW", "EnumServicesStatusW", "GetServiceDisplayNameA", "GetServiceDisplayNameW", "GetServiceKeyNameA", "GetServiceKeyNameW", "I_ScPnPGetServiceName", "I_ScSetServiceBitsA", "I_ScSetServiceBitsW", "LockServiceDatabase", "OpenServiceA", "OpenServiceW", "PrivilegedServiceAuditAlarmA", "PrivilegedServiceAuditAlarmW", "QueryServiceConfig2A", "QueryServiceConfig2W", "QueryServiceConfigA", "QueryServiceConfigW", "QueryServiceLockStatusA", "QueryServiceLockStatusW", "QueryServiceObjectSecurity", "QueryServiceStatus", "QueryServiceStatusEx", "RegisterServiceCtrlHandlerA", "RegisterServiceCtrlHandlerExA", "RegisterServiceCtrlHandlerExW", "RegisterServiceCtrlHandlerW", "SetServiceBits", "SetServiceObjectSecurity", "SetServiceStatus", "StartServiceA", "StartServiceCtrlDispatcherA", "StartServiceCtrlDispatcherW", "StartServiceW", "UnlockServiceDatabase", "WdmWmiServiceMain"]
     }, {
         "tag": "File",
+        "name": "File handling",
         "group": "FILE",
         "api_names": ["CompareFileTime", "CopyFileA", "CopyFileExA", "CopyFileExW", "CopyFileW", "CopyLZFile", "CreateFileA", "CreateFileMappingA", "CreateFileMappingW", "CreateFileW", "DeleteFileA", "DeleteFileW", "DosDateTimeToFileTime", "FileTimeToDosDateTime", "FileTimeToLocalFileTime", "FileTimeToLocalFileTime", "FileTimeToSystemTime", "FlushFileBuffers", "FlushViewOfFile", "GetCPFileNameFromRegistry", "GetCompressedFileSizeA", "GetCompressedFileSizeW", "GetFileAttributesA", "GetFileAttributesExA", "GetFileAttributesExW", "GetFileAttributesW", "GetFileInformationByHandle", "GetFileSize", "GetFileSizeEx", "GetFileTime", "GetFileType", "GetSystemTimeAsFileTime", "GetTempFileNameA", "GetTempFileNameW", "LZCloseFile", "LZCreateFileW", "LZOpenFileA", "LZOpenFileW", "LocalFileTimeToFileTime", "LocalFileTimeToFileTime", "LockFile", "LockFileEx", "MapViewOfFile", "MapViewOfFileEx", "MoveFileA", "MoveFileExA", "MoveFileExW", "MoveFileW", "MoveFileWithProgressA", "MoveFileWithProgressW", "OpenDataFile", "OpenFile", "OpenFileMappingA", "OpenFileMappingW", "OpenProfileUserMapping", "PrivCopyFileExW", "PrivMoveFileIdentityW", "ReadFile", "ReadFileEx", "ReplaceFile", "ReplaceFileA", "ReplaceFileW", "SetEndOfFile", "SetFileAttributesA", "SetFileAttributesW", "SetFilePointer", "SetFilePointerEx", "SetFileShortNameA", "SetFileShortNameW", "SetFileTime", "SetFileValidData", "SystemTimeToFileTime", "UnlockFile", "UnlockFileEx", "UnmapViewOfFile", "WriteFile", "WriteFileEx", "WriteFileGather", "GetFileSecurityA", "GetFileSecurityW", "SetFileSecurityA", "SetFileSecurityW", "CreateFileU"]
     }, {
         "tag": "Info",
+        "name": "System information",
         "group": "CFG",
         "api_names": ["GetComputerNameA", "GetComputerNameExA", "GetComputerNameExW", "GetComputerNameW", "GetDiskFreeSpaceA", "GetDiskFreeSpaceExA", "GetDiskFreeSpaceExW", "GetDiskFreeSpaceW", "GetDriveTypeA", "GetDriveTypeW", "GetVersion", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetSystemMetrics", "CheckTokenMembership"]
     }, {
         "tag": "Cert",
+        "name": "Certificates",
         "group": "CRYPT",
         "api_names": ["CertAddCRLContextToStore", "CertAddCRLLinkToStore", "CertAddCTLContextToStore", "CertAddCTLLinkToStore", "CertAddCertificateContextToStore", "CertAddCertificateLinkToStore", "CertAddEncodedCRLToStore", "CertAddEncodedCertificateToStore", "CertAddEncodedCertificateToSystemStoreA", "CertAddEncodedCertificateToSystemStoreW", "CertAddEnhancedKeyUsageIdentifier", "CertAddSerializedElementToStore", "CertAddStoreToCollection", "CertAlgIdToOID", "CertCloseStore", "CertCompareCertificate", "CertCompareCertificateName", "CertCompareIntegerBlob", "CertComparePublicKeyInfo", "CertControlStore", "CertCreateCTLContext", "CertCreateCTLEntryFromCertificateContextProperties", "CertCreateCertificateChainEngine", "CertCreateCertificateContext", "CertCreateContext", "CertCreateSelfSignCertificate", "CertDeleteCTLFromStore", "CertDeleteCertificateFromStore", "CertDuplicateCTLContext", "CertDuplicateCertificateChain", "CertDuplicateCertificateContext", "CertDuplicateStore", "CertEnumCRLContextProperties", "CertEnumCRLsInStore", "CertEnumCTLContextProperties", "CertEnumCTLsInStore", "CertEnumCertificateContextProperties", "CertEnumCertificatesInStore", "CertEnumPhysicalStore", "CertEnumSubjectInSortedCTL", "CertEnumSystemStore", "CertEnumSystemStoreLocation", "CertFindAttribute", "CertFindCRLInStore", "CertFindCertificateInCRL", "CertFindCertificateInStore", "CertFindChainInStore", "CertFindExtension", "CertFindRDNAttr", "CertFindSubjectInCTL", "CertFindSubjectInSortedCTL", "CertFreeCRLContext", "CertFreeCertificateChain", "CertFreeCertificateChainEngine", "CertFreeCertificateContext", "CertGetCRLContextProperty", "CertGetCRLFromStore", "CertGetCTLContextProperty", "CertGetCertificateChain", "CertGetCertificateContextProperty", "CertGetEnhancedKeyUsage", "CertGetIssuerCertificateFromStore", "CertGetNameStringA", "CertGetNameStringW", "CertGetPublicKeyLength", "CertGetStoreProperty", "CertGetSubjectCertificateFromStore", "CertGetValidUsages", "CertIsRDNAttrsInCertificateName", "CertIsValidCRLForCertificate", "CertNameToStrA", "CertNameToStrW", "CertOIDToAlgId", "CertOpenStore", "CertOpenSystemStoreA", "CertOpenSystemStoreW", "CertRDNValueToStrA", "CertRDNValueToStrW", "CertRegisterPhysicalStore", "CertRegisterSystemStore", "CertRemoveEnhancedKeyUsageIdentifier", "CertRemoveStoreFromCollection", "CertResyncCertificateChainEngine", "CertSaveStore", "CertSerializeCRLStoreElement", "CertSerializeCertificateStoreElement", "CertSetCRLContextProperty", "CertSetCertificateContextPropertiesFromCTLEntry", "CertSetCertificateContextProperty", "CertSetEnhancedKeyUsage", "CertSetStoreProperty", "CertStrToNameA", "CertStrToNameW", "CertUnregisterPhysicalStore", "CertUnregisterSystemStore", "CertVerifyCRLRevocation", "CertVerifyCRLTimeValidity", "CertVerifyCTLUsage", "CertVerifyCertificateChainPolicy", "CertVerifyCertificateChainPolicy", "CertVerifyRevocation", "CertVerifySubjectCertificateContext", "CertVerifyTimeValidity", "CertVerifyValidityNesting", "CloseCertPerformanceData", "CollectCertPerformanceData", "CryptAcquireCertificatePrivateKey", "CryptFindCertificateKeyProvInfo", "CryptGetMessageCertificates", "CryptHashCertificate", "CryptSignAndEncodeCertificate", "CryptSignCertificate", "CryptVerifyCertificateSignature", "CryptVerifyCertificateSignatureEx", "I_CertProtectFunction", "I_CertSrvProtectFunction", "I_CertSyncStore", "I_CertUpdateStore", "I_CryptAddSmartCardCertToStore", "I_CryptFindSmartCardCertInStore", "OpenCertPerformanceData", "PFXExportCertStore", "PFXExportCertStoreEx", "PFXImportCertStore"]
     }, {
         "tag": "FSear",
+        "name": "File searching",
         "group": "FILE",
         "api_names": ["FindFirstFileW", "FindNextFileW", "FindClose"]
     }, {
         "tag": "Mod",
+        "name": "Memory",
         "group": "MEM",
         "api_names": ["WriteProcessMemory", "ReadProcessMemory"]
     }, {
         "tag": "Virt",
+        "name": "Virtual memory",
         "group": "MEM",
         "api_names": ["VirtualAlloc", "VirtualAllocEx", "VirtualBufferExceptionHandler", "VirtualFree", "VirtualFreeEx", "VirtualLock", "VirtualProtect", "VirtualProtectEx", "VirtualQuery", "VirtualQueryEx", "VirtualUnlock"]
     }, {
         "tag": "CrSec",
+        "name": "Critical Section",
         "group": "EXEC",
         "api_names": ["DeleteCriticalSection", "EnterCriticalSection", "InitializeCriticalSection", "InitializeCriticalSectionAndSpinCount", "LeaveCriticalSection", "SetCriticalSectionSpinCount", "TryEnterCriticalSection"]
     }, {
         "tag": "Proc",
+        "name": "Process/Threading",
         "group": "EXEC",
         "api_names": ["CreateProcessA", "CreateProcessW", "CreateThread", "CreateRemoteThread", "ShellExecute", "ShellExecuteEx"]
     }, {
         "tag": "Str",
+        "name": "String manipulation",
         "group": "MEM",
         "api_names": ["sprintf", "strcat", "strcmp", "strncmp", "strcpy", "strncpy", "strstr"]
     }]
Add a comment to this file

idascope/icons/filter.png

Added
New image

idascope/widgets/FunctionFilterDialog.py

+#!/usr/bin/python
+########################################################################
+# Copyright (c) 2012
+# Daniel Plohmann <daniel.plohmann<at>gmail<dot>com>
+# Alexander Hanel <alexander.hanel<at>gmail<dot>com>
+# All rights reserved.
+########################################################################
+#
+#  This file is part of IDAscope
+#
+#  IDAscope is free software: you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see
+#  <http://www.gnu.org/licenses/>.
+#
+########################################################################
+
+from PySide import QtGui
+
+
+class FunctionFilterDialog(QtGui.QDialog):
+
+    def __init__(self, context_filter, parent=None):
+        QtGui.QDialog.__init__(self, parent)
+        self.context_filter = context_filter
+        # create GUI elements
+        self._createGroupingModeBox()
+        self._createTagsBox()
+        self._createGroupsBox()
+        self._createGroupsTagsWidget()
+        self._createAdditionalsBox()
+        self._createDecisionWidget()
+        self._createButtons()
+        # glue everything together
+        dialog_layout = QtGui.QVBoxLayout()
+        dialog_layout.addWidget(self.decision_widget)
+        dialog_layout.addLayout(self.button_layout)
+        self.setLayout(dialog_layout)
+        self.setWindowTitle(self.tr("Filter Function Results"))
+        self._updateGroupingModeDisplay()
+
+    def _createGroupingModeBox(self):
+        self.grouping_mode_box = QtGui.QGroupBox("Display granularity")
+        self.grouping_mode_all = QtGui.QRadioButton("Show all")
+        self.grouping_mode_all.clicked.connect(self._updateGroupingModeDisplay)
+        if self.context_filter.display_all:
+            self.grouping_mode_all.setChecked(True)
+        self.grouping_mode_tags = QtGui.QRadioButton("Show individual tags")
+        self.grouping_mode_tags.clicked.connect(self._updateGroupingModeDisplay)
+        if self.context_filter.display_tags:
+            self.grouping_mode_tags.setChecked(True)
+        self.grouping_mode_grouped = QtGui.QRadioButton("Group by semantics")
+        self.grouping_mode_grouped.clicked.connect(self._updateGroupingModeDisplay)
+        if self.context_filter.display_groups:
+            self.grouping_mode_grouped.setChecked(True)
+        self.grouping_mode_hbox = QtGui.QHBoxLayout()
+        self.grouping_mode_hbox.addWidget(self.grouping_mode_all)
+        self.grouping_mode_hbox.addWidget(self.grouping_mode_tags)
+        self.grouping_mode_hbox.addWidget(self.grouping_mode_grouped)
+        self.grouping_mode_hbox.addStretch(1)
+        self.grouping_mode_box.setLayout(self.grouping_mode_hbox)
+
+    def _createTagsBox(self):
+        height_split = 6
+        self.tags_box = QtGui.QGroupBox("Display Tags")
+        self.tags_hbox = QtGui.QHBoxLayout()
+        self.tags_map = {}
+        current_col_vbox = QtGui.QVBoxLayout()
+        for index, tag in enumerate(self.context_filter.tags):
+            tags_cb = QtGui.QCheckBox(tag[2])
+            self.tags_map[tags_cb] = tag
+            if tag in self.context_filter.enabled_tags:
+                tags_cb.setChecked(True)
+            if index > 0 and index % height_split == 0:
+                vbox_widget = QtGui.QWidget()
+                vbox_widget.setLayout(current_col_vbox)
+                self.tags_hbox.addWidget(vbox_widget)
+                current_col_vbox = QtGui.QVBoxLayout()
+            if index == (len(self.context_filter.tags) - 1):
+                current_col_vbox.addWidget(tags_cb)
+                current_col_vbox.addStretch(1)
+                vbox_widget = QtGui.QWidget()
+                vbox_widget.setLayout(current_col_vbox)
+                self.tags_hbox.addWidget(vbox_widget)
+            else:
+                current_col_vbox.addWidget(tags_cb)
+        self.tags_hbox.addStretch(1)
+        self.tags_box.setLayout(self.tags_hbox)
+
+    def _createGroupsBox(self):
+        self.groups_box = QtGui.QGroupBox("Display Groups")
+        self.groups_vbox = QtGui.QVBoxLayout()
+        self.groups_map = {}
+        for group in self.context_filter.groups:
+            groups_cb = QtGui.QCheckBox(group[2])
+            self.groups_map[groups_cb] = group
+            if group in self.context_filter.enabled_groups:
+                groups_cb.setChecked(True)
+            self.groups_vbox.addWidget(groups_cb)
+        self.groups_vbox.addStretch(1)
+        self.groups_box.setLayout(self.groups_vbox)
+
+    def _createGroupsTagsWidget(self):
+        self.groups_tags_widget = QtGui.QWidget()
+        self.groups_tags_hbox = QtGui.QHBoxLayout()
+        self.groups_tags_hbox.addWidget(self.tags_box)
+        self.groups_tags_hbox.addWidget(self.groups_box)
+        self.groups_tags_hbox.addStretch(1)
+        self.groups_tags_widget.setLayout(self.groups_tags_hbox)
+
+    def _createAdditionalsBox(self):
+        self.additionals_box = QtGui.QGroupBox("Additional Information")
+        self.additionals_vbox = QtGui.QVBoxLayout()
+        self.additionals_map = {}
+        for additional in self.context_filter.additionals:
+            additional_cb = QtGui.QCheckBox(additional[2])
+            self.additionals_map[additional_cb] = additional
+            if additional in self.context_filter.enabled_additionals:
+                additional_cb.setChecked(True)
+            self.additionals_vbox.addWidget(additional_cb)
+        self.additionals_vbox.addStretch(1)
+        self.additionals_box.setLayout(self.additionals_vbox)
+
+    def _createDecisionWidget(self):
+        self.decision_widget = QtGui.QWidget()
+        self.decision_layout = QtGui.QVBoxLayout()
+        self.decision_layout.addWidget(self.grouping_mode_box)
+        self.decision_layout.addWidget(self.groups_tags_widget)
+        self.decision_layout.addWidget(self.additionals_box)
+        self.decision_widget.setLayout(self.decision_layout)
+
+    def _createButtons(self):
+        self.button_layout = QtGui.QHBoxLayout()
+        self.ok_button = QtGui.QPushButton(self.tr("OK"))
+        self.cancel_button = QtGui.QPushButton(self.tr("Cancel"))
+        self.ok_button.clicked.connect(self.accept)
+        self.cancel_button.clicked.connect(self.reject)
+        self.button_layout.addStretch(1)
+        self.button_layout.addWidget(self.ok_button)
+        self.button_layout.addWidget(self.cancel_button)
+
+    def accept(self):
+        # display mode
+        self.context_filter.display_tags = self.grouping_mode_tags.isChecked()
+        self.context_filter.display_groups = self.grouping_mode_grouped.isChecked()
+        self.context_filter.display_all = self.grouping_mode_all.isChecked()
+        # tags
+        self.context_filter.enabled_tags = []
+        for tag_cb in self.tags_map:
+            if tag_cb.isChecked():
+                self.context_filter.enabled_tags.append(self.tags_map[tag_cb])
+        self.context_filter.enabled_tags.sort()
+        # groups
+        self.context_filter.enabled_groups = []
+        for group_cb in self.groups_map:
+            if group_cb.isChecked():
+                self.context_filter.enabled_groups.append(self.groups_map[group_cb])
+        self.context_filter.enabled_groups.sort()
+        # additionals
+        self.context_filter.enabled_additionals = []
+        for additional_cb in self.additionals_map:
+            if additional_cb.isChecked():
+                self.context_filter.enabled_additionals.append(self.additionals_map[additional_cb])
+        self.context_filter.enabled_additionals.sort()
+
+        self.done(1)
+
+    def getAdjustedFunctionFilter(self):
+        return self.context_filter
+
+    def _updateGroupingModeDisplay(self):
+        if self.grouping_mode_tags.isChecked():
+            self.tags_box.setEnabled(True)
+            self.groups_box.setEnabled(False)
+        elif self.grouping_mode_grouped.isChecked():
+            self.tags_box.setEnabled(False)
+            self.groups_box.setEnabled(True)
+        else:
+            self.tags_box.setEnabled(False)
+            self.groups_box.setEnabled(False)

idascope/widgets/FunctionInspectionWidget.py

 from PySide.QtGui import QIcon
 
 from NumberQTableWidgetItem import NumberQTableWidgetItem
-from idascope.core.structures.FunctionContextFilter import FunctionContextFilter
+from FunctionFilterDialog import FunctionFilterDialog
 
 
 class FunctionInspectionWidget(QtGui.QMainWindow):
         self.icon = QIcon(self.parent.config.icon_file_path + "semantics.png")
         # This widget relies on the semantic identifier and uses some functions via IDA proxy
         self.si = self.parent.semantic_identifier
+        self.context_filter = self.si.createFunctionContextFilter()
         self.dh = self.parent.documentation_helper
         self.ida_proxy = self.parent.ida_proxy
         # references to Qt-specific modules
         self.QtGui = QtGui
         self.QtCore = QtCore
         self.NumberQTableWidgetItem = NumberQTableWidgetItem
+        self. FunctionFilterDialog = FunctionFilterDialog
         self.central_widget = self.QtGui.QWidget()
         self.setCentralWidget(self.central_widget)
         self._createGui()
 
         function_info_widget = QtGui.QWidget()
         function_info_layout = QtGui.QHBoxLayout()
-        self.function_dummy_only_cb = QtGui.QCheckBox("Only dummy names")
-        self.function_dummy_only_cb.stateChanged.connect(self.populateFunctionTable)
-        self.function_tag_only_cb = QtGui.QCheckBox("Only tag function")
-        self.function_tag_only_cb.setCheckState(self.QtCore.Qt.Checked)
-        self.function_tag_only_cb.stateChanged.connect(self.populateFunctionTable)
         function_info_layout.addWidget(self.funcs_label)
-        function_info_layout.addWidget(self.function_dummy_only_cb)
-        function_info_layout.addWidget(self.function_tag_only_cb)
         function_info_widget.setLayout(function_info_layout)
 
         upper_table_widget = QtGui.QWidget()
         self._createFixUnknownCodeWithProloguesAction()
         self._createFixAllUnknownCodeAction()
         self._createRenameWrappersAction()
+        self._createFilterAction()
 
         self.toolbar = self.addToolBar('Function Inspection Toobar')
         self.toolbar.addAction(self.refreshAction)
         self.toolbar.addAction(self.fixUnknownCodeWithProloguesAction)
         self.toolbar.addAction(self.fixAllUnknownCodeAction)
         self.toolbar.addAction(self.renameWrappersAction)
+        self.toolbar.addAction(self.filterAction)
 
     def _createRefreshAction(self):
         """
             "Rename potential wrapper functions", self)
         self.renameWrappersAction.triggered.connect(self._onRenameWrappersButtonClicked)
 
+    def _createFilterAction(self):
+        """
+        Create the action which fixes unknown code to functions via I{DocumentationHelper}.
+        """
+        self.filterAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "filter.png"), \
+            "Adjust filter settings", self)
+        self.filterAction.triggered.connect(self._onFilterButtonClicked)
+
     def _createFunctionsTable(self):
         """
         Create the top table used for showing all functions covered by scanning for semantic information.
         Populate the function table with information from the last scan of I{SemanticIdentifier}.
         """
         self.funcs_table.setSortingEnabled(False)
-        self.funcs_header_labels = ["Address", "Name", "Blocks"]
-        for tag in sorted(self.si.getTags()):
-            self.funcs_header_labels.append(tag)
+        self.funcs_header_labels = ["Address", "Name"]
+        for heading in self.context_filter.generateColumnHeadings():
+            self.funcs_header_labels.append(heading)
         self.funcs_table.clear()
         self.funcs_table.setColumnCount(len(self.funcs_header_labels))
         self.funcs_table.setHorizontalHeaderLabels(self.funcs_header_labels)
         # Identify number of table entries and prepare addresses to display
-        context_filter = self._getContextFilter()
-        function_addresses = self.si.getFunctionAddresses(context_filter)
+        function_addresses = self.si.getFunctionAddresses(self.context_filter)
         if self.ida_proxy.BAD_ADDR in function_addresses:
             self.funcs_table.setRowCount(len(function_addresses) - 1)
         else:
                     tmp_item = self.QtGui.QTableWidgetItem("0x%x" % function_address)
                 elif column == 1:
                     tmp_item = self.QtGui.QTableWidgetItem(self.ida_proxy.GetFunctionName(function_address))
-                elif column == 2:
-                    tmp_item = self.NumberQTableWidgetItem("%d" % \
-                        self.si.getNumberOfBasicBlocksForFunctionAddress(function_address))
                 else:
-                    tmp_item = self.NumberQTableWidgetItem("%d" % \
-                        self.si.getTagCountForFunctionAddress(column_name, function_address))
+                    query = self.context_filter.getQueryForHeading(column_name)
+                    field_count = self.si.getFieldCountForFunctionAddress(query, function_address)
+                    tmp_item = self.NumberQTableWidgetItem("%d" % field_count)
                 tmp_item.setFlags(tmp_item.flags() & ~self.QtCore.Qt.ItemIsEditable)
                 self.funcs_table.setItem(row, column, tmp_item)
             self.funcs_table.resizeRowToContents(row)
         self.parameter_table.setHorizontalHeaderLabels(self.parameter_header_labels)
 
     def updateFunctionsLabel(self):
-        context_filter = self._getContextFilter()
-        num_displayed_functions = len(self.si.getFunctionAddresses(context_filter))
-        self.funcs_label.setText("Functions of Interest (%d/%d)" %
-            (num_displayed_functions, self.si.calculateNumberOfFunctions()))
-
-    def _getContextFilter(self):
-        context_filter = FunctionContextFilter()
-        context_filter.display_tag_only = self.function_dummy_only_cb.isChecked()
-        context_filter.display_tag_only = self.function_tag_only_cb.isChecked()
-        return context_filter
+        displayed_function_addresses = self.si.getFunctionAddresses(self.context_filter)
+        num_displayed_functions = len(displayed_function_addresses)
+        if self.ida_proxy.BAD_ADDR in displayed_function_addresses:
+            num_displayed_functions -= 1
+        self.funcs_label.setText("Functions: %d - Tagged: %d - Displayed: %d" %
+            (self.si.calculateNumberOfFunctions(), self.si.calculateNumberOfTaggedFunctions(), num_displayed_functions))
 
 ################################################################################
 # Button actions
         Action for refreshing the window data by performing another scan of I{SemanticIdentifier}.
         """
         self.si.scanByReferences()
+        self.context_filter = self.si.createFunctionContextFilter()
         self.populateFunctionTable()
         self._resetLowerTables()
 
         Action for refreshing the window data by performing a deep scan of I{SemanticIdentifier}.
         """
         self.si.scan()
+        self.context_filter = self.si.createFunctionContextFilter()
         self.populateFunctionTable()
         self._resetLowerTables()
 
         """
         self.si.renamePotentialWrapperFunctions()
 
+    def _onFilterButtonClicked(self):
+        """
+        Action for renaming potential wrapper functions to the wrapped API if they have a dummy name.
+        """
+        dialog = self.FunctionFilterDialog(self.context_filter)
+        dialog.exec_()
+        self.context_filter = dialog.getAdjustedFunctionFilter()
+        self.populateFunctionTable()
+
     def _onFunctionClicked(self, mi):
         """
         If a function in the functions table is clicked, the view of the calls and parameter table are updated.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.