feat(analysis): add type information to xref and label entries
This commit is contained in:
parent
dcb4cf6a3c
commit
b26631c5aa
@ -4,6 +4,7 @@ static main() {
|
|||||||
auto ea, func_end, curr_inst, func_name, disasm, file;
|
auto ea, func_end, curr_inst, func_name, disasm, file;
|
||||||
auto last_inst, xref, ref, label_name;
|
auto last_inst, xref, ref, label_name;
|
||||||
auto entry_ea, entry_name;
|
auto entry_ea, entry_name;
|
||||||
|
auto xref_type, type_str;
|
||||||
|
|
||||||
Message("Aguardando fim da analise...\n");
|
Message("Aguardando fim da analise...\n");
|
||||||
Wait();
|
Wait();
|
||||||
@ -31,12 +32,20 @@ static main() {
|
|||||||
fprintf(file, " \"function\": \"%s\",\n", func_name);
|
fprintf(file, " \"function\": \"%s\",\n", func_name);
|
||||||
fprintf(file, " \"address\": \"0x%08X\",\n", ea);
|
fprintf(file, " \"address\": \"0x%08X\",\n", ea);
|
||||||
|
|
||||||
// --- XREFS TO (Simplificado e direto para o IDA 5) ---
|
// --- XREFS TO (com tipo: CALL ou JUMP) ---
|
||||||
fprintf(file, " \"xrefs\": \"");
|
fprintf(file, " \"xrefs\": \"");
|
||||||
xref = RfirstB(ea);
|
xref = RfirstB(ea);
|
||||||
while (xref != BADADDR) {
|
while (xref != BADADDR) {
|
||||||
if (GetFunctionName(xref) != "") {
|
if (GetFunctionName(xref) != "") {
|
||||||
fprintf(file, "%s ", GetFunctionName(xref));
|
xref_type = XrefType();
|
||||||
|
if (xref_type == fl_CN || xref_type == fl_CF) {
|
||||||
|
type_str = "CALL";
|
||||||
|
} else if (xref_type == fl_JN || xref_type == fl_JF) {
|
||||||
|
type_str = "JUMP";
|
||||||
|
} else {
|
||||||
|
type_str = "UNKNOWN";
|
||||||
|
}
|
||||||
|
fprintf(file, "%s:%s ", GetFunctionName(xref), type_str);
|
||||||
}
|
}
|
||||||
xref = RnextB(ea, xref);
|
xref = RnextB(ea, xref);
|
||||||
}
|
}
|
||||||
@ -63,7 +72,7 @@ static main() {
|
|||||||
}
|
}
|
||||||
fprintf(file, "\",\n");
|
fprintf(file, "\",\n");
|
||||||
|
|
||||||
// --- LABELS (code references from instructions) ---
|
// --- LABELS (code references with type) ---
|
||||||
fprintf(file, " \"labels\": \"");
|
fprintf(file, " \"labels\": \"");
|
||||||
curr_inst = ea;
|
curr_inst = ea;
|
||||||
last_inst = 0;
|
last_inst = 0;
|
||||||
@ -78,7 +87,15 @@ static main() {
|
|||||||
while (ref != BADADDR) {
|
while (ref != BADADDR) {
|
||||||
label_name = Name(ref);
|
label_name = Name(ref);
|
||||||
if (label_name != "") {
|
if (label_name != "") {
|
||||||
fprintf(file, "%s:0x%08X ", label_name, ref);
|
xref_type = XrefType();
|
||||||
|
if (xref_type == fl_CN || xref_type == fl_CF) {
|
||||||
|
type_str = "CALL";
|
||||||
|
} else if (xref_type == fl_JN || xref_type == fl_JF) {
|
||||||
|
type_str = "JUMP";
|
||||||
|
} else {
|
||||||
|
type_str = "UNKNOWN";
|
||||||
|
}
|
||||||
|
fprintf(file, "%s:0x%08X:%s ", label_name, ref, type_str);
|
||||||
}
|
}
|
||||||
ref = Rnext(curr_inst, ref);
|
ref = Rnext(curr_inst, ref);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -279,7 +279,10 @@ public class ChatContextBuilder {
|
|||||||
|
|
||||||
sb.append("Callers: ");
|
sb.append("Callers: ");
|
||||||
sb.append(
|
sb.append(
|
||||||
String.join(", ", callers.stream().limit(5).map(x -> x.getCaller().getName()).toList()));
|
callers.stream()
|
||||||
|
.limit(5)
|
||||||
|
.map(x -> x.getCaller().getName() + " [" + x.getType() + "]")
|
||||||
|
.collect(java.util.stream.Collectors.joining(", ")));
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +293,10 @@ public class ChatContextBuilder {
|
|||||||
|
|
||||||
sb.append("Callees: ");
|
sb.append("Callees: ");
|
||||||
sb.append(
|
sb.append(
|
||||||
String.join(", ", callees.stream().limit(10).map(x -> x.getCallee().getName()).toList()));
|
callees.stream()
|
||||||
|
.limit(10)
|
||||||
|
.map(x -> x.getCallee().getName() + " [" + x.getType() + "]")
|
||||||
|
.collect(java.util.stream.Collectors.joining(", ")));
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package ai.decompile.analysis.model.dto;
|
|||||||
|
|
||||||
import ai.decompile.analysis.model.entity.StaticLabel;
|
import ai.decompile.analysis.model.entity.StaticLabel;
|
||||||
|
|
||||||
public record LabelResponse(String name, String address) {
|
public record LabelResponse(String name, String address, String type) {
|
||||||
public static LabelResponse from(StaticLabel l) {
|
public static LabelResponse from(StaticLabel l) {
|
||||||
return new LabelResponse(l.getName(), l.getAddress());
|
return new LabelResponse(l.getName(), l.getAddress(), l.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,4 +25,8 @@ public class StaticLabel {
|
|||||||
|
|
||||||
@Column(nullable = false, length = 20)
|
@Column(nullable = false, length = 20)
|
||||||
private String address;
|
private String address;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 10)
|
||||||
|
@Builder.Default
|
||||||
|
private String type = "CALL";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,7 @@ public class AnalysisService {
|
|||||||
.function(func)
|
.function(func)
|
||||||
.name(label.name())
|
.name(label.name())
|
||||||
.address(label.address())
|
.address(label.address())
|
||||||
|
.type(label.type())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,13 +146,13 @@ public class AnalysisService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var calleeName : funcResult.xrefNames()) {
|
for (var xrefEntry : funcResult.xrefs()) {
|
||||||
var calleeId = nameToId.get(calleeName);
|
var calleeId = nameToId.get(xrefEntry.name());
|
||||||
if (calleeId == null) {
|
if (calleeId == null) {
|
||||||
log.debug(
|
log.debug(
|
||||||
"Skipping xref from '{}' to unknown function '{}' (likely external/lib)",
|
"Skipping xref from '{}' to unknown function '{}' (likely external/lib)",
|
||||||
funcResult.name(),
|
funcResult.name(),
|
||||||
calleeName);
|
xrefEntry.name());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ public class AnalysisService {
|
|||||||
StaticXref.builder()
|
StaticXref.builder()
|
||||||
.caller(functionRepository.getReferenceById(callerId))
|
.caller(functionRepository.getReferenceById(callerId))
|
||||||
.callee(functionRepository.getReferenceById(calleeId))
|
.callee(functionRepository.getReferenceById(calleeId))
|
||||||
.type("CALL")
|
.type(xrefEntry.type())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,5 @@ public record FunctionResult(
|
|||||||
String assembly,
|
String assembly,
|
||||||
String decompiledCode,
|
String decompiledCode,
|
||||||
String signature,
|
String signature,
|
||||||
List<String> xrefNames,
|
List<XrefEntry> xrefs,
|
||||||
List<LabelEntry> labels) {}
|
List<LabelEntry> labels) {}
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
package ai.decompile.engine.model;
|
package ai.decompile.engine.model;
|
||||||
|
|
||||||
public record LabelEntry(String name, String address) {}
|
public record LabelEntry(String name, String address, String type) {}
|
||||||
|
|||||||
3
src/main/java/ai/decompile/engine/model/XrefEntry.java
Normal file
3
src/main/java/ai/decompile/engine/model/XrefEntry.java
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package ai.decompile.engine.model;
|
||||||
|
|
||||||
|
public record XrefEntry(String name, String type) {}
|
||||||
@ -6,6 +6,7 @@ import ai.decompile.engine.model.AnalysisResult;
|
|||||||
import ai.decompile.engine.model.EngineType;
|
import ai.decompile.engine.model.EngineType;
|
||||||
import ai.decompile.engine.model.FunctionResult;
|
import ai.decompile.engine.model.FunctionResult;
|
||||||
import ai.decompile.engine.model.LabelEntry;
|
import ai.decompile.engine.model.LabelEntry;
|
||||||
|
import ai.decompile.engine.model.XrefEntry;
|
||||||
import com.github.dockerjava.api.model.Bind;
|
import com.github.dockerjava.api.model.Bind;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -185,10 +186,9 @@ public class Ida5EngineService implements EngineService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xrefNames =
|
var xrefs = parseXrefs(xrefsRaw.trim());
|
||||||
xrefsRaw.isBlank() ? List.<String>of() : Arrays.asList(xrefsRaw.trim().split("\\s+"));
|
|
||||||
var labels = parseLabels(labelsRaw.trim());
|
var labels = parseLabels(labelsRaw.trim());
|
||||||
functions.add(new FunctionResult(name, address, assembly, null, null, xrefNames, labels));
|
functions.add(new FunctionResult(name, address, assembly, null, null, xrefs, labels));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functions.isEmpty()) {
|
if (functions.isEmpty()) {
|
||||||
@ -210,6 +210,23 @@ public class Ida5EngineService implements EngineService {
|
|||||||
return idx < 0 ? null : text.substring(idx + delim.length());
|
return idx < 0 ? null : text.substring(idx + delim.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<XrefEntry> parseXrefs(String raw) {
|
||||||
|
if (Objects.isNull(raw) || raw.isBlank()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Arrays.stream(raw.trim().split("\\s+")).map(Ida5EngineService::parseXrefEntry).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XrefEntry parseXrefEntry(String token) {
|
||||||
|
var colon = token.lastIndexOf(':');
|
||||||
|
if (colon < 0) {
|
||||||
|
return new XrefEntry(token, "CALL");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new XrefEntry(token.substring(0, colon), token.substring(colon + 1));
|
||||||
|
}
|
||||||
|
|
||||||
private static List<LabelEntry> parseLabels(String raw) {
|
private static List<LabelEntry> parseLabels(String raw) {
|
||||||
if (raw == null || raw.isBlank()) {
|
if (raw == null || raw.isBlank()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
@ -221,10 +238,19 @@ public class Ida5EngineService implements EngineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static LabelEntry parseLabelEntry(String token) {
|
private static LabelEntry parseLabelEntry(String token) {
|
||||||
int colon = token.lastIndexOf(':');
|
var lastColon = token.lastIndexOf(':');
|
||||||
if (colon < 0) {
|
if (lastColon < 0) {
|
||||||
return new LabelEntry(token, "");
|
return new LabelEntry(token, "", "CALL");
|
||||||
}
|
}
|
||||||
return new LabelEntry(token.substring(0, colon), token.substring(colon + 1));
|
|
||||||
|
var type = token.substring(lastColon + 1);
|
||||||
|
var nameAddr = token.substring(0, lastColon);
|
||||||
|
var addrColon = nameAddr.lastIndexOf(':');
|
||||||
|
if (addrColon < 0) {
|
||||||
|
return new LabelEntry(nameAddr, "", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LabelEntry(
|
||||||
|
nameAddr.substring(0, addrColon), nameAddr.substring(addrColon + 1), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE static_label ADD COLUMN IF NOT EXISTS type VARCHAR(10) NOT NULL DEFAULT 'CALL';
|
||||||
@ -114,6 +114,7 @@ CREATE TABLE IF NOT EXISTS static_label
|
|||||||
id UUID PRIMARY KEY,
|
id UUID PRIMARY KEY,
|
||||||
function_id UUID NOT NULL REFERENCES static_function (id) ON DELETE CASCADE,
|
function_id UUID NOT NULL REFERENCES static_function (id) ON DELETE CASCADE,
|
||||||
name VARCHAR(500) NOT NULL,
|
name VARCHAR(500) NOT NULL,
|
||||||
address VARCHAR(20) NOT NULL
|
address VARCHAR(20) NOT NULL,
|
||||||
|
type VARCHAR(10) NOT NULL DEFAULT 'CALL'
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS idx_static_label_function_id ON static_label (function_id);
|
CREATE INDEX IF NOT EXISTS idx_static_label_function_id ON static_label (function_id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user