📄 tracer.txt
字号:
what it is.
a tracer is normally used to single step some stream of instructions and
because of this it is able to intervene at any point and act accordingly.
in our case, this tracer engine runs under win9x, and traces win32 threads
as long as they execute in their natural environment (ring-3 protected
mode).
the primary goal was to create an engine that determines the original entry
point of PE executables that have been wrapped by some compression and/or
protection layer. the end result is a bit more powerful since it can serve
many other purposes by simple changes to the engine.
how it works.
the engine is implemented as a VxD and is currently part of icedump,
although technically it could be a standalone product. user interface
and other issues made this integration a natural choice though.
the basic idea behind the whole scheme is that each traced thread is
attached a state machine which is tracking various state changes of the
thread and makes sure that the thread perceives an execution environment
as if it was not traced at all (hence making the tracer undetectable).
this includes emulating all instructions that read/write EFLAGS.T, DR6.BS
and some other stuff specific to win9x/win32 (SIDT, GetTickCount for the
time being). this list is of course far from being complete (not everything
is implemented of it in fact in the current version), but proved to be
enough for tracing most known PE protections and compressors.
once a thread is traced, the engine will get the first chance to respond
to various exceptions (most importantly the debug one of course) that occur
in the given thread. the responses depend on the state of the thread, e.g.
after a PUSHFD the engine clears EFLAGS.T on the thread's stack if the
thread was not tracing itself (and hence expects a cleared state). also
depending on the state of the thread and the nature of the exception the
engine may call down the original exception handler chain to let the win32
specific Structured Exception handling mechanism carry out its work.
other smaller details have to do with various ways a thread's context can
be read/written and which the tracer must take care of (same emulation job
as with the x86 instructions). this is accomplished by a few hooks into
VWIN32.
what it can do.
in its current implementation the engine is able to trace win32 threads
(i.e. no V86 mode support, mainly due to some lazyness in emulating 16 bit
instructions ;-) as long as they run in ring-3. on normal ring transitions
the engine will remain in control of EFLAGS.T, on illegal ring transitions
it is at the mercy of the illegal handler (supporting this would pretty
much amount to writing a full instruction decoder and an emulator, neither
of which was my goal. also, some schemes simply do more damage than what's
worth the effort to support them, think of C-Dilla/Safedisc blindly
OVERWRITING the System VM's divide error handler with its own... talk about
competent programmers).
the engine will trace into Structured Exception handlers as well and follow
execution flow just as if the thread itself was executing them (which is
what win9x itself does as some reverse engineering of kernel32/vwin32
reveals it).
since the engine was designed as a thread based state machine (i.e. state
info maintained on a per thread basis, object oriented design? ;-), it is
able to trace any number of threads simultaneously. right now it can
automatically start tracing a newly created thread if there is at least one
traced thread already in the same process or in the parent process (there
already are some schemes that use multiple threads as an anti-debugging
measure).
the engine stops tracing a thread when it dies (only a message is logged
in winice) or when EIP reaches a user defined range. in this latter case
winice will break in and the user can do whatever he wants (e.g. try to
dump the process to a PE file).
how to use it.
the engine is controlled from icedump/winice via 2 commands: TRACE and
TRACEX. as usual, the latter handles the current thread and exits winice,
otherwise they do (almost) the same job. these commands are described in
the main doc in full detail.
the behaviour of the engine also depends on a few flags which determine how
much trace info to log and what should happen when a new thread is detected
in a process (note that these flags by no way reflect what can be done,
they're only what i found useful during my experiments).
for logging there are 3 choices: all executed instructions, those that can
change the flow of execution (branches, calls, etc) and finally the last
but one traced instruction before winice breaks in (the idea being that one
could go back and see where the original entry point was reached from).
the log information contains CS:EIP, SS:ESP and R0TCB, but again, this can
be easily enhanced/fine-tuned by changing the engine code.
new-born threads can be handled in 3 basic ways (after they become eligible
for tracing at all, see previous section on what the conditions are in the
current version): let them run without further tracing, trace them
automatically without bothering the user (in this case the EIP range will
be simply inherited) or have winice break in right at the beginning of the
new thread and give the user the choice to start tracing it via TRACEX.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -