KBDLLHOOKSTRUCT: Is there a reason why field vkCode is 32-bit unsigned DWORD? - winapi

From this page, KBDLLHOOKSTRUCT is defined as:
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
Field vkCode has type DWORD. According to this page DWORD is defined as A 32-bit unsigned integer.
However, the field docs say: The code must be a value in the range 1 to 254.
Is there an undocumented purpose for the additional 3 bytes of data in this field? Or is this either (a) byte alignment concerns or (b) future expansion of virtual key codes?

Related

How to convert DWORD to Hex

I've searched a lot and found nothing useful regarding this thing.
If anyone knows please share the knowledge.
Problem: I have a DWORD "-476053499" and I want to convert it to hex (e.g. XX XX XX XX).
DWORD is just a typedef for a a 32-bit unsigned integer (e.g. unsigned int or uint32_t). Notice that it's "unsigned", so I'm not sure how that plays into your value of -476053499
You didn't specify which language, but to convert a DWORD to a hexadecimal string is easily accomplished like this in C:
DWORD dwValue = (DWORD)(-476053499);
char szHexString[20];
sprintf(szHexString, "%X"); // use %x if you want lowercase hex
Equivalent in C++:
DWORD dwValue = (DWORD)(-476053499);
std::ostringstream ss;
ss << std::hex << dwValue;
std::string s = ss.str();
If your original value is actually a string, and not a DWORD, then to convert it to a number is simply:
const char* s = "-476053499";
DWORD value = (DWORD)atoi(s);

How do you explain gcc's inline assembly constraints for the IN, OUT instructions of i386?

As far as I can tell, the constraints used in gcc inline assembly tell gcc where input and output variables must go (or must be) in order to generate valid assembly. As the Fine Manual says, "constraints on the placement of the operand".
Here's a specific, working example from a tutorial.
static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
inb is AT&T syntax-speak for the i386 IN instruction that receives one byte from an I/O port.
Here are the specs for this instruction, taken from the i386 manual. Note that port numbers go from 0x0000 to 0xFFFF.
IN AL,imm8 // Input byte from immediate port into AL
IN AX,imm8 // Input word from immediate port into AX
IN EAX,imm8 // Input dword from immediate port into EAX
IN AL,DX // Input byte from port DX into AL
IN AX,DX // Input word from port DX into AX
IN EAX,DX // Input dword from port DX into EAX
Given a statement like uint8_t x = inb(0x80); the assembly output is, correctly, inb $0x80,%al. It used the IN AL,imm8 form of the instruction.
Now, let's say I just care about the IN AL,imm8 form, receiving a uint8_t from a port between 0x00 and 0xFF inclusive. The only difference between this and the working example is that port is now a uint8_t template parameter (to make it effectively a constant) and the constraint is now "N".
template<uint8_t port>
static inline uint8_t inb()
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "N"(port) );
return ret;
}
Fail!
I thought that the "N" constraint would mean, "you must have a constant unsigned 8-bit integer for this instruction", but clearly it does not because it is an "impossible constraint". Isn't the uint8_t template param a constant unsigned 8-bit integer?
If I replace "N" with "Nd", I get a different error:
./test.h: Assembler messages:
./test.h:23: Error: operand type mismatch for `in'
In this case, the assembler output is inb %dl, %al which obviously is not valid.
Why would this only work with "Nd" and uint16_t and not "N" and uint8_t?
EDIT:
Here's a stripped-down version I tried on godbolt.org:
#include <cstdint>
template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;
asm volatile("inb %[port], %%al"
:
: [port] "N" (N)
: // clobbers
);
return data;
}
};
void func() {
Port<0x7F>().in();
}
Interestingly, this works fine, except if you change N to anything between 0x80 and 0xFF. On clang this generates a "128 is out of range for constraint N" error. This generates a more generic error in gcc.
Based on how constraints are documented your code should work as expected.
This appears to still be a bug more than a year later. It appears the compilers are converting N from an unsigned value to a signed value and attempting to pass that into an inline assembly constraint. That of course fails when the value being passed into the constraint can't be represented as an 8-bit signed value. The input constraint "N" is suppose to allow an unsigned 8-bit value and any value between 0 and 255 (0xff) should be accepted:
N
Unsigned 8-bit integer constant (for in and out instructions).
There is a similar bug report to GCC's bugzilla titled "Constant constraint check sign extends unsigned constant input operands".
In one of the related threads it was suggested you can fix this issue by ANDing (&) 0xff to the constant (ie: N & 0xff). I have also found that static casting N to an unsigned type wider than uint8_t also works:
#include <cstdint>
template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;
asm volatile("inb %[port], %0"
: "=a"(data)
: [port] "N" (static_cast<uint16_t>(N))
: // clobbers
);
return data;
}
};
void func() {
Port<0x7f>().in();
Port<0x80>().in();
// Port<0x100>().in(); // Fails as expected since it doesn't fit in a uint8_t
}
To test this you can play with it on godbolt.

PEB_LDR_DATA structure has different members and sizes

The PEB structure contains process information and the pointer of PEB_LDR_DATA structure which contains information about the loaded modules for the process is one of PEB members.
From MSDN, PEB structure syntax is as follows:
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr; <-- I'm curious about this one.
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
After searching for the structure, I found that there are various forms and they make me confused:
// Form #1: this is described in MSDN
typedef struct _PEB_LDR_DATA { // 28 bytes
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
// Form #2
typedef struct _PEB_LDR_DATA { // 40 bytes
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
// Form #3
typedef struct _PEB_LDR_DATA { // 36 bytes
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
How could they have different members and sizes?
These are essentially internal undocumented data structures that can change between versions and even service packs. In the beginning only the first few fields of the TEB/TIB were semi-documented because they are used by compilers to implement SEH and TLS.
Over time people figured out some of the other fields and started using them which essentially forced Microsoft to document them. All other members have reserved names because Microsoft does not want you to use them because there might be a documented API for it or it might change in the future.
On 32-bit Windows 8 the PEB_LDR_DATA struct looks like this:
0x000 Length : Uint4B
0x004 Initialized : UChar
0x008 SsHandle : Ptr32 Void
0x00c InLoadOrderModuleList : _LIST_ENTRY
0x014 InMemoryOrderModuleList : _LIST_ENTRY
0x01c InInitializationOrderModuleList : _LIST_ENTRY
0x024 EntryInProgress : Ptr32 Void
0x028 ShutdownInProgress : UChar
0x02c ShutdownThreadId : Ptr32 Void
Symbols are not always 100% correct but it is often the best source when dealing with these types of structs. This matches the memory layout of the structs you posted (except for Form #2 which incorrectly uses DWORD for the BOOLEAN). Accessing anything beyond the LIST_ENTRYs must be done after you have checked the length member (or the Windows version) because they don't exist in older versions.
The size can be different because new fields have been added over time. The members can be different because the field actually changed over time but more likely it is a bug because somebody just used a different name/type for a field.
If your goal is to list the loaded modules then you can use the documented ToolHelp API instead...

PVS-Studio: V641 - false positive for WIN API structs

The last member WCHAR Name[1] is assumed to be a string. It's a well-known technic.
// c:\Program Files (x86)\Windows Kits\8.0\Include\um\DbgHelp.h
typedef struct _SYMBOL_INFOW {
ULONG SizeOfStruct;
ULONG TypeIndex; // Type Index of symbol
ULONG64 Reserved[2];
ULONG Index;
ULONG Size;
ULONG64 ModBase; // Base Address of module comtaining this symbol
ULONG Flags;
ULONG64 Value; // Value of symbol, ValuePresent should be 1
ULONG64 Address; // Address of symbol including base address of module
ULONG Register; // register holding value or pointer to value
ULONG Scope; // scope of the symbol
ULONG Tag; // pdb classification
ULONG NameLen; // Actual length of name
ULONG MaxNameLen;
WCHAR Name[1]; // Name of symbol
} SYMBOL_INFOW, *PSYMBOL_INFOW;
But the following code generates V641. Why?
PSYMBOL_INFOW pSym = NULL;
pSym = (PSYMBOL_INFOW) malloc(sizeof(SYMBOL_INFOW) + MAX_SYM_NAME);
Thank you for the interest to our product and the issues you described. We will examine the provided code fragments and will try to fix these issues.

Are LVITEM fields puColumns and piColFmt pointers or integers?

After discovering the fields of LVITEM for 64 bit in this question, there is one last thing I don't know. The documentation says that:
puColumns is a UINT. It is a pointer to an array of column indices, specifying which columns are displayed for this item, and the order of those columns.
piColFmt is a int. It is a pointer to an array of the following flags (alone or in combination), specifying the format of each subitem in extended tile view.
My question is why they are integers and not pointers? And in a 64 bit architecture, should they take 8 bytes like pointers or 4 bytes like integers?
Thank you!
So the Windows SDK says:
typedef struct tagLVITEMA
{
UINT mask;
int iItem;
int iSubItem;
UINT state;
UINT stateMask;
LPSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iIndent;
#endif
#if (_WIN32_WINNT >= 0x0501)
int iGroupId;
UINT cColumns; // tile view columns
PUINT puColumns;
#endif
#if _WIN32_WINNT >= 0x0600 // Will be unused downlevel, but sizeof(LVITEMA) must be equal to sizeof(LVITEMW)
int* piColFmt;
int iGroup; // readonly. only valid for owner data.
#endif
} LVITEMA, *LPLVITEMA;

Resources