Anti-Debugging – A Quick Guide to Avoid Malwares and Mobile App Hacks

Malwares are all around us. Newer ways of not getting detected are being employed by attackers all around the globe. Using evasion techniques, these attackers can be invisible to threat analysis professionals as well. By hiding indicators of malicious activities, such attacks continue for a longer period. One of the common methods employed to stop attacks is anti-debugging, which ensures that a program is not running under a debugger. It ensures that an application’s core functions are protected, and attacks don’t surface easily, thereby making it even more difficult to reverse engineer the code. Once a debugger is detected, the problem doesn’t stop there. The minute the malware gets to know that it has been detected by a debugger, it changes its behavior, adjusts the code execution path or simply modifies itself to evoke a crash. Once the system crashes, it is back to square one for the cyber security analysts and experts.

Anti-Debugging

When developers are working on their codes, they use some best practices to protect their code and ultimately the application that they are writing the code for. A debugger helps them test their code in controlled environments against known attacks, change certain variables, upgrade configurations etc. Bugs, errors and security loopholes can be tested and fixed, so that data is ultimately protected. However, even though they are useful for developers, these debuggers can themselves open up the playground for attackers to observe the application being tested under specific conditions, thereby helping them better their attack techniques. Anti-debugging can help change the behavior of the apps to protect themselves and, in most cases, slow down the reverse engineering process. Some common methods used in anti-debugging techniques are:

  • Analysis of data being exchanged between applications using a packet sniffer
  • Disassembly of software binary code so it gets added in the assembly language
  • Recreating source code by decompiling binary or byte-code

Ready to protect your app?

Start 30-days FREE TRIAL. No credit card required. Deliver Secure Mobile Apps Faster in minutes with the leader in application security.

Best Techniques of Anti-Debugging

Looking for modifications in the code

Debugging usually relies on modifying the original code by changing instructions from code strings. Thus, the app can be programmed to identify debuggers in such cases and have defensive techniques ready.

Adding exceptions in code

When certain exceptions are not executed, it most likely would mean that a debugger is present. A good cybersecurity professional should be able to manage this

Self-debugging

When an application is running, it is possible to create a new process that can get attached to the debugger of the original parent process. Now if another debugger is running, an alert will get generated. This might be a more strenuous process since it is to be started from scratch, but it is worth the effort.

Using system API calls

APIs are commonly provided with every application. Using these would be the easiest to know whether a debugger is running in the background.

Exploiting bugs in popular debuggers

Debuggers are not always perfect and this technique uses that point to its advantage. Every application has some flaw, and so is the case with every debugger. By introducing data values or specific instructions that can cause a crash or make the system behave in a certain manner, a debugger can be revealed.

Using hardware breakpoint detection

Breakpoints are meant to test for certain signals, and similarly, when encountered by a developer, they can help detect a debugger too

Relying on timing-based detection

Common sense tells us that an application is usually expected to execute in a set time interval. Developers are usually aware of the different steps and procedures which make up an application and its features. So a lag in execution of certain steps can give a clue towards a debugger. Of course, when multiple applications are running or interacting with each other, with different time intervals for action between them, this could get a bit tricky. The best way out would be to keenly observe the time intervals between processes and interactions to see any lags/delays which could be attributed to a debugger

Keeping an eye on certain libraries

Debuggers usually come with their specific set of libraries. A simple look at the list of libraries attached to an application can reveal the presence or absence of a debugger

Mixing and matching technique

A good mix of different techniques is what will ultimately come in handy when you want to make the lives of attackers a tad bit difficult. Reverse engineering a code will become all the more difficult when you confuse the attacker.

Some other functions which help with anti-debugging are:

  1. IsDebuggerPresent: One of the simplest methods, this function checks if a calling program is begin debugged by a user-mode debugger. Calling this function will help stop the debugger. A sample code:
    int main()
    {if (IsDebuggerPresent())
    {
    std::cout << “Stop debugging program!” << std::endl;
    exit(-1);
    }
    return 0;
    }
  2. PEB (Process Environment Block): This is used in the Windows OS. Sample code for calling the function:
    // Current PEB for 64bit and 32bit processes accordingly
    PVOID GetPEB()
    {
    #ifdef _WIN64
    return (PVOID)__readgsqword(0x0C * sizeof(PVOID));
    #else
    return (PVOID)__readfsdword(0x0C * sizeof(PVOID));
    #endif
    }
  3. TLS Callback: The main function of an application is usually the place which is targeted by attackers and reverse engineering experts. Hence, performing a debugger check there may not be that fruitful. Also, the checks can be erased. The TLS Callback is thus a better place for checking for debuggers. Sample code:
    #pragma section(“.CRT$XLY”, long, read)
    __declspec(thread) int var = 0xDEADBEEF;
    VOID NTAnopPI TlsCallback(PVOID DllHandle, DWORD Reason, VOID Reserved)
    {
    var = 0xB15BADB0; // Required for TLS Callback call
    if (IsDebuggerPresent())
    {
    MessageBoxA(NULL, “Stop debugging program!”, “Error”, MB_OK | MB_ICONERROR);
    TerminateProcess(GetCurrentProcess(), 0xBABEFACE);
    }
    }
    __declspec(allocate(“.CRT$XLY”))PIMAGE_TLS_CALLBACK g_tlsCallback = TlsCallback;
  4. NtGlobalFlag: When it comes to system tracking, debugging and control, the global variable NtGlobalFlag is useful. Sample code:
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\GlobalFlag]
    FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
    FLG_HEAP_ENABLE_FREE_CHECK (0x20)
    FLG_HEAP_VALIDATE_PARAMETERS (0x40)Some other techniques are:
    • Heap Flags and ForceFlags
    • Trap Flag Check
    • CheckRemoteDebuggerPresent and NtQueryInformationProcess
    • ProcessDebugPort 0x07
    • ProcessDebugObjectHandle 0x1E
    • ProcessDebugFlags 0x1F
    • ProcessBasicInformation 0x00
    • Debugger detection using the FindWindow function
    • Time calculation approach
    • NtQueryObject
    • BlockInput
    • NtSetDebugFilterState
    • Self-modifying code
    • Memory debug code

Final Thoughts

The above methods help to identify debuggers and protect applications from hackers. But, often prevention is better than cure (I am sure you have heard this a lot of times). This truly applies to anti-debugging strategies. It is always best to stop attacks even before they take place. Mobile app security is often an area that is overlooked. But given the vast amount of information and important data present in mobile applications, it is an area that requires more focus. With AppSealing, developers can focus on developing high-quality applications which are rich in features, while also staying in the safety net with AppSealing’s robust runtime application self protection (RASP) and threat analytics modules. Be it gaming apps, movie apps, apps in the ecommerce departments or the ones which help customers take care of their finances, our solutions help companies stay a step ahead of attackers. Real-time security checks and indicators help fix the problems even before they arise. We offer cloud-based pay-as-you-go features which require zero lines of code. Our solutions are affordable, dynamically priced and support both android and ios applications.

Ready to protect your app?

Start 30-days FREE TRIAL. No credit card required. Deliver Secure Mobile Apps Faster in minutes with the leader in application security.

About the Author

Govindraj Basatwar, Global Business Head
Govindraj Basatwar, Global Business Head
A Techo-Commerical evangelist who create, develop, and execute a clear vision for teams. Successfully created a SaaS business model with multi Million Dollar revenues globally. Proven leadership track record of establishing foreign companies in India with market entering strategy, business plan, sales, and business development activities.