Forum > Windows

WinAPI - examples - post 3

(1/3) > >>

440bx:
Here are some examples of simple, yet often very useful API functions.

WinAPI - DebugBreak

This example demonstrates using DebugBreak() to transfer control to a debugger. The example should be executed both, under a debugger and directly.

This example also serves to demonstrate how a program can detect if it is running under a debugger without using the IsDebuggerPresent() API.

Use the "DebugBreak()" menu item to cause the program execution to fall under debugger control.  Use F7/F8/F9 to control execution.

DebugBreak() is very useful to create conditional breakpoints with very complex conditions that are beyond the capabilities of an application debuggers.

Also, DebugBreak() is useful to set breakpoints where it is usually not possible to set them.  For instance, during the loading of a program. Windows automatically loads and calls the associated DLLs entry points. A strategically placed DebugBreak instruction allows a debugger to gain control during the DLLs load process.  This combined with the use of a system debugger, such as SoftICE, allows debugging almost any code in the executable.


In addition to that, combining the use of DebugBreak() with conditional compilation directives allows having the breakpoints, which in a large program may be numerous, in the program itself.  This prevents "losing" breakpoints by exceeding the "breakpoint history" capacity in most debuggers and aids in future maintenance as, at least in theory, calls to DebugBreak() should only appear (or be left) in the most important or complex section of the code.

DebugBreak() can also be useful to make reverse engineering a program more cumbersome.  By littering the executable with a fairly large number of calls to it (say about 60 or more) this can make reverse engineering the application very tedious when it is run under a debugger.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    WM_COMMAND:    begin      case LOWORD(wParam) of        IDM_INT3:        begin          { execute an INT 3h instruction - this should be executed           }          { under a debugger.                                                 }           try            DebugBreak();            MessageBox(Wnd,                       'Running under a debugger - executed DebugBreak() ' +                       '- int 3; ret - instructions',                       'DebugBreak()',                       MB_OK);          except            MessageBox(Wnd,                       'This example should be run under a debugger '      +                       '(and it isn''t.)',                       'DebugBreak()',                       MB_OK);          end;           exit;        end; The above is the "critical" part of the code in the example.  By executing DebugBreak() in a try/except, the application can detect whether or not it is running under a debugger.  If the code in the exception handler is _not_ executed then, the program is not being debugged because, if it were, the DebugBreak() would have transferred control to the debugger instead of activating the exception handler.

To make reverse engineering more cumbersome, a program could place code that _should be_ executed in the exception handler.  If the program is running under a debugger, the piece of code that is actually part of the normal operation of the program is not executed thus causing the program to later fail in some way.    Put around fifty (50) of those cases around in the program and, that will try the patience of whoever is trying to find out how the code works. :)

This works particularly well when present in functions/procedures that are conditionally executed and/or are not executed often (it increases the chances of one or more of them being missed.)


WinAPI - IsDebuggerPresent

This example demonstrates how to use the API IsDebuggerPresent() to determine if a program is running under a debugger or not.   If the program is running under a debugger, selecting "Break into the debugger" from the IsDebuggerPresent() menu, will cause a break into the debugger, otherwise the request to break into the debugger will be ignored.

It also demonstrates the difference between using DebugBreak() and an inline int 3.  When using DebugBreak(), application debuggers will stop at the DebugBreak() line because the _entire_ DebugBreak() procedure has _not_ yet been executed, specifically, it stops at the "ret" that is inside DebugBreak().

When using an inline "int 3" the debugger will stop at the next source line because the "int 3" has been fully executed unlike the DebugBreak() procedure.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---      case LOWORD(wParam) of        IDM_ISDEBUGGERPRESENT:        begin          { if we are running under a debugger, break into it with an INT 3   }           if IsDebuggerPresent() then DebugBreak();   { debugger stop here    }           { the above statement can also be implemented as :                  }           if IsDebuggerPresent() then          begin            asm int 3 end;       { same as DebugBreak() but "inline"          }          end;           exit;                  { debugger will stop here after the int 3    }        end; IsDebuggerPresent() is particularly useful to guard calls to DebugBreak().  That way, it is not necessary to remove the calls to DebugBreak() in the "release" executable since they are triggered only when the executable is run under a debugger (normal users rarely run a program under a debugger and, many of them don't even know what a debugger is anyway.)


WinAPI - QueryPerformanceCounter
WinAPI - QueryPerformanceFrequency

QueryPerformanceCounter along with QueryPerformanceFrequency can be used to measure elapsed time very accurately.  That's the combined purpose of these two APIs.

To determine elapsed time in seconds, simply subtract the first query from the second query and divide the result by the frequency.

The attached examples only show how to call each of these functions.  They do not include how to calculate elapsed time (it is reasonable to believe that programmers can subtract one number from another and divide the result by yet another number, i.e (b - a) div c)


WinAPI - SetLastError

SetLastError can be used by an application's procedures to indicate whether or not they successfully performed their task.  Note that it is strongly recommended to mark these custom application errors (the example shows how that is done.)

Also, it is important NOT to call any Windows API functions after setting the last error as it is very likely that the API function will overwrite the last error set by the application.

Fun experiment :

1. Start the SetLastError example
2. Select "LoadLibrary failure" from the "SetLastError" menu
3. Notice the value of the error (should be $A1)
4. Select "About SetLastError" from the "Help" menu
5. Click the OK button on the About box
6. Notice the value of the error (should still be $A1

Now repeat step 1 through 4 above

5. Move the About box vertically a couple of pixels up and click the OK button
6. Notice the value of the error (should be $0 instead of $A1)

7. Why did moving the About box cause the value of SetLastError to change ?


WinAPI - Sleep

The MSDN documentation states quite a few things about the Sleep API.  This test program demonstrates what _actually_ happens when the sleep interval changes.

RECOMMENDATION : _NEVER_ use an interval of zero (0).  An interval of zero (0) causes most versions of Windows (maybe all) to consume significantly more CPU than expected.  Run the example while watching the CPU usage in Task Manager and selecting various values from the menu.

To eliminate the overhead of repainting the screen, uncomment the NOPAINT define. (painting does not perceptibly alter the cpu consumption, the DEFINE is there to test and prove that is the case.


Enjoy!

lucamar:
Just a tiny observation: wouldn't it be better if each thread had kind of an "index" pointing to the other threads? That way one could look over all your contributions without having to search the forum. Though it's not very important :-[

Martin_fr:

--- Quote from: 440bx on January 21, 2021, 05:56:16 pm ---Also, DebugBreak() is useful to set breakpoints where it is usually not possible to set them.  For instance, during the loading of a program. Windows automatically loads and calls the associated DLLs entry points. A strategically placed DebugBreak instruction allows a debugger to gain control during the DLLs load process.  This combined with the use of a system debugger, such as SoftICE, allows debugging almost any code in the executable.

--- End quote ---
Windows actually transfers control to the debugger for each loaded dll. It is of course up to the debuggers capabilities what should happen on such events.


--- Quote from: 440bx on January 21, 2021, 05:56:16 pm ---By executing DebugBreak() in a try/except, the application can detect whether or not it is running under a debugger.  If the code in the exception handler is _not_ executed then, the program is not being debugged because, if it were, the DebugBreak() would have transferred control to the debugger instead of activating the exception handler.

--- End quote ---
Of course one can easily modify a debugger not to stop at a DebugBreak (or int3, when it is original code).
And one can also modify a debugger to let the application have the exception.
I just tested this myself, with a modified fpdebug.

440bx:

--- Quote from: lucamar on January 21, 2021, 11:27:04 pm ---Just a tiny observation: wouldn't it be better if each thread had kind of an "index" pointing to the other threads? That way one could look over all your contributions without having to search the forum. Though it's not very important :-[

--- End quote ---
I will create an index.  Like you I believe that would be useful in the long run.

Thank you for the suggestion.



--- Quote from: Martin_fr on January 22, 2021, 12:52:26 am ---Windows actually transfers control to the debugger for each loaded dll. It is of course up to the debuggers capabilities what should happen on such events.

--- End quote ---
Maybe the dll case I mentioned wasn't the best example but, I remember having to manually place an int 3 directly in the code to get the debugger to break at a specific time.  Unfortunately, I don't remember the details of the case.


--- Quote from: Martin_fr on January 22, 2021, 12:52:26 am ---Of course one can easily modify a debugger not to stop at a DebugBreak (or int3, when it is original code).
And one can also modify a debugger to let the application have the exception.
I just tested this myself, with a modified fpdebug.

--- End quote ---
When the programmer has the luxury and expertise to modify the debugger then what you mentioned is definitely applicable.  I believe, for most programmers, placing an int 3 in a strategic place will likely be the preferred method.

Martin_fr:

--- Quote from: 440bx on January 22, 2021, 01:24:55 am ---
--- Quote from: Martin_fr on January 22, 2021, 12:52:26 am ---Windows actually transfers control to the debugger for each loaded dll. It is of course up to the debuggers capabilities what should happen on such events.

--- End quote ---
Maybe the dll case I mentioned wasn't the best example but, I remember having to manually place an int 3 directly in the code to get the debugger to break at a specific time.  Unfortunately, I don't remember the details of the case.

--- End quote ---
The example is not invalidated by my statement. However, the need for int3/debugbreak depends not just on what you try to debug, but also what the debugger offers. In theory a debugger could offer a solution for 99.99% of int3 usage. However, no debugger really does.


--- Quote from: 440bx on January 22, 2021, 01:24:55 am ---
--- Quote from: Martin_fr on January 22, 2021, 12:52:26 am ---Of course one can easily modify a debugger not to stop at a DebugBreak (or int3, when it is original code).
And one can also modify a debugger to let the application have the exception.
I just tested this myself, with a modified fpdebug.

--- End quote ---
When the programmer has the luxury and expertise to modify the debugger then what you mentioned is definitely applicable.  I believe, for most programmers, placing an int 3 in a strategic place will likely be the preferred method.

--- End quote ---
This 2nd part was about int3 as a "anti hacker" protection.
And yes, like the above it depends. Only now it depends what hacker you try to defeat.
An inexperienced hacker may indeed be bothered like hell.
An experienced one, might have a debugger that will not be fooled.
There would still be subtle differences, an int3 in such a special debugger would still have different timings. If it enters the debugger other threads will be paused too, for just a moment. I have not explored those effects in detail, but they probably can be used to make a hackers plans go south.

Navigation

[0] Message Index

[#] Next page

Go to full version