Skip to content

Commit

Permalink
Merge branch 'main' into gradlew
Browse files Browse the repository at this point in the history
  • Loading branch information
sei-eschwartz authored Nov 15, 2024
2 parents f597dda + 988b416 commit 76a12cc
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 62 deletions.
16 changes: 8 additions & 8 deletions src/main/java/kaiju/tools/disasm/DisasmStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,25 @@ public interface DisasmStrategy extends KaijuLogger {

// returns array of categories in use by this architecture
Pair<AddressRange, Integer> analyzeGap(final AddressRange range);

/**
* recognizes bytes at an address as alignment bytes.
* this is a default implementation that shouldn't rely on
* architecture, but can be overriden if needed for some reason.
*/
default Pair<AddressRange, Integer> makeAlignment(Listing listing, final Address address, TaskMonitor monitor) {
default Pair<AddressRange, Integer> makeAlignment(Listing listing, final Address address, long length, TaskMonitor monitor) {
DataType alignmentType = GhidraTypeUtilities.findGhidraType("Alignment");
try {
Data alignData = listing.createData(address, alignmentType);
Data alignData = listing.createData(address, alignmentType, (int) length);
final Address minAddr = alignData.getMinAddress();
final Address maxAddr = alignData.getMaxAddress();
final AddressRange range = new AddressRangeImpl(minAddr, maxAddr);
debug(this, "Created alignment at: " + range);
debug(this, "Created alignment of " + range.getLength() + " bytes at: " + range);
//alignmentAddresses.add(range);
return new Pair<AddressRange, Integer>(range, 1);
} catch (final CodeUnitInsertionException e) {
// Don't report the exception, because we're going to just leave the address alone?
debug(this, "Failed to make alignment at " + address);
debug(this, "Failed to make alignment at " + address + " length= " + length);
//skippedAddresses.add(address);
try {
final AddressRange range = new AddressRangeImpl(address, 1);
Expand All @@ -89,7 +89,7 @@ default Pair<AddressRange, Integer> makeAlignment(Listing listing, final Address
}
}
}

/**
* recognizes bytes at a starting address as assembly code.
* this relies on disassembling at the given starting address.
Expand Down Expand Up @@ -140,7 +140,7 @@ default Pair<AddressRange, Integer> makeCode(Program currentProgram, Listing lis
return new Pair<AddressRange, Integer>(range, 1);
}
}

default Pair<AddressRange, Integer> makeString(Program currentProgram, Listing listing, final Address address, TaskMonitor monitor) {
DataType stringType = GhidraTypeUtilities.findGhidraType("string");
Data stringData;
Expand All @@ -150,7 +150,7 @@ default Pair<AddressRange, Integer> makeString(Program currentProgram, Listing l
final Address maxAddr = stringData.getMaxAddress();
final AddressRange range = new AddressRangeImpl(minAddr, maxAddr);
debug(this, "Created string at: " + range);
currentProgram.getBookmarkManager().setBookmark(address, "string", "KaijuDiasmImprovements", "created a string at this address");
currentProgram.getBookmarkManager().setBookmark(address, "string", "KaijuDisasmImprovements", "created a string at this address");
//stringAddresses.add(range);
return new Pair<AddressRange, Integer>(range, 1);
} catch (final CodeUnitInsertionException e) {
Expand Down
26 changes: 15 additions & 11 deletions src/main/java/kaiju/tools/disasm/GhidraTypeUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
*/
package kaiju.tools.disasm;

import ghidra.util.Msg;

import ghidra.program.model.address.Address;
import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.data.CategoryPath;
Expand All @@ -40,6 +42,7 @@
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;

/**
* A static class with utility functions for locating Ghidra
Expand All @@ -50,7 +53,7 @@ public class GhidraTypeUtilities {
public enum BlockType {
CODE, DATA, ALIGNMENT, OTHER
}

public static DataType findGhidraType(final String name) {
DataTypeManager dataTypeManager = BuiltInDataTypeManager.getDataTypeManager();
DataType dt = dataTypeManager.getDataType(CategoryPath.ROOT, name);
Expand All @@ -62,7 +65,7 @@ public static DataType findGhidraType(final String name) {
}
return dt;
}

// Return the type of the block at address.
public static BlockType getBlockType(final Listing listing, final Address address) {
// Instruction insn = listing.getInstructionContaining(address);
Expand All @@ -88,8 +91,8 @@ public static BlockType getBlockType(final Listing listing, final Address addres
// CodeUnit properties are *not* set by the Framework code
// Use /isinstance/ instead.
}
/*

/*
* Note this gets the Minimum address in a CodeUnit that
* may correspond to the Address OR _address_ if no CodeUnit is found;
* this should not be confused
Expand All @@ -100,15 +103,15 @@ public static Address getStartAddress(final Listing listing, final Address addre
final CodeUnit cu = listing.getCodeUnitContaining(address);
if (cu == null) {
//debug(this, "No CodeUnit for " + address);
// Why is this passed back with no error?
// When do we want to keep processing when
// no CodeUnit is defined with _address_ as
// a member?
// Why is this passed back with no error?
// When do we want to keep processing when
// no CodeUnit is defined with _address_ as
// a member?
return address;
}
return cu.getMinAddress();
}

public static Address getPreviousStartAddress(final Listing listing, final Address startAddress) {
// We can't call getStartAddress here, because previous might not be a valid address.
//final Address previous = startAddress.subtract(1);
Expand All @@ -126,10 +129,11 @@ public static Address getPreviousStartAddress(final Listing listing, final Addre
// Otherwise, everything went smoothly.
return previousStart;
}

// Return the type of the block immediately before address, skipping over one alignment
// block if the immediately preceding block is an alignment block.
public static BlockType getPreviousBlockType(final Listing listing, final Address address) {
public static BlockType getPreviousBlockType(final Program program, final Address address) {
final Listing listing = program.getListing();
final Address previous = getPreviousStartAddress(listing, address);
// TODO: what happens here if (previous == address)?
final BlockType blockType = getBlockType(listing, previous);
Expand Down
103 changes: 86 additions & 17 deletions src/main/java/kaiju/tools/disasm/impl/X86ImproverStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@
*/
package kaiju.tools.disasm.impl;

import java.util.Arrays;

import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressRangeImpl;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.listing.Bookmark;
import ghidra.program.model.listing.BookmarkManager;
import ghidra.util.task.TaskMonitor;

import kaiju.tools.disasm.DisasmStrategy;
Expand All @@ -56,47 +61,113 @@ public class X86ImproverStrategy implements DisasmStrategy {
private TaskMonitor monitor;
private Memory memory;
private Listing listing;

private BookmarkManager bookmarkManager;

public X86ImproverStrategy(Program currentProgram, TaskMonitor monitor) {
this.currentProgram = currentProgram;
this.monitor = monitor;
memory = currentProgram.getMemory();
listing = currentProgram.getListing();
bookmarkManager = currentProgram.getBookmarkManager();
}

private Pair<AddressRange, Integer>
makeX86Alignment(Listing listing, final AddressRange range, TaskMonitor monitor) {
// Length is the length of the gap, not necessarily the length that we want to
// turn into alignment. We should only make alignment from matching CC or zero
// bytes.

// Get the initial byte and ensure that it is 0x00 or 0xCC.
final Address minAddr = range.getMinAddress();
int initialByte = 0;
try {
initialByte = memory.getByte(minAddr) & 0xFF;
}
catch (final MemoryAccessException e) {
return new Pair<AddressRange, Integer>(range, 0);
}
if (initialByte != 0x00 && initialByte != 0xCC) {
return new Pair<AddressRange, Integer>(range, 0);
}

// Count how many adjacent bytes are also 0x00 or 0xCC.
Address nextAddr;
int alignLength = 0;
while (alignLength < range.getLength()) {
try {
nextAddr = minAddr.add(alignLength);
if ((memory.getByte(nextAddr) & 0xFF) != initialByte) break;
}
catch (final MemoryAccessException e) {
// If we run past the end of memory,
break;
}
alignLength += 1;
}

// Make alignment just for the bytes that are 0x00 or 0xCC.
return makeAlignment(listing, range.getMinAddress(), alignLength, monitor);
}

public Pair<AddressRange, Integer> analyzeGap(final AddressRange range) {
// debug(this, "Undefined bytes at " + range);
final Address minAddr = range.getMinAddress();

// If we've already processed this address, don't try again.
//if (skippedAddresses.contains(minAddr))
// return 0;

// debug(this, "Analyzing gap: " + range + " with block type " + getBlockType(minAddr));

// Upgrade the byte to an integer because types are signed in Java.
int b = 0;
// Look at the next byte.
int byteLookAhead = 0;
try {
b = memory.getByte(minAddr) & 0xFF;
byteLookAhead = memory.getByte(minAddr) & 0xFF;
} catch (final MemoryAccessException e) {
e.printStackTrace();
//return 0;
return new Pair<AddressRange, Integer>(range, 0);
}


// Look at the next four bytes.
int wordLookAhead = 0xFF;
try {
wordLookAhead = memory.getInt(minAddr) & 0xFFFFFFF;
} catch (final MemoryAccessException e) {
wordLookAhead = 0xFF;
}

// Address previous = minAddr.subtract(1);

final BlockType previousBlockType = GhidraTypeUtilities.getPreviousBlockType(listing, minAddr);
final BlockType previousBlockType = GhidraTypeUtilities.getPreviousBlockType(currentProgram, minAddr);
switch (previousBlockType) {
case CODE:
if (b == 0xCC) {
return makeAlignment(listing, minAddr, monitor);
} else {
return makeCode(currentProgram, listing, minAddr, monitor);
if (byteLookAhead == 0xCC) {
return makeX86Alignment(listing, range, monitor);
}
else if (wordLookAhead == 0) {
return makeX86Alignment(listing, range, monitor);
}
else {
// Make sure the previous block did not end with a disassembly
// failure. If it did, we probably do not want to make more code at
// that location.
Bookmark[] bookmarks = bookmarkManager.getBookmarks(minAddr);

boolean hasDisassemblyError = Arrays.stream(bookmarks)
.anyMatch(bookmark -> bookmark.getCategory().equals("Bad Instruction") && bookmark.getTypeString().equals("Error"));

if (hasDisassemblyError) {
debug(this, "Disassembly error at " + minAddr + "; making alignment instead of code.");
return makeX86Alignment(listing, range, monitor);
}
else {
return makeCode(currentProgram, listing, minAddr, monitor);
}
}
case DATA:
if (b == 0x00)
return makeAlignment(listing, minAddr, monitor);
// If there's a reference to this address, it is probably NOT alignment!
if (byteLookAhead == 0)
return makeX86Alignment(listing, range, monitor);
break;
case ALIGNMENT:
debug(this, "I'm a little surprised to find alignment at " + minAddr);
Expand All @@ -107,8 +178,6 @@ public Pair<AddressRange, Integer> analyzeGap(final AddressRange range) {
}

debug(this, "Skipping address: " + minAddr);
//skippedAddresses.add(minAddr);
//return 0;
return new Pair<AddressRange, Integer>(range, 0);
}

Expand Down
Loading

0 comments on commit 76a12cc

Please sign in to comment.