Sometimes I just hate M$....maybe I should start hating them all the time instead
did you know that QueryServiceConfig() will crash if you pass it pointer to buffer that is not on dword alignment?
check out this code



.data
buff db 1024 dup(?)
dummy dd ?
.code
start:
invoke OpenSCManager,0,0,SC_MANAGER_ALL_ACCESS
invoke OpenService,eax,CTEXT("Alerter"),SERVICE_ALL_ACCESS ; instead alerter use any other available service name
invoke QueryServiceConfig,eax,offset buff,1024,addr dummy



Thatwill work fine if we assume that buff is on dword boundary (align it if its not under debugger or somthing like that) , but try this



.data
buff db 1024 dup(?)
dummy dd ?
.code
start:
invoke OpenSCManager,0,0,SC_MANAGER_ALL_ACCESS
invoke OpenService,eax,CTEXT("Alerter"),SERVICE_ALL_ACCESS ; instead alerter use any other available service name
invoke QueryServiceConfig,eax,[color=red]offset buff +1[/color],1024,addr dummy



yup... effectively craches program on my XP and I wasted 3 wasted hours of my life figuring what is the problem..
Posted on 2003-11-04 18:03:57 by Mikky
Hi

That's a good thing to keep in mind. Horrors, an MS bug, who would have thunk it? ;-)

Here's another one that caught me with MmIsAddressValid. Straight from the DDK:

-------------------------------------------
MmIsAddressValid checks whether a page fault will occur for a read or write operation at a given virtual address.

MmIsAddressValid(
IN PVOID VirtualAddress

VirtualAddress - Points to the virtual address to check.
Return Value - If no page fault will occur from reading or writing at the given virtual address, MmIsAddressValid returns TRUE.
-------------------------------------------

One would assume then, I believe, you would use the function something like

invoke MmIsAddressValid, VirtualAddress
.if EAX == TRUE
...

The only problem is that in the MmIsAddressValid function, the return value (0 or 1) is passed only to AL and not EAX. Plus, EAX immediately becomes the argument you pushed and is further manipulated, almost guaranteeing EAX won't be zero before the return value is passed. A partial disassembly of the function shows the offending(?) code in ntoskrnl.exe:



:00442A08 MmIsAddressValid proc near
:00442A08 mov ecx, [esp+arg_0]
:00442A0C mov eax, ecx
...
:00442A5C cmp dword_4836A4, 0
:00442A63 jz short loc_442A69
:00442A65 xor al, al ; memory protected or not paged in
:00442A67 jmp short locret_442A6B
:00442A69 mov al, 1 ; memory paged in and valid
:00442A6B retn 4
:00442A6B MmIsAddressValid endp


The caution here is to only check if AL is TRUE, not EAX. Since TRUE equ 1 and not 00000001, I guess there's nothing wrong with this, but it does seem to go against principle in 32 bit code, no?
How about a Microsoft bug forum? ;)

Cheers,
Kayaker
Posted on 2003-11-04 20:43:50 by Kayaker
Maybe I'm wrong here but I don't think this is a bug. The second parameter is not just any old buffer, but actually a structure that Windows fills. The definition is:



typedef struct _QUERY_SERVICE_CONFIG {
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
LPTSTR lpBinaryPathName;
LPTSTR lpLoadOrderGroup;
DWORD dwTagId;
LPTSTR lpDependencies;
LPTSTR lpServiceStartName;
LPTSTR lpDisplayName;
} QUERY_SERVICE_CONFIG, *LPQUERY_SERVICE_CONFIG;


If the first field is supposed to be a DWORD, shouldn't the buffer you allocate be aligned on a DWORD boundry?
Posted on 2003-11-04 20:44:27 by Mecurius
Kayaker, thats what am talking about, but note that even though TRUE usually means 1 it is actually every non-zero value (at least in C/C++). In ether case they should point that procedure returns non-zero value for success.

Mecurius, data is data, you can store it in buffer declared as dwords, bytes, or QUERY_SERVICE_CONFIG. Note that QUERY_SERVICE_CONFIG struct have not fixed length so thats why I used that big buffer. And yes everything on 32bit processor should be be on dword boundary becouse of performances, but in no way a non-alignment data should crash the program.
Posted on 2003-11-05 04:41:43 by Mikky
Kayaker: The only problem is that in the MmIsAddressValid function, the return value (0 or 1) is passed only to AL and not EAX.
Hi, Kayaker. No problem with MmIsAddressValid because its defined like this:

BOOLEAN
MmIsAddressValid(
IN PVOID VirtualAddress
);

You see the return value is of type BOOLEAN. And BOOLEAN defined in ddk headers like this:

typedef UCHAR BOOLEAN;
Posted on 2003-11-05 06:05:37 by Four-F
Thank you Four-F, that clarifies things immensely. I never considered that BOOLEAN in the API declaration signified anything other than a dword return value. I can see this (BOOLEAN return value being passed in AL) in several other functions now as well. Darn, and it was so easy to blame M$ too, instead of my own ignorance and lack of formal C training ;-)

Still, it bears a bit of caution, from windows.inc it appears
BOOLEAN != BOOL, but also
bool != BOOL
a bit confusing perhaps.

----------------------
; 8 bit BYTE
bool typedef BYTE
BOOLEAN typedef BYTE

; 32 bit DWORD
BOOL typedef DWORD
----------------------

Heheh, there's a phrase that's somewhat appropriate, I don't know how well this would translate into Russian ;)

"I see said the blind man to his deaf dog"

Regards,
Kayaker
Posted on 2003-11-05 21:14:54 by Kayaker
BTW, primarily BOOLEN was defined as DWORD. I wrote about it here:
WINDOWS.INC version 125b
But two different definitions of one type!... windows.inc is still buggy :-(
Posted on 2003-11-06 03:28:52 by Four-F