Hello @yohei watanabe ,
To your first question, I don't think you missed anything. Windows simply doesn't publish a GENERIC_MAPPING table for process and thread objects. As far as I know, the mapping is defined inside the kernel (on PsProcessType and PsThreadType), it isn't part of the public Win32 contract, and it isn't guaranteed to stay constant across versions. That's why the Process and Thread security pages only list the specific and standard rights along with *_ALL_ACCESS. So, I'd advise against hard-coding the four values, since there's no stable contract to rely on.
On your second question about a dynamic method, I'm not aware of a fully documented, supported way to read the mapping from user mode. The only call I know of that returns it is NtQueryObject with ObjectTypeInformation, where the mapping shows up in OBJECT_TYPE_INFORMATION.GenericMapping. But that field sits in the reserved, subject-to-change part of winternl.h, the same area you've already decided not to depend on so I wouldn't treat it as a supported contract either.
I think your third question is where the problem actually resolves. GENERIC_MAPPING is only used to translate generic bits, and since you already validate and reject generic bits in both DesiredAccess and every ACE mask before calling AccessCheck, no translation happens so whatever you pass in that structure can't change the result. You just need a valid, non-NULL pointer; setting all four fields to the object's *_ALL_ACCESS is fine. The same holds with MAXIMUM_ALLOWED: it wants a valid mapping pointer, but the contents don't matter once the descriptor has no generic bits.
If what you're really after is checking whether the granted rights are a subset of an allowed mask, I'd suggest avoiding the mapping altogether. Let AccessCheck compute GrantedAccess under MAXIMUM_ALLOWED, then compare with bit math:
// AccessCheck(..., MAXIMUM_ALLOWED, &genericMapping, ..., &granted, &status);
BOOL isSubset = ((granted & ~AllowedMask) == 0);
As long as you express AllowedMask in specific and standard bits, this is fully supported and doesn't depend on any version-specific mapping. So, my suggestion is to keep rejecting generic bits at your input boundary, pass a valid placeholder mapping, and run the subset test on GrantedAccess. That keeps everything on documented behavior.
Hope this helps. If you found my response helpful or informative, I would greatly appreciate it if you could follow this guide for your confirmation.
Thank you.