mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 07:40:38 -08:00
Merge branch 'master' into web-add-releases-workflow
This commit is contained in:
@@ -13,11 +13,14 @@
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
- extractor: fix exception when PE extractor encounters unknown architecture #2440 @Tamir-K
|
- extractor: fix exception when PE extractor encounters unknown architecture #2440 @Tamir-K
|
||||||
|
- IDA Pro: rename ida to idapro module for plugin and idalib in IDA 9.0 #2453 @mr-tz
|
||||||
|
|
||||||
### capa Explorer Web
|
### capa Explorer Web
|
||||||
|
|
||||||
### capa Explorer IDA Pro plugin
|
### capa Explorer IDA Pro plugin
|
||||||
|
|
||||||
|
- fix bug preventing saving of capa results via Save button @mr-tz
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
### Raw diffs
|
### Raw diffs
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ if hasattr(ida_bytes, "parse_binpat_str"):
|
|||||||
return
|
return
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
ea, _ = ida_bytes.bin_search3(start, end, patterns, ida_bytes.BIN_SEARCH_FORWARD)
|
ea, _ = ida_bytes.bin_search(start, end, patterns, ida_bytes.BIN_SEARCH_FORWARD)
|
||||||
if ea == idaapi.BADADDR:
|
if ea == idaapi.BADADDR:
|
||||||
break
|
break
|
||||||
start = ea + 1
|
start = ea + 1
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def is_idalib_installed() -> bool:
|
def is_idalib_installed() -> bool:
|
||||||
try:
|
try:
|
||||||
return importlib.util.find_spec("ida") is not None
|
return importlib.util.find_spec("idapro") is not None
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -44,6 +44,7 @@ def get_idalib_user_config_path() -> Optional[Path]:
|
|||||||
def find_idalib() -> Optional[Path]:
|
def find_idalib() -> Optional[Path]:
|
||||||
config_path = get_idalib_user_config_path()
|
config_path = get_idalib_user_config_path()
|
||||||
if not config_path:
|
if not config_path:
|
||||||
|
logger.error("IDA Pro user configuration does not exist, please make sure you've installed idalib properly.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
config = json.loads(config_path.read_text(encoding="utf-8"))
|
config = json.loads(config_path.read_text(encoding="utf-8"))
|
||||||
@@ -51,6 +52,9 @@ def find_idalib() -> Optional[Path]:
|
|||||||
try:
|
try:
|
||||||
ida_install_dir = Path(config["Paths"]["ida-install-dir"])
|
ida_install_dir = Path(config["Paths"]["ida-install-dir"])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
logger.error(
|
||||||
|
"IDA Pro user configuration does not contain location of IDA Pro installation, please make sure you've installed idalib properly."
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not ida_install_dir.exists():
|
if not ida_install_dir.exists():
|
||||||
@@ -73,7 +77,7 @@ def find_idalib() -> Optional[Path]:
|
|||||||
if not idalib_path.exists():
|
if not idalib_path.exists():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not (idalib_path / "ida" / "__init__.py").is_file():
|
if not (idalib_path / "idapro" / "__init__.py").is_file():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return idalib_path
|
return idalib_path
|
||||||
@@ -96,7 +100,7 @@ def has_idalib() -> bool:
|
|||||||
|
|
||||||
def load_idalib() -> bool:
|
def load_idalib() -> bool:
|
||||||
try:
|
try:
|
||||||
import ida
|
import idapro
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -106,7 +110,7 @@ def load_idalib() -> bool:
|
|||||||
|
|
||||||
sys.path.append(idalib_path.absolute().as_posix())
|
sys.path.append(idalib_path.absolute().as_posix())
|
||||||
try:
|
try:
|
||||||
import ida # noqa: F401 unused import
|
import idapro # noqa: F401 unused import
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -1309,10 +1309,17 @@ class CapaExplorerForm(idaapi.PluginForm):
|
|||||||
|
|
||||||
s = self.resdoc_cache.model_dump_json().encode("utf-8")
|
s = self.resdoc_cache.model_dump_json().encode("utf-8")
|
||||||
|
|
||||||
path = Path(self.ask_user_capa_json_file())
|
path = self.ask_user_capa_json_file()
|
||||||
if not path.exists():
|
if not path:
|
||||||
|
# dialog canceled
|
||||||
return
|
return
|
||||||
|
|
||||||
|
path = Path(path)
|
||||||
|
if not path.parent.exists():
|
||||||
|
logger.warning("Failed to save file: parent directory '%s' does not exist.", path.parent)
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("Saving capa results to %s.", path)
|
||||||
write_file(path, s)
|
write_file(path, s)
|
||||||
|
|
||||||
def save_function_analysis(self):
|
def save_function_analysis(self):
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ def get_extractor(
|
|||||||
if not idalib.load_idalib():
|
if not idalib.load_idalib():
|
||||||
raise RuntimeError("failed to load IDA idalib module.")
|
raise RuntimeError("failed to load IDA idalib module.")
|
||||||
|
|
||||||
import ida
|
import idapro
|
||||||
import ida_auto
|
import ida_auto
|
||||||
|
|
||||||
import capa.features.extractors.ida.extractor
|
import capa.features.extractors.ida.extractor
|
||||||
@@ -333,7 +333,7 @@ def get_extractor(
|
|||||||
# so as not to screw up structured output.
|
# so as not to screw up structured output.
|
||||||
with capa.helpers.stdout_redirector(io.BytesIO()):
|
with capa.helpers.stdout_redirector(io.BytesIO()):
|
||||||
with console.status("analyzing program...", spinner="dots"):
|
with console.status("analyzing program...", spinner="dots"):
|
||||||
if ida.open_database(str(input_path), run_auto_analysis=True):
|
if idapro.open_database(str(input_path), run_auto_analysis=True):
|
||||||
raise RuntimeError("failed to analyze input file")
|
raise RuntimeError("failed to analyze input file")
|
||||||
|
|
||||||
logger.debug("idalib: waiting for analysis...")
|
logger.debug("idalib: waiting for analysis...")
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ known_first_party = [
|
|||||||
"binaryninja",
|
"binaryninja",
|
||||||
"flirt",
|
"flirt",
|
||||||
"ghidra",
|
"ghidra",
|
||||||
"ida",
|
"idapro",
|
||||||
"ida_ida",
|
"ida_ida",
|
||||||
"ida_auto",
|
"ida_auto",
|
||||||
"ida_bytes",
|
"ida_bytes",
|
||||||
|
|||||||
@@ -160,7 +160,7 @@
|
|||||||
|
|
||||||
<!-- Source code dialog -->
|
<!-- Source code dialog -->
|
||||||
<Dialog v-model:visible="sourceDialogVisible" style="width: 50vw">
|
<Dialog v-model:visible="sourceDialogVisible" style="width: 50vw">
|
||||||
<highlightjs autodetect :code="currentSource" />
|
<highlightjs :autodetect="false" language="yaml" :code="currentSource" />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,12 @@
|
|||||||
|
|
||||||
<!-- example node: "exit(0) -> 0" (if the node type is call-info, we highlight node.data.name.callInfo) -->
|
<!-- example node: "exit(0) -> 0" (if the node type is call-info, we highlight node.data.name.callInfo) -->
|
||||||
<template v-else-if="node.data.type === 'call-info'">
|
<template v-else-if="node.data.type === 'call-info'">
|
||||||
<highlightjs lang="c" :code="node.data.name.callInfo" class="text-xs" />
|
<highlightjs
|
||||||
|
:autodetect="false"
|
||||||
|
language="c"
|
||||||
|
:code="node.data.name.callInfo"
|
||||||
|
class="text-xs highlightjs-wrapper"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- example node: " = IMAGE_NT_SIGNATURE (PE)" -->
|
<!-- example node: " = IMAGE_NT_SIGNATURE (PE)" -->
|
||||||
@@ -83,3 +88,11 @@ const getTooltipContent = (data) => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.highlightjs-wrapper {
|
||||||
|
width: 120ch;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -215,6 +215,12 @@
|
|||||||
|
|
||||||
<h2 class="mt-3">Tool Updates</h2>
|
<h2 class="mt-3">Tool Updates</h2>
|
||||||
|
|
||||||
|
<h3 class="mt-2">v7.4.0 (<em>2024-10-04</em>)</h3>
|
||||||
|
<p class="mt-0">
|
||||||
|
The <a href="https://github.com/mandiant/capa/releases/tag/v7.4.0">v7.4.0</a> capa release fixes a bug when processing VMRay analysis archives and enhances API extraction for all dynamic backends. For better terminal rendering capa now solely relies on the rich library.<br />
|
||||||
|
The standalone capa executable can now automatically detect installations of relevant third party applications and use their backends (notably, idalib and Binary Ninja). For the extra standalone Linux build we've upgraded from Python 3.11 to 3.12.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 class="mt-2">v7.3.0 (<em>2024-09-20</em>)</h3>
|
<h3 class="mt-2">v7.3.0 (<em>2024-09-20</em>)</h3>
|
||||||
<div class="mt-0">
|
<div class="mt-0">
|
||||||
The <a href="https://github.com/mandiant/capa/releases/tag/v7.3.0">capa v7.3.0</a> release comes with the following three major enhancements:
|
The <a href="https://github.com/mandiant/capa/releases/tag/v7.3.0">capa v7.3.0</a> release comes with the following three major enhancements:
|
||||||
|
|||||||
Reference in New Issue
Block a user