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.

  #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

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.

/******************************************************
*       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;
    }; }
    }

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:

# !usr/bin/python
import immlib
def main(args):
 dbg = immlib.Debugger()
 return ""
 dbg = immlib.Debugger() – define a instance to a debugger class

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:

import immlib

def main(args):
    dbg = immlib.Debugger()
    dbg.writeLog(“Hello world!”)
    return ""

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

Want to learn more?? The InfoSec Institute Reverse Engineering course teaches you everything from reverse engineering malware to discovering vulnerabilities in binaries. These skills are required in order to properly secure an organization from today's ever evolving threats. In this 5 day hands-on course, you will gain the necessary binary analysis skills to discover the true nature of any Windows binary. You will learn how to recognize the high level language constructs (such as branching statements, looping functions and network socket code) critical to performing a thorough and professional reverse engineering analysis of a binary. Some features of this course include:

  • CREA Certification
  • 5 days of Intensive Hands-On Labs
  • Hostile Code & Malware analysis, including: Worms, Viruses, Trojans, Rootkits and Bots
  • Binary obfuscation schemes, used by: Hackers, Trojan writers and copy protection algorithms
  • Learn the methodologies, tools, and manual reversing techniques used real world situations in our reversing lab.

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:

 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;
}

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

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

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"