Skip to main content
Glama
FindUsesOfStructMember.java8.3 kB
package com.lauriewired.handlers.get; import com.lauriewired.handlers.Handler; import com.sun.net.httpserver.HttpExchange; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataTypeComponent; import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.Structure; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.FunctionIterator; import ghidra.program.model.listing.Program; import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileResults; import ghidra.util.task.TaskMonitor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import java.util.regex.Matcher; import static com.lauriewired.util.ParseUtils.*; import ghidra.program.model.data.CategoryPath; import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram; /** * Handler to find all uses of a specific member of a structure by analyzing decompiled code. * This comprehensive approach searches through all functions to find member accesses in * function parameters, local variables, dynamic allocations, and other contexts that * wouldn't be found by only examining global typed data. * * The handler decompiles each function and uses regex patterns to find: * - Direct member access: variable.member_name * - Pointer member access: variable->member_name * - Dereference access: (*variable).member_name * * Expects query parameters: struct_name, member_name, offset, limit */ public final class FindUsesOfStructMember extends Handler { public FindUsesOfStructMember(PluginTool tool) { super(tool, "/find_uses_of_struct_member"); } /** * Handles the HTTP request to find uses of a struct member. * Expects query parameters: struct_name, member_name, offset, limit * * @param exchange the HTTP exchange containing the request * @throws Exception if an error occurs while processing the request */ @Override public void handle(HttpExchange exchange) throws Exception { Map<String, String> qparams = parseQueryParams(exchange); String structName = qparams.get("struct_name"); String memberName = qparams.get("member_name"); int offset = parseIntOrDefault(qparams.get("offset"), 0); int limit = parseIntOrDefault(qparams.get("limit"), 100); sendResponse(exchange, findUsesOfStructMember(structName, memberName, offset, limit)); } /** * Finds all uses of a specific member of a structure by searching through decompiled code. * This approach finds member accesses in function parameters, local variables, and other contexts * that wouldn't be found by just looking at global typed data. * * @param structName the name of the structure * @param memberName the name of the member within the structure * @param offset the starting index for pagination * @param limit the maximum number of results to return * @return a string containing the member uses or an error message */ private String findUsesOfStructMember(String structName, String memberName, int offset, int limit) { Program program = getCurrentProgram(tool); if (program == null) return "No program loaded"; if (structName == null || structName.isEmpty()) return "Struct name is required"; if (memberName == null || memberName.isEmpty()) return "Member name is required"; try { // Verify the structure exists DataTypeManager dtm = program.getDataTypeManager(); CategoryPath path = new CategoryPath("/"); DataType dt = dtm.getDataType(path, structName); if (dt == null || !(dt instanceof Structure)) { return "Error: Struct " + structName + " not found"; } Structure struct = (Structure) dt; // Verify the member exists in the structure boolean memberFound = false; DataTypeComponent[] components = struct.getDefinedComponents(); for (DataTypeComponent component : components) { if (memberName.equals(component.getFieldName())) { memberFound = true; break; } } if (!memberFound) { return "Error: Member '" + memberName + "' not found in struct " + structName; } List<String> refs = new ArrayList<>(); // Initialize decompiler DecompInterface decompiler = new DecompInterface(); decompiler.openProgram(program); // Create regex patterns to find struct member accesses // Pattern 1: variable.member_name Pattern dotPattern = Pattern.compile("\\b\\w+\\." + Pattern.quote(memberName) + "\\b"); // Pattern 2: variable->member_name Pattern arrowPattern = Pattern.compile("\\b\\w+\\->" + Pattern.quote(memberName) + "\\b"); // Pattern 3: (*variable).member_name Pattern derefPattern = Pattern.compile("\\(\\*\\w+\\)\\." + Pattern.quote(memberName) + "\\b"); // Search through all functions FunctionIterator functionIterator = program.getFunctionManager().getFunctions(true); while (functionIterator.hasNext()) { Function function = functionIterator.next(); try { // Decompile the function DecompileResults results = decompiler.decompileFunction(function, 30, TaskMonitor.DUMMY); if (results != null && results.decompileCompleted()) { String decompiledCode = results.getDecompiledFunction().getC(); // Search for member access patterns in the decompiled code refs.addAll(findMemberAccesses(decompiledCode, structName, memberName, function.getName(), function.getEntryPoint(), dotPattern, arrowPattern, derefPattern)); } } catch (Exception e) { // Continue with next function if decompilation fails continue; } } decompiler.dispose(); if (refs.isEmpty()) { return "No uses found of " + structName + "." + memberName + " in decompiled code"; } return paginateList(refs, offset, limit); } catch (Exception e) { return "Error finding struct member uses: " + e.getMessage(); } } /** * Searches for member access patterns in decompiled C code. * * @param decompiledCode the decompiled C code to search * @param structName the name of the structure * @param memberName the name of the member * @param functionName the name of the function being searched * @param functionAddress the entry point address of the function * @param dotPattern regex pattern for dot notation (var.member) * @param arrowPattern regex pattern for arrow notation (var->member) * @param derefPattern regex pattern for dereference notation ((*var).member) * @return list of formatted reference strings */ private List<String> findMemberAccesses(String decompiledCode, String structName, String memberName, String functionName, Address functionAddress, Pattern dotPattern, Pattern arrowPattern, Pattern derefPattern) { List<String> accesses = new ArrayList<>(); if (decompiledCode == null || decompiledCode.isEmpty()) { return accesses; } // Split code into lines for better context reporting String[] lines = decompiledCode.split("\n"); for (int lineNum = 0; lineNum < lines.length; lineNum++) { String line = lines[lineNum].trim(); // Skip empty lines and comments if (line.isEmpty() || line.startsWith("//") || line.startsWith("/*")) { continue; } // Check for dot notation (var.member) Matcher dotMatcher = dotPattern.matcher(line); while (dotMatcher.find()) { accesses.add(String.format("Access to %s.%s in %s() at %s (line %d): %s", structName, memberName, functionName, functionAddress, lineNum + 1, line)); } // Check for arrow notation (var->member) Matcher arrowMatcher = arrowPattern.matcher(line); while (arrowMatcher.find()) { accesses.add(String.format("Access to %s->%s in %s() at %s (line %d): %s", structName, memberName, functionName, functionAddress, lineNum + 1, line)); } // Check for dereference notation ((*var).member) Matcher derefMatcher = derefPattern.matcher(line); while (derefMatcher.find()) { accesses.add(String.format("Access to (*%s).%s in %s() at %s (line %d): %s", structName, memberName, functionName, functionAddress, lineNum + 1, line)); } } return accesses; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/harry-cysic/GhidraMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server