Scripts and Tools

Table of Contents

  1. Overview
  2. Installation
  3. Scripts and Tools
  4. Console (GUI) and Modules
  5. Developer Docs

Debuggee Procedure Call (DPC)

Interface: Command Line
Requires: PyDbg

This allows you to attach to a process and call arbitrary functions for exploratory purposes. Once attached you are presented with a prompt that can accept any valid Python statements. Use the dbg variable to access the current PyDbg instance pointer. For example if you want to resolve the address of an API, you can call dbg.func_resolve_debuggee(). A few convenience wrappers exist for allocating (alloc()), free-ing (free(), free_all()) and displaying allocated chunks (show_all()) of memory. To call a function within the debuggee, use the dpc() routine. This routine is the real core of the script. Given an address and arguments it will allocate and initialize space in the debuggee for storing the necessary instructions and arguments and then redirect EIP from the current thread to the newly created instructions. A breakpoint is written after the assembled instruction set that is caught by our breakpoint handler which re-prompts the user for further commands. Note: You *can not* directly assign the return value from dpc(). You must explicitly assign Eax, example:
    var = dpc(0xdeadbeef, "pedram")     # INCORRECT
    
    dpc(0xdeadbeef, "pedram")           # CORRECT
    var = dbg.context.Eax
DPC also supports fast-call, to use simple specify a register value as a keyword argument. For example:
    dpc(function, 10, "string", eax=0xdeadbeef, ecx="string")
Other valid commands from the prompt include DONE, GO and G for leaving the command prompt loop and continuing the process (available for more advanced usage of the script). On a final note, while assigning variables from the command prompt is perfectly ok, assigned variables are not persistant across calls to dpc() or the various continue commands. A special global class pointer is available for storing persistant variables called glob, usage is simple:
    glob.string = "A" * 500
    glob.list   = []
    glob.mbox   = dbg.func_resolve("user32", "MessageBoxA")
To view assigned variables within the glob structure, simply print glob.

The general logic of the script is as follows:
  • Allocate memory in the process.
  • Reverse the argument list.
  • For each numeric argument generate and write a PUSH instruction to the allocated block.
  • For each string argument, allocate memory for the string then generate and write a PUSH instruction to the allocated block.
  • For each specified register value, set it appropriately. If it is a string, allocate memory for the string and place the string address in the register.
  • Generate and write a CALL instruction to the allocated block.
  • Write an INT 3 (breakpoint) to the allocated block to resume debugger control and re-prompt the user for further inputs.

OllyDbg Connector / Receiver

Interface: Command line, OllyDbg
Requires: uDraw, PIDA, OllyDbg

To use this utility you must install the OllyDbg connector plug-in from ollydbg_connector\Release, source code for the plug-in is available. Once installed, three new hotkeys are registered:
  • , < Step into (F7) and transmit current location to OllyDbg receiver.
  • . > Step over (F8) and transmit current location to OllyDbg receiver.
  • / ? Transmit current location to OllyDbg receiver.
The first time one of the hotkeys is hit, a dialog is displayed asking for the IP address of the OllyDbg receiver. When requested, the plug-in transmits the current module name and location to the receiver. The OllyDbg receiver script (ollydbg_receiver.py) listens on TCP port 7033 for connections from the connector plug-in. It will look in the current directory for .PIDA modules matching the transmitted module name. If found, a graph is generated and transmitted to uDraw(Graph). The receiver defaults to attempting to connect to uDraw(Graph) on 127.0.0.1:2542, this default setting can be overridden by the optional -h, --host and -p, --port parameters respectively. Note: The receiver script expects uDraw(Graph) to be started with the -server option. Example:
    "C:\Program Files\uDraw(Graph)\bin\uDrawGraph.exe" -server
When you transmit your location at the top of a function, a call graph is displayed. When you transmit your location from within a function, a control-flow graph is displayed. The current node you are in is highlighted orange, previously visited (and transmitted) nodes are highlighted in blue.

PIDA Dump / Load

Interface: IDA
Requires: PIDA, IDA

The PIDA dump script, pida_dump.py, is an IDA Python script that must be run after IDA has completed its auto-analysis on your target binary. The script presents a few dialogs prior to asking for the output PIDA module name. The first is what level of analysis you want "functions", "basic blocks" or "full". The memory consumption and file size difference between each of the three levels of analysis are drastically different, most notably so between "basic blocks" and "full". The next option controls whether or not to create nodes and edges within the PIDA module for API calls, if you're interested in seeing the relationship between the routines within your module and API calls then you should enable this option. Finally, you are asked if you would like the dump script to enumerate any available RPC interfaces and dispatch routines in the current module.

Note: If you are generating a PIDA module for whatever.dll, you *must* name the PIDA module whatever.dll.pida as a number of tools / utilities (such as pstalker and the OllyDbg receiver) expect this convention.

The PIDA load script, pida_load.py, is more of an example than anything else. Demonstrating how to load the contents of a PIDA module into memory. Occasionally, I find use in actually loading a PIDA module into my IDA session, this script can be used to accomplish that task.

Proc Peek / Proc Peek Recon

Interface: IDA, command line
Requires: PyDbg, IDA Python

This is a two part utility designed for locating "low hanging fruit" vulnerabilities in Windows software. To use this utility, you must first run the proc_peek_recon.py IDA Python script, again after IDA has finished its auto-analysis. A .recon file will be generated that contains the locations (I call these "peek points") of various potentially interesting locations within the binary. Example locations include discovered inline memcpy()'s, calls to various routines that take format strings and are passed a %s format string token as well as calls to potentially dangerous API such as strcat, strcpy and the like. For the full list, see the source code. It's by no means an exhaustive list in the current release.

Once the .recon file is generated, use the proc_peek.py script to attach to your target process and examine the data that comes across those various interesting locations. There are various command line options:
  • <-r | --recon RECON FILE>: name of proc_peek_recon output file, this is the only required argument
  • [-p | --pid PID]: pid to attach to (must specify this or watch)
  • [-w | --watch PROC]: target name to watch for and attach to
  • [-i | --ignore PID]: ignore a specific PID when watching for a target
  • [-n | --noint]: disable interactive prompts
  • [-q | --quiet]: disable run-time context dumps
  • [-l | --log LOG FILE]: report to file instead of screen
  • [-h | --host REMOTE HOST]: connect to a pydbg server
  • [-b | --boron KEYWORD]: alert us when a keyword is found within the context
  • [-t | --track_recv]: enable recv() and recvfrom() hit logging
There are also various run-time prompt options that allow you to disable further examination of specific "peek points".