Debugging anti-debugging
Korui has been learning for almost a year. Recently, anti-debugging technology for Anti-Spam software has been released to check if you can find friends who are interested in it ..
There are too many anti-debugging methods, starting with the simplest...
1> IsDebuggerPresent
The APIS provided by Microsoft can call IsDebuggerPresent in their own programs at any time to detect whether their programs have been debugged...
The following code first creates a console test program in vc ++ 6.0:
# Include <windows. h>
Typedef BOOL (_ stdcall * LPAPI_IDP) (VOID );
Int main (int argc, char * argv [])
{
HMODULE hModule = LoadLibrary ("Kernel32"); // load the module Kernel32
If (hModule = NULL)
{
ExitProcess (0); // exit the process directly if the program is found to be debugged.
}
LPAPI_IDP IsDebuggerPresent = GetProcAddress (hModule, "IsDebuggerPresent"); // obtain the address
If (IsDebuggerPresent = NULL)
{
ExitProcess (0); // exit the process directly if the program is found to be debugged.
}
If (* (BYTE *) IsDebuggerPresent = 0xcc | // check whether a breakpoint has been deleted before calling
* (BYTE *) IsDebuggerPresent! = 0x64 |
IsDebuggerPresent () // call
{
ExitProcess (0); // exit the process directly if the program is found to be debugged.
}
// If the program can be executed here, it indicates that the program has not been debugged.
MessageBox (NULL, "Antidebug", NULL, MB_ OK );
Return 0;
}
Run directly...
Press F5 to debug and run the program ..
One-step tracing can test that the program exits after IsDebuggerPresent is called ..
Now use the compiled Executable File ollydbg (the od with the anti-debugging plug-in installed will be immune, if you want to learn it, it is best to clear the plug-in first) for testing... the program exited immediately after being unfocused...
Let's take a look at how to solve this small problem. (because the code is self-written, it is easy to locate the key points. In reality, there are various means ...)
Run the od again and break it to the entrance to find the main function... followed in is our code...
// Main ()
00401000/$56 push esi
00401001 |. 57 push edi
00401002 |. 68 50604000 push 00406050;/FileName = "Kernel32"
00401007 |. FF15 08504000 call dword ptr [<& KERNEL32.LoadLibrar>; \ LoadLibraryA
0040100D |. 8B3D 04504000 mov edi, dword ptr [<& kernel32.expri>; kernel32.ExitProcess
00401013 |. 8BF0 mov esi, eax
00401015 |. 85F6 test esi, esi
00401017 |. 75 04 jnz short 0040101D
00401019 |. 6A 00 push 0;/ExitCode = 0
0040101B |. FFD7 call edi; \ ExitProcess
0040101D |> 68 3C604000 push 0040603C;/ProcNameOrOrdinal = "IsDebuggerPresent"
00401022 |. 56 push esi; | hModule
00401023 |. FF15 00504000 call dword ptr [<& KERNEL32.GetProcAdd>; \ GetProcAddress
00401029 |. 8BF0 mov esi, eax
0040102B |. 85F6 test esi, esi
0040102D |. 75 03 jnz short 00401032
0040102F |. 50 push eax
00401030 |. FFD7 call edi
00401032 |> 8A06 mov al, byte ptr [esi]
00401034 |. 3C CC cmp al, 0CC
00401036 |. 74 0A je short 00401042
00401038 |. 3C 64 cmp al, 64
0040103A |. 75 06 jnz short 00401042
0040103C |. FFD6 call esi // call IsDebuggerPresent
0040103E |. 85C0 test eax, eax
00401040 |. 74 04 je short 00401046
00401042 |> 6A 00 push 0
00401044 |. FFD7 call edi
00401046 |> 6A 00 push 0;/Style = MB_ OK | MB_APPLMODAL
00401048 |. 6A 00 push 0; | Title = NULL
0040104A |. 68 30604000 push 00406030; | Text = "Antidebug"
0040104F |. 6A 00 push 0; | hOwner = NULL
00401051 |. FF15 9C504000 call dword ptr [<& USER32.MessageBoxA>; \ MessageBoxA
00401057 |. 5F pop edi
00401058 |. 33C0 xor eax, eax
0040105A |. 5E pop esi
0040105B \. C3 retn
Here, the simple method is to modify 0040103C |. FFD6 call esi.
0040103C 33C0 xor eax, eax
Don't give the program the chance to call IsDebuggerPresent... but you can't modify it every time you debug it... and some applications simply don't know when to check it...
The effective solution is to make a little effort in the API so that he can return an error result... now follow up to IsDebuggerPresent to see the implementation of IsDebuggerPresent.
7c8131_kernel32.isdebuggerpresent/$64: A1 1800000> mov eax, dword ptr fs: [18]
7C813139 |. 8B40 30 mov eax, dword ptr [eax + 30]
7C81313C 0FB640 02 movzx eax, byte ptr [eax + 2]
7C813140 C3 retn
Unexpectedly, only a few simple commands can be used to randomly change the return value of the function to 0...
You can write a small tool or an ollydbg plug-in to help us modify the code every time... because this program can already be debugged, the tool is of little significance. Write a Simple plug-in ., the process is similar...
Let's talk about the principle:
Locate the address of the kernel32.IsDebuggerPresent function in the process.
Write the bytes to be modified to the memory...
You can refer to the previous post for details about plug-in development.
The code is missing...
/*
7C813133>/$64: A1 1800000> mov eax, dword ptr fs: [18]
7C813139 |. 8B40 30 mov eax, dword ptr [eax + 30]
7C81313C 0FB640 01 movzx eax, byte ptr [eax + 1] // eax, byte ptr [eax + 2]
7C813140 \. C3 retn
*/
Typedef BOOL (_ stdcall * LP_IDP) (VOID );
Void Hook_IsDebuggerPresent ()
{
Int hIn = Plugingetvalue (VAL_HPROCESS );
If (hIn! = NULL)
{
HMODULE hModule = GetModuleHandle ("Kernel32 ");
If (hModule = NULL)
{
MessageBox (NULL, "Error GetModuleHandle (Kernel32)", NULL, MB_ OK );
Return;
}
LP_IDP lpAddr = GetProcAddress (hModule, "IsDebuggerPresent ");
If (hModule = NULL)
{
MessageBox (NULL, "Error GetProcAddress (IsDebuggerPresent)", NULL, MB_ OK );
Return;
}
BYTE c = 0x01;
BYTE * p = (BYTE *) lpAddr;
Writememory (& c, (DWORD) (p + 0x0c), sizeof (c), MM_RESTORE );
}
}
Postscript:
The program plug-ins that call APIs can be generic. if you add the implementation of IsDebuggerPresent to your own program, the plug-in will be useless. For the debugger, you have to re-analyze the plug-ins ....
// IsDebuggerPresent implementation code
7c8131_kernel32.isdebuggerpresent/$64: A1 1800000> mov eax, dword ptr fs: [18]
7C813139 |. 8B40 30 mov eax, dword ptr [eax + 30]
7C81313C 0FB640 02 movzx eax, byte ptr [eax + 2]
7C813140 C3 retn
Author MogulKahn