Windbg Break on Access Without Hardware

A few days ago, I had to break into a graphic application just after I clicked on a button. Sadly I didn't have the source code, and then my purpose was just to get the name of the applicative function chosen just afterwards a user event (in my case, a click). Of course, when the role handling an effect is called, I look to see a Windows user mode role in the telephone call stack. So I designed a small MFC application with just a push button, made a function named OnBnClickedButton to handle clicks, added a breakpoint on this part, and tried to notice on the call stack which function is e'er called when an awarding process an event.

I eventually foundUSER32!SendMessageW, and I was quite happy with it: this function is well-known for every MFC programmer because it allows you to ship a Windows bulletin to whatever application (including yours). A click on a button is of class a Windows message, and I was pretty certain I found my entry role. Then I started the former graphic application, attached to it with WinDbg, and endeavour to get the focus back to my application and then I tin click on the button. Sadly, my debugger broke earlier I could…why? Well, trying to put the focus on an application that is not visible triggers (at least!) a WM_PAINT bulletin, processed past USER32!SendMessageW. And information technology is not the only one: a simple graphical continually receivesA LOT of various messages. I conspicuously had to break only on a specific message. Hopefully the epitome of USER32!SendMessageW is well known: the second parameter is an unsigned int containing the message ID. Sounds nice, just how can y'all pause on a function ONLY when a parameter take a specific value?

The beginning thing you accept to know: how the stack is used when yous call a office

To communicate the parameters to a function, most compiler mainly utilize the stack (if you don't know what is this key region of memory of your process called 'the stack', read this, this, and come back :) ). When you call a function, your process will:

  • Push button all the parameters value of the function in the stack, in reverse order. Equally a stack on x86 grows down in memory, it ways that the first parameter will accept the lower address and the last one the higher accost.
  • Push 'the return address' of the function. It is merely a pointer to the next instruction later on the call, and then the function can exercise a 'goto' (more precisely a 'ret', who is just a 'goto' to a detail address retrieved from the stack) to this accost when its execution is finished. Peradventure yous didn't know it, only a processor does not understand the 'return something' of a function. What a processor understands is goto'southward, and quitting a function is just a 'goto' to some other part. Maybe you tried all your life avoiding goto's in your code (and especially TO Some other Role! SIGH!), then yous may be shocked to larn that the compiler doesn't care about it: if you don't desire to execute the very next pedagogy, it will issue a 'leap', a 'call' or a 'ret', only other names for a goto. Pretty sad.
  • Call the function, in other words…outcome a goto! For convenience, the last two steps are fabricated by a unmarried well named education: 'call'.

Let'southward say that we call a part Foo from a function Bar, with 3 parameters, something like this in C++:

void Bar() { 	Foo(one, 2, 3); }  void Foo(int p1, int p2, int p3) { 	// I'm so called! }        

Here is how looks like the pseudo-assembler code of Bar when it calls Foo (I chose randomly the address in retention):

          Address of the teaching	Assembler instruction  in retention          0x00010000			push 3 0x00010001			push 2 0x00010002			push i 0x00010003			push button 0x00010005 0x00010004			Goto Foo 0x00010005			// do what y'all have to do next

In the real world, the last 'push button' and the 'goto' is made by a simple instruction named 'phone call', simply the primary principles are here. And so, when I enter the function Foo, my stack looks like this (once again, I chose randomly the address in retentivity, the point is that it is not the same than the previous i):

          Address in retentiveness	Value          0x30000000		0x00010005    <- where I will 'goto' at the end of Foo 0x30000004		0x00000001    <- my first parameter 0x30000008		0x00000002    <- my second parameter 0x3000000C		0x00000003    <- my third parameter

Now you know everything about a proper part call on x86. The concluding matter I have to say is that the processor use a special register to store the electric current retentiveness address of the stack: ESP. That is to say, just after calling Foo, ESP has the value0x30000000.

I fabricated the (huge!) endeavor to read all this stuff until know, please give me the trick now

Well, we almost get the answer at present: to get the value of the nth parameter, we have to check the value of (ESP + 4*n) if I start counting parameters at 1. Just remember a few things:

  • On x64, each address is eight bytes, so the formula is (ESP + eight*n)
  • If your function is a class function, remember that each member role has a first hidden parameter: 'this'.
  • Sometimes, compiler optimizations make this formula wrong…but if you lot read advisedly the offset affiliate, y'all can always discover the right address for your particular function. But use the Memory, the Registry and the Disassembly windows of your debugger.

The fox on WinDbg

WinDbg tin (obviously) execute a command when information technology hits a breakpoint with the post-obit syntax :

bu <breakpoint address> "<control>"

All you take to exercise is writing the command. For this ane, hither is what you demand to know:

  • The value of the register XXX is accessed by using the grapheme '@' earlier the proper name, in other words @30
  • The content of a given address is accessed through the function poi(address) (similar 'pointer' I guess???)
  • The bones if-then-else can be written like this: j (condition) 'action if truthful' ; 'action if fake' (j like 'jump' in assembler, likewise a guess)
  • Resume the execution of the debugger is gc (for go!). EDIT: as said Jean-Jacques in the comments, you should always use gc instead of g in conditional breakpoints, so the debugger can resume in the same way information technology arrived at you breakpoint: past continuing, or stepping, etc.

To put things together, if I desire the debugger to break only when the second parameter of the functionUSER32!SendMessageW is 0x111, I have to issue the command:

bu USER32!SendMessageW "j (poi(@esp+8)=111) ''; 'gc'"

Easy :)

The trick on Visual Studio 2010

I realized that I wrote only a little about Visual Studio, so I searched how to realize that, and it is possible! First you accept to set a breakpoint on the function. Every bit we don't have the source lawmaking, things are pretty difficult and I but made a post about how to do it on Visual Studio 2010. If you read it, you know that you lot have to brandish the Breakpoint window (CTRL+ALT+B by default, orCarte Debug->Windows->Breakpoints), click on the buttonNew->Suspension at office… (or blazonCTRL+B), and fill the popup windows with the context operator {,,user32.dll} _SendMessageW@xvi, like this:

Then nosotros have to add a condition to this breakpoint. To do so, correct click on the newly created breakpoint and hit "Condition…". Nosotros have to write pretty much the same thing than we did with WinDbg, except that keywords and conventions are different:

  • The value of the register XXX is simply accessed using XXX
  • By default , number literal are decimal, so we have to use '0x' before any hexadecimal number
  • There is no 'get the value pointed by' role in Visual Studio, but you can cast a value to an 'unsigned int*' so go the referenced value using the C++ operator '*'

Given that, the condition can exist written like this: '*(unsigned int*)(esp + 8) == 0x111', every bit illustrated in this screenshot:

And so here you are: a breakpoint on a function without source code, breaking only when a given parameter has a specific value. In Visual Studio 2010. Non easy, but viable.

0 Response to "Windbg Break on Access Without Hardware"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel