Back to the main page

Table Of Contents

Intro

A while ago I wrote a fix for the "Corel Painter" program and I needed a utility that would spy every API call made by a program in order to find out which API call could have been causing the problem I was trying to resolve.

Soon I found out there are a lot of API tracing tools out there, but they all focus on specific API calls and none of them would actually trace "as deep as possible".  Even the Windows debugger (WinDbg) with the logexts would not reveal every API call made...  So I thought there is probably a need for such a utility.  Especially since my background is UNIX, I'm used to having tools like "truss" or "strace" available to me and it was surprising to see that such a tool was not available on Windows.

I have to say upfront that the current release is just "something that works", but doesn't contain any bells and whistles, yet.  The hardest part was "being able to log just about anything" and making sure the trace would not mess up the program it is tracing.  So it does the job for what I need it for, but that doesn't necessarily mean it will do the job for you.  Of course I'm interested to hear your feedback (see below on the page).

License

The program I used makes extensive use of the Detours Library provided by Microsoft Research.

Because of that, the current version of the tool (that can be downloaded from this website), is licensed under the same license as Detours.  See here for those license details.

I have not provided source code with this tool, because I plan to improve it a lot more...

Download


The zip file with xptruss can be downloaded here.

If this works for you and you find it worthwhile, feel free to donate something for it using Paypal or your credit card. Just to give you an idea, most people donate between 5 and 10 USD, 4 and 8 Euro or 700 and 1400 Yen.

Euro
US Dollars
Yen

How To Use xptruss

  1. Download the zip file and unpack it in an empty directory.
  2. Open a command prompt in that directory
  3. run: xptruss "executable + arguments"
For your first test, pick something simple like xptruss "calc" or xptruss "notepad" ... don't run a very large or long test until you know the amount of output it will produce.

After the run, you will see a *.txt file for every library the executable loaded.
In those txt files you will see calls which could not be instrumented (current limitations of Detours technology).
These files are called "exception files" and you can modify them yourself and add calls for which you don't want tracing enabled.  However, if you remove lines from the exception file, you will see xptruss will add those again.

In the same directory you will find an out.txt file ... this file will contain information about the execution.

"out.txt" will contain a full multithreaded trace of all DLL calls.

The log file starts with a list of functions that have been instrumented (and which were not).
Then it provides an execution trace of the program it launched in the following format :
    (<thread id>:<stackdepth>) (direction) <dll>!<function>

The call direction is indicated by > and < : where a “>” means function entry and a “<” means function exit

So although I think it traces more calls than I've seen in any other tool, it still doesn’t trace every call just yet.  To be able to track what is not traced, the exception files I mentioned before are created.  Each call in an exception file will be skipped during instrumentation.  Besides adding calls to this file to filter them, you can also add very simple directives to the the txt files (actually currently only one is useful).
If you add "SKIP_THIS_ONE" (without the quotes/all caps) at the top of an exception file, then that dll will be skipped altogether... I know this is rather basic and will need to be improved later, but it works for now.

The “exception files” are created at the first run, so in case your executable crashes right after startup, it might help  to run the same command twice.  There are probably programs that this will not work with (besides the Detours library, it also contains some hardcore assembly) … but my tests look promising. Anyway, if you find a crash, let me know…

I think this tool is useful because:

  1. It can show you a stack trace where a debugger would be lost (if stackframe corruption happens).
  2. It shows some indepth information on call sequences on Windows
  3. You can clearly follow how exceptions cause stack unwinding
  4. Will show you the exported functions for every dll and show which functions are aliases (aliases are not instrumented) or forwarded (also not instrumented)

That's about it for now ... no fancy features yet, but expect them soon.

Current Limitations

Anyway, I will be improving on it because I like this kind of work… Please don’t distribute it to anyone for now. Just looking for feedback … if you have any…

Future Plans

 

Basically I would like to overcome all the limitations (one at a time).  In addition to that I would like to

Anyway, I will be improving this tool over time... If you have questions you can email me and I will try to answer (email address on main page).

The mandatory screenshot

Excerpt from the initialization section in "out.txt"
LOAD C:\WINDOWS\system32\ntdll.dll              
kernel32.dll!DuplicateHandle : Instrumented
kernel32.dll!EncodePointer : Forwarded Function: NTDLL.RtlEncodePointer
Found new exception: EncodePointer
kernel32.dll!EncodeSystemPointer : Forwarded Function: NTDLL.RtlEncodeSystemPointer
Found new exception: EncodeSystemPointer
kernel32.dll!EndUpdateResourceA : Instrumented
kernel32.dll!EndUpdateResourceW : Instrumented
kernel32.dll!EnterCriticalSection : Forwarded Function: NTDLL.RtlEnterCriticalSection
Found new exception: EnterCriticalSection
kernel32.dll!EnumCalendarInfoA : Instrumented
kernel32.dll!EnumCalendarInfoExA : Instrumented
kernel32.dll!EnumCalendarInfoExW : Instrumented
kernel32.dll!EnumCalendarInfoW : Instrumented
kernel32.dll!EnumDateFormatsA : Instrumented
kernel32.dll!EnumDateFormatsExA : Instrumented
Excerpt from the Trace section in "out.txt".  This is an example of what _write() "really" does
Note the RtlEnterCriticalSection which happens to be a forwarded from kernel32 EnterCriticalSection.
(0000090C:2)       > msvcrt.dll!_write
(0000090C:3)          > ntdll.dll!RtlEnterCriticalSection
(0000090C:3)          < ntdll.dll!RtlEnterCriticalSection
(0000090C:3)          > kernel32.dll!WriteFile
(0000090C:4)             > kernel32.dll!WriteConsoleA
(0000090C:5)                > ntdll.dll!CsrClientCallServer
(0000090C:6)                   > ntdll.dll!NtRequestWaitReplyPort
(0000090C:6)                   < ntdll.dll!NtRequestWaitReplyPort
(0000090C:5)                < ntdll.dll!CsrClientCallServer
(0000090C:4)             < kernel32.dll!WriteConsoleA
(0000090C:3)          < kernel32.dll!WriteFile
(0000090C:3)          > ntdll.dll!RtlLeaveCriticalSection
(0000090C:3)          < ntdll.dll!RtlLeaveCriticalSection
(0000090C:2)       < msvcrt.dll!_write

Example Exception file (ntdll.dll)

RtlSetUnicodeCallouts
RtlDebugPrintTimes
KiFastSystemCallRet
DbgUserBreakPoint
DbgBreakPoint

These are the 5 only calls that can't be instrumented in ntdll.dll with Detours.  Of course there are other ways of making sure those calls do get traced, but that will require a lot more work.  At least you know what can't be traced...

Kudos

Thanks to:

 

Back to the main page