Skip to content

Instantly share code, notes, and snippets.

@oopsmishap
Last active January 28, 2025 21:46
Show Gist options
  • Save oopsmishap/3c3d1942fb7d067053c9fe8e68a4ea71 to your computer and use it in GitHub Desktop.
Save oopsmishap/3c3d1942fb7d067053c9fe8e68a4ea71 to your computer and use it in GitHub Desktop.
TTDRecord Wrapper
#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <Unknwn.h>
typedef enum _TTD_LOG_LEVEL
{
TTD_LOG_LEVEL_ERROR = 1,
TTD_LOG_LEVEL_WARNING,
TTD_LOG_LEVEL_INFO,
} TTD_LOG_LEVEL;
typedef enum _TTD_TRACE_MODE
{
EXTENDED = 0,
UNRESTRICTED = 1,
STANDALONE = 2,
} TTD_TRACE_MODE;
// {6E7D7B43-642B-4898-9E58-C5A205F862A7}
constexpr IID IID_ITtdDiagnosticsSink = {
0x6E7D7B43, 0x642B, 0x4898, {0x9E, 0x58, 0xC5, 0xA2, 0x05, 0xF8, 0x62, 0xA7}
};
struct ITtdDiagnosticsSink : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetMaximumLevelOfInterest(
/* [out] */ TTD_LOG_LEVEL* level
) = 0;
virtual HRESULT STDMETHODCALLTYPE ReportMessage(
/* [in] */ TTD_LOG_LEVEL level,
/* [in] */ HRESULT errorHR,
/* [in] */ const wchar_t* message
) = 0;
};
class TtdDiagnosticsSinkImpl : public ITtdDiagnosticsSink
{
public:
TtdDiagnosticsSinkImpl() : m_refCount(1), m_maxLevel(TTD_LOG_LEVEL_INFO){};
~TtdDiagnosticsSinkImpl() = default;
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
STDMETHODIMP GetMaximumLevelOfInterest(TTD_LOG_LEVEL* level) override;
STDMETHODIMP ReportMessage(TTD_LOG_LEVEL level, HRESULT errorHR, const wchar_t* message) override;
private:
LONG m_refCount;
TTD_LOG_LEVEL m_maxLevel;
};
STDMETHODIMP TtdDiagnosticsSinkImpl::QueryInterface(REFIID riid, void** ppvObject)
{
if (riid == IID_IUnknown || riid == IID_ITtdDiagnosticsSink)
{
*ppvObject = static_cast<ITtdDiagnosticsSink*>(this);
AddRef();
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) TtdDiagnosticsSinkImpl::AddRef()
{
return InterlockedIncrement(&m_refCount);
}
STDMETHODIMP_(ULONG) TtdDiagnosticsSinkImpl::Release()
{
ULONG res = InterlockedDecrement(&m_refCount);
if (res == 0)
{
// delete this;
}
return res;
}
STDMETHODIMP TtdDiagnosticsSinkImpl::GetMaximumLevelOfInterest(TTD_LOG_LEVEL* level)
{
if (!level)
{
return E_POINTER;
}
*level = m_maxLevel;
return S_OK;
}
STDMETHODIMP TtdDiagnosticsSinkImpl::ReportMessage(TTD_LOG_LEVEL level, HRESULT errorHR, const wchar_t* message)
{
switch (level)
{
case TTD_LOG_LEVEL_ERROR:
wprintf(L"[ERROR] %s, Error: %S, Code: 0x%08X\n", message, errorMsg.ErrorMessage(), errorHR);
break;
case TTD_LOG_LEVEL_WARNING:
wprintf(L"[WARNING] %s, Error: %S, Code: 0x%08X\n", message, errorMsg.ErrorMessage(), errorHR);
break;
case TTD_LOG_LEVEL_INFO:
wprintf(L"[INFO] %s\n", message);
break;
default:
wprintf(L"[UNKNOWN] %s, Error: %S, Code: 0x%08X\n", message, errorMsg.ErrorMessage(), errorHR);
break;
}
return S_OK;
}
int main()
{
ITtdDiagnosticsSink* diagnosticsSink = new TtdDiagnosticsSinkImpl();
if (diagnosticsSink == nullptr)
{
wprintf(L"[ERROR] Failed to create TtdDiagnosticsSinkImpl instance.\n");
return 1;
}
HMODULE ttdrecord = LoadLibraryA("ttdrecord.dll");
if (ttdrecord == NULL)
{
printf("[ERROR] Failed to load ttdrecord.dll\n");
diagnosticsSink->Release();
return 1;
}
using ExecuteTTTracerCommandLine_fn = HRESULT (*)(ITtdDiagnosticsSink*, LPWSTR, int, LPWSTR);
auto ExecuteTTTracerCommandLine =
(ExecuteTTTracerCommandLine_fn)GetProcAddress(ttdrecord, "ExecuteTTTracerCommandLine");
if (!ExecuteTTTracerCommandLine)
{
printf("[ERROR] Failed to get ExecuteTTTracerCommandLine function.\n");
FreeLibrary(ttdrecord);
diagnosticsSink->Release();
return 1;
}
ExecuteTTTracerCommandLine(diagnosticsSink, GetCommandLineW(), EXTENDED, L"");
// Cleanup
FreeLibrary(ttdrecord);
diagnosticsSink->Release();
return 0;
}
> ./tttlauncher.exe -??
Release: (unknown)
Copyright (C) Microsoft Corporation. All rights reserved.

Error getting the current version: GetFileVersionInfoSize failed with error 1813



[INFO] Usage: tttlauncher.exe  [options] [mode] [program [<arguments>] | <package> <app>]]

Options:
 -?                Display this help.
 -help             Display this help.
 -acceptEula       Accept one-time EULA without prompting.
 -bg               Attach to a process in non-interactive mode and return
                   control to the console after it starts tracing.
 -children         Trace through family of child processes.
 -cleanup          Uninstall process monitor driver
 -cmdLineFilter "<string>"
                   Must be combined with -onLaunch or -monitor and it will only
                   record the target if its command line contains the string.
                   This is useful for situations when the command line argument
                   uniquely identifies the process you are interested in,
                   e.g., notepad.exe specialfile.txt only the instance of
                   notepad.exe with that file name will be recorded.
 -delete           Stop future tracing of a program previously specified
                   with -onLaunch.  Does not stop current
                   tracing. For -plm apps you can only specify the
                   package (-delete <package>) and all apps within that
                   package will be removed from future tracing
 -disableCETSS     Disable CET shadow stacks before launching the target process.
                   Recording of processes that have shadow stacks enabled is currently
                   not supported, so this allows TTD to record processes that would
                   otherwise have shadow stacks enabled by the OS.
                   Note that this can only be done during process creation,
                   so it cannot be used when attaching to processes
                   that TTD didn't create.
 -injectMode <mode> Specify how recording DLLs are injected into the target process.
                   If '-injectMode' is not specified, LoaderForCombinedRecording is assumed by default,
                   Possible modes:
                   LoaderForCombinedRecording - Inject the loader to load one combined DLL for recording.
                                                This is the default value.
                   LoaderForEmulator          - Inject the loader to load the emulator without recording,
                                                useful for measuring emulation behaviors and performance.
                   EmulatorForRecording       - Inject one combined DLL for recording, useful for
                                                recording sandbox processes like Chromium.
                   EmulatorOnly               - Inject only the emulator without recording, useful for
                                                measuring emulation behaviors and performance.
 -managed          Enables managed recording (default is full tracing). However, if
                   paired with -selectiveRecording then the corresponding ttdconfig
                   passed in must be of managed selective recording format.
                   (As used in the Standalone Collector scenario).
 -maxConcurrentRecordings <count>
                   Maximum number of recordings that can be ongoing at any one
                   point in time.
 -maxFile <size>   Maximum size of the trace file in MB.  When in full trace
                   mode the default is 1024GB and the minimum value is 1MB.
                   When in ring buffer mode the default is 2048MB, the minimum
                   value is 1MB, and the maximum value is 32768MB.
                   The default for in-memory ring on 32-bit processes is 256MB.
 -numVCpu <number> Specifies a number of Virtual CPUs to be reserved and used
                   when tracing. This value affects the total memory overhead
                   placed on the guest process' memory by TTD. If not
                   specified then default per platform is used: 55 for x64/ARM64
                   and 32 for x86. Change this setting in order to
                   limit the memory impact ONLY if you are running out of
                   memory. The .out file will give hints this effect.
                   Note: Changing this value to a lower number can severely
                         impact the performance of tracing and should only
                         be done to work around memory impact issues.
 -onInitCompleteEvent <eventName>
                   Allows an event to be signaled when tracing initialization
                   is complete.
 -onMonitorReadyEvent <eventName>
                   Allows an event to be signaled when the recording monitor is ready
                   to record new processes.
 -out <file>       Specify a trace file name or a directory.  If a directory, the
                   directory must already exist. If a file name, the directory
                   of the file name must already exist. If a file name, and the file
                   name already exists, it will be overwritten without prompting.
                   If a file name, the tracer will replace the first instance of '%'
                   with a version number.  By default the executable's base name with
                   a version number is used to prefix the trace file name.
 -parent <name>    Use with -onLaunch to specify a currently running parent
                   process when the traced process will run with low privileges.
                   Prefer to use -monitor <program> instead of -parent/-onlaunch
                   which may be deprecated in the future.
 -passThroughExit  Pass the guest process exit value through as the
                   tttlauncher.exe 's exit value.
 -quiet            Do not display any standard output.
 -recordMode <mode> Specifies how recording is triggered in the target process. Possible modes:
                   Automatic - Recording occurs automatically, according to the other
                               specified options (default).
                   Manual    - Recording is disabled to start, but can be turned on/off
                               via API calls.
 -replayCpuSupport <support>  Specifies what support is expected from
                   the CPUs that will be used to replay the trace.
                   Possible <support> values:
                   Default           - Default CPU support, just requires basic
                                       commonly-available support in the replay CPU.
                   MostConservative  - Requires no special support in the replay CPU.
                                       Adequate for traces that will be replayed on a
                                       completely different CPU architecture,
                                       like an Intel trace on ARM64.
                   MostAggressive    - Assumes that the replay CPU will be similar
                                       and of equal or greater capability
                                       than the CPU used to record.
                   IntelAvxRequired  - Assumes that the replay CPU will be
                                       Intel/AMD 64-bit CPU supporting AVX.
                   IntelAvx2Required - Assumes that the replay CPU will be
                                       Intel/AMD 64-bit CPU supporting AVX2.
 -ring             Trace to a ring buffer. The file size will not grow beyond
                   the limits specified by -maxFile. Only the latter portion of the
                   recording that fits within the given size will be preserved.
 -ringMode <mode>  Specify how to record a ring trace. Possible modes:
                   file - The ring will be in a file on disk.
                       This is the default.
                   mappedFile - The ring will be in a file, but the entire
                       file will be fully mapped in memory. This reduces the
                       I/O overhead, but the entire file is mapped in
                       contiguous address space, which may add significant
                       memory pressure to 32-bit processes.
 -selectiveRecording <path>
                   Enables selective recording using the configuration file
                   located at the specified path.  The configuration file must
                   be readable by the process being traced. (Managed selective recording format
                   required when paired with -managed flag)
 -tExit <ecode>    (Only with -timer) Forces the application to terminate with
                   the specified exit code after the timer runs out.
 -timer <seconds>  Stops recording after the specified amount of time.
 -timestamp        When choosing a name for the .run file use current time
                   as part of the file name, instead of an increasing counter.
                   When repeatedly recording the same executable, use this
                   switch to reduce time to start tracing.
 -tracingOff       Starts application with trace recording off.  You can
                   use the UI to turn tracing on.

Modes:
 -attach <PID>     Attach to a running process specified by process ID.
 -launch           Launch and trace the program (default).
                   This is the only mode that allows arguments to be passed
                   to the program.
                   For -plm apps it must be specified, and you must include
                   the package and the app (-launch <package> <app>).
                   Note: This must be the last option in the command-line,
                   followed by the program + <arguments> or the package + app
 -monitor <Program> Trace programs or services each time they are started
                    (until reboot or Ctrl+C pressed). You must specify a full
                    path to the output location with -out. More than one
                    -monitor switch may be specified.
 -onLaunch         Trace programs each time they are started
                   (until reboot or Ctrl+C pressed). For -plm apps you can
                   only specify the package (-onLaunch <package>) and all apps
                   within that package will be set for TTD tracing on their next
                   launch. There is no ability to specify only 1 app. You must
                   specify a full path to the output location with -out. More
                   than one -onLaunch may be specified.
 -persistent       Trace program or service each time it starts (forever).
                   You must specify a full path to the output location with
                   -out. You may specify -persistent more than once. Use
                   -cleanup to stop monitoring the program / service.
 -plm              To specify a PLM app/package for tracing from launch or to
                   launch that app. These PLM apps can only be setup for
                   tracing if specifying the plm option. See -launch, -onlaunch,
                   and -delete for the parameters required for each case.
                   The default name for a single app package is 'app' and
                   must be included. You must specify a full path to the output
                   location with -out.

Control:
 -mark "<string>" <PID>
                   Signal a guest process to insert the string into its
                   trace file.  The string must be less than 256 characters.
 -status           Show programs scheduled for future tracing.
 -stop             Stop tracing the process specified (name, PID or "all").
 -terminate <code> <PID>
                   Terminate with the specified exit code a process
                   specified by process ID.
 -wait <timeout>   Wait for up to the amount of seconds specified for all
                   trace sessions on the system to end.  Specify -1 to wait
                   infinitely.

Restricted Options (internal only):
 -attemptRecordWithCETSS Record even if CET shadow stacks are enabled in the target process.
                   Recording of processes that have shadow stacks enabled is currently
                   not supported, so TTD will fail with an error message.
                   This option allows the user to override this behavior, at their own risk.
 -autoStart        If tracing stops in a guest process, automatically restart
                   it if the guest is still active.  Use -stop all to cancel
                   auto mode.
 -console <file>   Re-direct console output to the specified file or directory.
                   <file> format is similar to format of -out.
 -context <name>   Launches the guest process with the security context
                   of the passed in process name.  The process must
                   be in the same session as this client.  This
                   is not supported on OneCore.
 -dumpBinaries     An alias for -dumpModules.
 -dumpFull         In addition to dumping every loaded module image into the
                   trace file, takes a snapshot of the guest process on attach.
                   This option is enabled by default for non-ring traces.  This
                   option is incompatible with -ring.
 -dumpModules      Dumps a copy of every loaded module image into the trace
                   file.  This option may significantly increase the size of
                   the trace file.  This option is enabled by default for ring
                   traces.
 -initialize       Manually initialize your system for tracing.
                   You can trace without administrator privileges
                   after the system is initialized. Not supported by inbox TTTracer.exe
 -loadOnly <PID>   Loads TTT into the process, but does not start a trace
                   session.  This is useful if the client starting the trace
                   session is not running with high enough privileges to load
                   TTT into the process.
 -maxInstructionsPerFragment <num> Specifies how many instructions can be emulated
                   contiguously before artificially breaking into a new fragment.
                   Default value is 10000.
 -maxInstructionsPerSegment <num> Specifies how many instructions will be emulated
                   per segment, which determines the parallelism granularity used
                   during replay. Default value is 3000000.
 -module <module>  Restrict recording to specified module. More than one -module
                   may be specified. The module name is specified without a path,
                   such as notepad.exe or shell32.dll.
 -ni               Attach to a process in non-interactive mode.  The tracer
                   cannot attach to a waiting/sleeping process, so -ni prevents
                   timing out while waiting for the guest.
 -ni_detached      An alias for -bg.
 -noAutoDumpFull   Turns off the automatic application of -dumpFull to managed
                   processes, useful when there's no intent to do managed debugging.
                   Implies -noDumpFull. -noDumpFull       Explicitly turns off both -dumpFull and -dumpModules behavior.
 -noRing           Take a full trace of the guest process (default).
 -noSkipContiguousAtomics Do not ignore atomic instructions whose sequence IDs are contiguous
 -noUI             Disables the UI for manual control of recording.
                   (default on OS with no UI)
 -p                An alias for -attach.
 -recordMemoryProtect   Records a custom event with the initial memory protection
                   state of the process.
 -recordProcessorSwitches  Records a thread-local custom event whenever
                   each thread switches processors.
 -saveCrash <file> If the guest process hits an unhandled exception,
                   exit the process and save the trace file to
                   <file>.%.crash.  Do not combine with -out.
 -skipContiguousAtomics Ignore atomic instructions whose sequence IDs are contiguous
                   with the previous in the same thread. This makes it harder to
                   determine causality but it optimizes recording performance and trace
                   file size. This is the default.
 -threadsRunNativelyByDefault  Threads don't start recording automatically,
                   instead thread recording must be initiated via API call.
 -traceChildren    An alias for -children.

Unsupported Options:
 -??               Display this help.
 -boot             Used internally to mark a service program tracing from boot (may be
                   specified more than once.
 -bootSvc          Used internally to mark a svchost.exe service tracing from boot (may be
                   specified more than once.
 -confighelp       Display help for the process configuration file format.
 -deleteTraceFilesOnExit Ensures that any trace and output files created by
                   this instance of TTTracer will be deleted after the guest
                   processes exit (or, for any processes still running when
                   the computer shuts down, on the next reboot).
 -dumpMinimalModuleData Explicitly turns off both -dumpFull and -dumpModules behavior,
                   and further reduces the data captured for each module
                   to the debugger's bare necessities.
 -enableBreak      Allow breaking process
 -errCheck <0|1|2|3> Enable or disable placing extra error debug checking
                   information in the log.
                   The current setting is 0 (Off).
 -getTracePID <file> Get process ID from target trace file(*.run).
 -hardware key1=value1,key2=value2,... Control hardware tracing. To get more information, use '-hardware help'.
 -inheritHandles   Specifies that the process to be recorded must inherit handles.
                   This is useful when the process initiating the recording
                   wishes to pass a handle to the process being recorded.
 -noAttachViaThread Specifies to not use an injected thread to initialize the recorder.
                    The recorder will be initialized using the old method,
                    from the process instrumentation callback instead.
 -noConfigConnect  Does not connect to running processes in service mode
 -noExit           Do not exit after trace complete
 -noFlush          Don't flush the trace file before exiting.
                   This may allows TTTracer to exit much quicker after recording ends.
 -nogroup          Does not collect extra information in the trace to allow
                   for inter-process analysis on traces taken simultaneously.
 -noReconfigureProcMon Instructs TTTracer to fail if a reconfiguration of the process monitor server would be performed otherwise.
 -scenario <name>  Use this flag to mark your usage of this tool with a
                   scenario name. We collect this information and use it to
                   identify key scenarios where the tool is used.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment