mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 15:49:46 -08:00
feature: show regex captures
This commit is contained in:
@@ -63,7 +63,7 @@
|
||||
props.data.meta.flavor === 'dynamic' && col.field === 'address' ? 'Process' : col.header
|
||||
"
|
||||
:sortable="col.field !== 'source'"
|
||||
:class="{ 'w-3': col.field === 'mbc' }"
|
||||
:class="{ 'w-3': col.field === 'mbc', 'w-full': col.field === 'name' }"
|
||||
filterMatchMode="contains"
|
||||
>
|
||||
<!-- Filter template -->
|
||||
@@ -78,7 +78,7 @@
|
||||
<!-- Address column body template -->
|
||||
<template v-if="col.field === 'address'" #body="slotProps">
|
||||
<span style="font-family: monospace">
|
||||
{{ slotProps.node.data.address }}
|
||||
{{ slotProps.node.data.type === 'match location' ? "" : slotProps.node.data.address}}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="node.data.type === 'feature'">
|
||||
<span>- {{ node.data.typeValue }}: <span class="text-green-700" style="font-family: monospace;">{{ node.data.name }}</span></span>
|
||||
<span>- {{ node.data.typeValue }}: <span :class="{'text-green-700': node.data.typeValue !== 'regex'}" style="font-family: monospace;">{{ node.data.name }}</span></span>
|
||||
</template>
|
||||
<template v-else-if="node.data.type === 'regex-capture'">
|
||||
- <span class="text-green-700" style="font-family: monospace;">{{ node.data.name }}</span>
|
||||
</template>
|
||||
<span v-if="node.data.description" class="text-gray-500 text-sm" style="font-size: 90%;">
|
||||
= {{ node.data.description }}
|
||||
|
||||
@@ -49,11 +49,11 @@ export function parseRules(rules, flavor) {
|
||||
type: 'match location',
|
||||
name:
|
||||
flavor === 'static'
|
||||
? `${rule.meta.scopes.static} @ ${formatStaticAddress(match[0].value)}`
|
||||
? `${rule.meta.scopes.static} @ ${formatHex(match[0].value)}`
|
||||
: `${formatDynamicAddress(match[0].value)}`,
|
||||
address:
|
||||
flavor === 'static'
|
||||
? `${formatStaticAddress(match[0].value)}`
|
||||
? `${formatHex(match[0].value)}`
|
||||
: formatDynamicAddress(match[0].value),
|
||||
},
|
||||
children: [parseNode(match[1], `${matchKey}`, rules, rule.meta.lib)]
|
||||
@@ -259,9 +259,62 @@ function parseNode(node, key, rules, lib) {
|
||||
if (result.children.length === 0) return null
|
||||
}
|
||||
|
||||
if (processedNode.node.feature && processedNode.node.feature.type === 'regex') {
|
||||
result.children = processRegexCaptures(processedNode, key);
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function processRegexCaptures(node, key) {
|
||||
if (!node.captures) return [];
|
||||
|
||||
return Object.entries(node.captures).map(([capture, locations]) => ({
|
||||
key: key,
|
||||
data: {
|
||||
type: 'regex-capture',
|
||||
name: `"${escape(capture)}"`,
|
||||
address: formatAddress(locations[0])
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function formatAddress(address) {
|
||||
switch (address.type) {
|
||||
case 'absolute':
|
||||
return formatHex(address.value);
|
||||
case 'relative':
|
||||
return `base address+${formatHex(address.value)}`;
|
||||
case 'file':
|
||||
return `file+${formatHex(address.value)}`;
|
||||
case 'dn_token':
|
||||
return `token(${formatHex(address.value)})`;
|
||||
case 'dn_token_offset':
|
||||
const [token, offset] = address.value;
|
||||
return `token(${formatHex(token)})+${formatHex(offset)}`;
|
||||
case 'process':
|
||||
//const [ppid, pid] = address.value;
|
||||
//return `process{pid:${pid}}`;
|
||||
return formatDynamicAddress(address.value);
|
||||
case 'thread':
|
||||
//const [threadPpid, threadPid, tid] = address.value;
|
||||
//return `process{pid:${threadPid},tid:${tid}}`;
|
||||
return formatDynamicAddress(address.value);
|
||||
case 'call':
|
||||
//const [callPpid, callPid, callTid, id] = address.value;
|
||||
//return `process{pid:${callPid},tid:${callTid},call:${id}}`;
|
||||
return formatDynamicAddress(address.value);
|
||||
case 'no address':
|
||||
return '';
|
||||
default:
|
||||
throw new Error('Unexpected address type');
|
||||
}
|
||||
}
|
||||
|
||||
function escape(str) {
|
||||
return str.replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts the success values for children of a 'not' statement
|
||||
* @param {Object} node - The node to invert
|
||||
@@ -381,9 +434,12 @@ function getRangeName(statement) {
|
||||
* @returns {string|null} The formatted address or null if not found
|
||||
*/
|
||||
function getNodeAddress(node) {
|
||||
if (node.locations && node.locations.length > 0 && node.locations[0].type === 'absolute') {
|
||||
if (node.node.feature && node.node.feature.type === 'regex') return null
|
||||
if (node.locations && node.locations.length > 0) {
|
||||
// for example: 0x400000
|
||||
return `0x${node.locations[0].value.toString(16).toUpperCase()}`
|
||||
//return `0x${node.locations[0].value.toString(16).toUpperCase()}`
|
||||
console.log(node.locations[0])
|
||||
return formatAddress(node.locations[0]);
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -414,6 +470,6 @@ function formatDynamicAddress(value) {
|
||||
.join(' ← ')
|
||||
}
|
||||
|
||||
function formatStaticAddress(address) {
|
||||
function formatHex(address) {
|
||||
return `0x${address.toString(16).toUpperCase()}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user