From bb457b9a6a0a48881027577fbf3f35ed72bc98f9 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 29 Mar 2023 23:20:19 +0000 Subject: [PATCH] GP-3270 improve AIFF embedded media search Don't trigger on 'FORM....AIFF' pattern unless it has a valid size value. Add AIFC since its the same thing with slightly different magic bytes. --- .../core/analysis/EmbeddedMediaAnalyzer.java | 5 +- .../program/model/data/AIFFDataType.java | 62 +++++++++++++++---- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/EmbeddedMediaAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/EmbeddedMediaAnalyzer.java index 27c3157d1b..141404a300 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/EmbeddedMediaAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/EmbeddedMediaAnalyzer.java @@ -85,7 +85,10 @@ public class EmbeddedMediaAnalyzer extends AbstractAnalyzer { AUDataType.MAGIC, AUDataType.MAGIC_MASK); addByteSearchPattern(searcher, program, foundMedia, new AIFFDataType(), "AIFF", - AIFFDataType.MAGIC, AIFFDataType.MAGIC_MASK); + AIFFDataType.MAGIC_AIFF, AIFFDataType.MAGIC_MASK); + + addByteSearchPattern(searcher, program, foundMedia, new AIFFDataType(), "AIFC", + AIFFDataType.MAGIC_AIFC, AIFFDataType.MAGIC_MASK); searcher.search(program, searchSet, monitor); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java index 586bca85c3..9088cfbc40 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java @@ -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. @@ -20,15 +20,45 @@ import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; import ghidra.util.Msg; +/** + * AIFF / AIFC header format: + *
+ * struct {
+ * int32 ckID; 'FORM'
+ * int32 ckDataSize;
+ * int32 formType; 'AIFF', 'AIFC'
+ * -variable length chunk data-
+ * }
+ *
+ *
+ */
public class AIFFDataType extends BuiltIn implements Dynamic {
- //first four bytes must = FORM then skip four then next four must = AIFF
- public static byte[] MAGIC =
- new byte[] { (byte) 'F', (byte) 'O', (byte) 'R', (byte) 'M', (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 'A', (byte) 'I', (byte) 'F', (byte) 'F' };
+ /**
+ * Magic bytes for 'AIFF' audio file header
+ */
+ public static byte[] MAGIC_AIFF =
+ new byte[] {
+ (byte) 'F', (byte) 'O', (byte) 'R', (byte) 'M',
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 'A', (byte) 'I', (byte) 'F', (byte) 'F' };
+ /**
+ * Magic bytes for 'AIFC' audio file header (almost same as AIFF)
+ */
+ public static byte[] MAGIC_AIFC =
+ new byte[] {
+ (byte) 'F', (byte) 'O', (byte) 'R', (byte) 'M',
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 'A', (byte) 'I', (byte) 'F', (byte) 'C' };
+
+ /**
+ * Byte search mask for magic bytes
+ */
public static byte[] MAGIC_MASK =
- new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+ new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
public AIFFDataType() {
this(null);
@@ -46,11 +76,17 @@ public class AIFFDataType extends BuiltIn implements Dynamic {
@Override
public int getLength(MemBuffer buf, int maxLength) {
try {
- if (!checkMagic(buf)) {
+ if (!checkMagic(buf, MAGIC_AIFF) && !checkMagic(buf, MAGIC_AIFC)) {
return -1;
}
- return (buf.getInt(4) + 8);
+ int dataSize = buf.getInt(4);
+ if (dataSize <= 0) {
+ // check dataSize for validity. TODO: more strict with upper bounds
+ return -1;
+ }
+
+ return dataSize + 8;
}
catch (Exception e) {
Msg.debug(this, "Invalid AIFF data at " + buf.getAddress());
@@ -58,9 +94,9 @@ public class AIFFDataType extends BuiltIn implements Dynamic {
return -1;
}
- private boolean checkMagic(MemBuffer buf) throws MemoryAccessException {
- for (int i = 0; i < MAGIC.length; i++) {
- if (MAGIC[i] != (buf.getByte(i) & MAGIC_MASK[i])) {
+ private boolean checkMagic(MemBuffer buf, byte[] magicBytes) throws MemoryAccessException {
+ for (int i = 0; i < magicBytes.length; i++) {
+ if (magicBytes[i] != (buf.getByte(i) & MAGIC_MASK[i])) {
return false;
}
}