Agentic API-Hashing Resolver is a local backend for resolving API hashes during reverse engineering.
It is built for agentic workflows where a coding or RE agent inspects a binary, reconstructs the API hashing algorithm, adds that algorithm as a plugin, and asks this tool to resolve hashes back to concrete exports such as kernel32.dll!GetProcAddress.
This repository provides:
- a Python CLI
- a FastAPI REST backend
- a stdio MCP bridge for agent tools
- a browser UI for local exploration
- convention-based Python and native hash plugin packs
- bundled reference packs, including FLARE-derived hashes and imported OALabs HashDB algorithms
LLMs often hallucinate plausible Windows API imports when malware uses API hashing. The Agentic API-Hash Resolver framework gives the agent a deterministic tool call instead: implement or select the exact hash algorithm, run it against export catalogs, and return real candidates. The project contains a compressed exports of almost all DLLs from a recent Windows installation, it also has an option to ignore DLLs containing hyphens (almost exclusively forwarders to other DLLs) and also a selection of most common DLLs. The prefiltering of DLLs can speed up bruteforcing. In addition, the framework uses multithreading when checking hashes. Packs of hash function implementations can be used to share a repository of hashes within an organization.
The idea and compatibility model come from OALabs HashDB and its open-source implementation at github.com/OALabs/hashdb. This framework ports that workflow into a local, agent-friendly system where an AI tool can add or adapt hash implementations, reload them, and resolve hashes without leaving the reverse-engineering loop.
You can use the framework in your agentic reverse engineering setup to let any model write the API hash implementation for you.
Sometimes, specially non-frontier models tend to hallucinate assembly operations when porting logical or arithmetical operations into Python (at the time of writing, LLMs tend to produce wrong byte-lengths of registers, e.g. missing a modulo operation).
The "library" byteops tries to fix this. ByteOps provides explicit arithmetic, logical, rotate, shift, and width behavior, which prevents hallucinations around assembly operations and CPU register semantics.
Agents shall prefer concrete helpers such as ror_dword, rol_dword, shl_dword, and shr_dword instead of asking an agent to invent Python equivalents for machine instructions, this is also explicitly added in the skill file.
In addition to Python code, one can also create a C function that implements the hash function and registers it to the framework.
The browser UI is mostly interesting for debugging and/or testing single strings if manually reversing a sample. Docker can be used for launching the REST API and the MCP server, but even the command line interface combined with the skill files works well.
Launch the server backend with Docker:
docker compose up --buildThen open:
- Backend:
http://localhost:8000 - UI:
http://localhost:5173
Or run the backend locally:
python3 -m venv venv
. venv/bin/activate
python -m pip install -e .
uvicorn apihashing.app:create_app --factory --reloadThe CLI works without Docker:
apihashing algorithms
apihashing hash-string --algorithm payouts_king_crc32 --library kernel32.dll --symbol GetProcAddress
apihashing search-hash --hash 0x7c0017bb --dll kernel32.dllThe installable skill is in:
apihashing-contributor-skill/SKILL.md
If you experience that the agent cannot find the project (for example when you don't use the mcp server), let your agent add an absolute path pointing to the framework, the agent spends less time searching for the project. You can also tell it to use your venv in case the agent tries to install the dependencies locally.
For Claude Code, install it as a local user skill:
mkdir -p ~/.claude/skills
cp -R apihashing-contributor-skill ~/.claude/skills/apihashing-contributorStart a new Claude Code session after installing. If you use Claude.ai Skills instead of Claude Code, zip the apihashing-contributor-skill folder and upload it through the Claude Skills settings. Keep SKILL.md at the root of the uploaded folder.
For a repository-scoped Codex skill, install it under .agents/skills:
mkdir -p .agents/skills
cp -R apihashing-contributor-skill .agents/skills/apihashing-contributorFor a personal Codex skill available across repositories, install it under your home directory:
mkdir -p ~/.agents/skills
cp -R apihashing-contributor-skill ~/.agents/skills/apihashing-contributorCodex detects skill changes automatically in many cases. If the skill does not appear, restart Codex or start a new thread. You can then ask Codex to use the skill explicitly with:
$apihashing-contributor
apihashing search-hash \
--hash 0x7c0017bb \
--dll kernel32.dllWith an algorithm parameter:
apihashing search-hash \
--hash 0x234C1F67 \
--algorithm d68_fnv1a \
--base 0x8E8A2795apihashing hash-string \
--algorithm payouts_king_crc32 \
--library kernel32.dll \
--symbol GetProcAddressWith an XOR modifier:
apihashing hash-string \
--algorithm payouts_king_crc32 \
--library kernel32.dll \
--symbol CreateFileW \
--xor 0x13579BDFapihashing export-enum \
--algorithm payouts_king_crc32 \
--dll kernel32.dll \
--dll user32.dll \
--output headers/apihashing build-catalog \
--input /path/to/System32 \
--output system32.json.xzBy default, the CLI expects to run from the project root so it can find packs/. If needed, set APIHASHING_PROJECT_ROOT or pass --project-root.
When installed via pipx or uv tool, bundled packs are used automatically if no local packs/ directory is present.
Run the stdio MCP server for Codex, Claude, Gemini, or another MCP-capable tool:
APIHASHING_MCP_API_URL=http://localhost:8000 python -m apihashing.mcp_serverThe MCP server wraps the API endpoints for:
- pack, catalog, and algorithm listing
- hash, search, resolve, and enum export actions
- admin reload and native rebuild actions
- pack and algorithm scaffolding helpers
Tool argument examples are in docs/mcp-examples.md.
Run the UI locally:
npm --prefix ui install
npm --prefix ui run devThe UI has tabs for:
HashesExport EnumPacksDocs
The browser UI uses shipped catalogs by default. For extra libraries, attach files directly in the Search Hash or Export Enum form for that request.
The compose file is a hot-reload development stack for local or submodule-based API hashing method packs.
On Linux, export your host UID and GID before starting the stack so bind-mounted files stay owned by your user:
export UID=$(id -u)
export GID=$(id -g)
docker compose up --buildIf UID and GID are not set, compose falls back to 1000:1000.
If an older compose setup installed dependencies as root, reset stale volumes once:
docker compose down -v
docker compose up --buildRuntime development endpoints:
POST /admin/reloadafter Python algorithm or catalog changesPOST /admin/rebuild-nativeafter C/native changes
Docker details:
- Backend startup runs
make -C packs/default-pack/algorithms/native allbefore launching uvicorn. - Python reload uses polling through
WATCHFILES_FORCE_POLLING=true. - Vite reload uses polling.
APIHASHING_SEARCH_MAX_WORKERSlimits workers for/search-hash.APIHASHING_EXPORT_MAX_WORKERSlimits workers for multi-library enum export.APIHASHING_ENABLE_MP_SEARCHdefaults to enabled with1.APIHASHING_MP_SEARCH_MAX_WORKERScaps process-pool workers for/search-hash.
If you change vite.config.js, Dockerfiles, or dependency metadata, rebuild the affected service:
docker compose up --build -d backend uiPython hash plugins are discovered from:
packs/<pack>/algorithms/**/*.py
Native hash plugins are discovered from:
packs/<pack>/algorithms/native/**/*.hash.so
Catalog files are discovered from:
packs/<pack>/catalogs/**/*.json
packs/<pack>/catalogs/**/*.json.xz
pack.yaml is optional. Discovery is convention-based.
A minimal Python pack:
packs/
my-pack/
catalogs/
pe/
kernel32.json
algorithms/
my_hash.py
A minimal native pack:
packs/
native-pack/
catalogs/
pe/
demo.json
algorithms/
native/
Makefile
native_bundle.hash.so
Use init to create a separate workspace and a new pack skeleton for agent-driven hash authoring:
apihashing init --workspace ./apihashing-workspace --pack-name team-packThis creates:
apihashing-workspace/packs/team-pack- bundled reference packs, unless
--no-bundled-packsis used
Recommended separation workflow:
cd apihashing-workspace/packs/team-pack
git init
# push this pack to its own repositoryThen link it back into the core repository if desired:
git submodule add <pack-repo-url> packs/team-packThe simplest authoring path is one file in algorithms/. You can export HASH_IMPLEMENTATION directly or drop in a HashDB-style file with a hash(data) function.
Project-native example:
from byteops import ByteOps
from apihashing.plugin_api import FunctionHashImplementation, HashValue
OPS = ByteOps()
def _hash(library_name: str, symbol_name: str, params: dict[str, object]) -> HashValue:
seed = int(params.get("seed", 0))
value = seed
for byte in symbol_name.encode("ascii"):
raw = (value & 0xFFFFFFFF).to_bytes(4, "little")
value = int.from_bytes(OPS.ror_dword(raw, 13), "little")
value = (value + byte) & 0xFFFFFFFF
return HashValue.from_int(value, bit_length=32)
HASH_IMPLEMENTATION = FunctionHashImplementation(
id="demo_ror13_add",
callback=_hash,
display_name="Demo ROR13 Add",
description="Example API hash using ByteOps for assembly-like 32-bit behavior.",
author="Your Team Name",
hash_size_bits=32,
)Rules:
- Keep one Python hash implementation in one file.
- Keep logic and metadata together.
- Keep IDs unique.
- Use the 3-argument callback when the malware varies a seed, base, XOR constant, case mode, or other per-call modifier.
- Use ByteOps for assembly-style arithmetic, rotates, shifts, masks, and width-specific behavior.
HashDB-style example:
DESCRIPTION = "Simple symbol-only hash"
TYPE = "unsigned_int"
TEST_1 = 0x12345678
SOURCE = "https://example.test/demo_hash.py"
LICENSE = "Apache-2.0"
def hash(data):
return 0x12345678Only the algorithm file needs to be added. No YAML edit is required.
Each discovered .hash.so exports a descriptor-based ABI:
uint32_t apihash_plugin_count(void)const apihash_descriptor* apihash_plugin_descriptor(uint32_t index)- one exported compute function per descriptor named by
symbol_name
This allows one shared object to expose one or many hash implementations.
Author attribution is implementation-level:
- Python: set
author=inFunctionHashImplementation, orAUTHORin HashDB-style modules. - Native C: optionally export
const char* apihash_plugin_author(uint32_t index).
Build native plugins locally:
make -C packs/default-pack/algorithms/native allOr trigger rebuild and reload through the running backend:
curl -sS -X POST http://localhost:8000/admin/rebuild-native \
-H 'Content-Type: application/json' \
-d '{}'The REST API includes HashDB-compatible routes that mimic the backend expected by the HashDB IDA plugin. Pointing that plugin at APIHashing lets you keep the familiar IDA workflow while using local catalogs, custom packs, and newly implemented agent-generated algorithms.
Useful read endpoints:
GET /healthGET /packsGET /algorithmsGET /catalogs
Core POST endpoints:
POST /hash-stringPOST /search-hashPOST /resolvePOST /export-enumPOST /bulk-autoPOST /build-catalogs
Admin endpoints:
POST /admin/reloadPOST /admin/rebuild-native
HashDB-compatible endpoints:
GET /hashGET /hash/{algorithm_id}/{hash_value}GET /module/{module_name}/{algorithm_id}/{permutation}POST /hunt
Example:
curl -sS -X POST http://localhost:8000/hash-string \
-H 'Content-Type: application/json' \
-d '{
"algorithm_id": "payouts_king_crc32",
"library_name": "kernel32.dll",
"symbol_name": "GetProcAddress"
}'- REST API, web UI, local CLI, and MCP bridge share the same backend service layer.
- Hash results carry both hex and unsigned integer representations.
- Project-native plugins and HashDB-style one-file modules are supported.
- HashDB-compatible routes are exposed as a drop-in backend for the HashDB IDA plugin.
- Optional XOR modifiers are supported in REST and CLI flows.
- Runtime reload endpoints allow zero-restart development.
- Bundled reference packs are shipped inside the Python package for standalone
pipxanduvusage.
packs/default-packno longer containspack.yaml; it was only a leftover from the legacy manifest-based loader.- The default pack ships
payouts_king_crc32,internal_djb2_symbol_c, a compressedsystem32.json.xzWindows library catalog, and one merged Payouts King wordlist sourced from the Zscaler research post. packs/oalabs-hashdbcontains imported one-file algorithms fromOALabs/hashdbwith per-file source and Apache-2.0 license metadata.- Imported OALabs HashDB algorithms that trace back to FLARE shellcode are marked with
copied_from_flare_shellcodein API results and shown in the UI asflare shellcode lineage. - Scaffolding templates are file-based under
apihashing/templates/algorithms/{python,c}and are consumed byPOST /scaffold/algorithm.
More details: