flag Ukraine Stand with Ukraine

In this article, I will tell you how to write an anti-debug plugin for OllyDbg v. 2.01. The task is to prevent the application being debugged from detecting the debugger.

Written by:
Sergey Prepodobniy,
Software Developer of Driver Development Team


  • Introduction
  • General Information
  • Plugin Operation Principle
  • Development
    • Plugin Development
    • Auxiliary dll for Plugin
    • Hooked Function Operation Principle
  • Plugin in Action
  • Recommendations on Time Setup
  • Issues
  • Summary
  • Possible Future Improvements
  • References


We’ll consider two steps:

  • Writing the plugin,
  • Writing the auxiliary module for plugin.

This article is intended for people experienced in C++ and dll writing.

General Information

Modern computer programs are more complex in writing and more difficult for reversing. Serious programs use various anti-debugging techniques to prevent application reversing.

Measuring time to identify that an application is being debugged becomes the widespread practice lately. The OllyDbg has the «HideOD» and «Hide Debugger» anti-debug plugins, which have no possibility to hide actual time. This causes difficulties in application reversing.

Let’s consider the system of debugger identification. The debuggers are capable of making breakpoints in code. In this case the operation of the program is suspended. The program can detect such stopping by monitoring the system time. If there is a too long pause between the instructions – most likely the program has been stopped for analysis.

const int g_doSmthExecutionTime = 1050;
void DoSmth()
int main(int argc, char* argv[])
   SYSTEMTIME sysTimeStart;
   SYSTEMTIME sysTimeEnd;
   FILETIME timeStart, timeEnd;
   SystemTimeToFileTime(&sysTimeStart, &timeStart);
   SystemTimeToFileTime(&sysTimeEnd, &timeEnd);
   double timeExecution = (timeEnd.dwLowDateTime - timeStart.dwLowDateTime) / 10000.0;
   if (timeExecution < g_doSmthExecutionTime)
      std::cout << "Debugger not present";
      std::cout << "Debugger present";
   return 0;

This example measures the time of function execution, which is then compared to standard. This standard equals to the maximal normal function execution time.

The following functions can be used to measure time:


  • GetSystemTime;
  • GetSystemTimeAsFileTime;
  • QueryPerformanceCounter/QueryPerformanceFrequency;
  • GetTickCount;
  • GetTickCount64.


Hiding of OllyDbg by execution time substitutes custom time value for the original time, returned by the function. This is implemented by means of function hooks, as such a solution is painless and unnoticeable by an application.

You can read more details about hooking technique in our Windows API hooking article.

I.e. the pointer of the original function is replaced with the custom function with custom implementation, where the value is substituted. This implementation is written in dll loaded into the target process. dll includes exported functions – Start and Stop. Start sets up the hooks, and Stop removes them.

3. Plugin Operation Principle

The application is split into two parts:

  • Main dll (AntiDebugTimePlugin)
  • Auxiliary dll (Plugin)

The main dll is the plugin that interacts with OllyDbg and has the interface for interaction with auxiliary dll. It loads the auxiliary dll into the address space of the target process to perform the required actions.

The auxiliary dll has the code for setting and removing hooks. It also has the altered logic of functions that work with time. This dll replaces the true value of original function with the value set in the main dll. Thus the time for measurement is substituted, which prevents the debugger from being detected.

The plugin operation principle is as follows:


We can see from the scheme how OllyDbg loads the plugin. The plugin writes the values to the registry for interaction with the auxiliary dll. The plugin embeds the auxiliary dll into the process launched by OllyDbg.


Let’s get to the development itself.

Plugin Development

OllyDbg performs a search in dll located in the current folder and calls the exported functions it requires. Thus, after the function is found, OllyDbg loads it and adds the corresponding menu.

First, OllyDbg calls ODBG2_Pluginquery function. Inside this function, we check the OllyDbg version. If the version is suitable, we allow the plugin to be loaded into a process.

extc int __cdecl ODBG2_Pluginquery(int ollydbgversion,
                                   ulong *features,
                                   wchar_t pluginname[SHORTNAME],
                                   wchar_t pluginversion[SHORTNAME])
    if (ollydbgversion < 201)
        return 0;
    wcscpy_s(pluginname, SHORTNAME, g_pluginName);
    wcscpy_s(pluginversion, SHORTNAME, g_version);
    return PLUGIN_VERSION;

Then we need to initialize the variables before execution. We need to initialize a variable to create a window in OllyDbg style and set a range of values for auxiliary dll.

extc int __cdecl ODBG2_Plugininit(void)
    StrcopyW(g_table.name, SHORTNAME ,g_pluginName);
    g_table.mode = TABLE_SAVEALL;
    g_table.bar.visible = 1;
    g_table.bar.nbar = 1;
    g_table.tabfunc = SetRangeWND;
    g_table.custommode = 0;
    g_table.customdata = NULL;
    g_table.updatefunc = NULL;
    g_table.drawfunc = reinterpret_cast<DRAWFUNC*>(SetRangeDraw);
    g_table.tableselfunc = NULL;
    g_table.menu = NULL;
    // Init registry value
    SetRange(g_defaultMinValue, g_defaultMaxValue);
    // Report success.
    return 0;

Now we need to create a menu for OllyDbg to draw it in its own menu.

To do this, we create an array with the description of all menu items and their processing functions.

static t_menu mainmenu[] = {
    { L"Set range",
       L"Set min-max value of time",
       K_NONE, SetRangeMenu, NULL, 0 },
    { L"On",
       L"Hide OllyDbg in debugging process which uses functions time for defines OllyDbg",
       K_NONE, HideOllyDbgMenu, NULL, 0 },
    { L"|About",
       L"About Antidebug time-plugin",
       K_NONE, AboutMenu, NULL, 0 },

The function for returning menu for OllyDbg.

extc t_menu* __cdecl ODBG2_Pluginmenu(wchar_t *type)
    if (wcscmp(type, PWM_MAIN) == 0 ||
       (wcscmp(type, PWM_DISASM) == 0)
        return mainmenu;
    return NULL;

Now let’s consider the basic functions for work with menu.

The first item is intended for creation of the window, in which the range is entered.

int SetRangeMenu(t_table *pt, wchar_t *name, ulong index, int mode)
    if (mode == MENU_VERIFY)
        return MENU_NORMAL; 
    if (mode == MENU_EXECUTE)
        if (g_table.hw == NULL)
            Createtablewindow(&g_table, 0, g_table.bar.nbar, NULL, L"ICO_D", g_wndRangeName);
            SendMessage(g_table.hw, WM_CREATE, 0, 0);
        return MENU_NOREDRAW;
    return MENU_ABSENT;

The Createtablewindow is the function for creating a window in OllyDbg style. In our case – the window without a table, but with edit elements is used.

The second item turns the plugin on and off.

int HideOllyDbgMenu(t_table *pt, wchar_t *name, ulong index, int mode)
    if (mode == MENU_VERIFY)
        return (g_isNeedHooking ? MENU_CHECKED : MENU_NORMAL);
    else if (mode == MENU_EXECUTE)
        g_isNeedHooking = !g_isNeedHooking;
        return MENU_REDRAW;
    return MENU_ABSENT;

As the second item is checked, we return the menu item state depending on the flag state.

The only thing left is to subscribe to OllyDbg events to receive the information on the process being loaded.

extc void __cdecl ODBG2_Pluginnotify(int code, void *data, ulong parm1, ulong parm2)
    if (PN_NEWPROC == code)
        CThreadStateGuard threadState;
        if (IsNeedHooking())
            // Hooking
            g_processID = parm1;
            ::CloseHandle(::CreateThread(NULL, 0, SetHookThread, NULL, NULL, NULL));
    else if(PN_ENDPROC == code)
        CThreadStateGuard threadState;
        // UnHookHooking
        g_processID = parm1;
        ::CloseHandle(::CreateThread(NULL, 0, UnHookThread, NULL, NULL, NULL));
    else if (PN_ENDTHR == code)

There are 3 interesting events in this function: the emergence of a new process, process termination, and  thread termination.

After the notification about a new process is received, we load the auxiliary dll into the process address space.

Before the process is terminated, we remove the hooks set earlier.

In order for auxiliary dll to work properly, we need to set hooks before the process starts to execute the code. To do this, first, we freeze the main thread of the process so that no code is executed.After the process is loaded into OllyDbg completely, we unfreeze the process, and then the functions from auxiliary dll are executed instead of the original functions.

Starting with Windows Vista, it became more complicated to execute custom code in another process by means of CreateRemoteThread. The complication is that with each new start of the same process the functions are loaded to different adresses each time. Thus it’s impossible to pass LoadLibrary to CreateRemoteThread as parameter, so that it loads the auxiliary dll in another process.

The solution is to allocate memory in another process and write  code for execution bit-by-bit. I took the CodeProject code as a basis.

Auxiliary dll for plugin

This dll hooks such functions:


  • GetSystemTime
  • GetSystemTimeAsFileTime
  • QueryPerformanceCounter
  • QueryPerformanceFrequency
  • GetTickCount
  • GetTickCount64


It has two exported functions used by the main dll to set and remove hooks.

extern "C" __declspec(dllexport) void Start(void);
extern "C" __declspec(dllexport) void Stop(void);

The HookFunction function is used to set hooks. It generates an exception in case of an error and checks if a function has already been hooked.

FARPROC GetHookedFunctionAddr(const wchar_t* functionModuleName, const char* functionName)
    HMODULE hm = GetModuleHandleW(functionModuleName);
    return GetProcAddress(hm, functionName);
template <typename FunctionType>
bool HookFunction(FunctionType& originalFunction, 
                  void* hookFunction, 
                  const wchar_t* functionModuleName, 
                  const char* functionName,
                  bool isFunctionHooked)
        if (!originalFunction && !isFunctionHooked)
            originalFunction = reinterpret_cast<FunctionType>(GetHookedFunctionAddr(functionModuleName, 
            if (originalFunction)
                if (!Mhook_SetHook(reinterpret_cast<void**>(&originalFunction), hookFunction))
                    throw std::runtime_error("not successfully hooked"); 
            return true;
        return true;
    catch(const std::exception&amp: ex)
        return false;

To simplify the hook setting, let’s wrap this function into a macros with  function name and the name of the module, it is located in, as input parameters.

    (HookFunction(g_original_##FUNCTION_NAME, \
    HookFor_##FUNCTION_NAME, \
    is_hook_set_for_##FUNCTION_NAME##)) \

Then we set a flag to indicate the function has been hooked.

    (is_hook_set_for_##FUNCTION_NAME = true)

To unhook the function, we use macros as well:

    if (!Mhook_Unhook(reinterpret_cast<PVOID*>(&g_original_##FUNCTION_NAME)) ) \
    { \
        throw std::runtime_error("Can't unhook "#FUNCTION_NAME" function");\
    } \
    else \
    { \
        g_original_##FUNCTION_NAME = NULL; \
        is_hook_set_for_##FUNCTION_NAME = false; \
 } \

Now we use the macros to set hooks:

extern "C" __declspec(dllexport) void Start(void)
        OpenRange(g_minRangeValue, g_maxRangeValue);
        const std::wstring kernelName = L"kernel32.dll";
        HOOK_FUNCTION(GetSystemTime, kernelName.c_str());
        HOOK_FUNCTION(GetSystemTimeAsFileTime, kernelName.c_str());
    catch(const std::exception& exp)

To remove hooks:

extern "C" __declspec(dllexport) void Stop(void)
    catch(const std::exception& exp)

Hooked Function Operation Principle

Let’s consider an example for one function, as all functions have the same logic.

BOOL __stdcall HookFor_QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount)
    LARGE_INTEGER perfomanceCount = {0};
    std::wstringstream str;
    if (g_isFirstCallingQueryPerformanceCounter)
        perfomanceCount.LowPart = static_cast<WORD>(g_minRangeValue);
        perfomanceCount.LowPart = static_cast<WORD>(RandValue(g_minRangeValue, g_maxRangeValue));
       perfomanceCount.LowPart += static_cast<WORD>(g_minRangeValue);
    perfomanceCount.QuadPart = static_cast<LONGLONG>(perfomanceCount.LowPart);
    g_isFirstCallingQueryPerformanceCounter = !g_isFirstCallingQueryPerformanceCounter;
    *lpPerformanceCount = perfomanceCount;
    return g_original_QueryPerformanceCounter(&perfomanceCount);

First this function returns the minimum value from the range set in the main dll, then it returns a random value from the same range (min < number < max).

I.e. if the execution time is calculated (the difference between the end and the beginning of the execution), the application will always receive a value in this range: min < number < max.

Plugin in Action

To perform testing, let’s write an application that returns the difference between the beginning of the Sleep function work and its end. We’ll take 1000 milliseconds for the delay. We show this value in MessageBox.

int _tmain(int argc, _TCHAR* argv[])
        SYSTEMTIME lpSysTimeStart;
        SYSTEMTIME lpSysTimeEnd;
        FILETIME tmEnd,tmStart;
        SystemTimeToFileTime(&lpSysTimeStart, &tmStart);
        SystemTimeToFileTime(&lpSysTimeEnd, &tmEnd);
        int value = (tmEnd.dwLowDateTime - tmStart.dwLowDateTime) / 10000;
        std::wstringstream stream;
        stream << value;
        MessageBox(NULL, stream.str().c_str(), L"Testing", 0);
    return 0;

Here is the result of application work:


Now let’s set up the range of values in plugin. Let’s take the range between 2000 and 3000 milliseconds as an example. Now we turn the plugin on and load the process being tested to OllyDbg.

Here is the result:



As you can see from the test example above, the value from the indicated range is returned.

Recommendations on Time Setup

The values are set in milliseconds. The milliseconds threshold below 10 decreases accuracy.

The values may be different, but they depend on the values checked in other program. You may start with a wide range and then gradually decrease it until the application execution begins.


There is an interesting situation: if you take an application that does not use functions connected with time, it calls GetTickCount, QueryPerformanceCounter, and QueryPerformanceFrequency one way or another. This may sometimes lead to results being slightly different from the expected ones.

The application was developed for x86 platform, as there is OllyDbg only for x32 version, and there is no OllyDbg x64 at the moment of finishing this article.


We considered the writing of the plugin for OllyDbg 2.01 in this article. We also wrote the plugin that prevents OllyDbg from being detected by function execution time.

This plugin helps in code reversing, if there are functions that detect OllyDbg by measuring time. The code with such functions embedded may close OllyDbg prematurely or may not be executed at all.

This article provides the plugin source code, which you can compile and use.

9. Possible Future Improvements

The auxiliary dll, which sets hooks, is injected into the process during its loading to OllyDbg. However it unloads from it either at application closing or after initiating the restart of the debugging application in OllyDbg.

OllyDbg can detach from an application without stopping the application’s work. If in addition the auxiliary dll was loaded, it will not be unloaded from the process.

The unloading of the dll after pressing “Detach” could be an improvement to this dll’s principle of operation. This would give an application the possibility to continue work in a normal mode.


  1. http://www.ollydbg.de/version2.html
  2. http://www.codeproject.com/Articles/20084/A-More-Complete-DLL-Injection-Solution-Using-Creat
  3. http://codefromthe70s.org/mhook22.aspx


Download archive with the source files (ZIP, 166 KB)


Take a look at our anti-debugging technologies: Linux code protection software development kit

Read more about how reverse engineering can augment your project below!

Recommended for you
White Paper

Reverse Engineering in the IT Project Lifecycle

Tell us about your project
Send us a request for proposal! We’ll get back to you with details and estimations.

By clicking Send you give consent to processing your data

Book an Exploratory Call

Do not have any specific task for us in mind but our skills seem interesting?

Get a quick Apriorit intro to better understand our team capabilities.

Contact Us

  • +1 202-780-9339
  • [email protected]
  • 3524 Silverside Road Suite 35B Wilmington, DE 19810-4929 United States
  • D-U-N-S number: 117063762