pub struct Sandbox {
pub mmu: Mmu,
pub cpu: Cpu,
pub registry: Registry,
pub host: HostState,
}Expand description
One sandbox instance per loaded codec DLL.
Fields§
§mmu: Mmu§cpu: Cpu§registry: Registry§host: HostStateImplementations§
Source§impl Sandbox
impl Sandbox
Sourcepub fn coverage(&self) -> &CoverageMap
pub fn coverage(&self) -> &CoverageMap
Borrow the always-on coverage map populated by the
interpreter. Records every dispatched instruction’s
entry EIP plus every guest memory write. See
crate::coverage::CoverageMap for the consumer
surface.
Sourcepub fn coverage_mut(&mut self) -> &mut CoverageMap
pub fn coverage_mut(&mut self) -> &mut CoverageMap
Mutable accessor for the coverage map — useful for
per-export resets (coverage_mut().clear()) between
runs of the same sandbox.
Sourcepub fn context(&self) -> &Context
pub fn context(&self) -> &Context
Borrow the emulation-context layer (virtual filesystem,
virtual registry, future surfaces). Always present;
the per-surface options decide whether the guest
observes synthetic state or the fail-soft Win32
default. See crate::context::Context.
Sourcepub fn context_mut(&mut self) -> &mut Context
pub fn context_mut(&mut self) -> &mut Context
Mutable accessor for the context.
Sourcepub fn with_vfs(self, vfs: VirtualFs) -> Self
pub fn with_vfs(self, vfs: VirtualFs) -> Self
Builder: attach a virtual filesystem so guest file-API
calls land in-memory instead of fail-soft no-ops. See
crate::VirtualFs for the stage-some-files / capture-
what’s-written workflow.
Sourcepub fn with_registry(self, reg: VirtualRegistry) -> Self
pub fn with_registry(self, reg: VirtualRegistry) -> Self
Builder: attach a virtual registry so guest Reg* calls
observe analyst-staged keys and writes land in-memory.
See crate::VirtualRegistry.
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a fresh sandbox with the heap arena and stack
pre-mapped, the kernel32 stub set registered, and the
CPU’s esp pointing at a freshly-allocated stack.
Sourcepub fn with_rand_seed(self, seed: u32) -> Self
pub fn with_rand_seed(self, seed: u32) -> Self
Builder-style seed setter for the msvcrt!rand LCG.
PRNG state for msvcrt!rand calls from sandboxed codec
code. Default 1 matches MSVC’s documented “no srand
called yet” initial value. Set via with_rand_seed /
set_rand_seed for reproducible encode output: two
sandboxes seeded identically produce identical rand
sequences, which makes encode regression tests
deterministic across runs.
The guest’s own msvcrt!srand(seed) call writes to the
same field, so the codec may re-seed at any time; in that
case Self::rand_seed will report whatever value the
codec last installed.
Round 55.
Sourcepub fn set_rand_seed(&mut self, seed: u32)
pub fn set_rand_seed(&mut self, seed: u32)
Set the msvcrt!rand LCG state at runtime.
Same contract as Self::with_rand_seed, but mutates an
already-constructed sandbox — useful for tests that drive
multiple encode runs with different seeds, or for fuzzing
harnesses that want to force the codec into a known state
before each iteration.
Round 55.
Sourcepub fn set_command_line(&mut self, cmdline: &str) -> Result<(), Error>
pub fn set_command_line(&mut self, cmdline: &str) -> Result<(), Error>
Override the value kernel32!GetCommandLineA returns to
the guest. The string is stashed (NUL-terminated) in the
host’s const arena and a pointer to it is parked at
command_line_ptr. Installer-class binaries consult
this to pick up /quiet, /qn, /S and similar
silent-install flags.
Sourcepub fn rand_seed(&self) -> u32
pub fn rand_seed(&self) -> u32
Read the current msvcrt!rand LCG state.
Reflects whatever the host or the guest last wrote: a
fresh sandbox returns 1 (MSVC’s documented “no srand
called yet” initial value); after host
Self::set_rand_seed / Self::with_rand_seed returns
that value; after a guest msvcrt!srand(s) call returns
s; after any number of msvcrt!rand calls returns the
post-step LCG state.
Round 55.
Sourcepub fn load(&mut self, name: &str, bytes: &[u8]) -> Result<Image, Error>
pub fn load(&mut self, name: &str, bytes: &[u8]) -> Result<Image, Error>
Load a PE32 image from bytes, mapping it into the
sandbox’s MMU. The returned Image holds the entry
point + export table.
Strict-resolution: any IAT entry the
crate::win32::Registry doesn’t satisfy is a hard
load-time error. Use Sandbox::load_fail_soft for
EXEs whose import list exceeds the codec-class stub
surface (installers, GUI apps, etc.).
Sourcepub fn load_fail_soft(
&mut self,
name: &str,
bytes: &[u8],
) -> Result<(Image, Vec<(String, String)>), Error>
pub fn load_fail_soft( &mut self, name: &str, bytes: &[u8], ) -> Result<(Image, Vec<(String, String)>), Error>
Load a PE32 image in fail-soft import-resolution mode.
Imports the codec-class stub registry doesn’t satisfy
get a trap-on-call fallback thunk so the load succeeds.
Returns the loaded Image plus the list of
(dll, name) pairs that received a fallback — i.e.
the set of APIs the operator now knows the binary uses
but we don’t yet stub.
Intended for the install-monitor workflow: load QuickTimeInstaller.exe with fail-soft, drive the entry point, watch the trap stream for the next missing API.
Sourcepub fn call_dll_main(
&mut self,
image: &Image,
reason: u32,
) -> Result<u32, Error>
pub fn call_dll_main( &mut self, image: &Image, reason: u32, ) -> Result<u32, Error>
Synchronously call DllMain(hModule, fdwReason, lpvReserved)
inside the emulator and return the dword eax value at
the point the function returned to the synthetic
RET_SENTINEL.
The DllMain ABI is stdcall (callee-cleanup), so we push
lpvReserved first, then fdwReason, then hModule,
then the return-address sentinel. The callee’s RET 12
(or equivalent) cleans the args.
Resolution: prefer the DllMain named export (Indeo
codecs); fall back to the PE AddressOfEntryPoint
(mpg4c32.dll and other CRT-startup-driven DLLs that
don’t export DllMain by name). Both expose the same
stdcall (HINSTANCE, DWORD, LPVOID) ABI.
Sourcepub fn call_export(
&mut self,
image: &Image,
name: &str,
args: &[u32],
) -> Result<u32, Error>
pub fn call_export( &mut self, image: &Image, name: &str, args: &[u32], ) -> Result<u32, Error>
Generic stdcall guest-call helper. Resolves name against
image’s export table, pushes args right-to-left + the
RET_SENTINEL, and runs until the callee returns.
Returns eax.
Used both internally (by Self::call_dll_main) and by
future codec adapter layers that need to drive arbitrary
codec exports — DriverProc, MyCodecGetVersion,
MyCodecExtraInit, etc. The round-2 vfw32::ic_* host
surface uses crate::win32::call_guest directly with
the codec’s DriverProc VA.
Sourcepub fn call_entry_point(&mut self, image: &Image) -> Result<u32, Error>
pub fn call_entry_point(&mut self, image: &Image) -> Result<u32, Error>
Call the image’s PE entry point (AddressOfEntryPoint).
For an EXE this is the CRT startup, which expects no
arguments and never returns under normal Windows
semantics (it calls ExitProcess). Here it runs until
the runtime returns to the synthetic RET_SENTINEL or
hits a trap (e.g. unresolved import, instruction limit).
Sourcepub fn run_until_sentinel(&mut self) -> Result<(), Error>
pub fn run_until_sentinel(&mut self) -> Result<(), Error>
Drive the CPU until eip == RET_SENTINEL, dispatching to
Win32 stubs whenever eip lands on a registered thunk
address. Thin wrapper over crate::win32::run_until_sentinel
kept for API stability.
Sourcepub fn install_codec(&mut self, image: &Image) -> Result<(), Error>
pub fn install_codec(&mut self, image: &Image) -> Result<(), Error>
Mark image as the codec the next Self::ic_open call
should target.
Round 2 supports a single codec image per sandbox — round 3
will lift that into a multi-codec registry. The image must
export DriverProc.
Sourcepub fn ic_open(
&mut self,
fcc_type: u32,
fcc_handler: u32,
mode: u32,
) -> Result<u32, Error>
pub fn ic_open( &mut self, fcc_type: u32, fcc_handler: u32, mode: u32, ) -> Result<u32, Error>
Open the installed codec (DRV_OPEN).
Sourcepub fn ic_get_info(&mut self, hic: u32, cb: u32) -> Result<Vec<u8>, Error>
pub fn ic_get_info(&mut self, hic: u32, cb: u32) -> Result<Vec<u8>, Error>
Read the codec’s ICINFO block.
Sourcepub fn ic_decompress_query(
&mut self,
hic: u32,
input: &Bih,
output: Option<&Bih>,
) -> Result<u32, Error>
pub fn ic_decompress_query( &mut self, hic: u32, input: &Bih, output: Option<&Bih>, ) -> Result<u32, Error>
ICDecompressQuery — does the codec accept this format?
Sourcepub fn ic_decompress_get_format(
&mut self,
hic: u32,
input: &Bih,
) -> Result<(u32, Bih), Error>
pub fn ic_decompress_get_format( &mut self, hic: u32, input: &Bih, ) -> Result<(u32, Bih), Error>
ICDecompressGetFormat — ask the codec for the output BIH
matching input. Round 30 uses this to probe stream
dimensions when CodecParameters lacks them.
Sourcepub fn ic_decompress_begin(
&mut self,
hic: u32,
input: &Bih,
output: &Bih,
) -> Result<u32, Error>
pub fn ic_decompress_begin( &mut self, hic: u32, input: &Bih, output: &Bih, ) -> Result<u32, Error>
ICDecompressBegin — set up the decoder pipeline.
Sourcepub fn ic_decompress_end(&mut self, hic: u32) -> Result<u32, Error>
pub fn ic_decompress_end(&mut self, hic: u32) -> Result<u32, Error>
ICDecompressEnd — tear down the decoder pipeline.
Sourcepub fn watch(&mut self, addr: u32, size: u32, mode: WatchMode)
pub fn watch(&mut self, addr: u32, size: u32, mode: WatchMode)
Install a memory watchpoint covering [addr, addr+size).
Any guest access whose address range intersects the
watchpoint emits a kind=mem_write (or mem_read) JSONL
event to the configured sink. Multiple watchpoints may
overlap; each fires independently.
Sourcepub fn unwatch(&mut self, addr: u32, size: u32)
pub fn unwatch(&mut self, addr: u32, size: u32)
Remove watchpoints whose (addr, size) exactly matches.
Mode is ignored for the match.
Sourcepub fn set_exec_trace(&mut self, on: bool)
pub fn set_exec_trace(&mut self, on: bool)
Toggle per-instruction execution trace at runtime. Has no
effect unless the crate was built with the trace-exec
sub-feature.
Sourcepub fn set_trace_sink(&mut self, sink: Box<dyn Write + Send>)
pub fn set_trace_sink(&mut self, sink: Box<dyn Write + Send>)
Override the trace JSONL sink at runtime. Defaults to
honouring OXIDEAV_VFW_TRACE_FILE.
Sourcepub fn dll_get_class_object(
&mut self,
image: &Image,
clsid: Guid,
riid: Guid,
) -> Result<u32, Error>
pub fn dll_get_class_object( &mut self, image: &Image, clsid: Guid, riid: Guid, ) -> Result<u32, Error>
Drive DllGetClassObject(rclsid, riid, ppv) on image,
staging the GUID arguments + the ppv out-slot in a
freshly-allocated heap region inside the sandbox. On
success returns the guest pointer the codec wrote into
*ppv — typically a guest-side IClassFactory.
When riid == IID_IClassFactory, the returned pointer is
also registered with crate::com::ComObjectTable::register_class_factory
keyed under clsid, so subsequent
Self::co_create_instance calls can resolve clsid
without re-driving DllGetClassObject.
MSDN: HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) — every COM in-process server
exports it; DirectShow filter binaries (.ax) export it
instead of DriverProc.
Sourcepub fn co_create_instance(
&mut self,
clsid: Guid,
riid: Guid,
) -> Result<u32, Error>
pub fn co_create_instance( &mut self, clsid: Guid, riid: Guid, ) -> Result<u32, Error>
Drive CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppv) against the in-process class-factory cache.
The CLSID must already be registered (typically by a
prior Self::dll_get_class_object call); otherwise
surfaces CLASS_E_CLASSNOTAVAILABLE as an error.
Sourcepub fn query_interface(&mut self, obj: u32, riid: Guid) -> Result<u32, Error>
pub fn query_interface(&mut self, obj: u32, riid: Guid) -> Result<u32, Error>
Drive obj->QueryInterface(riid, ppv) on a guest COM
object, staging the IID + out-slot in arena memory.
Returns the new interface pointer on success, or surfaces
the HRESULT in an error message.
Sourcepub fn mint_host_filter_graph(&mut self) -> Result<u32, Error>
pub fn mint_host_filter_graph(&mut self) -> Result<u32, Error>
Round 27 — mint a host-side IFilterGraph stub so the
codec’s IBaseFilter::JoinFilterGraph(pGraph, pName) call
has a non-NULL parent graph to record. The returned guest
pointer’s vtable function-pointer slots are synthetic
thunk addresses that route into the host stubs registered
by crate::com::host_iface::register.
QueryInterface(IID_IUnknown | IID_IFilterGraph) →
S_OK + *ppv = obj; every other IID returns
E_NOINTERFACE. All eight IFilterGraph methods return
E_NOTIMPL — none are exercised on the
JoinFilterGraph → ReceiveConnection path the round-27
probe takes.
Sourcepub fn mint_host_output_pin(&mut self, amt_addr: u32) -> Result<u32, Error>
pub fn mint_host_output_pin(&mut self, amt_addr: u32) -> Result<u32, Error>
Round 27 — mint a host-side IPin stub that pretends to
be an OUTPUT pin advertising amt_addr (a pointer to a
staged AM_MEDIA_TYPE). Suitable as the pConnector
argument of IPin::ReceiveConnection.
QueryDirection reports PIN_OUTPUT; QueryAccept
returns S_OK; ConnectionMediaType copies the staged
AMT; EnumMediaTypes vends an enumerator yielding the
staged AMT once.
Sourcepub fn mint_host_output_pin_with_connection(
&mut self,
amt_addr: u32,
connected_pin: u32,
) -> Result<u32, Error>
pub fn mint_host_output_pin_with_connection( &mut self, amt_addr: u32, connected_pin: u32, ) -> Result<u32, Error>
Round 37 — same as Self::mint_host_output_pin but also
stamps the codec’s input-pin pointer (connected_pin) into
the new pin object so IPin::ConnectedTo can return it,
and synthesizes a parent HostIBaseFilter so
IPin::QueryPinInfo can fill in PIN_INFO::pFilter.
connected_pin == 0 falls back to the round-30 behaviour
where the pin reports VFW_E_NOT_CONNECTED from
ConnectedTo.
Sourcepub fn query_pin_info_call_count(&self) -> usize
pub fn query_pin_info_call_count(&self) -> usize
Round 37 — number of IPin::QueryPinInfo calls the codec
has driven against any host pin during this sandbox’s
lifetime.
Sourcepub fn query_filter_info_call_count(&self) -> usize
pub fn query_filter_info_call_count(&self) -> usize
Round 37 — number of IBaseFilter::QueryFilterInfo calls
the codec has driven against any host filter during this
sandbox’s lifetime.
Sourcepub fn query_pin_info_calls(&self) -> Vec<u32>
pub fn query_pin_info_calls(&self) -> Vec<u32>
Round 37 — this pointers of every IPin::QueryPinInfo
call observed.
Sourcepub fn query_filter_info_calls(&self) -> Vec<u32>
pub fn query_filter_info_calls(&self) -> Vec<u32>
Round 37 — this pointers of every
IBaseFilter::QueryFilterInfo call observed.
Sourcepub fn clear_query_info_log(&self)
pub fn clear_query_info_log(&self)
Round 37 — drop every captured introspection call from this sandbox’s per-state log.
Sourcepub fn mint_host_mem_allocator(
&mut self,
pool_size: u32,
sample_capacity: u32,
media_type_ptr: u32,
) -> Result<u32, Error>
pub fn mint_host_mem_allocator( &mut self, pool_size: u32, sample_capacity: u32, media_type_ptr: u32, ) -> Result<u32, Error>
Round 30 — mint a host-side IMemAllocator backed by a
pool of pool_size IMediaSample slots, each carrying a
fresh sample_capacity-byte data region. The returned
guest pointer is suitable as the pAllocator argument of
IMemInputPin::NotifyAllocator.
media_type_ptr is returned by every minted sample’s
IMediaSample::GetMediaType — pass 0 if no AMT should
surface there (codecs then fall back to the upstream pin’s
connection media type).
Sourcepub fn mint_host_mem_allocator_class_factory(&mut self) -> Result<u32, Error>
pub fn mint_host_mem_allocator_class_factory(&mut self) -> Result<u32, Error>
Round 35 — mint a host-side IClassFactory whose
CreateInstance mints fresh HostIMemAllocator instances.
Pre-registered in Sandbox::new under
crate::com::CLSID_MEMORY_ALLOCATOR; this method exists
for tests that want a raw factory pointer to drive
IClassFactory::CreateInstance directly without going
through the ole32!CoCreateInstance cascade.
Sourcepub fn mint_host_media_sample(
&mut self,
data_capacity: u32,
media_type_ptr: u32,
) -> Result<u32, Error>
pub fn mint_host_media_sample( &mut self, data_capacity: u32, media_type_ptr: u32, ) -> Result<u32, Error>
Round 30 — mint a single host-side IMediaSample wrapping
a fresh data_capacity-byte data region. Useful for
stand-alone tests; production paths typically mint samples
implicitly via Self::mint_host_mem_allocator.
Sourcepub fn media_sample_set_payload(
&mut self,
sample: u32,
payload: &[u8],
sync_point: bool,
) -> Result<(), Error>
pub fn media_sample_set_payload( &mut self, sample: u32, payload: &[u8], sync_point: bool, ) -> Result<(), Error>
Round 30 — copy a payload into a previously-minted sample
- flag whether it is a sync (key) frame.
Sourcepub fn host_iface_r31_mint_input_pin_pair(
&mut self,
) -> Result<(u32, u32), Error>
pub fn host_iface_r31_mint_input_pin_pair( &mut self, ) -> Result<(u32, u32), Error>
Round 31 — mint a paired downstream (HostIPin, HostIMemInputPin)
for receiving samples the codec pushes from its output pin.
Sourcepub fn host_iface_r31_mint_base_filter(
&mut self,
input_pin: u32,
) -> Result<u32, Error>
pub fn host_iface_r31_mint_base_filter( &mut self, input_pin: u32, ) -> Result<u32, Error>
Round 31 — mint a minimal HostIBaseFilter exposing
input_pin.
Sourcepub fn pop_received_sample(&self) -> Option<ReceivedSample>
pub fn pop_received_sample(&self) -> Option<ReceivedSample>
Round 31 — pop the oldest sample captured by the
downstream HostIMemInputPin::Receive callback.
Sourcepub fn received_samples_len(&self) -> usize
pub fn received_samples_len(&self) -> usize
Round 31 — number of samples currently waiting in the host-side queue.
Sourcepub fn last_set_properties(&self) -> Option<AllocatorPropertiesCapture>
pub fn last_set_properties(&self) -> Option<AllocatorPropertiesCapture>
Round 33 — return the most recent
IMemAllocator::SetProperties capture observed on this
sandbox, or None if no codec has called SetProperties
yet. See crate::com::AllocatorPropertiesCapture for
the captured field shape.
Sourcepub fn all_set_properties(&self) -> Vec<AllocatorPropertiesCapture>
pub fn all_set_properties(&self) -> Vec<AllocatorPropertiesCapture>
Round 33 — return every SetProperties capture observed on
this sandbox, in arrival order.
Sourcepub fn clear_set_properties_log(&self)
pub fn clear_set_properties_log(&self)
Round 33 — drop every captured SetProperties for this
sandbox. Useful for resetting per-test state.
Sourcepub fn com_add_ref(&mut self, obj: u32) -> Result<u32, Error>
pub fn com_add_ref(&mut self, obj: u32) -> Result<u32, Error>
Drive obj->AddRef(). Returns the codec-reported new
refcount; the host’s bookkeeping is updated automatically.
Sourcepub fn com_release(&mut self, obj: u32) -> Result<u32, Error>
pub fn com_release(&mut self, obj: u32) -> Result<u32, Error>
Drive obj->Release(). Returns the codec-reported new
refcount. The host’s bookkeeping is updated automatically.
Sourcepub fn ic_decompress(
&mut self,
hic: u32,
flags: u32,
input_bih: &Bih,
input_bytes: &[u8],
output_bih: &Bih,
output_capacity: u32,
) -> Result<(u32, Vec<u8>), Error>
pub fn ic_decompress( &mut self, hic: u32, flags: u32, input_bih: &Bih, input_bytes: &[u8], output_bih: &Bih, output_capacity: u32, ) -> Result<(u32, Vec<u8>), Error>
ICDecompress — decode one frame.
Sourcepub fn ic_compress_query(
&mut self,
hic: u32,
input: &Bih,
output: Option<&Bih>,
) -> Result<u32, Error>
pub fn ic_compress_query( &mut self, hic: u32, input: &Bih, output: Option<&Bih>, ) -> Result<u32, Error>
ICCompressQuery — does the codec accept this input/output
format pair? output may be None to defer the choice.
Sourcepub fn ic_compress_get_format(
&mut self,
hic: u32,
input: &Bih,
) -> Result<(u32, Bih), Error>
pub fn ic_compress_get_format( &mut self, hic: u32, input: &Bih, ) -> Result<(u32, Bih), Error>
ICCompressGetFormat — ask the codec for the output BIH
describing what its compressed format looks like for the
supplied input.
Sourcepub fn ic_compress_get_size(
&mut self,
hic: u32,
input: &Bih,
output: &Bih,
) -> Result<u32, Error>
pub fn ic_compress_get_size( &mut self, hic: u32, input: &Bih, output: &Bih, ) -> Result<u32, Error>
ICCompressGetSize — max encoded-frame byte count for the
supplied input/output BIH pair.
Sourcepub fn ic_compress_begin(
&mut self,
hic: u32,
input: &Bih,
output: &Bih,
) -> Result<u32, Error>
pub fn ic_compress_begin( &mut self, hic: u32, input: &Bih, output: &Bih, ) -> Result<u32, Error>
ICCompressBegin — set up the encoder pipeline.
Sourcepub fn ic_compress_end(&mut self, hic: u32) -> Result<u32, Error>
pub fn ic_compress_end(&mut self, hic: u32) -> Result<u32, Error>
ICCompressEnd — tear down the encoder pipeline.
Sourcepub fn ic_compress(
&mut self,
hic: u32,
flags: u32,
input_bih: &Bih,
input_bytes: &[u8],
output_bih: &Bih,
output_capacity: u32,
ckid: u32,
frame_num: i32,
frame_size_limit: u32,
quality: u32,
prev_bih_opt: Option<&Bih>,
prev_bytes_opt: Option<&[u8]>,
) -> Result<CompressOutcome, Error>
pub fn ic_compress( &mut self, hic: u32, flags: u32, input_bih: &Bih, input_bytes: &[u8], output_bih: &Bih, output_capacity: u32, ckid: u32, frame_num: i32, frame_size_limit: u32, quality: u32, prev_bih_opt: Option<&Bih>, prev_bytes_opt: Option<&[u8]>, ) -> Result<CompressOutcome, Error>
ICCompress — encode one frame. Returns the full encode
outcome: codec LRESULT, encoded bytes, the post-call output
BIH (whose biSizeImage holds the actual encoded byte
count), the codec-written *lpdwFlags (e.g. whether the
codec marked the emitted frame as a keyframe), and the
codec-written *lpckid.
prev_bih_opt / prev_bytes_opt are the previous
reconstructed frame (P-frame encoding). Pass None for
keyframes.
Sourcepub fn ic_get_state(
&mut self,
hic: u32,
dst_buf: &mut [u8],
) -> Result<u32, Error>
pub fn ic_get_state( &mut self, hic: u32, dst_buf: &mut [u8], ) -> Result<u32, Error>
ICGetState — ask the codec to serialise its private
per-instance state into dst_buf. Returns the byte count
the codec actually wrote.
Round 70 — wraps ICM_GETSTATE (0x5009) per MSDN; required
by oxideav-tracevfw to drive the encoder’s per-quality knob
round-trip alongside Self::ic_set_state. See MSDN
ICGetState topic page for the public contract.
Sourcepub fn ic_set_state(&mut self, hic: u32, src_buf: &[u8]) -> Result<(), Error>
pub fn ic_set_state(&mut self, hic: u32, src_buf: &[u8]) -> Result<(), Error>
ICSetState — ask the codec to deserialise src_buf into
its private per-instance state. Returns Ok(()) on
ICERR_OK, or crate::Error wrapping the codec’s raw
LRESULT otherwise.
Round 70 — wraps ICM_SETSTATE (0x500A) per MSDN. See
MSDN ICSetState topic page for the public contract.
Sourcepub fn msadds32_patch_helper_addref(
&mut self,
image_base: u32,
value: u32,
) -> Result<(), Error>
pub fn msadds32_patch_helper_addref( &mut self, image_base: u32, value: u32, ) -> Result<(), Error>
Round 63 — patch msadds32.ax’s helper_addref thunk (at
RVA 0x5cea) to unconditionally return value (32-bit
integer).
Why. Round-62 forensics
(docs/codec/msadds32-receive-null-0x20.md) traced the
IMemInputPin::Receive NULL-deref trap at RVA 0x256a to
a buffer-pool init that’s handed a size of zero. The size
is (h * 10) / size_calc(...) where h is what
helper_addref returns. On a fresh codec instance the
helper-object field at helper_90 + 0x3c (the “initialised”
flag the addref checks) is zero, so helper_addref returns
0, the quotient is 0, operator new(0) returns NULL,
buffer_pool_init fails, and the Receive cleanup branch
trips a NULL+0x20 deref.
In a real DirectShow host the flag is set during
IFilterGraph::JoinFilterGraph / Pause (the codec stamps
the field as part of its run-state machine). Until we
drive that path, the surgical workaround is to short-circuit
helper_addref to return a fixed non-zero value — which
empirically lifts the trap and lets Receive run to
completion (with HRESULT 0x8000ffff from the decode body,
which is the next round’s investigation surface).
Encoding. The original function (RVA 0x5cea, 10 bytes)
is:
0x5cea: 83 79 20 00 cmp [ecx+0x20], 0
0x5cee: 74 04 jz +4
0x5cf0: 8b 41 28 mov eax, [ecx+0x28]
0x5cf3: c3 ret
0x5cf4: 33 c0 xor eax, eax
0x5cf6: c3 retWe overwrite the first 6 bytes with:
b8 XX XX XX XX mov eax, imm32
c3 retThe remaining bytes at 0x5cf0..0x5cf6 are unreachable
after the patch (no caller enters there directly), so the
dead-code is harmless.
image_base is the address the codec was loaded at; pass
the value returned by Self::load on msadds32.ax.
§Reference material (clean-room only)
- Intel SDM Vol. 2A —
MOV imm32(B8+rd),RET(C3). - Raw bytes of
msadds32.axfromdocs/video/msmpeg4/reference/binaries/wmpcdcs8-2001/.
No Wine / ReactOS / MinGW / Microsoft DShow source consulted.