Early this month, a new version of Vivisect was released which fixed a large amount of bugs, and added a tremendous amount of new features. While looking over the changelog and documentation, I realized that there doesn’t really seem to be a good tutorial or primer for getting familiar with the Vivisect framework so hopefully we can remediate that today. In this series, we’ll be covering the usage of VDB (dynamic debugging component) and vivisect (static analysis tool). One thing that makes Vivisect so powerful is the fact that it’s completely scriptable in Python. If you’re looking for an example of scripting VDB, check out fitblip’s post since I don’t plan on covering it at this time. This post assumes the reader has some introductory knowledge of reverse engineering and reading (dis)assembly.
For the rest of this post, we’ll be working with a 32-bit version of Ubuntu 12.04, Python 2.7.3 and three trivial binaries (source code to follow). The only dependencies for Vivisect on Ubuntu is Python, which ships with the distro, and PyQT4 which can be installed with “sudo apt-get install python-qt4.” The code for the binaries is as follows and can be complied by simply running:
user@ubuntu:~/vivisect_20130901$ gcc readword.c -o readword user@ubuntu:~/vivisect_20130901$ gcc conditional.c -o conditional
readword.c
#include <stdio.h> #define MAX_LEN 80 int main (int argc, char *argv[]) { char a_word[MAX_LEN]; printf ("Enter a word: "); scanf ("%s", a_word); printf ("You entered: %s\n", a_word); return 0; }
conditional.c
#include <stdio.h> int main() { int age; printf( "Please enter your age" ); scanf( "%d", &age ); if ( age < 100 ) { printf ("You are pretty young!\n" ); } else if ( age == 100 ) { printf( "You are old\n" ); } else { printf( "You are really old\n" ); } return 0; }
Before continuing, please ignore the ugly code above and pay no mind to the use of deprecated functions…
The two programs above will be built and compiled on our Ubuntu machine, and the third file we’re going to use is a Win32 PE which is also the same file used by in the well-known series “Lena’s Reversing for Newbies.”
Now that we have all that business out of the way, let’s get started.
While we do distinguish between “vivisect” and “vdb,” and sometimes “vtrace,” they’re all part of the same framework, which is simply called Vivisect. Within this framework, there is also a tool called vivisect which is what we’re talking about now. Vivisect is a static analysis component of the framework which allows us to generate a .viv workspace for a given binary file. Currently, Vivisect supports PE, PE32+, Elf32, Elf64 and Mach-O. To get started, let’s generate a .viv workspace for reverseme.exe and start doing some static analysis of the binary. Oh, and in case you’re curious, reverseme.exe is a very simple crackme which checks for a keyfile, and spits out an error message if the keyfile isn’t found or if it’s invalid.
No keyfile.dat present
Invalid keyfile.dat in Path
Using these error messages and the Vivisect workspace, we’ll start to navigate through the binary to see more about how it works, but most importantly, how to use Vivisect.*
*We don’t focus too much on the binary, what it does, and how to crack it since that’s already been done in multiple tutorials elsewhere. If you want to see the solution to the crackme and patching the application, check out TiGa’s tutorial which uses IDA 5.x and this binary.
To generate a workspace for our binary file, run the following command:
user@ubuntu:~/vivisect_20130901$ ./vivbin -B reverseme.exe Loaded (0.2901 sec) reverseme.exe ANALYSIS TIME: 0.217390775681 Saving workspace: reverseme.exe.viv
Now that we’ve generated our workspace, we don’t need the binary for static analysis since everything is contained within the outputted .viv file. To open this file within vivisect, simply run ./vivbin reverseme.exe.viv and upon completion, you’ll have a boring screen that looks something like the below:
While you can pick and chose items from the menu bar up top, I recommend loading the default layout as documented in the default display screen. Once you load the layout, your workspace should now look like the below image.
At a glance, we can immediately see some very useful and familiar things in our new layout. The top left window is the function graph panel which displays the graph for a given function, as we’ll see shortly. To the right of the function graph is another window currently displaying functions in the analyzed application. Immediately under this window there are 5 tabs labeled “Strings,” “Segments,” “Imports,” “Exports,” and “Functions” (which is your current display). As you can guess, these tabs change the window to display functions imported and exported by the target binary, strings found in the binary, and the segments which make up the executable. For the sake of learning, let’s play dumb and act like we don’t know anything about this application other than what the error messages showed us and let’s start with the firs error message, “Evaluation period out of date.” To find out where this string comes from, we’ll locate the string in Vivisect, find cross-references to this string, identify the function responsible for this, and see what else the program can do.
Click the strings tab and find the string which shows this text. Right click this string and from the popup menu, chose “xrefs to >” and mouse over “0x00401084 reverseme.__entry,” “send to FuncGraph0.” Once this is done, open up and maximize FuncGraph0 which will show a graph of the corresponding function.
FuncGraph0
To zoom in/out of the graph, hold shift and scroll your mouse wheel up or down. To move left, right, up, or down, hold shift and simply drag your mouse. Zooming out gives us a better idea of the flow of the application, even if it’s not as legible.
Zoomed Out funcGraph0
Because this is a very simple program, it’s pretty easy to scroll around and get an idea of what does what and what goes where. In looking at the first block (entry point 0x00401000), we can see at the end that there is a comparison (0x00401078) and a conditional branch (0x0040107b).
CODE:0x0040106e 6879204000 push str_Keyfile.dat_00402079 CODE:0x00401073 e80b020000 call CreateFileA_00401283 ;kernel32.CreateFileA(0x00402079,0xc0000000,3,0,3,0x0040216f,0) CODE:0x00401078 83f8ff cmp eax,0xffffffff CODE:0x0040107b 751d jnz loc_0040109a
The code path to the left is what we hit when no key file is in the currently running path and the program immediately exits.
No Key File Present
CODE:0x0040107d 6a00 push 0 CODE:0x0040107f 6800204000 push str_ Key File Revers_00402000 CODE:0x00401084 6817204000 push str_Evaluation perio_00402017 CODE:0x00401089 6a00 push 0 CODE:0x0040108b e8d7020000 call MessageBoxA_00401367 ;user32.MessageBoxA(0,0x00402017,0x00402000,0) CODE:0x00401090 e824020000 call ExitProcess_004012b9 ;kernel32.ExitProcess(sp+0)
Without digging into the disassembly too much, we can see some fairly obvious things here. Let’s go backwards. 0x00401090, ExitProcess is called and the program exits. 0x0040108b, MessageBoxA is called and this is what causes the message box to appear displaying the text. Next, 0x00401084, “push str_Evaluation perio_00402017.” This looks like it’s related to the evaluation period error message, but because we’re playing dumb, we can’t be for sure so let’s get some additional information. Highlight “CODE:0x00401084”, right click, send to viv. Once that’s done, click the viv tab under the FuncGraph0 window and you’ll see some new stuff.
Send to Viv
Viv View
The viv view doesn’t show us the function graph (since it’s a different view and all…), but it does give us some navigation improvements. For example, we want to know more about str_Evaluation perio_00402017 but the graph view had nothing to say about it. In viv view, double click str_Evaluation perio_00402017 and voila! We now know everything there is to know about this string, and what a beautiful string it is.
Our String (what a beauty)
If you’re feeling particularly fancy, you should notice that the viv view, when displaying the DATA section of the binary, shows us that there are 3 cross-references (XREFS) to this string. Right click the DATA block and select “xrefs to” if you care to see where these xrefs are. Following any of these xrefs to funcGraph0 will adjust the function graph to show you where that xref exists in the program.
Well, that’s all for now and thank you for reading. Be sure to check back next week where we’ll do some more work with reverseme.exe, manipulate our ELF32 binaries, add code comments, rename functions, identify code paths through the binary, and get started working with the vivisect debugger.