From dfbdcca8b91544e08e3a46b447fc1143ef25542c Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 9 Feb 2026 17:03:07 -0800 Subject: [PATCH] [WARP] Allow containers to be constructed programmatically --- plugins/warp/api/python/warp.py | 7 +++++++ plugins/warp/api/warp.cpp | 8 ++++++++ plugins/warp/api/warp.h | 3 +++ plugins/warp/api/warpcore.h | 1 + plugins/warp/src/cache/container.rs | 5 +++++ plugins/warp/src/plugin/ffi/container.rs | 19 ++++++++++++++++++- 6 files changed, 42 insertions(+), 1 deletion(-) diff --git a/plugins/warp/api/python/warp.py b/plugins/warp/api/python/warp.py index fc487a4d80..a699ebbcb7 100644 --- a/plugins/warp/api/python/warp.py +++ b/plugins/warp/api/python/warp.py @@ -350,6 +350,13 @@ def all() -> List['WarpContainer']: warpcore.BNWARPFreeContainerList(containers, count.value) return result + @staticmethod + def add(name: str) -> 'WarpContainer': + container = warpcore.BNWARPAddContainer(name) + if container is None: + raise ValueError(f"Failed to add container: {name}") + return WarpContainer(container) + @staticmethod def by_name(name: str) -> Optional['WarpContainer']: for container in WarpContainer: diff --git a/plugins/warp/api/warp.cpp b/plugins/warp/api/warp.cpp index f6106605f8..c051e3c78f 100644 --- a/plugins/warp/api/warp.cpp +++ b/plugins/warp/api/warp.cpp @@ -246,6 +246,14 @@ std::vector > Container::All() return result; } +Ref Container::Add(const std::string &name) +{ + BNWARPContainer *result = BNWARPAddContainer(name.c_str()); + if (!result) + return nullptr; + return new Container(result); +} + std::string Container::GetName() const { char *rawName = BNWARPContainerGetName(m_object); diff --git a/plugins/warp/api/warp.h b/plugins/warp/api/warp.h index 14be9a0d8d..01f4aaee8e 100644 --- a/plugins/warp/api/warp.h +++ b/plugins/warp/api/warp.h @@ -381,6 +381,9 @@ namespace Warp { /// Retrieve all available containers. static std::vector > All(); + /// Add a new container with the given name. + static Ref Add(const std::string &name); + std::string GetName() const; std::vector GetSources() const; diff --git a/plugins/warp/api/warpcore.h b/plugins/warp/api/warpcore.h index 633ffcbf86..c52485aace 100644 --- a/plugins/warp/api/warpcore.h +++ b/plugins/warp/api/warpcore.h @@ -111,6 +111,7 @@ extern "C" WARP_FFI_API BNWARPFunction* BNWARPGetFunction(BNFunction* analysisFunction); WARP_FFI_API BNWARPFunction* BNWARPGetMatchedFunction(BNFunction* analysisFunction); WARP_FFI_API BNWARPContainer** BNWARPGetContainers(size_t* count); + WARP_FFI_API BNWARPContainer* BNWARPAddContainer(const char* name); WARP_FFI_API char* BNWARPContainerGetName(BNWARPContainer* container); diff --git a/plugins/warp/src/cache/container.rs b/plugins/warp/src/cache/container.rs index 0b478ed172..99746d9aca 100644 --- a/plugins/warp/src/cache/container.rs +++ b/plugins/warp/src/cache/container.rs @@ -35,3 +35,8 @@ pub fn cached_containers() -> Vec>>> { let containers_cache = CONTAINER_CACHE.get_or_init(Default::default); containers_cache.iter().map(|c| c.clone()).collect() } + +pub fn cached_container_by_name(name: &str) -> Option>>> { + let containers_cache = CONTAINER_CACHE.get_or_init(Default::default); + containers_cache.get(name).map(|c| c.clone()) +} diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs index 2376ef1062..a107a78538 100644 --- a/plugins/warp/src/plugin/ffi/container.rs +++ b/plugins/warp/src/plugin/ffi/container.rs @@ -1,4 +1,5 @@ -use crate::cache::container::cached_containers; +use crate::cache::container::{add_cached_container, cached_container_by_name, cached_containers}; +use crate::container::disk::DiskContainer; use crate::container::{ ContainerSearchItem, ContainerSearchItemKind, ContainerSearchQuery, SourcePath, SourceTag, }; @@ -12,6 +13,7 @@ use binaryninja::rc::Ref; use binaryninja::string::BnString; use binaryninja::types::Type; use binaryninjacore_sys::{BNArchitecture, BNBinaryView, BNType}; +use std::collections::HashMap; use std::ffi::{c_char, CStr}; use std::mem::ManuallyDrop; use std::ops::Deref; @@ -172,6 +174,21 @@ pub unsafe extern "C" fn BNWARPContainerSearchItemGetFunction( } } +#[no_mangle] +pub unsafe extern "C" fn BNWARPAddContainer(name: *const c_char) -> *mut BNWARPContainer { + let name_cstr = unsafe { CStr::from_ptr(name) }; + let name_str = name_cstr.to_str().unwrap(); + // TODO: Using this generic API name for disk container, I think anything like the network container + // TODO: should probably be a second class name so something like BNWARPAddNetworkContainer. + let disk_container = DiskContainer::new(name_str.to_string(), HashMap::new()); + let container_name = disk_container.to_string(); + add_cached_container(disk_container); + match cached_container_by_name(&container_name) { + Some(container) => Arc::into_raw(container) as *mut BNWARPContainer, + None => std::ptr::null_mut(), + } +} + #[no_mangle] pub unsafe extern "C" fn BNWARPGetContainers(count: *mut usize) -> *mut *mut BNWARPContainer { // NOTE: Leak the arc pointers to be freed by BNWARPFreeContainerList