Automatic debugging and API monitoring

The debugger allows you to set a break point with commands which is executed on the break point. For example, the following debugging commands shows the stack trace whenever CreateFileW API is called and write them into the log file.

* Whenever CreateFileW is called, get the stack trace

.logopen log.txt
bp kernel32!CreateFileW "kb;gc"

How about logging the result code of the function? Unfortunately, any command that resumes program execution after a breakpoint (such as g or t) ends the execution of the command list. For example, the following command doesn’t work as expected.

* !! Doesn't work !!
* Whenever CreateFileW is called, get the stack trace and exit last error code.

.logopen log.txt
bp kernel32!CreateFileW "kb;pt;!gle;gc"

Here is a solution. On the function call break point, we can get the function return address at poi(@esp). Set another break point there before continue.

* Whenever CreateFileW is called, get the stack trace and exit last error code.

.logopen log.txt
bp kernel32!CreateFileW "kb;bp poi(@esp) \"!gle;gc\";gc"

There is another problem. We should disable the second break point after hit otherwise it would trigger the program break which is not expected.

Also, to make it a little more fun, let’s display the arguments to the function as well.

bp[1] kernel32!CreateFileW ".echo CreateFileW;db poi(@esp+4);bp[101] poi(@esp) \"bd[101];r;gc\";gc"

You can apply this technique to make a poor man’s API tracer program. It’s sometimes more convenient than !logext because we can trace user functions in addition to the Win32 functions.

Here is a debug command list to trace some of file I/O related functions.

bp[10] kernel32!GetFileAttributesA ".echo GetFileAttributeA;db poi(@esp+4);bp[51] poi(@esp) \"bd[51];r;!gle;gc\";gc"
bp[11] kernel32!CreateFileA ".echo CreateFileA;db poi(@esp+4);bp[50] poi(@esp) \"bd[50];r;gc\";gc"
bp[12] kernel32!GetShortPathNameA ".echo GetShortPathNameA;.echo long_name;db poi(@esp+4);bp[52] poi(@esp) \"bd[52];r;.echo short_name;db poi(@esp-8);gc\";gc"
bp[13] kernel32!DeleteFileA ".echo DeleteFileA;db poi(@esp+4);bp[53] poi(@esp) \"bd[53];r;gc\";gc"
bp[14] kernel32!GetLongPathNameA  ".echo GetLongPathNameA;.echo short_name;db poi(@esp+4);bp[54] poi(@esp) \"bd[54];r;.echo long_name;db poi(@esp-8);gc\";gc"
bp[15] kernel32!FindFirstFileW ".echo FindFirstFileW;db poi(@esp+4) L200;bp[55] poi(@esp) \"bd[55];r;!gle;.echo dstamt!WIN32_FIND_DATAW;dt poi(@esp-4) dstamt!WIN32_FIND_DATAW;gc\";gc"
bp[16] kernel32!GetFullPathNameA  ".echo GetFullPathNameA;.echo input_name;db poi(@esp+4);bp[55] poi(@esp) \"bd[55];r;.echo reuslt_name;db poi(@esp-8);gc\";gc"
bp[17] kernel32!SetCurrentDirectoryA  ".echo SetCurrentDirectoryA;db poi(@esp+4);bp[56] poi(@esp) \"bd[56];r;gc\";gc"
bp[18] kernel32!GetVolumePathNameW ".echo GetVolumePathNameW;.echo input_name;db poi(@esp+4);bp[57] poi(@esp) \"bd[57];r;.echo reuslt_name;db poi(@esp-8);gc\";gc"
bp[19] Shlwapi!PathFindFileNameW  ".echo PathFindFileNameW;.echo input_name;db poi(@esp+4);bp[58] poi(@esp) \"bd[58];r;.echo result_name;db @eax;gc\";gc"
bp[20] kernel32!GetTempPathW ".echo GetTempPathW;bp[59] poi(@esp) \"bd[59];r;gc\";gc"

About Moto

Engineer who likes coding
This entry was posted in Advanced Debugging. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s