Reverse engineering

Extending Debuggers

SecRat
June 25, 2014 by
SecRat

Sometimes we come across situations when we are in need of doing something inside our debuggers or to extend the functionality of them. For such things, debuggers usually provide an API interface to extend or provide extra functionality for the debugger.

There are two types of API provided by the debuggers:

1: SDK API

2: Scripting API

One can choose any based on the requirements. Usually when there is a rapid requirement, scripting will come in handy, but if something requires system or low level access, then SDK is useful. SDK API requires being compiled, while scripts can be modified easily.

Ollydbg Plugin Interface

Ollydbg supports API for plugins. Plugins are compiled DLL written in C programming language. The following constants define particular actions in a debugger context.

[c]

#define ODBG_Plugindata _ODBG_Plugindata

#define ODBG_Plugininit _ODBG_Plugininit

#define ODBG_Pluginmainloop _ODBG_Pluginmainloop

#define ODBG_Pluginsaveudd _ODBG_Pluginsaveudd

#define ODBG_Pluginuddrecord _ODBG_Pluginuddrecord

#define ODBG_Pluginmenu _ODBG_Pluginmenu

#define ODBG_Pluginaction _ODBG_Pluginaction

#define ODBG_Pluginshortcut _ODBG_Pluginshortcut

#define ODBG_Pluginreset _ODBG_Pluginreset

#define ODBG_Pluginclose _ODBG_Pluginclose

#define ODBG_Plugindestroy _ODBG_Plugindestroy

#define ODBG_Paused _ODBG_Paused

#define ODBG_Pausedex _ODBG_Pausedex

#define ODBG_Plugincmd _ODBG_Plugincmd

[/c]

Plugins for ollybdg are written as shared library in C. We need to define the dll enrty point and inilitize the plug in before it is used. Events are also defined using exports.

Plugins are initialized using the ODBG_Plugininit() export function.

[c]

/******************************************************

* Sample Ollgdbg Plugin file

*

*******************************************************/

#include <stdio.h>
#include <plugin.h>

#pragma once
#pramga Comment ("lib", "ollydbg.lib") // Inlude the library file

BOOL WINAPI DllEntryPoint(HINSTANCE hi,DWORD reason,LPVOID reserved) {

if (reason==DLL_PROCESS_ATTACH)

hinst=hi; // Mark plugin instance

return 1; // Report success

};

extc int _export cdecl ODBG_Plugininit()
{

}

extc void _export cdecl ODBG_Pluginmainloop(DEBUG_EVENT *debugevent) {
};

extc void _export cdecl ODBG_Pluginaction(int origin,int action,void *item) {

t_bookmark mark,*pb;

t_dump *pd;

if (origin==PM_MAIN) {

switch (action) {

case 0:

break;

case 1:

MessageBox(NULL, "Hello World", "Hello World! Plugin ", MB_OK);

default: break;

}; }

}

[/c]

Immunity Scripting

Immunity debugger also supports scripting based on Python programming language. The scripts written for immunity debugger are known as pycommands. They can be executed in the command bar as !.

Immunity scripting supports breakpoints, hooking, and loggers.

The default skeleton for a pycommands script is:

[c]

# !usr/bin/python

import immlib

def main(args):

dbg = immlib.Debugger()

return ""

dbg = immlib.Debugger() – define a instance to a debugger class

[/c]

The following are some of the basic functions inside the Debugger class:

The script's main body is located in the main function with arguments as args. To execute the script, we need to place the file in the "C:Program FilesImmunity IncImmunity DebuggerPyCommands" directory and execute from the immunity command bar as !filename

Let's now create a dummy hello world script that writes to the log window:

[c]
import immlib

def main(args):

dbg = immlib.Debugger()

dbg.writeLog(“Hello world!”)

return ""

[/c]

We can save this file in the "C:Program FilesImmunity IncImmunity DebuggerPyCommands" as helloworld.py and it can be executed using the following command: !helloworld

There are more functions inside Debugger() class, let's try to explore and use them.

Getting the PEB address

getPEBAddress() is a method inside the Debugger class that can be used to get the PEB address of the loaded application inside the debugger.

We can use the PEB address to patch many things. PEB is mainly used for thread related structures and processing information. We can get the details in Loaded modules, for example what this malware code does with PEB:

[c]

typedef struct _PEB {

BYTE Reserved1[2];

BYTE BeingDebugged;

BYTE Reserved2[1];

PVOID Reserved3[2];

PPEB_LDR_DATA Ldr;

PRTL_USER_PROCESS_PARAMETERS ProcessParameters;

BYTE Reserved4[104];

PVOID Reserved5[52];

PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;

BYTE Reserved6[128];

PVOID Reserved7[1];

ULONG SessionId;

} PEB, *PPEB;

v9 = *(_DWORD *)"LoadLibraryExA";

v10 = *(_DWORD *)&aLoadlibraryexa[4];

v11 = *(_DWORD *)&aLoadlibraryexa[8];

v12 = *(_WORD *)&aLoadlibraryexa[12];

v13 = aLoadlibraryexa[14];

v15 = sub_4001E92();

v20 = 0;

v16 = (int (__thiscall *)(int, int, int *))sub_4001EA7(v15, "GetProcAddress");

v20 = v16(v5, v15, &v9);

v3 = a1;

result = *(_DWORD *)(a1 + 60);

for ( i = a1 + *(_DWORD *)(result + a1 + 128); *(_DWORD *)(i + 4) || *(_DWORD *)(i + 12); i += 20 )

{

v7 = v3 + *(_DWORD *)i;

for ( j = v3 + *(_DWORD *)(i + 16); ; j += 4 )

{

result = *(_DWORD *)v7;

if ( !*(_DWORD *)v7 )

break;

v15 = -1;

if ( result < 0 )

{

v2 = (unsigned __int16)result;

v15 = (unsigned __int16)result;

}

v14 = v3 + result;

v8 = *(_DWORD *)(i + 12);

v17 = v3 + v8;

v19 = ((int (__fastcall *)(int, int, int, _DWORD, _DWORD))v20)(v3, v2, v3 + v8, 0, 0);

if ( v15 == -1 )

{

v17 = v14 + 2;

v18 = ((int (__stdcall *)(int, int))v16)(v19, v14 + 2);

}

else

{

v17 = v15;

v18 = ((int (__stdcall *)(int, int))v16)(v19, v15);

}

if ( *(_DWORD *)j != v18 )

*(_DWORD *)j = v18;

v3 = a1;

v7 += 4;

}

}

return result;

}

[/c]

This code snippet loads LEP loaded modules and parses the IAT.

Now let's try to try to write a call counter in pycommands.

[c]

import immlib

from immlib import LogBpHook

times = "

class instructionHook(LogBpHook):

def __init__(self):

LogBpHook.__init__(self)

return

def run(self, regs):

global times

imm = immlib.Debugger()

imm.log("instruction Executed %d" % times)

times = times + 1

return

def main(args):

memlocation = 0x401029

dbg = immlib.Debugger()

logbp = instructionHook()

funcName = dbg.getFunction(imemlocation).getName()

logbp.add(funcName,i)

return "Hooks Placed"
[/c]

Would you like to test your skills further with a CTF challenge? Check this out:

SecRat
SecRat

SecRat works at a start-up. He's interested in Windows Driver Programming.