GP-3952 Updated the script categories to simplify and reduce the number of folders.

This commit is contained in:
ghidra_blue
2025-06-13 15:00:15 +00:00
parent 7772d98143
commit 7db176b2bd
82 changed files with 885 additions and 981 deletions
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
//Annotates an HFS+ attributes b-Tree file.
//@category iOS
//@category Apple.iOS
import ghidra.app.script.GhidraScript;
import ghidra.app.util.bin.*;
@@ -180,7 +180,8 @@ public class BTreeAnnotationScript extends GhidraScript {
return data;
}
private Data createBTreeHeaderRecord(Program program, BTreeHeaderRecord headerRecord, int offset)
private Data createBTreeHeaderRecord(Program program, BTreeHeaderRecord headerRecord,
int offset)
throws Exception {
Address address = toAddr(offset);
DataType dataType = headerRecord.toDataType();
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,7 +15,7 @@
*/
//This script cleans up the disassembly for kext files by locating "Bad Instruction" bookmarks caused by incorrectly defined data in valid code flows.
//@author
//@category iOS
//@category Apple.iOS
//@keybinding
//@menupath
//@toolbar
@@ -56,7 +56,7 @@ public class BadInstructionCleanup extends GhidraScript {
}
}
public void cleanup(Address ba) throws Exception {
public void cleanup(Address ba) throws Exception {
Program p = currentProgram;
BookmarkManager bmgr = p.getBookmarkManager();
@@ -79,8 +79,9 @@ public void cleanup(Address ba) throws Exception {
Address paddr = listing.getInstructionBefore(ba).getAddress();
RegisterValue rv;
if (paddr != null) {
rv = p.getProgramContext().getRegisterValue(contextReg,
paddr);
rv = p.getProgramContext()
.getRegisterValue(contextReg,
paddr);
p.getProgramContext().setRegisterValue(ba, ba_end, rv);
}
}
@@ -89,13 +90,14 @@ public void cleanup(Address ba) throws Exception {
Function f = getFunctionBefore(ba);
if (f != null) {
CreateFunctionCmd cf = new CreateFunctionCmd(f.getName(), f
.getEntryPoint(), null, f.getSymbol().getSource(),
true, true);
.getEntryPoint(),
null, f.getSymbol().getSource(),
true, true);
cf.applyTo(p);
}
bmgr.removeBookmark(bm);
bmgr.setBookmark(ba, "Analysis", "Cleanup",
"Converted invalid pointer to code");
"Converted invalid pointer to code");
}
}
}
@@ -4,16 +4,16 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//@category iOS
//@category Apple.iOS
import java.util.ArrayList;
import java.util.List;
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
//Processes Mach-O BIND information.
//@category Mac OS X
//@category Apple.Mac OS X
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -35,28 +35,29 @@ public class MachoProcessBindScript extends GhidraScript {
@Override
public void run() throws Exception {
File file = new File( currentProgram.getExecutablePath() );
if ( !file.exists() ) {
file = askFile( "Please select original file used to import this program:", "Original File" );
File file = new File(currentProgram.getExecutablePath());
if (!file.exists()) {
file = askFile("Please select original file used to import this program:",
"Original File");
}
if (file == null) {
popup("File cannot be null");
return;
}
if ( !file.exists() ) {
popup( "Cannot find original binary at \n" + file.getAbsolutePath() );
if (!file.exists()) {
popup("Cannot find original binary at \n" + file.getAbsolutePath());
return;
}
ByteProvider provider = new RandomAccessByteProvider( file ) ;
ByteProvider provider = new RandomAccessByteProvider(file);
try {
MachHeader header = new MachHeader(provider);
header.parse();
List<DyldInfoCommand> commands = header.getLoadCommands( DyldInfoCommand.class );
for ( DyldInfoCommand command : commands ) {
if ( monitor.isCancelled() ) {
List<DyldInfoCommand> commands = header.getLoadCommands(DyldInfoCommand.class);
for (DyldInfoCommand command : commands) {
if (monitor.isCancelled()) {
break;
}
processCommand( header, provider, command );
processCommand(header, provider, command);
}
}
finally {
@@ -64,37 +65,39 @@ public class MachoProcessBindScript extends GhidraScript {
}
}
private void processCommand( MachHeader header, ByteProvider provider, DyldInfoCommand command ) throws Exception {
private void processCommand(MachHeader header, ByteProvider provider, DyldInfoCommand command)
throws Exception {
BindState bind = new BindState();
bind.header = header;
try {
boolean done = false;
byte [] commandBytes = provider.readBytes( command.getBindOffset(), command.getBindSize() );
ByteArrayInputStream byteServer = new ByteArrayInputStream( commandBytes );
while ( !done ) {
byte[] commandBytes =
provider.readBytes(command.getBindOffset(), command.getBindSize());
ByteArrayInputStream byteServer = new ByteArrayInputStream(commandBytes);
if ( monitor.isCancelled() ) {
while (!done) {
if (monitor.isCancelled()) {
break;
}
int value = byteServer.read();
if ( value == -1 ) {
if (value == -1) {
break;
}
byte b = (byte) value;
int opcode = b & DyldInfoCommandConstants.BIND_OPCODE_MASK;
int opcode = b & DyldInfoCommandConstants.BIND_OPCODE_MASK;
int immediate = b & DyldInfoCommandConstants.BIND_IMMEDIATE_MASK;
switch ( opcode ) {
switch (opcode) {
case DyldInfoCommandConstants.BIND_OPCODE_ADD_ADDR_ULEB: {
bind.segmentOffset += uleb128( byteServer );
bind.segmentOffset += uleb128(byteServer);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_DO_BIND: {
@@ -104,18 +107,20 @@ public class MachoProcessBindScript extends GhidraScript {
}
case DyldInfoCommandConstants.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: {
bind.doBind();
bind.segmentOffset += ( immediate * currentProgram.getDefaultPointerSize() ) + currentProgram.getDefaultPointerSize();
bind.segmentOffset += (immediate * currentProgram.getDefaultPointerSize()) +
currentProgram.getDefaultPointerSize();
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: {
bind.doBind();
bind.segmentOffset += uleb128( byteServer ) + currentProgram.getDefaultPointerSize();
bind.segmentOffset +=
uleb128(byteServer) + currentProgram.getDefaultPointerSize();
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
long count = uleb128( byteServer );
long skip = uleb128( byteServer );
for ( int i = 0 ; i < count ; ++i ) {
long count = uleb128(byteServer);
long skip = uleb128(byteServer);
for (int i = 0; i < count; ++i) {
bind.doBind();
bind.segmentOffset += skip + currentProgram.getDefaultPointerSize();
}
@@ -126,41 +131,43 @@ public class MachoProcessBindScript extends GhidraScript {
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_ADDEND_SLEB: {
bind.addend = sleb128( byteServer );
bind.addend = sleb128(byteServer);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: {
bind.libraryOrdinal = immediate;
bind.fromDylib = getOrdinalName( bind );
bind.fromDylib = getOrdinalName(bind);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: {
bind.libraryOrdinal = (int) uleb128( byteServer );
bind.fromDylib = getOrdinalName( bind );
bind.libraryOrdinal = (int) uleb128(byteServer);
bind.fromDylib = getOrdinalName(bind);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: {
//the special ordinals are negative numbers
if ( immediate == 0 ) {
if (immediate == 0) {
bind.libraryOrdinal = 0;
}
else {
byte signExtended = (byte) ( DyldInfoCommandConstants.BIND_OPCODE_MASK | immediate );
byte signExtended =
(byte) (DyldInfoCommandConstants.BIND_OPCODE_MASK | immediate);
bind.libraryOrdinal = signExtended;
}
bind.fromDylib = getOrdinalName( bind );
bind.fromDylib = getOrdinalName(bind);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: {
bind.segmentIndex = immediate;
bind.segmentStartAddress = getSegmentStartAddress( bind );
bind.segmentName = getSegmentName( bind );
bind.segmentOffset = uleb128( byteServer );
bind.segmentStartAddress = getSegmentStartAddress(bind);
bind.segmentName = getSegmentName(bind);
bind.segmentOffset = uleb128(byteServer);
break;
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: {
bind.symbolName = readString( byteServer );
if ( ( immediate & DyldInfoCommandConstants.BIND_SYMBOL_FLAGS_WEAK_IMPORT ) != 0 ) {
bind.symbolName = readString(byteServer);
if ((immediate &
DyldInfoCommandConstants.BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) {
bind.weak = true;
}
else {
@@ -170,51 +177,51 @@ public class MachoProcessBindScript extends GhidraScript {
}
case DyldInfoCommandConstants.BIND_OPCODE_SET_TYPE_IMM: {
bind.type = immediate;
bind.typeName = getTypeName( bind );
bind.typeName = getTypeName(bind);
break;
}
default: {
popup( "unknown bind opcode " + Integer.toHexString( opcode ) );
popup("unknown bind opcode " + Integer.toHexString(opcode));
return;
}
}
}
}
finally {
}
}
}
private String readString( ByteArrayInputStream byteServer ) {
private String readString(ByteArrayInputStream byteServer) {
StringBuffer buffer = new StringBuffer();
while ( !monitor.isCancelled() ) {
while (!monitor.isCancelled()) {
int value = byteServer.read();
if ( value == -1 ) {
if (value == -1) {
break;
}
byte b = (byte) value;
if ( b == '\0' ) {
if (b == '\0') {
break;
}
buffer.append( (char) ( b & 0xff ) );
buffer.append((char) (b & 0xff));
}
System.out.println( buffer.toString() );
System.out.println(buffer.toString());
return buffer.toString();
}
private long getSegmentStartAddress( BindState bind ) {
List<SegmentCommand> segments = bind.header.getLoadCommands( SegmentCommand.class );
SegmentCommand segment = segments.get( bind.segmentIndex );
private long getSegmentStartAddress(BindState bind) {
List<SegmentCommand> segments = bind.header.getLoadCommands(SegmentCommand.class);
SegmentCommand segment = segments.get(bind.segmentIndex);
return segment.getVMaddress();
}
private String getSegmentName( BindState bind ) {
List<SegmentCommand> segments = bind.header.getLoadCommands( SegmentCommand.class );
SegmentCommand segment = segments.get( bind.segmentIndex );
private String getSegmentName(BindState bind) {
List<SegmentCommand> segments = bind.header.getLoadCommands(SegmentCommand.class);
SegmentCommand segment = segments.get(bind.segmentIndex);
return segment.getSegmentName();
}
private String getTypeName( BindState bind ) {
switch ( bind.type ) {
private String getTypeName(BindState bind) {
switch (bind.type) {
case DyldInfoCommandConstants.BIND_TYPE_POINTER: {
return "pointer";
}
@@ -225,11 +232,11 @@ public class MachoProcessBindScript extends GhidraScript {
return "text_pcrel32";
}
}
throw new RuntimeException( "unknown type: " + Integer.toHexString( bind.type ) );
throw new RuntimeException("unknown type: " + Integer.toHexString(bind.type));
}
private String getOrdinalName( BindState bind ) {
switch ( bind.libraryOrdinal ) {
private String getOrdinalName(BindState bind) {
switch (bind.libraryOrdinal) {
case DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_SELF: {
return "this-image";
}
@@ -240,14 +247,15 @@ public class MachoProcessBindScript extends GhidraScript {
return "flat-namespace";
}
}
if ( bind.libraryOrdinal < DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_FLAT_LOOKUP ) {
return "unknown special ordinal" + Integer.toHexString( bind.libraryOrdinal );
if (bind.libraryOrdinal < DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_FLAT_LOOKUP) {
return "unknown special ordinal" + Integer.toHexString(bind.libraryOrdinal);
}
List<DynamicLibraryCommand> dylibCommands = bind.header.getLoadCommands( DynamicLibraryCommand.class );
if ( bind.libraryOrdinal > dylibCommands.size() ) {
return "library ordinal out of range" + Integer.toHexString( bind.libraryOrdinal );
List<DynamicLibraryCommand> dylibCommands =
bind.header.getLoadCommands(DynamicLibraryCommand.class);
if (bind.libraryOrdinal > dylibCommands.size()) {
return "library ordinal out of range" + Integer.toHexString(bind.libraryOrdinal);
}
DynamicLibraryCommand dylibCommand = dylibCommands.get( bind.libraryOrdinal - 1 );
DynamicLibraryCommand dylibCommand = dylibCommands.get(bind.libraryOrdinal - 1);
DynamicLibrary dynamicLibrary = dylibCommand.getDynamicLibrary();
LoadCommandString name = dynamicLibrary.getName();
return name.getString();
@@ -256,15 +264,15 @@ public class MachoProcessBindScript extends GhidraScript {
/**
* Unsigned Little-endian Base-128
*/
private long uleb128( ByteArrayInputStream byteServer ) throws Exception {
private long uleb128(ByteArrayInputStream byteServer) throws Exception {
long result = 0;
int bit = 0;
int bit = 0;
while ( !monitor.isCancelled() ) {
while (!monitor.isCancelled()) {
int value = byteServer.read();
if ( value == -1 ) {
if (value == -1) {
break;
}
@@ -272,16 +280,16 @@ public class MachoProcessBindScript extends GhidraScript {
long slice = b & 0x7f;
if ( ( b & 0x80 ) == 0x80 ) {//if upper bit is set
if ( bit >= 64 || slice << bit >> bit != slice ) {//then left shift and right shift
throw new RuntimeException( "uleb128 too big" );
if ((b & 0x80) == 0x80) {//if upper bit is set
if (bit >= 64 || slice << bit >> bit != slice) {//then left shift and right shift
throw new RuntimeException("uleb128 too big");
}
}
result |= ( slice << bit );
result |= (slice << bit);
bit += 7;
if ( ( b & 0x80 ) == 0 ) {//if upper bit NOT set, then we are done
if ((b & 0x80) == 0) {//if upper bit NOT set, then we are done
break;
}
}
@@ -291,23 +299,23 @@ public class MachoProcessBindScript extends GhidraScript {
/**
* Signed Little-endian Base-128
*/
private long sleb128( ByteArrayInputStream byteServer ) throws Exception {
private long sleb128(ByteArrayInputStream byteServer) throws Exception {
long result = 0;
int bit = 0;
while ( !monitor.isCancelled() ) {
int bit = 0;
while (!monitor.isCancelled()) {
int value = byteServer.read();
if ( value == -1 ) {
if (value == -1) {
break;
}
byte nextByte = (byte) value;
result |= ( ( nextByte & 0x7f ) << bit );
result |= ((nextByte & 0x7f) << bit);
bit += 7;
if ( ( nextByte & 0x80 ) == 0 ) {
if ((nextByte & 0x80) == 0) {
break;
}
}
@@ -339,51 +347,51 @@ public class MachoProcessBindScript extends GhidraScript {
String sectionName = "no section";
List<Section> sections = header.getAllSections();
for ( Section section : sections ) {
for (Section section : sections) {
long start = section.getAddress();
long end = section.getAddress() + section.getSize();
if ( sectionAddress.getOffset() >= start && sectionAddress.getOffset() < end ) {
long end = section.getAddress() + section.getSize();
if (sectionAddress.getOffset() >= start && sectionAddress.getOffset() < end) {
sectionName = section.getSectionName();
}
}
File file = new File( fromDylib );
File file = new File(fromDylib);
StringBuffer buffer = new StringBuffer();
buffer.append( segmentName );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append(segmentName);
buffer.append(' ');
buffer.append(' ');
buffer.append(StringUtilities.pad(sectionName, ' ', -20));
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append( sectionAddress );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append( typeName );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append( weak );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append( addend );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append(' ');
buffer.append(' ');
buffer.append(sectionAddress);
buffer.append(' ');
buffer.append(' ');
buffer.append(typeName);
buffer.append(' ');
buffer.append(' ');
buffer.append(weak);
buffer.append(' ');
buffer.append(' ');
buffer.append(addend);
buffer.append(' ');
buffer.append(' ');
buffer.append(StringUtilities.pad(file.getName(), ' ', -20));
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append( symbolName );
buffer.append( ' ' );
buffer.append( ' ' );
buffer.append(' ');
buffer.append(' ');
buffer.append(symbolName);
buffer.append(' ');
buffer.append(' ');
return buffer.toString();
}
void doBind() throws Exception {
monitor.setMessage( "Performing bind: " + symbolName );
monitor.setMessage("Performing bind: " + symbolName);
SymbolIterator symbolIterator = currentProgram.getSymbolTable().getSymbols( symbolName );
SymbolIterator symbolIterator = currentProgram.getSymbolTable().getSymbols(symbolName);
if ( !symbolIterator.hasNext() ) {
printerr( "Not found: " + symbolName );
if (!symbolIterator.hasNext()) {
printerr("Not found: " + symbolName);
return;
}
@@ -391,22 +399,25 @@ public class MachoProcessBindScript extends GhidraScript {
long offset = symbol.getAddress().getOffset();
DataConverter converter = DataConverter.getInstance(currentProgram.getLanguage().isBigEndian());
DataConverter converter =
DataConverter.getInstance(currentProgram.getLanguage().isBigEndian());
if ( currentProgram.getDefaultPointerSize() == 8 ) {
setBytes( getAddress(), converter.getBytes( offset ) );
if (currentProgram.getDefaultPointerSize() == 8) {
setBytes(getAddress(), converter.getBytes(offset));
}
else {
setBytes( getAddress(), converter.getBytes( (int)offset ) );
setBytes(getAddress(), converter.getBytes((int) offset));
}
Reference reference = currentProgram.getReferenceManager().addMemoryReference( getAddress(), symbol.getAddress(), RefType.READ, SourceType.IMPORTED, 0 );
currentProgram.getReferenceManager().setPrimary( reference, true );
Reference reference = currentProgram.getReferenceManager()
.addMemoryReference(getAddress(), symbol.getAddress(), RefType.READ,
SourceType.IMPORTED, 0);
currentProgram.getReferenceManager().setPrimary(reference, true);
}
Address getAddress() {
long result = segmentStartAddress + segmentOffset;//TODO
Address sectionAddress = toAddr( result & 0xffffffffL );
Address sectionAddress = toAddr(result & 0xffffffffL);
return sectionAddress;
}
}
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
//Pulls symbol name through pointer references.
//@category Mac OS X
//@category Apple.Mac OS X
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
@@ -97,8 +97,9 @@ public class PointerPullerScript extends GhidraScript {
}
Namespace nameSpace = getNamespace(null, nameSpaceName);
if (nameSpace == null) {
nameSpace = currentProgram.getSymbolTable().createNameSpace(null, nameSpaceName,
SourceType.ANALYSIS);
nameSpace = currentProgram.getSymbolTable()
.createNameSpace(null, nameSpaceName,
SourceType.ANALYSIS);
}
return nameSpace;
}
@@ -1,20 +1,19 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//@category References
//@category
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
@@ -23,31 +22,31 @@ import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.symbol.*;
public class RemoveAllOffcutReferencesScript extends GhidraScript {
@Override
public void run() throws Exception {
Listing listing = currentProgram.getListing();
ReferenceManager referenceManager = currentProgram.getReferenceManager();
AddressIterator iterator = referenceManager.getReferenceDestinationIterator(currentProgram.getMinAddress(), true);
AddressIterator iterator =
referenceManager.getReferenceDestinationIterator(currentProgram.getMinAddress(), true);
while (iterator.hasNext()) {
if (monitor.isCancelled()) {
break;
}
Address address = iterator.next();
CodeUnit codeUnit = listing.getCodeUnitContaining(address);
if (codeUnit != null) {
if (!codeUnit.getMinAddress().equals(address)) {
monitor.setMessage("Removing offcut reference at "+address);
ReferenceIterator referencesTo = referenceManager.getReferencesTo(address);
while (referencesTo.hasNext()) {
if (monitor.isCancelled()) {
break;
}
Reference reference = referencesTo.next();
referenceManager.delete(reference);
}
Address address = iterator.next();
CodeUnit codeUnit = listing.getCodeUnitContaining(address);
if (codeUnit != null) {
if (!codeUnit.getMinAddress().equals(address)) {
monitor.setMessage("Removing offcut reference at " + address);
ReferenceIterator referencesTo = referenceManager.getReferencesTo(address);
while (referencesTo.hasNext()) {
if (monitor.isCancelled()) {
break;
}
Reference reference = referencesTo.next();
referenceManager.delete(reference);
}
}
}
}
@@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,7 +14,7 @@
* limitations under the License.
*/
//Removes any offcut references to the current code unit.
//@category References
//@category
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
@@ -29,38 +28,38 @@ public class RemoveOffcutReferenceToCurrentInstructionScript extends GhidraScrip
Instruction instruction = getInstructionAt(currentAddress);
if ( instruction != null ) {
removeReferences( instruction );
if (instruction != null) {
removeReferences(instruction);
}
Data data = getDataAt(currentAddress);
if ( data != null ) {
removeReferences( data );
if (data != null) {
removeReferences(data);
}
}
private void removeReferences(CodeUnit codeUnit) {
Address address = currentAddress.add( 1 );
Address address = currentAddress.add(1);
while ( address.compareTo( codeUnit.getMaxAddress() ) <= 0) {
while (address.compareTo(codeUnit.getMaxAddress()) <= 0) {
if ( monitor.isCancelled() ) {
if (monitor.isCancelled()) {
break;
}
Reference [] referencesTo = getReferencesTo(address);
Reference[] referencesTo = getReferencesTo(address);
for ( Reference reference : referencesTo ) {
for (Reference reference : referencesTo) {
if ( monitor.isCancelled() ) {
if (monitor.isCancelled()) {
break;
}
removeReference(reference);
}
address = address.add( 1 );
address = address.add(1);
}
}
}
@@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,7 +15,7 @@
*/
//Resolves relative references computed off EBX.
//This will resolve references to strings in the "__cstring" section.
//@category Mac OS X
//@category Apple.Mac OS X
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
@@ -38,19 +37,19 @@ public class ResolveReferencesRelativeToEbxScript extends GhidraScript {
FunctionIterator functions = currentProgram.getListing().getFunctions(true);
while ( functions.hasNext() ) {
while (functions.hasNext()) {
if ( monitor.isCancelled() ) {
if (monitor.isCancelled()) {
break;
}
Function function = functions.next();
monitor.setMessage( function.getName() );
monitor.setMessage(function.getName());
loopOverInstructionsInFunction( function );
loopOverInstructionsInFunction(function);
function = getFunctionAfter( function );
function = getFunctionAfter(function);
}
}
@@ -59,49 +58,53 @@ public class ResolveReferencesRelativeToEbxScript extends GhidraScript {
long ebx = -1;
InstructionIterator instructions = currentProgram.getListing().getInstructions( function.getBody(), true ) ;
InstructionIterator instructions =
currentProgram.getListing().getInstructions(function.getBody(), true);
while ( instructions.hasNext() ) {
while (instructions.hasNext()) {
Instruction instruction = instructions.next();
if ( monitor.isCancelled() ) {
if (monitor.isCancelled()) {
break;
}
if ( ebx == -1 ) {
ebx = getValueForEBX( instruction );
if (ebx == -1) {
ebx = getValueForEBX(instruction);
}
if ( ebx == -1 ) {
if (ebx == -1) {
continue;
}
for (int i = 0 ; i < instruction.getNumOperands() ; ++i ) {
for (int i = 0; i < instruction.getNumOperands(); ++i) {
Object [] opObjects = instruction.getOpObjects(i);
Object[] opObjects = instruction.getOpObjects(i);
if ( opObjects.length == 2 ) {
if (opObjects.length == 2) {
if (opObjects[ 0 ] instanceof Scalar && opObjects[ 1 ] instanceof Register ) {
if (opObjects[0] instanceof Scalar && opObjects[1] instanceof Register) {
Scalar scalar = (Scalar) opObjects[ 0 ];
Scalar scalar = (Scalar) opObjects[0];
Register register = (Register) opObjects[ 1 ];
Register register = (Register) opObjects[1];
if ( register.equals( EBX ) ) {
if (register.equals(EBX)) {
Address address = toAddr( (ebx + scalar.getUnsignedValue()) & Conv.INT_MASK );
Address address =
toAddr((ebx + scalar.getUnsignedValue()) & Conv.INT_MASK);
if ( isValid( address ) ) {
if (isValid(address)) {
removeReferencesFrom(instruction);
Reference reference = createMemoryReference( instruction, 1, address, RefType.DATA );
Reference reference =
createMemoryReference(instruction, 1, address, RefType.DATA);
setReferencePrimary( reference );
setReferencePrimary(reference);
println( "Creating reference from " + instruction.getMinAddress() + " to " + address );
println("Creating reference from " + instruction.getMinAddress() +
" to " + address);
}
}
}
@@ -112,43 +115,43 @@ public class ResolveReferencesRelativeToEbxScript extends GhidraScript {
private boolean isValid(Address address) {
Instruction instruction = getInstructionContaining( address );
if ( instruction != null ) {
Instruction instruction = getInstructionContaining(address);
if (instruction != null) {
Address min = instruction.getMinAddress();
if ( address.compareTo( min ) > 0 ) {
if (address.compareTo(min) > 0) {
return false; //off-cut
}
}
Data data = getDataContaining( address );
if ( data != null ) {
Data data = getDataContaining(address);
if (data != null) {
Address min = data.getMinAddress();
if ( address.compareTo( min ) > 0 ) {
if (address.compareTo(min) > 0) {
return false; //off-cut
}
}
return currentProgram.getMemory().contains( address );
return currentProgram.getMemory().contains(address);
}
private void removeReferencesFrom(Instruction instruction) {
Reference [] referencesFrom = instruction.getReferencesFrom();
Reference[] referencesFrom = instruction.getReferencesFrom();
for (Reference reference : referencesFrom) {
removeReference( reference );
removeReference(reference);
}
}
private long getValueForEBX(Instruction instruction) {
if ( instruction.getMnemonicString().equals( "CALL" ) ) {
if (instruction.getMnemonicString().equals("CALL")) {
Address nextInstructionAddress = instruction.getMaxAddress().add( 1 );
Address nextInstructionAddress = instruction.getMaxAddress().add(1);
Reference [] referencesFrom = instruction.getReferencesFrom();
Reference[] referencesFrom = instruction.getReferencesFrom();
if ( referencesFrom.length == 1) {
if (referencesFrom.length == 1) {
if ( referencesFrom[0].getToAddress().equals( nextInstructionAddress ) ) {
if (referencesFrom[0].getToAddress().equals(nextInstructionAddress)) {
return nextInstructionAddress.getOffset();
}
@@ -1,152 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//Upgrade DEX program(s) that have function prototypes layed down prior to Ghidra 7.1
//@category Upgrade
import java.util.Map;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.script.GhidraScript;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.FunctionDefinitionDataType;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.*;
/**
* There was a major rearrangement of registers in the Dalvik.slaspec from 7.0 -> 7.1 which invalidates function prototypes
* laid down by "Android DEX Header Format" analyzer. This script repairs the prototypes to match the new register layout
* If run with a Program already up, the script will make all the changes, letting the user decide if they want to
* save (or undo) the changes. If the script is run from an empty code browser, it will search for all Dalvik programs
* in the current project and automatically upgrade and save the function prototypes.
*
*/
public class UpgradeDexToGhidra71Script extends GhidraScript {
@Override
public void run() throws Exception {
if ( currentProgram != null ) {
processProgram(currentProgram);
return;
}
PluginTool tool = state.getTool();
Project project = tool.getProject();
ProjectData projectData = project.getProjectData();
DomainFolder rootFolder = projectData.getRootFolder();
recurseProjectFolder( rootFolder );
}
private void recurseProjectFolder( DomainFolder domainFolder ) throws Exception {
DomainFile[] files = domainFolder.getFiles();
for ( DomainFile domainFile : files ) {
monitor.checkCancelled();
try {
processDomainFile( domainFile );
} catch(Exception ex) {
printerr(ex.getMessage());
}
}
DomainFolder[] folders = domainFolder.getFolders();
for ( DomainFolder folder : folders ) {
monitor.checkCancelled();
recurseProjectFolder( folder );
}
}
private void processDomainFile(DomainFile domainFile ) throws Exception {
Map<String, String> metadata = domainFile.getMetadata();
if (metadata == null) {
return;
}
String formatString = metadata.get("Executable Format");
if (formatString == null) {
return;
}
if (!formatString.equals("Dalvik Executable (DEX)")) {
return;
}
DomainObject domainObject = domainFile.getDomainObject(this, true, true, monitor);
try {
Program program = (Program) domainObject;
processProgram(program);
saveProgram(program);
} finally {
domainObject.release(this);
}
}
private void processProgram(Program program) throws CancelledException {
println("Updating program: "+program.getName());
int id = program.startTransaction("Update DEX parameters");
boolean success = false;
try {
for (Function func : program.getFunctionManager().getFunctions(true)) {
monitor.checkCancelled();
processFunction(func);
}
success = true;
} finally {
program.endTransaction(id, success);
}
}
private void processFunction(Function func) {
monitor.setMessage("Updating: "+func.getName());
FunctionDefinitionDataType sig = new FunctionDefinitionDataType(func,false);
try {
sig.setCallingConvention(CompilerSpec.CALLING_CONVENTION_stdcall);
}
catch (InvalidInputException e) {
throw new AssertException(e);
}
func.setCustomVariableStorage(false);
ApplyFunctionSignatureCmd cmd = new ApplyFunctionSignatureCmd(func.getEntryPoint(),sig,SourceType.ANALYSIS);
cmd.applyTo(func.getProgram());
Program program = func.getProgram();
Language language = program.getLanguage();
AddressSpace registerSpace = program.getAddressFactory().getRegisterSpace();
Variable[] localVariables = func.getLocalVariables();
for (Variable var : localVariables) {
Varnode varnode = var.getFirstStorageVarnode();
if (!varnode.isRegister()) {
continue;
}
if (varnode.getOffset() >= 0x1000)
{
continue; // Already converted
}
long offset = varnode.getOffset() + 0x1000 - 8;
int size = varnode.getSize();
Register localRegister = language.getRegister(registerSpace, offset, size);
try {
LocalVariableImpl newlocal = new LocalVariableImpl( var.getName(), 0, var.getDataType(), localRegister, func.getProgram() );
func.removeVariable(var);
func.addLocalVariable(newlocal, SourceType.ANALYSIS);
} catch (InvalidInputException e) {
} catch (DuplicateNameException e) {
}
}
}
}