mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-2426: Refactor emulator to use trace access shims. Implement register mapping conventions.
This commit is contained in:
parent
975db1919c
commit
e4f18ad824
202 changed files with 8221 additions and 4199 deletions
|
@ -17,12 +17,11 @@ package ghidra.pcode.emu.taint;
|
|||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ReadsTargetMemoryPcodeExecutorStatePiece;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ReadsTargetRegistersPcodeExecutorStatePiece;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.RWTargetMemoryPcodeExecutorStatePiece;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.RWTargetRegistersPcodeExecutorStatePiece;
|
||||
import ghidra.pcode.emu.*;
|
||||
import ghidra.pcode.emu.DefaultPcodeThread.PcodeThreadExecutor;
|
||||
import ghidra.pcode.emu.auxiliary.AuxPcodeEmulator;
|
||||
import ghidra.pcode.emu.taint.full.TaintDebuggerPcodeExecutorState;
|
||||
import ghidra.pcode.emu.taint.plain.TaintPcodeExecutorState;
|
||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorState;
|
||||
import ghidra.pcode.exec.*;
|
||||
|
@ -56,7 +55,7 @@ import ghidra.taint.model.TaintVec;
|
|||
* <ul>
|
||||
* <li>Stand alone: {@link TaintPcodeExecutorState}</li>
|
||||
* <li>Trace integrated: {@link TaintTracePcodeExecutorState}</li>
|
||||
* <li>Debugger integrated: {@link TaintDebuggerPcodeExecutorState}</li>
|
||||
* <li>Debugger integrated: {@link TaintTracePcodeExecutorState} (same as Trace integrated)</li>
|
||||
* </ul>
|
||||
* </ul>
|
||||
*
|
||||
|
@ -101,8 +100,8 @@ public enum TaintPartsFactory implements AuxDebuggerEmulatorPartsFactory<TaintVe
|
|||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* We have no thread-specific userops to add, which means we also have no need to stubs, so here
|
||||
* we just return the empty library.
|
||||
* We have no thread-specific userops to add, which means we also have no need for stubs, so
|
||||
* here we just return the empty library.
|
||||
*/
|
||||
@Override
|
||||
public PcodeUseropLibrary<Pair<byte[], TaintVec>> createLocalUseropStub(
|
||||
|
@ -202,16 +201,17 @@ public enum TaintPartsFactory implements AuxDebuggerEmulatorPartsFactory<TaintVe
|
|||
* <p>
|
||||
* If you're following the {@link ghidra.taint} package documentation, please finish reading
|
||||
* about the stand-alone and trace-integrated emulators before proceeding to this
|
||||
* Debugger-integrated part. This part extends the shared state of the trace-integrated emulator
|
||||
* so that it can also deserialize taint sets from mapped static programs. Since taint is not
|
||||
* generally a concept understood by a live debugger, we need not retrieve anything (other than
|
||||
* concrete state) from the target.
|
||||
* Debugger-integrated part. This part uses the same shared state as the trace-integrated
|
||||
* emulator but takes a different data access shim, so that it can also deserialize taint sets
|
||||
* from mapped static programs. Since taint is not generally a concept understood by a live
|
||||
* debugger, we need not retrieve anything new from the target. Note that the shim is passed to
|
||||
* us implicitly via the {@code concrete} state.
|
||||
*/
|
||||
@Override
|
||||
public TracePcodeExecutorState<Pair<byte[], TaintVec>> createDebuggerSharedState(
|
||||
AuxDebuggerPcodeEmulator<TaintVec> emulator,
|
||||
ReadsTargetMemoryPcodeExecutorStatePiece concrete) {
|
||||
return new TaintDebuggerPcodeExecutorState(concrete);
|
||||
RWTargetMemoryPcodeExecutorStatePiece concrete) {
|
||||
return new TaintTracePcodeExecutorState(concrete);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -221,16 +221,16 @@ public enum TaintPartsFactory implements AuxDebuggerEmulatorPartsFactory<TaintVe
|
|||
* If you're following the {@link ghidra.taint} package documentation, please finish reading
|
||||
* about the stand-alone and trace-integrated emulators before proceeding to this method. Since
|
||||
* taint is not generally a concept understood by a live debugger, we need not retrieve anything
|
||||
* (other than concrete state) from the target. Furthermore, because static program mappings do
|
||||
* not apply to registers, we need not consider them. Thus, we can just re-use the
|
||||
* trace-integrated local state. The concrete piece given to us, which we just pass to our
|
||||
* paired state, will handle retrieving concrete values from the live target, if applicable.
|
||||
* new from the target. Furthermore, because static program mappings do not apply to registers,
|
||||
* we need not consider them. Thus, we can just re-use the trace-integrated local state. The
|
||||
* concrete piece given to us, which we just pass to our paired state, will handle retrieving
|
||||
* concrete values from the live target, if applicable.
|
||||
*/
|
||||
@Override
|
||||
public TracePcodeExecutorState<Pair<byte[], TaintVec>> createDebuggerLocalState(
|
||||
AuxDebuggerPcodeEmulator<TaintVec> emulator,
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread,
|
||||
ReadsTargetRegistersPcodeExecutorStatePiece concrete) {
|
||||
RWTargetRegistersPcodeExecutorStatePiece concrete) {
|
||||
return new TaintTracePcodeExecutorState(concrete);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,12 @@
|
|||
*/
|
||||
package ghidra.pcode.emu.taint.full;
|
||||
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.*;
|
||||
import ghidra.pcode.emu.taint.TaintPartsFactory;
|
||||
import ghidra.pcode.emu.taint.plain.TaintPcodeEmulator;
|
||||
import ghidra.pcode.exec.debug.auxiliary.AuxDebuggerEmulatorPartsFactory;
|
||||
import ghidra.pcode.exec.debug.auxiliary.AuxDebuggerPcodeEmulator;
|
||||
import ghidra.taint.model.TaintVec;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
/**
|
||||
* A Debugger-integrated emulator with taint analysis
|
||||
|
@ -31,14 +29,10 @@ public class TaintDebuggerPcodeEmulator extends AuxDebuggerPcodeEmulator<TaintVe
|
|||
/**
|
||||
* Create an emulator
|
||||
*
|
||||
* @param tool the tool creating the emulator
|
||||
* @param trace the source trace
|
||||
* @param snap the source snap
|
||||
* @param recorder if applicable, the recorder for the trace's live target
|
||||
* @param data the trace-and-debugger access shim
|
||||
*/
|
||||
public TaintDebuggerPcodeEmulator(PluginTool tool, Trace trace, long snap,
|
||||
TraceRecorder recorder) {
|
||||
super(tool, trace, snap, recorder);
|
||||
public TaintDebuggerPcodeEmulator(PcodeDebuggerAccess data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,9 +17,7 @@ package ghidra.pcode.emu.taint.full;
|
|||
|
||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerPcodeEmulatorFactory;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerPcodeMachine;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.data.PcodeDebuggerAccess;
|
||||
|
||||
/**
|
||||
* An emulator factory for making the {@link TaintDebuggerPcodeEmulator} discoverable to the UI
|
||||
|
@ -36,8 +34,7 @@ public class TaintDebuggerPcodeEmulatorFactory implements DebuggerPcodeEmulatorF
|
|||
}
|
||||
|
||||
@Override
|
||||
public DebuggerPcodeMachine<?> create(PluginTool tool, Trace trace, long snap,
|
||||
TraceRecorder recorder) {
|
||||
return new TaintDebuggerPcodeEmulator(tool, trace, snap, recorder);
|
||||
public DebuggerPcodeMachine<?> create(PcodeDebuggerAccess data) {
|
||||
return new TaintDebuggerPcodeEmulator(data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +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.
|
||||
*/
|
||||
package ghidra.pcode.emu.taint.full;
|
||||
|
||||
import ghidra.app.plugin.core.debug.service.emulation.ReadsTargetMemoryPcodeExecutorStatePiece;
|
||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorState;
|
||||
|
||||
/**
|
||||
* A paired concrete-plus-taint Debugger-integrated state
|
||||
*
|
||||
* <p>
|
||||
* This contains the emulator's machine state along with the taint markings, just like
|
||||
* {@link TaintTracePcodeExecutorState}, except that it can also read state from mapped static
|
||||
* programs. In reality, this just composes concrete and taint state pieces, which actually do all
|
||||
* the work.
|
||||
*/
|
||||
public class TaintDebuggerPcodeExecutorState extends TaintTracePcodeExecutorState {
|
||||
|
||||
/**
|
||||
* Create a state from the two given pieces
|
||||
*
|
||||
* @param concrete the concrete piece
|
||||
* @param the taint piece
|
||||
*/
|
||||
public TaintDebuggerPcodeExecutorState(ReadsTargetMemoryPcodeExecutorStatePiece concrete,
|
||||
TaintDebuggerPcodeExecutorStatePiece taint) {
|
||||
super(concrete, taint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a state from the given concrete piece and an internally constructed taint piece
|
||||
*
|
||||
* @param concrete the concrete piece
|
||||
*/
|
||||
public TaintDebuggerPcodeExecutorState(ReadsTargetMemoryPcodeExecutorStatePiece concrete) {
|
||||
super(concrete, new TaintDebuggerPcodeExecutorStatePiece(
|
||||
concrete.getTool(), concrete.getTrace(), concrete.getSnap(), concrete.getThread(),
|
||||
concrete.getFrame(), concrete.getRecorder()));
|
||||
}
|
||||
}
|
|
@ -1,87 +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.
|
||||
*/
|
||||
package ghidra.pcode.emu.taint.full;
|
||||
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.pcode.emu.taint.trace.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
/**
|
||||
* The Debugger-integrated state piece for holding taint marks
|
||||
*
|
||||
* <p>
|
||||
* Because we don't require a derivative of this class, it is not split into abstract and
|
||||
* non-abstract classes (like its super-classes were). This substitutes {@link TaintDebuggerSpace}
|
||||
* for {@link TaintTraceSpace} and introduces parameters for loading information from mapped static
|
||||
* programs. We take the recorder more as a matter of form, since we don't really need it.
|
||||
*/
|
||||
public class TaintDebuggerPcodeExecutorStatePiece
|
||||
extends AbstractTaintTracePcodeExecutorStatePiece<TaintDebuggerSpace> {
|
||||
|
||||
protected final PluginTool tool;
|
||||
protected final TraceRecorder recorder;
|
||||
|
||||
/**
|
||||
* Create the taint piece
|
||||
*
|
||||
* @param tool the tool that created the emulator
|
||||
* @param trace the trace from which to load taint marks
|
||||
* @param snap the snap from which to load taint marks
|
||||
* @param thread if a register space, the thread from which to load taint marks
|
||||
* @param frame if a register space, the frame
|
||||
* @param recorder if applicable, the recorder for the trace's live target
|
||||
*/
|
||||
public TaintDebuggerPcodeExecutorStatePiece(PluginTool tool, Trace trace, long snap,
|
||||
TraceThread thread, int frame, TraceRecorder recorder) {
|
||||
super(trace, snap, thread, frame);
|
||||
this.tool = tool;
|
||||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Here we create a map that uses {@link TaintDebuggerSpace}s. There is some repeated code with
|
||||
* {@link TaintTracePcodeExecutorStatePiece#newSpaceMap()}. We could factor that, but I thought
|
||||
* it a little pedantic.
|
||||
*/
|
||||
@Override
|
||||
protected AbstractSpaceMap<TaintDebuggerSpace> newSpaceMap() {
|
||||
return new CacheingSpaceMap<TracePropertyMapSpace<String>, TaintDebuggerSpace>() {
|
||||
@Override
|
||||
protected TracePropertyMapSpace<String> getBacking(AddressSpace space) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
if (space.isRegisterSpace()) {
|
||||
return map.getPropertyMapRegisterSpace(thread, frame, false);
|
||||
}
|
||||
return map.getPropertyMapSpace(space, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaintDebuggerSpace newSpace(AddressSpace space,
|
||||
TracePropertyMapSpace<String> backing) {
|
||||
return new TaintDebuggerSpace(tool, trace, space, backing, snap);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,90 +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.
|
||||
*/
|
||||
package ghidra.pcode.emu.taint.full;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorStatePiece;
|
||||
import ghidra.pcode.emu.taint.trace.TaintTraceSpace;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.util.StringPropertyMap;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.taint.model.TaintSet;
|
||||
import ghidra.trace.model.DefaultTraceLocation;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
|
||||
/**
|
||||
* The storage space for taint sets in a trace's address space
|
||||
*
|
||||
* <p>
|
||||
* This adds to {@link TaintTraceSpace} the ability to load taint sets from mapped static programs.
|
||||
*/
|
||||
public class TaintDebuggerSpace extends TaintTraceSpace {
|
||||
protected final PluginTool tool;
|
||||
protected final Trace trace;
|
||||
|
||||
/**
|
||||
* Create the space
|
||||
*
|
||||
* @param tool the the tool that created the emulator
|
||||
* @param trace the trace backing this space
|
||||
* @param space the address space
|
||||
* @param backing if present, the backing object
|
||||
* @param snap the source snap
|
||||
*/
|
||||
public TaintDebuggerSpace(PluginTool tool, Trace trace, AddressSpace space,
|
||||
TracePropertyMapSpace<String> backing, long snap) {
|
||||
super(space, backing, snap);
|
||||
this.tool = tool;
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The taint trace space will call this when the cache misses and the trace has no taint set
|
||||
* stored, allowing us to populate it with a taint set stored in a mapped static program. See
|
||||
* notes in {@link TaintTraceSpace#whenNull(long)}.
|
||||
*/
|
||||
@Override
|
||||
protected TaintSet whenTraceNull(long offset) {
|
||||
DebuggerStaticMappingService mappingService =
|
||||
tool.getService(DebuggerStaticMappingService.class);
|
||||
ProgramLocation sloc =
|
||||
mappingService.getOpenMappedLocation(new DefaultTraceLocation(trace, null,
|
||||
Range.singleton(snap), space.getAddress(offset)));
|
||||
if (sloc == null) {
|
||||
return super.whenTraceNull(offset);
|
||||
}
|
||||
|
||||
// NB. This is stored in the program, not the user data, despite what the name implies
|
||||
StringPropertyMap map = sloc.getProgram()
|
||||
.getUsrPropertyManager()
|
||||
.getStringPropertyMap(TaintTracePcodeExecutorStatePiece.NAME);
|
||||
if (map == null) {
|
||||
return super.whenTraceNull(offset);
|
||||
}
|
||||
String string = map.getString(sloc.getAddress());
|
||||
if (string == null) {
|
||||
return super.whenTraceNull(offset);
|
||||
}
|
||||
return TaintSet.parse(string);
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ public class TaintSpace {
|
|||
* This retrieves as many taint sets as there are elements in the given buffer vector. This first
|
||||
* element becomes the taint set at the given offset, then each subsequent element becomes the
|
||||
* taint set at each subsequent offset until the vector is filled. This is analogous to the
|
||||
* manner in which bytes would be "read" from concrete state, starting at a given ofset, into a
|
||||
* manner in which bytes would be "read" from concrete state, starting at a given offset, into a
|
||||
* destination array.
|
||||
*
|
||||
* @param offset the offset
|
||||
|
|
|
@ -1,102 +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.
|
||||
*/
|
||||
package ghidra.pcode.emu.taint.trace;
|
||||
|
||||
import ghidra.pcode.emu.taint.AbstractTaintPcodeExecutorStatePiece;
|
||||
import ghidra.pcode.emu.taint.TaintPcodeArithmetic;
|
||||
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
||||
import ghidra.pcode.exec.trace.TracePcodeExecutorStatePiece;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.taint.model.TaintVec;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
/**
|
||||
* An abstract trace-integrated state piece
|
||||
*
|
||||
* <p>
|
||||
* See {@link AbstractTaintTracePcodeExecutorStatePiece} for framing. This class must remain
|
||||
* abstract since we need to derive the Debugger-integrated state piece from it. Thus it tightens
|
||||
* the bound on {@code <S>} and introduces the parameters necessary to source state from a trace.
|
||||
* We'll store taint sets in the trace's address property map, which is the recommended scheme for
|
||||
* auxiliary state.
|
||||
*
|
||||
* @param <S> the type of spaces
|
||||
*/
|
||||
public abstract class AbstractTaintTracePcodeExecutorStatePiece<S extends TaintTraceSpace>
|
||||
extends AbstractTaintPcodeExecutorStatePiece<S>
|
||||
implements TracePcodeExecutorStatePiece<byte[], TaintVec> {
|
||||
public static final String NAME = "Taint";
|
||||
|
||||
protected final Trace trace;
|
||||
protected final long snap;
|
||||
protected final TraceThread thread;
|
||||
protected final int frame;
|
||||
protected final TracePropertyMap<String> map;
|
||||
|
||||
/**
|
||||
* Create a state piece
|
||||
*
|
||||
* @param language the emulator's language
|
||||
* @param trace the trace from which to load taint marks
|
||||
* @param snap the snap from which to load taint marks
|
||||
* @param thread if a register space, the thread from which to load taint marks
|
||||
* @param frame if a register space, the frame
|
||||
*/
|
||||
public AbstractTaintTracePcodeExecutorStatePiece(Language language, Trace trace, long snap,
|
||||
TraceThread thread, int frame) {
|
||||
super(language,
|
||||
BytesPcodeArithmetic.forLanguage(language),
|
||||
TaintPcodeArithmetic.forLanguage(language));
|
||||
this.trace = trace;
|
||||
this.snap = snap;
|
||||
this.thread = thread;
|
||||
this.frame = frame;
|
||||
|
||||
this.map = trace.getAddressPropertyManager().getPropertyMap(NAME, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a state piece
|
||||
*
|
||||
* @param trace the trace from which to load taint marks
|
||||
* @param snap the snap from which to load taint marks
|
||||
* @param thread if a register space, the thread from which to load taint marks
|
||||
* @param frame if applicable, the frame
|
||||
*/
|
||||
public AbstractTaintTracePcodeExecutorStatePiece(Trace trace, long snap, TraceThread thread,
|
||||
int frame) {
|
||||
this(trace.getBaseLanguage(), trace, snap, thread, frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This does the inverse of the lazy loading. Serialize the state and store it back into the
|
||||
* trace. Technically, it could be a different trace, but it must have identically-named
|
||||
* threads.
|
||||
*/
|
||||
@Override
|
||||
public void writeDown(Trace trace, long snap, TraceThread thread, int frame) {
|
||||
TracePropertyMap<String> map =
|
||||
trace.getAddressPropertyManager().getOrCreatePropertyMap(NAME, String.class);
|
||||
for (TaintTraceSpace space : spaceMap.values()) {
|
||||
space.writeDown(map, snap, thread, frame);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,8 +19,9 @@ import ghidra.pcode.emu.taint.TaintPartsFactory;
|
|||
import ghidra.pcode.emu.taint.plain.TaintPcodeEmulator;
|
||||
import ghidra.pcode.exec.trace.auxiliary.AuxTraceEmulatorPartsFactory;
|
||||
import ghidra.pcode.exec.trace.auxiliary.AuxTracePcodeEmulator;
|
||||
import ghidra.pcode.exec.trace.data.*;
|
||||
import ghidra.taint.model.TaintVec;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
|
||||
/**
|
||||
* A trace-integrated emulator with taint analysis
|
||||
|
@ -29,11 +30,20 @@ public class TaintTracePcodeEmulator extends AuxTracePcodeEmulator<TaintVec> {
|
|||
/**
|
||||
* Create an emulator
|
||||
*
|
||||
* @param trace the trace the source trace
|
||||
* @param access the trace access shim
|
||||
*/
|
||||
public TaintTracePcodeEmulator(PcodeTraceAccess access) {
|
||||
super(access);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an emulator
|
||||
*
|
||||
* @param platform the platform to emulate
|
||||
* @param snap the source snap
|
||||
*/
|
||||
public TaintTracePcodeEmulator(Trace trace, long snap) {
|
||||
super(trace, snap);
|
||||
public TaintTracePcodeEmulator(TracePlatform platform, long snap) {
|
||||
super(platform, snap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,7 +36,7 @@ public class TaintTracePcodeExecutorState extends PairedTracePcodeExecutorState<
|
|||
* @param taint the taint piece
|
||||
*/
|
||||
public TaintTracePcodeExecutorState(BytesTracePcodeExecutorStatePiece concrete,
|
||||
AbstractTaintTracePcodeExecutorStatePiece<?> taint) {
|
||||
TaintTracePcodeExecutorStatePiece taint) {
|
||||
super(new PairedTracePcodeExecutorStatePiece<>(concrete, taint));
|
||||
}
|
||||
|
||||
|
@ -44,13 +44,11 @@ public class TaintTracePcodeExecutorState extends PairedTracePcodeExecutorState<
|
|||
* Create a state from the given concrete piece and an internally constructed taint piece
|
||||
*
|
||||
* <p>
|
||||
* We take all the parameters needed by the taint piece from the concrete piece.
|
||||
* We take the data access shim needed by the taint piece from the concrete piece.
|
||||
*
|
||||
* @param concrete the concrete piece
|
||||
*/
|
||||
public TaintTracePcodeExecutorState(BytesTracePcodeExecutorStatePiece concrete) {
|
||||
this(concrete,
|
||||
new TaintTracePcodeExecutorStatePiece(concrete.getTrace(), concrete.getSnap(),
|
||||
concrete.getThread(), concrete.getFrame()));
|
||||
this(concrete, new TaintTracePcodeExecutorStatePiece(concrete.getData()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,28 +15,47 @@
|
|||
*/
|
||||
package ghidra.pcode.emu.taint.trace;
|
||||
|
||||
import ghidra.pcode.emu.taint.AbstractTaintPcodeExecutorStatePiece;
|
||||
import ghidra.pcode.emu.taint.TaintPcodeArithmetic;
|
||||
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
||||
import ghidra.pcode.exec.trace.TracePcodeExecutorStatePiece;
|
||||
import ghidra.pcode.exec.trace.data.PcodeTraceDataAccess;
|
||||
import ghidra.pcode.exec.trace.data.PcodeTracePropertyAccess;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.taint.model.TaintVec;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
/**
|
||||
* The trace-integrated state piece for holding taint marks
|
||||
*
|
||||
* <p>
|
||||
* See {@link AbstractTaintTracePcodeExecutorStatePiece} for framing. We'll store taint sets in the
|
||||
* trace's address property map, which is the recommended scheme for auxiliary state.
|
||||
*/
|
||||
public class TaintTracePcodeExecutorStatePiece
|
||||
extends AbstractTaintTracePcodeExecutorStatePiece<TaintTraceSpace> {
|
||||
extends AbstractTaintPcodeExecutorStatePiece<TaintTraceSpace>
|
||||
implements TracePcodeExecutorStatePiece<byte[], TaintVec> {
|
||||
public static final String NAME = "Taint";
|
||||
|
||||
protected final PcodeTraceDataAccess data;
|
||||
protected final PcodeTracePropertyAccess<String> property;
|
||||
|
||||
/**
|
||||
* Create the taint piece
|
||||
* Create a state piece
|
||||
*
|
||||
* @param trace the trace from which to load taint marks
|
||||
* @param snap the snap from which to load taint marks
|
||||
* @param thread if a register space, the thread from which to load taint marks
|
||||
* @param frame if a register space, the frame
|
||||
* @param data the trace-data access shim
|
||||
*/
|
||||
public TaintTracePcodeExecutorStatePiece(Trace trace, long snap, TraceThread thread,
|
||||
int frame) {
|
||||
super(trace, snap, thread, frame);
|
||||
public TaintTracePcodeExecutorStatePiece(PcodeTraceDataAccess data) {
|
||||
super(data.getLanguage(),
|
||||
BytesPcodeArithmetic.forLanguage(data.getLanguage()),
|
||||
TaintPcodeArithmetic.forLanguage(data.getLanguage()));
|
||||
this.data = data;
|
||||
this.property = data.getPropertyAccess(NAME, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcodeTraceDataAccess getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,23 +71,33 @@ public class TaintTracePcodeExecutorStatePiece
|
|||
*/
|
||||
@Override
|
||||
protected AbstractSpaceMap<TaintTraceSpace> newSpaceMap() {
|
||||
return new CacheingSpaceMap<TracePropertyMapSpace<String>, TaintTraceSpace>() {
|
||||
return new CacheingSpaceMap<PcodeTracePropertyAccess<String>, TaintTraceSpace>() {
|
||||
@Override
|
||||
protected TracePropertyMapSpace<String> getBacking(AddressSpace space) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
if (space.isRegisterSpace()) {
|
||||
return map.getPropertyMapRegisterSpace(thread, frame, false);
|
||||
}
|
||||
return map.getPropertyMapSpace(space, false);
|
||||
protected PcodeTracePropertyAccess<String> getBacking(AddressSpace space) {
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaintTraceSpace newSpace(AddressSpace space,
|
||||
TracePropertyMapSpace<String> backing) {
|
||||
return new TaintTraceSpace(space, backing, snap);
|
||||
PcodeTracePropertyAccess<String> backing) {
|
||||
return new TaintTraceSpace(space, property);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This does the inverse of the lazy loading. Serialize the state and store it back into the
|
||||
* trace. Technically, it could be a different trace, but it must have identically-named
|
||||
* threads.
|
||||
*/
|
||||
@Override
|
||||
public void writeDown(PcodeTraceDataAccess into) {
|
||||
PcodeTracePropertyAccess<String> property = into.getPropertyAccess(NAME, String.class);
|
||||
for (TaintTraceSpace space : spaceMap.values()) {
|
||||
space.writeDown(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,10 @@ package ghidra.pcode.emu.taint.trace;
|
|||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.pcode.emu.taint.full.TaintDebuggerSpace;
|
||||
import ghidra.pcode.emu.taint.plain.TaintSpace;
|
||||
import ghidra.pcode.exec.trace.TracePcodeExecutorState;
|
||||
import ghidra.pcode.exec.trace.data.PcodeTracePropertyAccess;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.taint.model.TaintSet;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
/**
|
||||
* The storage space for taint sets in a trace's address space
|
||||
|
@ -39,8 +31,7 @@ import ghidra.trace.model.thread.TraceThread;
|
|||
*/
|
||||
public class TaintTraceSpace extends TaintSpace {
|
||||
protected final AddressSpace space;
|
||||
protected final TracePropertyMapSpace<String> backing;
|
||||
protected final long snap;
|
||||
protected final PcodeTracePropertyAccess<String> property;
|
||||
|
||||
/**
|
||||
* Create the space
|
||||
|
@ -49,10 +40,9 @@ public class TaintTraceSpace extends TaintSpace {
|
|||
* @param backing if present, the backing object
|
||||
* @param snap the source snap
|
||||
*/
|
||||
public TaintTraceSpace(AddressSpace space, TracePropertyMapSpace<String> backing, long snap) {
|
||||
public TaintTraceSpace(AddressSpace space, PcodeTracePropertyAccess<String> property) {
|
||||
this.space = space;
|
||||
this.backing = backing;
|
||||
this.snap = snap;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,73 +51,44 @@ public class TaintTraceSpace extends TaintSpace {
|
|||
* <p>
|
||||
* The taint space will call this when the cache misses, allowing us to populate it with a taint
|
||||
* set stored in the trace. Note that if the emulator writes to this offset <em>before</em>
|
||||
* reading it, this will not get called for that offset. Here we simply load the string property
|
||||
* from the map and parse the taint set. We'll also introduce a second extension point for when
|
||||
* neither the cache nor the trace have a taint set.
|
||||
* reading it, this will not get called for that offset. Here we simply get the string property
|
||||
* and parse the taint set.
|
||||
*/
|
||||
@Override
|
||||
protected TaintSet whenNull(long offset) {
|
||||
if (backing == null) {
|
||||
return whenTraceNull(offset);
|
||||
}
|
||||
String string = backing.get(snap, space.getAddress(offset));
|
||||
String string = property.get(space.getAddress(offset));
|
||||
if (string == null) {
|
||||
return whenTraceNull(offset);
|
||||
return TaintSet.EMPTY;
|
||||
}
|
||||
return TaintSet.parse(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point: Behavior when there is neither an in-memory nor a trace-stored taint set at
|
||||
* the given offset
|
||||
*
|
||||
* <p>
|
||||
* This will be overridden by {@link TaintDebuggerSpace} to implement loading from static mapped
|
||||
* programs.
|
||||
*
|
||||
* @param offset the offset
|
||||
* @return the taint set to use
|
||||
*/
|
||||
protected TaintSet whenTraceNull(long offset) {
|
||||
return TaintSet.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write this cache back down into a trace
|
||||
*
|
||||
* <p>
|
||||
* Here we simply iterate over every entry in this space, serialize the taint, and store it into
|
||||
* the property map at the entry's offset. Because a backing object may not have existed when
|
||||
* creating this space, we must re-fetch the backing object, creating it if it does not exist.
|
||||
* We can safely create such spaces, since the client is required to have an open transaction on
|
||||
* the destination trace while invoking this method (via
|
||||
* {@link TracePcodeExecutorState#writeDown(Trace, long, TraceThread, int)}).
|
||||
* Here we simply iterate over every entry in this space, serialize the taint, and put it into
|
||||
* the property at the entry's offset. If the taint set is empty, we clear the property rather
|
||||
* than putting the empty taint set into the property.
|
||||
*
|
||||
* @param map the backing object, which must now exist
|
||||
* @param snap the destination snap
|
||||
* @param thread if a register space, the destination thread
|
||||
* @param frame if a register space, the destination frame
|
||||
*/
|
||||
public void writeDown(TracePropertyMap<String> map, long snap, TraceThread thread, int frame) {
|
||||
public void writeDown(PcodeTracePropertyAccess<String> into) {
|
||||
if (space.isUniqueSpace()) {
|
||||
return;
|
||||
}
|
||||
TracePropertyMapSpace<String> backing;
|
||||
if (space.isRegisterSpace()) {
|
||||
backing = map.getPropertyMapRegisterSpace(thread, frame, true);
|
||||
}
|
||||
else {
|
||||
backing = map.getPropertyMapSpace(space, true);
|
||||
}
|
||||
|
||||
for (Entry<Long, TaintSet> entry : taints.entrySet()) {
|
||||
TaintSet taint = entry.getValue();
|
||||
Range<Long> span = DBTraceUtils.atLeastMaybeScratch(snap);
|
||||
Address address = space.getAddress(entry.getKey());
|
||||
if (taint.isEmpty()) {
|
||||
backing.clear(span, new AddressRangeImpl(address, address));
|
||||
into.clear(new AddressRangeImpl(address, address));
|
||||
}
|
||||
else {
|
||||
backing.set(span, address, taint.toString());
|
||||
into.put(address, taint.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,15 +23,19 @@ import ghidra.app.plugin.core.debug.gui.register.RegisterRow;
|
|||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorStatePiece;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
|
||||
/**
|
||||
* A factory for the "Taint" column in the "Registers" panel
|
||||
*
|
||||
* <p>
|
||||
* For the most part, this is just a matter of accessing the property map and rendering the value on
|
||||
* screen. As a cheap shortcut, we'll just instantiate a taint state piece at the panel's
|
||||
* coordinates and use it to retrieve the actual taint marks, then render that for display.
|
||||
* screen.
|
||||
*/
|
||||
public class TaintDebuggerRegisterColumnFactory implements DebuggerRegisterColumnFactory {
|
||||
protected static final String PROP_NAME = TaintTracePcodeExecutorStatePiece.NAME;
|
||||
|
@ -46,7 +50,7 @@ public class TaintDebuggerRegisterColumnFactory implements DebuggerRegisterColum
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getValue(RegisterRow rowObject, Settings settings, Void data,
|
||||
public String getValue(RegisterRow rowObject, Settings settings, Void dataSource,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
DebuggerCoordinates current = rowObject.getCurrent();
|
||||
Trace trace = current.getTrace();
|
||||
|
@ -54,11 +58,39 @@ public class TaintDebuggerRegisterColumnFactory implements DebuggerRegisterColum
|
|||
return "";
|
||||
}
|
||||
|
||||
TaintTracePcodeExecutorStatePiece piece =
|
||||
new TaintTracePcodeExecutorStatePiece(current.getTrace(), current.getViewSnap(),
|
||||
current.getThread(), current.getFrame());
|
||||
TracePropertyMap<String> taintMap = current.getTrace()
|
||||
.getAddressPropertyManager()
|
||||
.getPropertyMap(PROP_NAME, String.class);
|
||||
|
||||
return piece.getVar(rowObject.getRegister()).toDisplay();
|
||||
if (taintMap == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Register register = rowObject.getRegister();
|
||||
TracePropertyMapSpace<String> taintSpace;
|
||||
AddressSpace addressSpace = register.getAddressSpace();
|
||||
if (addressSpace.isRegisterSpace()) {
|
||||
taintSpace = taintMap.getPropertyMapRegisterSpace(current.getThread(),
|
||||
current.getFrame(), false);
|
||||
}
|
||||
else {
|
||||
taintSpace = taintMap.getPropertyMapSpace(addressSpace, false);
|
||||
}
|
||||
if (taintSpace == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Cheat the deserialization/reserialization here
|
||||
StringBuffer vec = new StringBuffer();
|
||||
int count = register.getNumBytes();
|
||||
Address start = register.getAddress();
|
||||
for (int i = 0; i < count; i++) {
|
||||
vec.append('[');
|
||||
String taint = taintSpace.get(current.getViewSnap(), start.addWrap(i));
|
||||
vec.append(taint == null ? "" : taint);
|
||||
vec.append(']');
|
||||
}
|
||||
return vec.toString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -121,9 +121,8 @@ public class TaintDebuggerPcodeEmulatorTest extends AbstractGhidraHeadedDebugger
|
|||
progTaintMap.add(tb.addr(0x00400800), "test_0");
|
||||
Assembler asm = Assemblers.getAssembler(program);
|
||||
|
||||
// TODO: I should be able to make this use a RIP-relative address
|
||||
asm.assemble(tb.addr(0x00400000),
|
||||
"MOV RAX, [0x55550800]"); // was [0x00400800], but fixed address is a problem.
|
||||
// NOTE: qword ptr [0x00400800] is RIP-relative
|
||||
asm.assemble(tb.addr(0x00400000), "MOV RAX, qword ptr [0x00400800]");
|
||||
}
|
||||
|
||||
TraceSchedule time = TraceSchedule.parse("0:t0-1");
|
||||
|
|
|
@ -18,6 +18,8 @@ package ghidra.pcode.emu.taint.trace;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -26,15 +28,27 @@ import org.junit.Test;
|
|||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.assembler.*;
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.trace.AbstractTracePcodeEmulatorTest;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.taint.model.*;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.target.DBTraceObjectManager;
|
||||
import ghidra.trace.database.target.DBTraceObjectManagerTest;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.guest.TraceGuestPlatform;
|
||||
import ghidra.trace.model.memory.TraceMemoryManager;
|
||||
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||
import ghidra.trace.model.target.TraceObject.ConflictResolution;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
|
@ -71,7 +85,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
taintMap.set(Range.atLeast(0L), tb.range(0x00400000, 0x00400003), "test_0");
|
||||
}
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getExecutor().executeSleigh("RAX = *0x00400000:8;");
|
||||
|
||||
|
@ -101,7 +115,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
mapSpace.set(Range.atLeast(0L), regEBX, "test_0");
|
||||
}
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getExecutor().executeSleigh("RAX = RBX;");
|
||||
|
||||
|
@ -121,7 +135,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
initTrace(tb, "", List.of());
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
TaintVec taintVal = TaintVec.empties(8);
|
||||
TaintSet testTaint = TaintSet.of(new TaintMark("test_0", Set.of()));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -132,7 +146,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
Pair.of(tb.arr(0, 0, 0, 0, 0, 0, 0, 0), taintVal));
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 1, 0);
|
||||
emu.writeDown(tb.host, 1, 0);
|
||||
}
|
||||
TracePropertyMap<String> taintMap =
|
||||
tb.trace.getAddressPropertyManager().getPropertyMap("Taint", String.class);
|
||||
|
@ -148,7 +162,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
AddressSpace rs = tb.language.getAddressFactory().getRegisterSpace();
|
||||
TraceThread thread = initTrace(tb, "", List.of());
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
TaintVec taintVal = TaintVec.empties(8);
|
||||
TaintSet testTaint = TaintSet.of(new TaintMark("test_0", Set.of()));
|
||||
|
@ -158,7 +172,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
emuThread.getState().setVar(tb.reg("EAX"), Pair.of(tb.arr(0, 0, 0, 0), taintVal));
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 1, 0);
|
||||
emu.writeDown(tb.host, 1, 0);
|
||||
}
|
||||
TracePropertyMap<String> taintMap =
|
||||
tb.trace.getAddressPropertyManager().getPropertyMap("Taint", String.class);
|
||||
|
@ -183,7 +197,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
"MOV qword ptr [0x00600000], RAX",
|
||||
"MOV qword ptr [0x00600000], RBX"));
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getState()
|
||||
.setVar(tb.reg("RAX"), Pair.of(
|
||||
|
@ -192,11 +206,11 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 1, 0);
|
||||
emu.writeDown(tb.host, 1, 0);
|
||||
}
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 2, 0);
|
||||
emu.writeDown(tb.host, 2, 0);
|
||||
}
|
||||
|
||||
TracePropertyMap<String> taintMap =
|
||||
|
@ -220,16 +234,19 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
List.of(
|
||||
"XOR RAX, RAX"));
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getState()
|
||||
.setVar(tb.reg("RAX"), Pair.of(
|
||||
tb.arr(1, 2, 3, 4, 5, 6, 7, 8),
|
||||
TaintVec.copies(TaintSet.parse("test_0"), 8)));
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.host, 0, 0);
|
||||
}
|
||||
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 1, 0);
|
||||
emu.writeDown(tb.host, 1, 0);
|
||||
}
|
||||
|
||||
TracePropertyMap<String> taintMap =
|
||||
|
@ -251,16 +268,19 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
List.of(
|
||||
"XOR EAX, EAX"));
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.trace, 0);
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(tb.host, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getState()
|
||||
.setVar(tb.reg("RAX"), Pair.of(
|
||||
tb.arr(1, 2, 3, 4, 5, 6, 7, 8),
|
||||
TaintVec.copies(TaintSet.parse("test_0"), 8)));
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.host, 0, 0);
|
||||
}
|
||||
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.trace, 1, 0);
|
||||
emu.writeDown(tb.host, 1, 0);
|
||||
}
|
||||
|
||||
TracePropertyMap<String> taintMap =
|
||||
|
@ -272,4 +292,64 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
Set.copyOf(mapSpace.getEntries(Range.singleton(1L), tb.reg("RAX"))));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGuestEmptyTaintClears() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "DATA:BE:64:default")) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
AddressSpace ram = tb.language.getAddressFactory().getDefaultAddressSpace();
|
||||
TraceThread thread;
|
||||
TraceGuestPlatform x64;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
SchemaContext ctx = XmlSchemaContext.deserialize(DBTraceObjectManagerTest.XML_CTX);
|
||||
DBTraceObjectManager objects = tb.trace.getObjectManager();
|
||||
objects.createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
thread = tb.getOrAddThread("Targets[0].Threads[0]", 0);
|
||||
|
||||
x64 = tb.trace.getPlatformManager()
|
||||
.addGuestPlatform(getSLEIGH_X86_64_LANGUAGE().getDefaultCompilerSpec());
|
||||
x64.addMappedRegisterRange();
|
||||
x64.addMappedRange(tb.addr(0x00000000), tb.addr(x64, 0x00400000), 0x10000);
|
||||
x64.addMappedRange(tb.addr(0x20000000), tb.addr(x64, 0x00600000), 0x10000);
|
||||
objects.createObject(TraceObjectKeyPath.parse("Targets[0].Threads[0].Registers"))
|
||||
.insert(Range.atLeast(0L), ConflictResolution.DENY);
|
||||
// TODO: Make Sleigh work in the guest platform
|
||||
TraceMemorySpace regs = mm.getMemoryRegisterSpace(thread, 0, true);
|
||||
regs.setValue(x64, 0,
|
||||
new RegisterValue(tb.reg(x64, "RIP"), BigInteger.valueOf(0x00400000)));
|
||||
|
||||
Assembler asm = Assemblers.getAssembler(x64.getLanguage());
|
||||
AssemblyBuffer buf = new AssemblyBuffer(asm, tb.addr(x64, 0x00400000));
|
||||
buf.assemble("MOV qword ptr [0x00600000], RAX");
|
||||
buf.assemble("MOV qword ptr [0x00600000], RBX");
|
||||
mm.putBytes(0, tb.addr(0x00000000), ByteBuffer.wrap(buf.getBytes()));
|
||||
}
|
||||
|
||||
TaintTracePcodeEmulator emu = new TaintTracePcodeEmulator(x64, 0);
|
||||
PcodeThread<Pair<byte[], TaintVec>> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.getState()
|
||||
.setVar(tb.reg(x64, "RAX"), Pair.of(
|
||||
tb.arr(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
TaintVec.copies(TaintSet.parse("test_0"), 8)));
|
||||
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(x64, 1, 0);
|
||||
}
|
||||
emuThread.stepInstruction();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(x64, 2, 0);
|
||||
}
|
||||
|
||||
TracePropertyMap<String> taintMap =
|
||||
tb.trace.getAddressPropertyManager().getPropertyMap("Taint", String.class);
|
||||
|
||||
assertEquals(makeTaintEntries(tb.trace, Range.singleton(1L), ram, Set.of(
|
||||
0x20000000L, 0x20000001L, 0x20000002L, 0x20000003L,
|
||||
0x20000004L, 0x20000005L, 0x20000006L, 0x20000007L),
|
||||
"test_0"),
|
||||
Set.copyOf(taintMap.getEntries(
|
||||
Range.singleton(1L), tb.range(0x20000000, 0x20000007))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue