如何将Joern生成的.bin格式代码属性图(CPG)转换为JSON格式?
Hey there! Converting Joern's binary CPGs (.bin files) to JSON for graph ML classification tasks is a workflow I’ve used plenty of times, and there are a couple of solid ways to pull it off—let’s break them down.
Method 1: Use Joern’s Built-in joern-export Tool
Joern ships with a dedicated export utility that’s the easiest way to dump your CPG to JSON without writing custom code. Here’s how to use it, either via the Joern shell or command line:
Via the Joern Shell
- First, launch the Joern shell (make sure your Joern setup is working and you have your .bin CPG ready):
joern - Load your binary CPG file into the shell:
val cpg = loadCpg("/full/path/to/your/cpg.bin") - Export the CPG to JSON. You can export the entire graph, or filter down to specific nodes/edges to keep your JSON lean (perfect for ML, where noise can hurt performance):
// Export all nodes and edges to a single JSON file cpg.export.toJson("/path/where/you/want/cpg.json") // Example: Only export Method nodes and Call edges cpg.export .withNodes(cpg.method) .withEdges(cpg.call) .toJson("/path/where/you/want/filtered_cpg.json")
Direct Command-Line Export (Great for Scripting)
If you want to automate the conversion without opening the Joern shell, use the joern-export command directly:
joern-export --input /full/path/to/your/cpg.bin --output /path/where/you/want/cpg.json --format json
This is ideal for adding to CI/CD pipelines or batch processing multiple CPGs.
Method 2: Custom Export with JQL (For Full Control)
If your graph ML library expects a specific JSON structure (like a separate node list and edge list, or custom feature fields), you can use Joern Query Language (JQL) to craft a tailored export.
For example, let’s say you need to export methods with their names, line numbers, and incoming calls—here’s how you’d do it:
// Fetch and format the data we need val methodGraphData = cpg.method.map(method => { Map( "node_id" -> method.id, "feature_name" -> method.name, "start_line" -> method.lineNumber.getOrElse(-1), "incoming_call_names" -> method.inCall.map(_.name).toList ) }).toList // Write the formatted data to a JSON file import java.io.File import scala.util.parsing.json.JSONObject val jsonOutput = JSONObject(Map("method_nodes" -> methodGraphData)).toString() new File("/path/where/you/want/custom_cpg.json").write(jsonOutput)
This approach lets you shape the JSON exactly how your model needs it—no extra fluff, just the data that matters.
Quick Tips for Graph ML Compatibility
- Filter aggressively: Most graph models don’t need every node/edge type from the full CPG. Stick to relevant elements (e.g., control flow edges, data dependencies, method nodes) to reduce overhead.
- Keep IDs consistent: Make sure node IDs in your edge list match the IDs in your node list—this is how the library builds the graph correctly.
- Pack in useful features: Add attributes like variable types, method modifiers, or code complexity metrics as node features—these will help your model learn meaningful patterns.
内容的提问来源于stack exchange,提问作者Junk Gear

