« March 2010 | Main | May 2010 »

April 30, 2010

Kernel debugging with IDA Pro / Windbg plugin and VirtualKd

The other day we received an email support question asking if IDA Pro / Windbg debugger plugin works with VirtualKd, a tool that allows speeding up (up to 45x) Windows kernel module debugging using VMWare and VirtualBox virtual machines. After we installed and experimented with VirtualKd, our answer was "yes, certainly". This blog entry aims at illustrating how to configure VirtualKd to be used with IDA Pro / Windbg plugin and VMWare.


Installing VirtualKd

First download the VirtualKd package, unzip its contents and copy the contents of the 'target' folder to the VMWare guest OS and run 'vminstall.exe'. After this step, reboot the guest and run the 'vmmon.exe' (or 'vmmon64.exe') inside the host. If everything is successful, you should see something like this:


Please take note of the 'Pipe name' value as shown in the screenshot. We will use this value when configuring the Windbg plugin.

Configuring IDA Pro / Windbg plugin

First, run IDA Pro without an input database and select Debugger / Attach / Windbg plugin:


Next, we get this screen:


Here we enter a connection string (designating that the com port is a pipe). The pipe name is the same value we read from the 'vmmon' tool from the above steps.

Before pressing OK, we need to make sure that the Windbg plugin is properly configured. Let us verify that by pressing on the 'Debug options' button:


This dialog is used to configure the debugger in general, it is common to all debugger modules. Since we don't need to change any of those settings now, let us instead select 'Set specific options':


Make sure that these two options are properly configured:

  1. Kernel debugging is selected
  2. Debugging tools path is correctly entered. Please note that even if you're debugging an x64 kernel you still need to point to the x86 version of the debugging tools.

After we configured everything, simply press OK all the way until the attach dialog shows up:


Pressing OK one last time will start the debugging session:


After debugging for a while, we were really amazed at the speed improvement achieved with the help of VirtualKd (nice work VirtualKd team). Kernel debugging speed using the Windbg plugin is almost comparable to the local win32 debugger plugin.

For a more elaborate tutorial on configuring and using the Windbg plugin please check our support page.

April 28, 2010

Book Review: The Art of Assembly Language, 2nd Edition

Have you ever tried to teach x86 assembly language programming to someone coming from high level language programming background and discovered that it was hard?

Before being able to write a simple "Hello World" program one needs to know a fair deal about the x86 architecture, the assembler language and the operating system. Obviously this is not the case with high level languages such as C for example.

I was reading The Art of Asssembly Language, 2nd edition book by Randall Hyde the other day and really enjoyed his approach to teaching the assembly language programming.

In his book, Randall introduces the reader to the HLA (High Level Assembler) compiler which will be used as a tool to learn the x86 assembly language.

The syntax of HLA can be thought of as a hybrid of Pascal and assembly language. Here's a sample "Hello world" HLA program:
program helloWorld; #include( "stdlib.hhf" ); begin helloWorld; stdout.put( "Hello, World of Assembly Language", nl ); end helloWorld;
You may argue that this was not an assembly language program, but what about this:
program h; #include("stdlib.hhf"); static s: string := "Hello World!"; procedure chksum_str; @returns( "eax" ); begin chksum_str; mov(s, edi); xor(ebx, ebx); xor(eax, eax); while( mov( [edi], al ) <> #0 ) do inc(edi); // advance str ptr add(eax, ebx); endwhile; mov(ebx, eax); end chksum_str; begin h; stdout.put("The checksum of '", s, " is: 0x"); chksum_str(); stdout.put(eax); if ( eax == 1234 ) then stdout.put("Special chksum!", nl); endif; end h;
Although this is also not pure assembler syntax, the newcomer will enjoy learning about the x86 architecture and instruction set with the help of the features provided by HLA:
  • Ability to create user types
  • Exception handling
  • Control and repetition structures (and other constructs found in high level languages)
  • Classes and objects
  • Various libaries: stl, file i/o, os, array manipulation, math, etc...
  • etc...
Throughout the book, before a programming concept is introduced, Randall talks about the necessary background information (architecture and instruction set) and then explains how to put the concept into practive using HLA.

For example, in Chapter 5 (Procedures and Units), he explains in detail how the stack is set up during a procedure call, how local variables are allocated and how to access the arguments, followed by explanation on how to use HLA to write procedures. Similarly in Chapter 6, when talking about FPU arithmetics, the author carefully explains about the FPU data and controls registers, related instruction set and finally how to use HLA to do FPU arithmetics.

If your aim is to learn assembly language in order to start reverse engineering, this book is probably not for you, however I highly recommend this book for programmers:
  • That always wanted to learn the x86 assembly language but found it difficult to start with. This book is well organized and easy to read
  • That want to teach the basics of the x86 architecture and assembly language
  • That want to put together an x86 assembly program quickly. HLA compiler and the built-in libraries give you the convenience of a high-level programming language and the power of a low level language. If you use the standard libraries provided by HLA then your program is portable

April 05, 2010

Environment variable editor

Normally, to change environment variables in a running process, one has to terminate the process, edit the environment variables and re-run the process. In this blog entry we are going to write an IDAPython script that allows us to add, edit or delete environment variables in a running process directly. To achieve this we will use Appcall to manage the variables and a custom viewer that serves as the graphical interface.

envedit.gif

Background

In MS Windows, environment variables can be managed using various API calls. For our script we are only interested in 3 calls:
  • GetEnvironmentStrings: Returns a block of memory pointing to all the environment variables in the process. This block is a list of zero terminated strings, the end of the list is marked with two \0 characters (such list is also known as MULTI_SZ)
  • FreeEnvironmentStrings: Frees the block returned by GetEnvironmentStrings()
  • SetEnvironmentVariable: Creates or edits an environment variable
In order to modify the environment variables in a process, we need to issue those API calls in the context of that process. One solution is to inject a DLL into the running process and ask it to call those APIs. Another simpler solution is to write a script that uses Appcall to issue those API calls.

Setting up Appcall

Let us use Appcall to retrieve 3 callable objects corresponding to the APIs in question:
GetEnvironmentStrings = Appcall.proto("kernel32_GetEnvironmentStringsA", "unsigned int __stdcall GetEnvironmentStrings();") SetEnvironmentVariable = Appcall.proto("kernel32_SetEnvironmentVariableA", "int __stdcall SetEnvironmentVariable(const char *lpName, const char *lpValue);") FreeEnvironmentStrings = Appcall.proto("kernel32_FreeEnvironmentStringsA", "int __stdcall FreeEnvironmentStrings(unsigned int block);")
Now we can use those callable objects to call the APIs in the context of the debugged process, for example:
# Add a new environment variable SetEnvironmentVariable("MY_VAR", "Some value")
Please notes that:
  • Both GetEnvironmentStrings() and FreeEnvironmentStrings() prototypes are re-declared to accept an unsigned int instead of a character pointer because Appcall does not support the MULTI_SZ type.
  • We are using the ASCII version of those APIs. Modifying the script to work with the unicode version is not very difficult to achieve.

Retrieving all environment variables

We need to write a function to retrieve all the environment variables in a list:
  1. Call the GetEnvironmentStrings() to retrieve a pointer to the environment block in the process. Save that pointer
  2. Read the debuggee's memory at that block and retrieve the variables accordingly.
  3. Free the block by calling FreeEnvironmentStrings()
To read the debuggee's memory, we can use idc.Bytes(), idaapi.get_many_bytes() or idaapi.dbg_read_memory(). Since we don't know how big the block is, we will read one character at a time and process it.
For demonstration purposes, we will use yet another mechanism to read from the debuggee's memory as if we were reading from a file. We will use the loader_input_t class followed by a call to open_memory() function:
def Variables(): """Returns all environment blocks""" # Get all environment strings env_ptr = GetEnvironmentStrings() if env_ptr == 0: return None # Always refresh the memory after a call # that could change the memory configuration idc.RefreshDebuggerMemory() # Open process memory f = idaapi.loader_input_t() f.open_memory(env_ptr) # Parse all environment variables into a list of variables vars = [] var = [] while True: ch = f.get_char() if not ch: break if ch == '\x00': # double-null -> end of list if not var: break vars.append(''.join(var)) var = [] else: var.append(ch) f.close() # Free the block FreeEnvironmentStrings(env_ptr) return vars

Writing a custom viewer to manage the environment variables

Now that we have all the required supporting code, we can write a custom viewer that does the following:
  • Retrieves all the environment variables: call GetEnvironmentStrings() and parse the result
    • Parse each environment variable into KEY/VALUE components
    • Add a colored line into the custom viewer with different colors for the KEY and VALUE
  • Add popup menu entries and handle keypresses to support three operations:
    • Insert: Ask the user for a key and value using the idaapi.askstr() then call the SetEnvironmentVariable() API as shown in the previous example
    • Edit: Retrieve the cursor position, extract the key name, ask the user for a new value only (w/o asking for a key) and call the SetEnvironmentVariable() API
    • Delete: Retrieve the key name and call SetEnvironmentVariable() API with value pointing to NULL
Before running the script, make sure that the debugged process is suspended. Right-click on an environment variable to edit/insert or delete.

Please download the script from here.