In WinDbg, how do I set a conditional breakpoint for checking a particular value contained in an address behind a register? - windbg

I want to do something like break at Process!Function+0x66 but only if [RDX + 0x01c] == 1.
What would the syntax of breakpoint like this be?

evaluate with ? Process!Function+0x66
copy the result for using in breakpoint 0x12345678`90abcdef
bp 0x12345678`90abcdef ".if ( poi(#rdx+0x1c) != 1) {gc}"
a sample flow
0:000> ? msvcrt!memcpy+0x40
Evaluate expression: 140735863146304 = 00007fff`9f214740
0:000> u msvcrt!memcpy+0x40 l1
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx]
0:000> bp 00007fff`9f214740 " .if( poi(#rcx+#rdx) != 0x20) {gc}"
0:000> bl 0 e 00007fff`9f214740 0001 (0001) msvcrt!memcpy+0x40 ".if( poi(#rcx+#rdx) != 0x20) {gc}"
0:000> g
Microsoft (R) Windows Debugger Version 10.0.17763.132 AMD64
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx] ds:000001d6`1ebc6ac1=20
0:000> .lastevent
Last event: 724.1718: Hit breakpoint 0
debugger time: Wed Jun 16 00:25:26.965 2021
0:000> g
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx] ds:000001d6`20407c4a=20
0:000> .lastevent
Last event: 724.1718: Hit breakpoint 0
debugger time: Wed Jun 16 00:25:45.283 2021
0:000>

Related

How to set an exception using masm64?

How can i access the exception chain (SEH) using masm64?
Using masm32, I get the first exception looking into fs:[0]
But when I checked in Windbg if fs:[0] still pointed at the first exception in x64, I figured that it wasn't.
I'd like to set an exception in x64 the same way I did in x86. Is it feasible (maybe looking at gs register)?
If this is coding related then you use
ml64seh PROC FRAME:ExceptionFilter
this adds your exception handler to .PDATA section RUNTIME_FUNCTION
if this is how to find this exception handler in windbg when the exception has been raised
use !exchain command
or if you want to find it before executing a specific function use .fnent command
a sample for x64 seh and finding it in windbg is as follows
;assemble and link with
;ml64 /Zi ml64seh.asm /link /debug /entry:ml64seh /subsystem:console
.data
safeplace DWORD ?
.code
ExceptionFilter PROC
jmp Handler
ExceptionFilter ENDP
PUBLIC ml64seh
ml64seh PROC FRAME:ExceptionFilter
.ENDPROLOG
mov rax, 0
mov [rax], rax ;access violation
jmp exit
Handler::
lea rax, safeplace
mov [r8+078h], rax ; replacing rax in exception handler so access is possible
mov rax, 0
ret
Exit:
ret
ml64seh ENDP
END
run without stopping in windbg
:\>cdb -g ml64seh.exe
(2aa0.3024): Access violation - code c0000005 (first chance)
ml64seh!ml64seh+0x7:
00007ff7`0e3b1029 488900 mov qword ptr [rax],rax ds:00000000`00000000=????????????????
0:000>
it crashed and broke now locating exception handlers
0:000> .fnent .
Debugger function entry 0000020b`e36c47a8 for:
(00007ff7`0e3b1022) ml64seh!ml64seh+0x7 | (00007ff7`0e3b32b0) ml64seh!$xdatasym
BeginAddress = 00000000`00001022
EndAddress = 00000000`00001042
UnwindInfoAddress = 00000000`000032b0
Unwind info at 00007ff7`0e3b32b0, c bytes
version 1, flags 3, prolog 0, codes 0
handler routine: ml64seh!ILT+0(ExceptionFilter) (00007ff7`0e3b1005), data 0 <<<<<<<<<
0:000> !exchain
3 stack frames, scanning for handlers...
Frame 0x00: ml64seh!ml64seh+0x7 (00007ff7`0e3b1029)
ehandler ml64seh!ILT+0(ExceptionFilter) (00007ff7`0e3b1005) <<<<<<<<<<<<
Frame 0x02: ntdll!RtlUserThreadStart+0x21 (00007ffe`213c26a1)
ehandler ntdll!_C_specific_handler (00007ffe`213fc720)
0:000>
lets see if we go to the handler and return back to re access the faulting place
0:000> bp .
0:000> bp 00007ff7`0e3b1005
0:000> bl
0 e 00007ff7`0e3b1029 0001 (0001) 0:**** ml64seh!ml64seh+0x7
1 e 00007ff7`0e3b1005 0001 (0001) 0:**** ml64seh!ILT+0(ExceptionFilter)
0:000> g
Breakpoint 1 hit
ml64seh!ILT+0(ExceptionFilter):
00007ff7`0e3b1005 e916000000 jmp ml64seh!ExceptionFilter (00007ff7`0e3b1020)
0:000> g
Breakpoint 0 hit
ml64seh!ml64seh+0x7: is accessible now
00007ff7`0e3b1029 488900 mov qword ptr [rax],rax ds:00007ff7`0e3b4000=0000000000000000
0:000>
btw you can use dumpbin or linker to spit out all the unwindinfos in a specific binary using -unwindinfo switch
:\>dumpbin /unwindinfo ml64seh.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30146.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file ml64seh.exe
File Type: EXECUTABLE IMAGE
Function Table (1)
Begin End Info Function Name
00000000 00001022 00001042 000032B0 ml64seh
Unwind version: 1
Unwind flags: EHANDLER UHANDLER
Size of prologue: 0x00
Count of codes: 0
Handler: 00001005 #ILT+0(ExceptionFilter)

How to set a data breakpoint on a variable address in CDB (WinDbg)

class Test
{
public:
Test()
{
std::cout << "ctor" << std::endl;
ptr = new int(5);
*(ptr + 1) = 42;
};
~Test() { std::cout << "dtor" << std::endl; };
int* ptr;
};
void foo()
{
Test test;
}
int main()
{
foo();
return 0;
}
In the above example I want to set a data breakpoint at the address pointed to by ptr plus an offset (4 bytes in this case), to detect the heap corruption.
After I break inside the Test constructor, I have tried using the following to set the breakpoint but have failed:
0:000> ba w 4 (ptr + 4)
Bp expression '(ptr + 4)' could not be resolved, adding deferred bp
*** Bp expression '(ptr + 4)' contains symbols not qualified with module name
If I put the address manually then it obviously works. But I don't want to hard code the address in the command because I am doing this as part of a script and the address inside ptr can change every time.
What is the correct syntax for adding the data breakpoint without hardcoding the address?
You need ##c++() or .expr /s c++:
0:000> bp MemoryBreak!Test::Test
0:000> g
Breakpoint 2 hit
MemoryBreak!Test::Test:
[...]
0:000> l+t
Source options are 1:
1/t - Step/trace by source line
0:000> p
MemoryBreak!Test::Test+0x42:
0:000> ? ##c++(ptr)
Evaluate expression: 2790386541360 = 00000289`afffa330
0:000> ba w 4 ##c++(ptr)+4
0:000> bl
1 e Disable Clear 00007ff7`5fac2720 [C:\....cpp # 23] 0001 (0001) 0:**** MemoryBreak!main
2 e Disable Clear 00007ff7`5fac1fa0 [C:\....cpp # 6] 0001 (0001) 0:**** MemoryBreak!Test::Test
3 e Disable Clear 00000289`afffa334 w 4 0001 (0001) 0:****
0:000> g
Breakpoint 3 hit
MemoryBreak!Test::Test+0xa7:

WinDbg: How do I include a thread id and time value in a breakpoint .printf _without_ using pseudo registers?

I have some breakpoint "pairs," and I'd like to measure the time in between when they are hit.
The simplest thing that would allow me to do this is to include some sort of timestamp (even if it's just clock ticks or something) in the .printf I use when the breakpoint is hit.
I could use the pseudo registers $tid and $dbgtime in the breakpoint code. When I do, the performance really suffers.
bp1000 ucrtbase!malloc ".printf \"[0x%08x] [ucrtbase] [0x%04x] [0x%08x] malloc(%d): \", $dbgtime, $tid, dwo(#esp), dwo(#esp+4); gc "
When the same code is used (without using meaningful values for timestamp and thread id), things work much better.
bp1000 ucrtbase!malloc ".printf \"[0x%08x] [ucrtbase] [0x%04x] [0x%08x] malloc(%d): \", 0, 0, dwo(#esp), dwo(#esp+4); gc "
Is there some other (high-performance) way to get this information? The current time is more valuable than the thread ID. I can always make the breakpoint only apply to a specific thread so that emitting the ID is only sugar.
try this
0:000> bp ucrtbase!malloc "~# ; .echotime ; dd #$csp l2 ; gc ;"
0:000> bl
0 e 00007ff8`ab61c9e0 0001 (0001) 0:**** ucrtbase!malloc "~# ; .echotime ; dd #$csp l2 ; gc ;"
0:000> g
. 0 Id: 1a84.1f14 Suspend: 1 Teb: 00000018`f49d1000 Unfrozen
Start: cdb!wmainCRTStartup (00007ff6`efd2bbf0)
Priority: 0 Priority class: 32 Affinity: f
Debugger (not debuggee) time: Wed Aug 7 22:17:44.992 2019
00000018`f47eeb58 ab622762 00007ff8
. 0 Id: 1a84.1f14 Suspend: 1 Teb: 00000018`f49d1000 Unfrozen
Start: cdb!wmainCRTStartup (00007ff6`efd2bbf0)
Priority: 0 Priority class: 32 Affinity: f
Debugger (not debuggee) time: Wed Aug 7 22:17:44.992 2019 (UTC + 5:30)
00000018`f47eeb08 ab622762 00007ff8

Windbg Crash Dump Stack Trace Keeps Every Over Function

So I have a crash dump, and using WinDbg, I am able to get the stack trace. However, it appears to be skipping every other function. For instance if the actual code is:
void a()
{
b();
}
void b()
{
c();
}
void c(){}
The stack trace would have a, and c in the stack frame and not b. Is this expected behavior, and is there something I can do to see the entire stack trace? I have using the command "kn" to view the stack trace.
The compiler may optimize the code. One optimization is to inline methods so that call and ret statements and everything related (push, pop etc.) are removed.
For demonstration purposes, I have added a std::cout statement to your code which we can identify so that the full code now reads
#include "stdafx.h"
#include <iostream>
void c()
{
std::cout << "Hello world";
}
void b()
{
c();
}
void a()
{
b();
}
int _tmain(int argc, _TCHAR* argv[])
{
a();
return 0;
}
Walkthrough in debug build
In a typical debug build, there are no optimizations and you can see the methods. To follow the example, start WinDbg first and run the executable via File/Open executable....
0:000> .symfix e:\debug\symbols
0:000> lm
start end module name
010d0000 010f3000 OptimizedInlined (deferred)
...
0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined
0:000> x OptimizedInlined!c
010e50c0 OptimizedInlined!c (void)
0:000> bp OptimizedInlined!c
0:000> bl
0 e 010e50c0 0001 (0001) 0:**** OptimizedInlined!c
0:000> g
Breakpoint 0 hit
eax=cccccccc ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=003ffa00
eip=010e50c0 esp=003ff930 ebp=003ffa00 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
OptimizedInlined!c:
010e50c0 55 push ebp
0:000> u eip L18
OptimizedInlined!c [e:\...\optimizedinlined.cpp # 8]:
010e50c0 55 push ebp
010e50c1 8bec mov ebp,esp
010e50c3 81ecc0000000 sub esp,0C0h
010e50c9 53 push ebx
010e50ca 56 push esi
010e50cb 57 push edi
010e50cc 8dbd40ffffff lea edi,[ebp-0C0h]
010e50d2 b930000000 mov ecx,30h
010e50d7 b8cccccccc mov eax,0CCCCCCCCh
010e50dc f3ab rep stos dword ptr es:[edi]
010e50de 6854ca0e01 push offset OptimizedInlined!`string' (010eca54)
010e50e3 a1e4000f01 mov eax,dword ptr [OptimizedInlined!_imp_?coutstd (010f00e4)]
010e50e8 50 push eax
010e50e9 e8c9c1ffff call OptimizedInlined!ILT+690(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (010e12b7)
010e50ee 83c408 add esp,8
010e50f1 5f pop edi
010e50f2 5e pop esi
010e50f3 5b pop ebx
010e50f4 81c4c0000000 add esp,0C0h
010e50fa 3bec cmp ebp,esp
010e50fc e838c2ffff call OptimizedInlined!ILT+820(__RTC_CheckEsp) (010e1339)
010e5101 8be5 mov esp,ebp
010e5103 5d pop ebp
010e5104 c3 ret
Walkthrough release build
In the release build, see how things change. The WinDbg commands are the same, but the methods c(), b() and a() cannot be found. The std::cout method call has been inlined into wmain():
0:000> .symfix e:\debug\symbols
0:000> lm
start end module name
01360000 01367000 OptimizedInlined (deferred)
...
0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined
0:000> x OptimizedInlined!c
0:000> x OptimizedInlined!b
0:000> x OptimizedInlined!a
0:000> x OptimizedInlined!wmain
013612a0 OptimizedInlined!wmain (int, wchar_t **)
0:000> bp OptimizedInlined!wmain
0:000> bl
0 e 013612a0 0001 (0001) 0:**** OptimizedInlined!wmain
0:000> g
Breakpoint 0 hit
eax=6142f628 ebx=00000000 ecx=0087a6e8 edx=0019def8 esi=00000001 edi=00000000
eip=013612a0 esp=0042f8f8 ebp=0042f934 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
OptimizedInlined!wmain:
013612a0 8b0d44303601 mov ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)] ds:002b:01363044={MSVCP120!std::cout (646c6198)}
0:000> u eip L4
OptimizedInlined!wmain [e:\...\optimizedinlined.cpp # 23]:
013612a0 8b0d44303601 mov ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)]
013612a6 e895040000 call OptimizedInlined!std::operator<<<std::char_traits<char> > (01361740)
013612ab 33c0 xor eax,eax
013612ad c3 ret
Like already mentioned by Lieven. this is a case where compiler is making function calls inline.
There are 2 things that i would suggest:
a. If you have control over the code and build environment. Build a non-optimized/debug version of the code. This will ensure that compiler does not inline functions on its own.
b. In WinDBG you can see the disassembly under View --> Disassembly. Here you can see that code for function b() is actually in lined under a().
In case you are comfortable with assembly debugging you can get the value of locals as well :)

WinDbg - count breakpoint hits when certain values are on the stack

I'm not talking about the call stack.
I want to count how many times a certain function is called when at the address hold by ESP there is a certain value. Before you tell me to check the return address, I'm not interested in that - the return address is at ESP+4 in this case, [ESP] holding a value that is popped before the function will return. Details unimportant.
I can count function calls with the following syntax:
bp MyFunction "r #$t0 = #$t0 + 1; r #$t0; gc"
I can display the double word at [ESP] by adding
dd $csp L1
to the above command.
The problem is that there are quite a lot of calls and I'm only interested in certain calls and tracking them down manually after each break point is annoying and time consuming.
I'm still getting used with WinDbg's syntax. How should the condition look in my .if statement?
I tried some crazy things like
.if( (dd $csp L1) == 2 )
But that is obviously wrong.
I also though about setting the breakpoint somewhere in the function after the value at [ESP] is moved in a local variable (something like bp MyFunction+eip_after_assignment), but that is a bit too late. I think I can work with that, but it will make things simpler if I could just check [ESP] at the beginning.
0:000> lsa .
2: int dummy=0;
3: void useless(int in) {
4: dummy=in;
5: }
> 6: void main(void) {
7: for(int i=0;i<0xffffffff;i++)
8: useless(i);
9: }
0:000> uf countfunc!useless
countfunc!useless [c:\countfunc.cpp # 3]:
3 00401000 55 push ebp
3 00401001 8bec mov ebp,esp
4 00401003 8b4508 mov eax,dword ptr [ebp+8]
4 00401006 a320bb4000 mov dword ptr [countfunc!dummy (0040bb20)],eax
5 0040100b 5d pop ebp
5 0040100c c3 ret
0:000> bl
0:000> bp 0040100b ".if ( poi(#$csp+8) != 1337 ) {gc}"
0:000> .bpcmds
bp0 0x0040100b ".if ( poi(#$csp+8) != 1337 ) {gc}";
0:000> g
> eax=00001337 ebx=7ffdf000 ecx=00001337 edx=0040c340 esi=00000000
> edi=0098f6ee eip=0040100b esp=0013ff68 ebp=0013ff68 iopl=0 nv
> up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b
> gs=0000 efl=00000213 countfunc!useless+0xb: 0040100b 5d
> pop ebp
0:000> ?? in
int 0n4919
0:000> dv
in = 0n4919
0:000> ? 0n4919/1
Evaluate expression: 4919 = 00001337
a bit more complex conditional break on same code conditional breaks do take a lot of time debugging time sensitive code can be quiet challenging
0:000> r $t0 = 0; bp 0040100b ".if ( poi(#$csp+8) != #$t0*1337 ) {gc} .else { .echotime ;? poi(#$csp+8) ; r$t0 = #$t0+1 ;gc }"
0:000> .bpcmds
bp0 0x0040100b ".if ( poi(#$csp+8) != #$t0*1337 ) {gc} .else { .echotime ;? poi(#$csp+8) ; r$t0 = #$t0+1 ;gc }";
0:000> .echotime
Debugger (not debuggee) time: Tue Sep 30 12:12:15.890 2014
0:000> g
Debugger (not debuggee) time: Tue Sep 30 12:12:24.062 2014
Evaluate expression: 0 = 00000000
Debugger (not debuggee) time: Tue Sep 30 12:12:32.578 2014
Evaluate expression: 4919 = 00001337
Debugger (not debuggee) time: Tue Sep 30 12:12:41.093 2014
Evaluate expression: 9838 = 0000266e
Debugger (not debuggee) time: Tue Sep 30 12:12:49.609 2014
Evaluate expression: 14757 = 000039a5
Debugger (not debuggee) time: Tue Sep 30 12:12:58.156 2014
Evaluate expression: 19676 = 00004cdc
Debugger (not debuggee) time: Tue Sep 30 12:13:06.687 2014
Evaluate expression: 24595 = 00006013
Debugger (not debuggee) time: Tue Sep 30 12:13:15.218 2014
Evaluate expression: 29514 = 0000734a
Debugger (not debuggee) time: Tue Sep 30 12:13:23.765 2014
Evaluate expression: 34433 = 00008681
Debugger (not debuggee) time: Tue Sep 30 12:13:32.828 2014
Evaluate expression: 39352 = 000099b8
Debugger (not debuggee) time: Tue Sep 30 12:13:40.906 2014
Evaluate expression: 44271 = 0000acef
this simple code may take 86 days to complete if it continued like this it seems it takes ~8.5 seconds to process 4919 function calls in windbg