Special Command: Using ??, @@c++() and poi() with C/C++ Expressions


I really like using C/C++ expressions from WinDbg. It’s a natural way to extract information from C and C++ applications if you know these programming languages; therefore, I think it’s useful to share how to do this.


 


First, let’s talk about poi().


poi() is used to get pointer-sized data. Think about the * operator for C and C++.


For example:


 


 


 


Therefore, poi is the best operator to use if you want pointer-sized data.


 


The double question mark (??) command evaluates and displays the value of an expression according to the C++ expression rules.


 


Now, let me show you how to get a pointer value using poi() and ??.


The single question mark (?) is used to evaluate expressions.


 


Tip: By using ?, you can easily convert a number from hexadecimal to decimal or vice versa. Remember to use the prefix 0x for hexadecimal and 0n for decimal.


 


Examples:


 


 


 


Finally, we have the C++ expression parser – @@c++() – that supports all forms of C++ expression syntax, such as:


 


      Numbers in C++ expressions


      Characters and strings in C++ expressions


      Symbols in C++ expressions. (see WinDbg documentation for details)


      Operators in C++ expressions


      Registers and pseudo-registers in C++ expressions


      Macros in C++ expressions


 


Examples:


 


 


 


 


 


 


For more information, you may want to read the Magic Pointers article.


Here you can see scripts that use the ??, @@c++() or poi() commands.


 


 

Comments (6)

  1. rembo says:

    Hi, I’m trying to learn how to use C/C++ expressions in WinDbg. Thanks for your article! I am having trouble with the following:

    0:000> ?? * (long*) ((@esp)+12) == -13

    bool true

    0:000> .if  (-13 == -13) {.echo do whatever}

    do whatever

    so far, so good.

    But how do I use this in a conditional? —

    0:000> .if  (?? * (long*) ((@esp)+12) == -13) {.echo do whatever}

    Syntax error at ‘?? * (long*) ((@esp)+12) == -13) {.echo do whatever}’

    0:000> .if  (? * (long*) ((@esp)+12) == -13) {.echo do whatever}

    Syntax error at ‘? * (long*) ((@esp)+12) == -13) {.echo do whatever}

  2. I’m not sure if I understand your question, but I’ll try to answer it anyway :)

    If you are comparing registers you don’t need to use a cast, for example:

    0:000> r @ecx

    ecx=00000030   <– By default this is hexadecimal.

    0:000> .if(@ecx == 0x30){.echo True}

    True

    0:000> .formats @ecx

    Evaluate expression:

     Hex:     00000030

     Decimal: 48        <– 0x30 == 0n48

     Octal:   00000000060

     Binary:  00000000 00000000 00000000 00110000

     Chars:   …0      <– 0x30 = ASCII char 0

     Time:    Wed Dec 31 16:00:48 1969

     Float:   low 6.72623e-044 high 0

     Double:  2.37152e-322

    0:000> .if(@ecx == 0n48){.echo True}

    True

    0:000> .if(@ecx == ‘0’){.echo True}

    True

    The expressions above are equivalent. The content in memory can be interpreted as char, hexadecimal, decimal, octal, binary… you choose.

    Now, if you want to compare C/C++ variables, you can use this approach:

    class CSize Size = class CSize

    0:000> dt Size

    Local var @ 0x12f890 Type CSize

      +0x000 cx               : 30

      +0x004 cy               : 39

    Now I use the C++ expression evaluator:

    0:000> .if(@@c++(Size.cx == 30)){.echo True}.else{.echo False}

    True

    0:000> .if(@@c++(Size.cx == 20)){.echo True}.else{.echo False}

    False

    Did it answer your question?

  3. rembo says:

    Yes, thank you for your detailed explanation, that was very helpful! I guess I was confused when to use ?, when @@c++ and when ?? , but you cleared it up. Apologies if my question was unclear; I understand how to use registers, but I was trying to use a parameter on the stack, and it seemed I had to cast it the way I did.