capa
capa copied to clipboard
add com class/interface features
in https://github.com/fboldewin/COM-Code-Helper/pull/2 @stevemk14ebr adds definitions for around 3k COM class GUIDs and 23k COM interface GUIDs. this is probably one of the most comprehensive databases of COM constants out there. we should consider incorporating it into capa, possibly as a new type of feature, like:
or:
com/class: WebBrowser # maps to bytes: emit-guid(8856F961-340A-11D0-A96B-00C04FD705A2)
com/interface: IWebBrowser # maps to bytes: emit-guid(EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B)
oh hey look its @fboldewin!
@williballenthin
https://github.com/fboldewin/COM-Code-Helper/blob/8d99c61f82541dd17a6232820ace1615fb92248b/code/interfaces.txt contains
5CE34C0D-0DC9-4C1F-897C-DAA1B78CEE7C IBackgroundCopyManager
is used as
0D 4C E3 5C C9 0D 1F 4C 89 7C DA A1 B7 8C EE 7C = IBackgroundCopyManager
in https://github.com/mandiant/capa-rules/issues/332.
As u mentioned in https://github.com/mandiant/capa-rules/issues/332#issuecomment-824974853, that the bytes need to be reordered while matching, is it true for all COMs or was above just an exception.
to go from bytes to GUID string, example code (by Willi) is:
guid = "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % \
(h[3], h[2], h[1], h[0],
h[5], h[4],
h[7], h[6],
h[8], h[9],
h[10], h[11], h[12], h[13], h[14], h[15])
return guid
https://github.com/mandiant/capa/blob/ec93ca5b2176457516edf14735bd98b4b68a34c4/capa/rules/init.py#L594-L602
We can store the com, guid as a map as @williballenthin said.
In above snippet of capa.rules.__init__.build_statements
- while building in
parse_feature
if key iscom/class
orcom/interface
then feature will becapa.features.common.Bytes
- in
parse_description
based on key value we can fetch guid from map and convert it to bytes literalb'\x61....'
and key value will become description, for example
or: com/class: WebBrowser # maps to bytes: emit-guid(8856F961-340A-11D0-A96B-00C04FD705A2) com/interface: IWebBrowser # maps to bytes: emit-guid(EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B)
for above features line 598 of code snipped will return feature as
feature = Bytes(b'\x61\xF9\x56\x88\x34\x0A\x11\xD0\xA9\x6B\x00\xC0\x4F\xD7\x05\xA2', "WebBrowser")
Also should there be a single map or two separate maps for classes and interfaces? It seems logical for the maps to already exist in "capa" rather than being generated at runtime.
Yes, we should store the database in capa. In fact, I have a COM database (one file for class and interface) like this:
...
'884e2046-217d-11da-b2a4-000e7bbb2b09': 'CX509Enrollment',
'884e2049-217d-11da-b2a4-000e7bbb2b09': 'CX509EnrollmentWebClassFactory',
'8854f6a0-4683-4ae7-9191-752fe64612c3': 'InkDivider',
'8856f961-340a-11d0-a96b-00c04fd705a2': 'WebBrowser',
'8858ffc3-3ac7-3dda-aec5-e43b3e425a4c': '_NotSerializableException',
'885b5e08-c26c-4ef9-af83-51580a750be1': 'IFaxInboundRoutingExtension',
'885c7b80-3fa2-4e5a-be07-cf01e1d6e2cd': 'iaudiomuteapo',
'885d2e90-3cfd-39bb-b5da-f5bbd6584828': '_PRINTER_DEFAULTS',
...
I agree with the proposals above.
I'd suggest that the GUID be encoded in at least two ways, as bytes and as a string, which we sometimes see. So the statement should be translated to:
- or:
- description: IBackgroundCopyManager
- string: "12380421-124-142-42-141141111" = IBackgroundCopyManager
- bytes: 731478127891287912879124879827912789 = IBackgroundCopyManager
@williballenthin @mr-tz So we have four following possible cases
- or:
- description: IBackgroundCopyManager
string: "12380421-124-142-42-141141111" = IBackgroundCopyManager
- description: IBackgroundCopyManager
bytes: 731478127891287912879124879827912789 = IBackgroundCopyManager
- com/class: WebBrowser # maps to bytes: emit-guid(8856F961-340A-11D0-A96B-00C04FD705A2)
- com/interface: IWebBrowser # maps to bytes: emit-guid(EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B)
and all of these will translate to
feature = Bytes(b'\x61\xF9\x56\x88\x34\x0A\x11\xD0\xA9\x6B\x00\xC0\x4F\xD7\x05\xA2', "WebBrowser")
not exactly. we want to write com/interface: IFoo
and have it be replaced by or: bytes: ..., string: ...
(sorry on mobile so the formatting isn't great). the values for the bytes and strings should come from the database referenced in the first few comments.
we want to let rule authors refer to the symbolic names for the COM classes and interfaces, and let capa do the translation to the machine representations of the identifiers (GUIDs).
Got it, thanks for explaining. Using symbolic names for COM classes/interfaces and having capa handle the translation to GUIDs sounds great.