The MASM Forum

General => The Campus => Topic started by: jj2007 on August 27, 2013, 02:16:53 AM

Title: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 02:16:53 AM
Simple idea:
  ; edi is dest buffer, esp is addr SizeValBuffer
  push -1         ; no limit
  invoke RegQueryValueEx, hKey, pValue, 0, addr rkType, edi, esp
  pop edx         ; balance stack

It works - sometimes. MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724911%28v=vs.85%29.aspx):

RegQueryValueEx(
  _In_         HKEY hKey,
  _In_opt_     LPCTSTR lpValueName,
  _Reserved_   LPDWORD lpReserved,
  _Out_opt_    LPDWORD lpType,
  _Out_opt_    LPBYTE lpData,
  _Inout_opt_  LPDWORD lpcbData

lpcbData [in, out, optional]

    A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes. When the function returns, this variable contains the size of the data copied to lpData.


Only the boyz in Redmond know why it chokes with "unlimited" size. With 65k it works, apparently...
Title: Re: RegQueryValueEx
Post by: Zen on August 27, 2013, 06:01:51 AM
JOCHEN,
Why not call RegQueryValueEx twice ???
Discussion at Raymond Chen's Blog that doesn't even remotely relate to your problem:  Beware of Non-Null-Terminated Registry Strings, Aug 2004 (http://blogs.msdn.com/b/oldnewthing/archive/2004/08/24/219444.aspx)
Title: Re: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 06:38:46 AM
Quote from: Zen on August 27, 2013, 06:01:51 AM
JOCHEN,
Why not call RegQueryValueEx twice ???

Why should I??? ::)
Title: Re: RegQueryValueEx
Post by: GoneFishing on August 27, 2013, 06:54:04 AM
Hi Jochen,
WinDbg has very nice event filter . I could try to find out what an exception occurs there if I had some more lines of your code ( + data definitions )
Title: Re: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 07:43:50 AM
Hi vertograd,
Nice offer :t

An exe with int 3 before the call to RegQueryValueEx is attached.

If you want to build it yourself, you need the latest version of MB (http://masm32.com/board/index.php?topic=94.0); afterwards, replace \Masm32\MasmBasic\MasmBasic.lib with the attached "special" edition.

include \masm32\MasmBasic\MasmBasic.inc        ; download (http://masm32.com/board/index.php?topic=94.0)
        Init
        mov f2sOlly, 123        ; flag for special edition of MasmBasic.lib
        void GetRegVal("HKCR\Applications\qeditor.exe\shell\open\command", 0, "No luck in HKCR/App...")
        deb 4, "Registry HKCR", $eax, $Err$()
        Inkey
        Exit
end start

Expected outcome:

Registry HKCR
$eax            "C:\masm32\qeditor.exe" "%1"
$Err$()         Operation successfully completed.

UnderWin7-32, it happened to me several times that it returned nothing, although the behaviour was not predictable. Everything is fine, though, since I replaced the push -1 for sizeofdata with 65k....
Title: Re: RegQueryValueEx
Post by: qWord on August 27, 2013, 09:39:38 AM
Quote from: jj2007 on August 27, 2013, 02:16:53 AMpush -1         ; no limit
[...]
A pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes.
[...]
Only the boyz in Redmond know why it chokes with "unlimited" size.
you may try it with a valid buffer.
Title: Re: RegQueryValueEx
Post by: MichaelW on August 27, 2013, 09:52:49 AM
It works for me, Windows XP SP3.

;==============================================================================
include \masm32\include\masm32rt.inc
include \masm32\include\Advapi32.inc
includelib \masm32\lib\Advapi32.lib
;==============================================================================
.data
    hKey    HKEY 0
    cbData  dd -1
.code
;==============================================================================
start:
;==============================================================================
    mov ebx, alloc(1024*1024*100)

    invoke RegOpenKeyEx, HKEY_LOCAL_MACHINE,
                         chr$("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
                         0,
                         KEY_QUERY_VALUE,
                         ADDR hKey
    .IF eax != ERROR_SUCCESS
        printf("RegOpenKeyEx %s\n\n", LastError$())
    .ENDIF

    invoke RegQueryValueEx, hKey,
                            chr$("Identifier"),
                            NULL,
                            NULL,
                            ebx,
                            ADDR cbData

    .IF eax != ERROR_SUCCESS
        printf("RegQueryValueEx %s\n\n", LastError$())
    .ENDIF

    printf("\n%s\n%d\n\n", ebx, cbData)

    invoke RegCloseKey, hKey
    free ebx
    inkey
    exit
;==============================================================================
end start


x86 Family 6 Model 7 Stepping 3
32


There is some related information here:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms724872(v=vs.85).aspx/html

But so far I have not been able to determine what "latest format" and "standard format" mean. Perhaps your system is using the standard format.
Title: Re: RegQueryValueEx
Post by: Antariy on August 27, 2013, 01:46:40 PM
Jochen, your code passes the buffer that's smaller than the it claimed to be - sometimes system functions check if the targed buffer doesn't satisfy claimed size, and probably if the buffer belongs specific memory location (stack or executable image). For me your code works, it may depend on SP2 vs SP3. Try your code with allocation of a buffer from a heap, not in exe .data? - probably it would work.

Quote from: jj2007 on August 27, 2013, 06:38:46 AM
Quote from: Zen on August 27, 2013, 06:01:51 AM
JOCHEN,
Why not call RegQueryValueEx twice ???

Why should I??? ::)


push 0
invoke RegQueryValueEx,hkey,offset valuename,0,0,0,esp ; lpData is set to zero - function will return the size of the data in variable pointed by lpcbData
; [esp] now is the exact size of the data
call crt_malloc ; the size is already in the stack, and this function doesn't pops it (cdecl).
xchg eax,ebx
invoke RegQueryValueEx,hkey,offset valuename,0,0,ebx,esp
pop edx

EBX now points the buffer with exact data
EDX - the size of the data

Title: Re: RegQueryValueEx
Post by: sinsi on August 27, 2013, 05:10:15 PM
You know what they say jj, "garbage in, garbage out". If you pass 4GB as a size you should have a 4GB buffer :P
Title: Re: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 05:21:09 PM
Quote from: MichaelW on August 27, 2013, 09:52:49 AM
It works for me, Windows XP SP3.

For me, too - even with mov ebx, alloc(1024). But not always... it's the kind of un-chaseable bug that you find only by sheer coincidence, such as sending myself to google for Visual Basic ;)

@Alex & Zen: Thanks, now I got it. I didn't check for required buffer size simply because the string goes into MB's rotating buffer, and 160k is more than enough.

The whole point is about logic: From a "legal" viewpoint, qWord & sinsi are right - pass a valid buffer size. From a practical viewpoint, passing -1 should signal "don't worry", and the response of the OS should be either "I trust you" or "invalid parameter". As I see it here, Win7-32 responds sometimes with "no problem", and sometimes with "ERROR_NOT_ENOUGH_MEMORY" - which is nonsense when you are waiting for a 20-character string.
Title: Re: RegQueryValueEx
Post by: sinsi on August 27, 2013, 05:36:46 PM
So it sometimes crashes with the exact same registry value? Or different ones?
Registry access has changed, admin rights affects things, so does a 32/64 bit OS.

For example, I don't think 32-bit vista/7 have a HKLM\Software\Wow6432Node (btw, can someone confirm this?) and that can be a silent redirect to HKLM\Software.
Title: Re: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 05:50:39 PM
Quote from: sinsi on August 27, 2013, 05:36:46 PM
So it sometimes crashes with the exact same registry value?

With the same value, but in a slightly different context:
a) launched from my Masm32 folders: OK
b) launched from a temp folder: fails with error 8 (but succeeds if 65k are passed as buffer size)
Title: Re: RegQueryValueEx
Post by: GoneFishing on August 27, 2013, 06:21:10 PM
Jochen,

I and WinDbg didn't found hard-coded breakpoint. Your app runs and terminates correctly here .
There's no exception reports in the debugger.
Title: Re: RegQueryValueEx
Post by: sinsi on August 27, 2013, 06:28:07 PM
Might be a permission problem. Add a manifest to run as admin then try from both places.
Title: Re: RegQueryValueEx
Post by: jj2007 on August 27, 2013, 08:34:57 PM
Quote from: vertograd on August 27, 2013, 06:21:10 PM
Jochen,

I and WinDbg didn't found hard-coded breakpoint. Your app runs and terminates correctly here .
There's no exception reports in the debugger.

Thanxalot to everybody. New version 27b (http://masm32.com/board/index.php?topic=94.0) uses a valid 65k buffer and reports error codes better (MbGuide.rtf, GetRegVal):
- error codes for RegOpenKeyEx are in rvRegKey, those for RegQueryValueEx are in rvRegQuery
Title: Re: RegQueryValueEx
Post by: Tedd on August 28, 2013, 12:16:04 AM
A quick guess would be the value is sometimes treated as unsigned and others as signed; so, "-1" would be 4294967295 or -1 -- indicating a huge buffer, or none at all (negative size.) If this is the case, you could probably get away with using 2147483647 (7FFFFFFh) as the largest signed value; though some functions may have been ported directly from their original 16-bit ini-file versions and cause further problems, naturally.

Anyway, if you know your buffer size is 'big enough' why not just pass its size straight in? You should already know its size if you know it's big enough.
If you're only expecting a 20 byte string, why say the buffer is any larger? And if it turns out to be larger, that actually should cause an error because it's an unexpected situation that you're not explicitly handling, which will eventually lead to difficult bugs elsewhere.

This is just corner-cutting for the sake of laziness -- do it right or it will (and should) bite you eventually.
Title: Re: RegQueryValueEx
Post by: dedndave on August 28, 2013, 12:30:11 AM
i rarely want to permanently retain the resulting string, anyways
i find it best to:
1) call the function with a null buffer to get the size
2) probe the stack down (as required) to create a temporary buffer
   if you are using the Nt functions, they return UNICODE strings that should be 16-aligned   :t
   so, calculate that alignment into the probe code
3) call the function again with the stack buffer and correct size

good code is bullet-proof - lol
well, almost

i know why Jochen wants to push a -1
it makes for small code   :P
Title: Re: RegQueryValueEx
Post by: Zen on August 28, 2013, 03:53:41 AM
JOCHEN, 
OK you got it. I was just being annoying. Alex explained perfectly.
Here, is Raymond Chen explaining: More Undocumented Behavior and the People Who Rely On It: Output Buffers, Sept 2005 (http://blogs.msdn.com/b/oldnewthing/archive/2005/09/01/459023.aspx)
...Sort of,...well, OK,...it's resolved,... :dazzled:
Title: Re: RegQueryValueEx
Post by: jj2007 on August 28, 2013, 07:01:57 AM
"the content of an output item, after a call has failed /absolutely/" (last post in Raymond Chen's log)

I usually try to return a short printable string on failure, like a single question mark, or "La$?" in the case of Launch$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1047); in the case of GetRegVal (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1047), you can specify a default string, or zero. No default string means in this case "throw an error".

@Tedd: I have difficulties to see how the same identical code could treat a number sometimes as signed, sometimes as unsigned...
Title: Re: RegQueryValueEx
Post by: Magnum on August 28, 2013, 11:51:36 AM
Quote from: Tedd on August 28, 2013, 12:16:04 AM
A quick guess would be the value is sometimes treated as unsigned and others as signed; so, "-1" would be 4294967295 or -1 -- indicating a huge buffer, or none at all (negative size.) If this is the case, you could probably get away with using 2147483647 (7FFFFFFh) as the largest signed value; though some functions may have been ported directly from their original 16-bit ini-file versions and cause further problems, naturally.

Anyway, if you know your buffer size is 'big enough' why not just pass its size straight in? You should already know its size if you know it's big enough.
If you're only expecting a 20 byte string, why say the buffer is any larger? And if it turns out to be larger, that actually should cause an error because it's an unexpected situation that you're not explicitly handling, which will eventually lead to difficult bugs elsewhere.

This is just corner-cutting for the sake of laziness -- do it right or it will (and should) bite you eventually.

Tedd,

I do not understand what you mean by saying the buffer is any larger.

Title: Re: RegQueryValueEx
Post by: Tedd on August 28, 2013, 11:35:22 PM
Quote from: jj2007 on August 28, 2013, 07:01:57 AM
@Tedd: I have difficulties to see how the same identical code could treat a number sometimes as signed, sometimes as unsigned...
If it's always the same function call, then obviously not; like I said, it was just a quick guess.



Quote from: Magnum on August 28, 2013, 11:51:36 AM
I do not understand what you mean by saying the buffer is any larger.
"If you're only expecting a 20 byte string, why say the buffer is some arbitrary amount larger?"