Drugwash

KernelEx -- On building, debugging and related matters...

152 posts in this topic

Edited by Leyok
0

Share this post


Link to post
Share on other sites

The definition of VxD_Desc_Block is in VMM.INC found in the 98 DDK. The name field is an 8 byte array (8 spaces). There may be something wrong with the declaration of that struct in util.h, so that it automatically adds an EndOfString character which replaces the rightful space. Xeno might know about this and may have not found a (simple) solution to it so he left it as is. That's just an assumption though.

On another note, my latest build still throws WinSta0 error. I'm stumped. :(

0

Share this post


Link to post
Share on other sites

@Leyok I did find a minor error in VKRNLEX.VXD. The 8 Byte Module Identifier was not space padded. It was "VKRNLEX", when it should have been "VKRNLEX " (space at end).

Where is it ?

It is in the VXD Descriptor Block. It is located at offset 0x101C in the 4.5.2 Version. It is supposed to be 8 Characters with Space padding and no termination character.

Do you mean VxD_Desc_Block in util.h ?

I get "C2117: 'VKRNLEX ' : array bounds overflow" when I replace #name by #name####" ". Is it really there ?

Yes.

In Assembly it is not a problem. In C/C++ you cannot use a string. You need to use a Character Array {'V','K','R','N','L','E','X',' '}

0

Share this post


Link to post
Share on other sites
In Assembly it is not a problem. In C/C++ you cannot use a string. You need to use a Character Array {'V','K','R','N','L','E','X',' '}

If I may ask, what are the implications of this wrong name field for the overall KernelEx operation? Since it's been introduced in 4.5.2 and that version appears to work correctly within its capabilities, could this be a big problem or it's just a cosmetic issue?

Anyway, looking at the code in util.h, it all appears to be a single #define:

#define	_Declare_Virtual_Device(name, ver_major, ver_minor, ctrl_proc, device_num, init_order, V86_proc, PM_proc, ref_data) \
BOOL __stdcall ControlDispatcher(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); \
\
void __declspec(naked) name##_CTRL(void) \
{ \
__asm PUSH EDI \
__asm PUSH ESI \
__asm PUSH EDX \
__asm PUSH ECX \
__asm PUSH EBX \
__asm PUSH EAX \
__asm CALL ctrl_proc \
__asm CMP EAX, TRUE \
__asm RET \
} \
\
EXTERNC struct VxD_Desc_Block name##_DDB = \
{ \
0, DDK_VERSION, device_num, ver_major, ver_minor, 0, \
#name, init_order, (ULONG)name##_CTRL, (ULONG)V86_proc, (ULONG)PM_proc, \
0, 0, ref_data, 0, 0, 0, 'Prev', sizeof(struct VxD_Desc_Block), \
'Rsv1', 'Rsv2', 'Rsv3' \
}

The name field is retrieved from the #name variable and there may be a reason why it's been made like this - flexibility comes to mind first. But given the way the structure is declared, I can't see a way to translate whatever name may be fed to the struct, into a fixed 8-byte array.

Of course, using a fixed array as you mentioned above is accepted by the compiler, but the declaration loses its flexibility. What would be the best way to handle this, I wonder?

0

Share this post


Link to post
Share on other sites
In Assembly it is not a problem. In C/C++ you cannot use a string. You need to use a Character Array {'V','K','R','N','L','E','X',' '}

If I may ask, what are the implications of this wrong name field for the overall KernelEx operation? Since it's been introduced in 4.5.2 and that version appears to work correctly within its capabilities, could this be a big problem or it's just a cosmetic issue?

Anyway, looking at the code in util.h, it all appears to be a single #define:

#define	_Declare_Virtual_Device(name, ver_major, ver_minor, ctrl_proc, device_num, init_order, V86_proc, PM_proc, ref_data) \
BOOL __stdcall ControlDispatcher(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); \
\
void __declspec(naked) name##_CTRL(void) \
{ \
__asm PUSH EDI \
__asm PUSH ESI \
__asm PUSH EDX \
__asm PUSH ECX \
__asm PUSH EBX \
__asm PUSH EAX \
__asm CALL ctrl_proc \
__asm CMP EAX, TRUE \
__asm RET \
} \
\
EXTERNC struct VxD_Desc_Block name##_DDB = \
{ \
0, DDK_VERSION, device_num, ver_major, ver_minor, 0, \
#name, init_order, (ULONG)name##_CTRL, (ULONG)V86_proc, (ULONG)PM_proc, \
0, 0, ref_data, 0, 0, 0, 'Prev', sizeof(struct VxD_Desc_Block), \
'Rsv1', 'Rsv2', 'Rsv3' \
}

The name field is retrieved from the #name variable and there may be a reason why it's been made like this - flexibility comes to mind first. But given the way the structure is declared, I can't see a way to translate whatever name may be fed to the struct, into a fixed 8-byte array.

Of course, using a fixed array as you mentioned above is accepted by the compiler, but the declaration loses its flexibility. What would be the best way to handle this, I wonder?

In the case of KernelEx it may only cosmetic. There may not be anything searching for the VKRNLEX.VXD image in memory.

Eight character names would be a problem with this definition.

Edited by rloew
0

Share this post


Link to post
Share on other sites

In the case of KernelEx it may only cosmetic. There may not be anything searching for the VKRNLEX.VXD image in memory.

Eight character names would be a problem with this definition.

Indeed, because it'll always append the EOS (NULL) character to the variable string, hence the overflow error. Do you happen to see any viable solution to this, while keeping the flexibility desired by the author? Or should we just leave it as is, waste no more time?

Edited by Drugwash
0

Share this post


Link to post
Share on other sites
:angel Since VxDs are not checksummed, you all could adopt a post-build patching procedure as a routine. It's not elegant, but does the job -- and can be automated (with hexalter, for instance)... :unsure:
0

Share this post


Link to post
Share on other sites

In the case of KernelEx it may only cosmetic. There may not be anything searching for the VKRNLEX.VXD image in memory.

Eight character names would be a problem with this definition.

Indeed, because it'll always append the EOS (NULL) character to the variable string, hence the overflow error. Do you happen to see any viable solution to this, while keeping the flexibility desired by the author? Or should we just leave it as is, waste no more time?

Unfortunately, I do not know a way to get around this issue in C++. C might allow the eight character string without the null. This would not fix the padding issue.

I cannot guarantee that a runtime fix would work, as I am not sure if the Descriptor is scanned or copied prior to Initialization.

Using a Character array may not be flexible but it only needs to be done once for a given VXD so it can be done for KernelEx fairly easily.

@dencorso: A patch would not work for eight character identifiers since the program cannot be patched if it cannot be compiled. It could only be used to fix the padding issue.

0

Share this post


Link to post
Share on other sites
@dencorso: A patch would not work for eight character identifiers since the program cannot be patched if it cannot be compiled. It could only be used to fix the padding issue.

With all due respect, of course it would: when the 8th character is a space, one patches 0x00 to 0x20. But if there are 8 characters, it's simply a question of using an incomplete 7 characters string at build time, and then patching the final 0x00, added by C++, with the right value for the 8th character. :w00t:

0

Share this post


Link to post
Share on other sites
@dencorso: A patch would not work for eight character identifiers since the program cannot be patched if it cannot be compiled. It could only be used to fix the padding issue.

With all due respect, of course it would: when the 8th character is a space, one patches 0x00 to 0x20. But if there are 8 characters, it's simply a question of using an incomplete 7 characters string at build time, and then patching the final 0x00, added by C++, with the right value for the 8th character. :w00t:

Yes, but that would require generating a separate 7 Character string when the Identifier is 8 Characters. That would defeat the purpose of using the util.h Macro as is. It would also require specifying the eighth Character to the Patcher.

VMM.H defines these Macros also, but Microsoft specifies a separate "quote_name" argument in addition to using a "name" argument.

0

Share this post


Link to post
Share on other sites

What if we built the struct in Assembler? Would there be a chance to crop whatever name variable to an 8-byte array then?

Or define a temporary zero-filled 8-byte array, memcpy the first (max.8) chars (bytes) from the #name variable to the array and use the array in the struct declaration.

Dunno if I'm making much sense here - as I said, I'm not a professional programmer.:blushing:

0

Share this post


Link to post
Share on other sites

What if we built the struct in Assembler? Would there be a chance to crop whatever name variable to an 8-byte array then?

Yes. Look at VMM.INC for more info.

Or define a temporary zero-filled 8-byte array, memcpy the first (max.8) chars (bytes) from the #name variable to the array and use the array in the struct declaration.

Dunno if I'm making much sense here - as I said, I'm not a professional programmer.:blushing:

The array is embedded in the Struct, you can't use a pointer to it. You would have to copy the characters into the Struct directly.

memcpy would run during initialization. As I said before, I cannot be sure that the Struct is not scanned or copied before initialization.

0

Share this post


Link to post
Share on other sites

Sorry, I tried but obviously my ASM knowledge is way too scarse for this (simple) task. Would you please do the honors? The only other people I know that could cope with ASM are Xeno86 and Tihiy; there used to be PassingBy, but he's long gone and I don't know if Leyok knows any ASM - never mentioned it so far.

And just to prove I did try:

struct VxD_Desc_Block name##_DDB = \
{ \
__asm DD 0 \
__asm DW DDK_VERSION \
__asm DW device_num \
__asm DB ver_major \
__asm DB ver_minor \
__asm DW 0 \
__asm DB[8] name " " \
__asm DD init_order \
__asm DD &name##_CTRL \
__asm DD &V86_proc \
__asm DD &PM_proc \
__asm DD 0 \
__asm DD 0 \
__asm DD ref_data \
__asm DD 0 \
__asm DD 0 \
__asm DD 0 \
__asm DD 'Prev' \
__asm DD SIZE(VxD_Desc_Block) \
__asm DD 'Rsv1' \
__asm DD 'Rsv2' \
__asm DD 'Rsv3' \
}

This one obviously works, but loses flexibility:


EXTERNC struct VxD_Desc_Block name##_DDB = \
{ \
0, DDK_VERSION, device_num, ver_major, ver_minor, 0, \
{'V', 'K', 'R', 'N', 'L', 'E', 'X', ' '}, init_order, (ULONG)name##_CTRL, (ULONG)V86_proc, (ULONG)PM_proc, \
0, 0, ref_data, 0, 0, 0, 'Prev', sizeof(struct VxD_Desc_Block), \
'Rsv1', 'Rsv2', 'Rsv3' \
}

0

Share this post


Link to post
Share on other sites
@dencorso: A patch would not work for eight character identifiers since the program cannot be patched if it cannot be compiled. It could only be used to fix the padding issue.

With all due respect, of course it would: when the 8th character is a space, one patches 0x00 to 0x20. But if there are 8 characters, it's simply a question of using an incomplete 7 characters string at build time, and then patching the final 0x00, added by C++, with the right value for the 8th character. :w00t:

Yes, but that would require generating a separate 7 Character string when the Identifier is 8 Characters. That would defeat the purpose of using the util.h Macro as is. It would also require specifying the eighth Character to the Patcher.

VMM.H defines these Macros also, but Microsoft specifies a separate "quote_name" argument in addition to using a "name" argument.

OMG. What is the problem? The driver works as is... so why patch, why bother?

0

Share this post


Link to post
Share on other sites

Well, one thing led to another and this came to attention at some point. We thought "Whadda heck, since we stumbled into it, let's fix it". But it turned out to be harder than expected, at least for an amateur like me. Dunno about Leyok, probably has bigger fish to fry. EDIT: Actually, he commited a fix to this already, although it seems more complicated than it should, considering flexibility is lost anyway.

But major problem for me is that none of my builds will work properly. Did you ever manage to compile and install from Leyok's repository succesfully? It compiles fine by me, but always stumbles in kexbases (logs are attached somewhere in previous posts). If I replace mine with Leyok's, it works fine. No idea what's going on, since your code builds and runs fine and I also built and ran many other projects without problems.

Edited by Drugwash
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.