• The Old New Thing

    If you can set enforcement for a rule, you can set up lack of enforcement

    • 9 Comments

    One of the things you can do with an internal tool I've been calling Program Q is run a program any time somebody wants to add or modify a record. The program has wide latitude in what it can do. It can inspect the record being added/modified, maybe record side information in another table, and one of the things it can decide to do is to reject the operation.

    We have set up a validator in our main table to ensure that the widget being added or modified is priced within the approver's limit. But sometimes, there is an urgent widget request and we want to be able to bypass the validation temporarily. Is there a way to disable the validator just for a specific record, or to disable it for all records temporarily?

    If you can set up a program to validate a record, you can also set up a program to not validate a record.

    Suppose your current validator for adding a widget goes like this:

    if (record.approver.limit < record.price) {
     record.Reject("Price exceeds approver's limit");
     return;
    }
    ... other tests go here ...
    

    And say you want to be able to allow emergency requests to go through even though, say, all approvers are unavailable. Because, maybe, the widget is on fire.

    You could decide that a widget whose description begins with the word EMERGENCY is exempt from all validation, but it generates email to a special mailing list.

    if (record.description.beginsWith("EMERGENCY"))
    {
     // emergency override: send email
     // and bypass the rest of validation
     generateNotificationEmail(record);
     return;
    }
    if (record.approver.limit < record.price) {
     record.Reject("Price exceeds approver's limit");
     return;
    }
    ... other tests go here ...
    

    Of course, the EMERGENCY rule was completely arbitrary. You can come up with whatever rules you like. The point is: If you wrote the rules, you can also write the rules so that they have exceptions.

  • The Old New Thing

    When you inadvertently become a collector of something you really aren't all that into

    • 25 Comments

    As I was heading home at the end of the day, I ran into one of my colleagues who was also going home, and he was carrying a Star Wars-themed metal lunchbox similar to this one. For those who didn't grow up in the United States, these metal lunchboxes are the type of things elementary school children use to carry their lunch to school.

    I remarked, "Nice lunchbox."

    My colleague explained, "Yeah, I sort of ended up as the lunchbox guy. It started when somebody gave me a lunchbox as a semi-humorous gift, and I kept it on my shelf. Then other people saw that I had a metal lunchbox and concluded, 'Oh, he must collect metal lunchboxes,' and they started giving me metal lunchboxes. And before I knew it, I became an unwitting collector of metal lunchboxes."

    The same thing happened to a different colleague of mine. As his first birthday after he got married approached, his new in-laws asked his wife, "What does Bob like?"

    His wife shrugged. "I dunno. He kind of likes Coca-Cola?"

    That year, he got a vintage Coca-Cola serving tray. The next year, he got a Coca-Cola clock. And then Coca-Cola drinking glasses. And so on.

    Eventually, he had to ask his wife to tell her family, "Okay, you can stop now. Bob doesn't like Coca-Cola that much."

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Code injection via QueueUserAPC

    • 11 Comments

    A security vulnerability report arrived that took the following form:

    The Queue­User­APC function can be used to effect an elevation of privilege, as follows:

    1. Identify a process you wish to attack.
    2. Obtain access to a thread with THREAD_SET_­CONTEXT access.
    3. Make some educated guesses as to what DLLs are loaded in that process. Start with kernel32.dll, since you're going to need it in step 5.
    4. From the attacking process, scan the memory of those DLLs looking for a backslash, followed by something that can pass for a path and file name. Such strings are relatively abundant because there are a lot of registry paths hard-coded into those binaries. Suppose you found the string \Windows NT\Current­Version\App­Compat­Flags. Even though ASLR randomizes DLL placement, the placement is consistent among all processes, so an address calculated in one process is highliy likely to be valid in all processes.
    5. Create a DLL called C:\Windows NT\Current­Version\App­Compat­Flags.dll. Put your payload in this DLL.
    6. From the attacking thread, call Queue­User­APC with the address of Load­LibraryW as the function pointer, the victim thread as the thread handle, and a pointer to the fixed string identified in part 4 as the last parameter.
    7. The next time the victim thread processes APCs, it will pass \Windows NT\Current­Version\App­Compat­Flags to the Load­LibraryW function, which will load the payload DLL, thereby effecting code injection and consequent elevation of privilege.

    Note that this attack fails if the victim thread never waits alertably, which is true of most threads.

    If you have been paying attention, the alarm bells probably went off at step 2. If you have THREAD_SET_­CONTEXT access to a thread, then you pwn that thread. There's no need to use Queue­User­APC to make the thread do your bidding. You already have enough to make the thread dance to your music. In other words, you are already on the other side of the airtight hatchway.

    Here's how: Look for a code sequence that goes

        push someregister
        call LoadLibraryW
    

    Use the ­Set­Thread­Context function to set the pushed register equal to the address of the string you found in step 4, and set the instruction pointer to the code fragment. The thread will then resume execution at the specified instruction pointer: It pushes the address of the string, and then it calls Load­LibraryW. Bingo, your DLL loads, and you didn't even have to wait for the thread to wait alertably.

    On non-x86 platforms, this is even easier: Since all other platforms use register-based calling conventions, you merely have to load the address of the string into the "first parameter" register (rcx for x64) and set the instruction pointer to the beginning of Load­LibaryW.

    By default, THREAD_SET_­CONTEXT access is granted only to the user, and never to lower integrity levels. In other words, a low IL process cannot get THREAD_SET_­CONTEXT access to a medium or high integrity thread, and a medium IL process cannot get access to a high integrity thread. This means that, by default, you can only get THREAD_SET_­CONTEXT access to threads that have equivalent permissions to what you already have, so there is no elevation.

  • The Old New Thing

    Determining programmatically whether a file was built with LAA, ASLR, DEP, or OS-assisted /GS

    • 25 Comments

    Today's Little Program parses a module to determine whether or not it was built with the following flags:

    Remember, Little Programs do little error checking. In particular, this Little Program does no range checking, so a malformed binary can result in wild pointers.

    #include <windows.h>
    #include <imagehlp.h>
    #include <stdio.h> // horrors! mixing stdio and C++!
    #include <stddef.h>
    
    class MappedImage
    {
    public:
     bool MapImage(const char* fileName);
     void ProcessResults();
     ~MappedImage();
    
    private:
     WORD GetCharacteristics();
    
     template<typename T>
     WORD GetDllCharacteristics();
    
     template<typename T>
     bool HasSecurityCookie();
    
    private:
     HANDLE file_ = INVALID_HANDLE_VALUE;
     HANDLE mapping_ = nullptr;
     void *imageBase_ = nullptr;
     IMAGE_NT_HEADERS* headers_ = nullptr;
     int bitness_ = 0;
    };
    
    bool MappedImage::MapImage(const char* fileName)
    {
     file_ = CreateFile(fileName, GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);
     if (file_ == INVALID_HANDLE_VALUE) return false;
    
     mapping_ = CreateFileMapping(file_, NULL, PAGE_READONLY,
                                  0, 0, NULL);
     if (!mapping_) return false;
    
     imageBase_ = MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, 0);
     if (!imageBase_) return false;
    
     headers_ = ImageNtHeader(imageBase_);
     if (!headers_) return false;
     if (headers_->Signature != IMAGE_NT_SIGNATURE) return false;
    
     switch (headers_->OptionalHeader.Magic) {
     case IMAGE_NT_OPTIONAL_HDR32_MAGIC: bitness_ = 32; break;
     case IMAGE_NT_OPTIONAL_HDR64_MAGIC: bitness_ = 64; break;
     default: return false;
     }
    
     return true;
    }
    
    MappedImage::~MappedImage()
    {
     if (imageBase_) UnmapViewOfFile(imageBase_);
     if (mapping_) CloseHandle(mapping_);
     if (file_ != INVALID_HANDLE_VALUE) CloseHandle(file_);
    }
    
    WORD MappedImage::GetCharacteristics()
    {
     return headers_->FileHeader.Characteristics;
    }
    
    template<typename T>
    WORD MappedImage::GetDllCharacteristics()
    {
      return reinterpret_cast<T*>(headers_)->
        OptionalHeader.DllCharacteristics;
    }
    
    template<typename T>
    bool MappedImage::HasSecurityCookie()
    {
     ULONG size;
     T *data = static_cast<T*>(ImageDirectoryEntryToDataEx(
        imageBase_, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
        &size, NULL));
     if (!data) return false;
     ULONG minSize = offsetof(T, SecurityCookie) +
                     sizeof(data->SecurityCookie);
     if (size < minSize) return false;
     if (data->Size < minSize) return false;
     return data->SecurityCookie != 0;
    }
    
    void MappedImage::ProcessResults()
    {
     printf("%d-bit binary\n", bitness_);
     auto Characteristics = GetCharacteristics();
     printf("Large address aware: %s\n",
        (Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
        ? "Yes" : "No");
    
     auto DllCharacteristics = bitness_ == 32
        ? GetDllCharacteristics<IMAGE_NT_HEADERS32>()
        : GetDllCharacteristics<IMAGE_NT_HEADERS64>();
    
     printf("ASLR: %s\n",
        (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)
        ? "Yes" : "No");
     printf("ASLR^2: %s\n",
        (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA)
        ? "Yes" : "No");
     printf("DEP: %s\n",
        (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT)
        ? "Yes" : "No");
     printf("TS Aware: %s\n",
        (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)
        ? "Yes" : "No");
    
     bool hasSecurityCookie =
        bitness_ == 32 ? HasSecurityCookie<IMAGE_LOAD_CONFIG_DIRECTORY32>()
                       : HasSecurityCookie<IMAGE_LOAD_CONFIG_DIRECTORY64>();
     printf("/GS: %s\n", hasSecurityCookie
        ? "Yes" : "No");
    }
    
    int __cdecl main(int argc, char**argv)
    {
     MappedImage mappedImage;
     if (mappedImage.MapImage(argv[1])) {
      mappedImage.ProcessResults();
     }
     return 0;
    }
    

    Let's see what happened.

    First we use the Map­Image method to load the binary and map it into memory. While we're at it, we sniff at the headers to determine whether it is a 32-bit or 64-bit binary.

    The Get­Characteristics method merely extracts the Characteristics from the File­Header. This is easy because the File­Header is the same for 32-bit and 64-bit binaries.

    The Get­Dll­Characteristics method has two versions depending on the image bitness. In both cases, it extracts the Dll­Characteristics field, but the location of the field depends on the structure.

    The Has­Security­Cookie method also has two versions depending on the image bitness. The minimum size necessary to get OS-assisted stack overflow protection is the size that encompasses the Security­Cookie member, and in order to get that extra protection, the member needs to be nonzero.

    What is OS-assisted stack overflow protection?

    First, I'm going to assume that you've read Compiler Security Checks In Depth.

    Okay, welcome back.

    In theory, /GS could be implemented entirely in application code, with no need for operating system assistance. And in fact, that's what happens when the executable is run on older versions of Windows (like Windows 98 or Windows 2000). But the module can tell the operating system, "Hey, here is where I put my security cookie," and if the operating system understands this field, then it will go in and make the security cookie even more randomer than random by mixing in some cryptographically secure random bits.

    Okay, so that's the program. Note that some of these flags are meaningless in DLLs, so be careful to interpret the output correctly.

  • The Old New Thing

    MapGenericMask is just a convenience function for converting generic access to specific access, according to the instructions you provide

    • 5 Comments

    For some reason, people call the Map­Generic­Mask function in order to calculate what access mask to pass to request access to something. That's not what Map­Generic­Mask is for. The Map­Generic­Mask function is to assist the server side of the access, not the client side.

    As the documentation says, the Map­Generic­Mask function maps the generic access rights in an access mask to specific and standard access rights. The function applies a mapping supplied in a GENERIC_MAPPING structure.

    This is further explained in the remarks:

    After calling the Map­Generic­Mask function, the access mask pointed to by the Access­Mask parameter has none of its generic bits (GenericRead, GenericWrite, GenericExecute, or GenericAll) or undefined bits¹ set, although it can have other bits set. If bits other than the generic bits are provided on input, this function does not clear them.

    What this function does is take the Access­Mask parameter and convert all of the GENERIC_* bits into object-specific bits, as defined by the GENERIC_MAPPING.

    In other words, the code for the Map­Generic­Mask function looks basically like this:

    void MapGenericMask(
      PDWORD AccessMask,
      PGENERIC_MAPPING GenericMapping
    )
    {
     if (*AccessMask & GENERIC_READ)
         *AccessMask |= GenericMapping->GenericRead;
    
     if (*AccessMask & GENERIC_WRITE)
         *AccessMask |= GenericMapping->GenericWrite;
    
     if (*AccessMask & GENERIC_EXECUTE)
         *AccessMask |= GenericMapping->GenericExecute;
    
     if (*AccessMask & GENERIC_ALL)
         *AccessMask |= GenericMapping->GenericAll;
    
     *AccessMask &= ~(GENERIC_READ | GENERIC_WRITE |
                      GENERIC_WRITE | GENERIC_ALL);
    }
    

    The function takes the access mask and sees if any of the generic access bits are set. If so, then it replaces them with the corresponding specific access bits provided by the Generic­Mapping parameter.

    Note that this function doesn't tell you anything you don't already know. It's just a helper function to make access checks easier to implement: If you are a component that manages an object and you need to perform an access check, you use Map­Generic­Access to convert all the generic access requests into specific requests according to the rules you specified in your GENERIC_MAPPING, and the rest of your code only needs to deal with specific requests.

    For example, we saw some time ago that a hypothetical Gizmo object could map GENERIC_READ to operations that query information from a Gizmo without modifying it, map GENERIC_WRITE to operations that alter the gizmo properties, map GENERIC_EXECUTE to operations that enable or disable the Gizmo, and map GENERIC_ALL to include all Gizmo operations.

    And if you needed to do a security check on a Gizmo, you would do something like this:

    BOOL IsGizmoAccessGranted(
     HTOKEN Token,
     PSECURITY_DESCRIPTOR SecurityDescriptor,
     DWORD AccessDesired,
     PDWORD AccessAllowed)
    {
     MapGenericMask(&AccessDesired, &GizmoGenericMapping);
    
     BOOL AccessGranted = FALSE;
     PRIVILEGE_SET PrivilegeSet;
     DWORD PrivilegeSetSize = sizeof(PrivilegeSet);
    
     return AccessCheck(SecurityDescriptor,
                Token,
                AccessDesired,
                &GizmoGenericMapping,
                &PrivilegeSet,
                &PrivilegeSetSize,
                AccessAllowed,
                &AccessGranted) && AccessGranted;
    }
    

    When somebody wants to access a Gizmo, you use Map­Generic­Mask to convert all the generic requests to specific requests. You then pass that request to Access­Check, along with token for the user making the request and the security descriptor for the widget. The Access­Check function does the heavy lifting of seeing which ACEs apply to the user specified by the token, then verifying that all the requested accesses have an Allow ACE, and that none of the requested accesses have a Deny ACE. It also takes care of the MAXIMMUM_ALLOWED access request by simply returning all the accesses that are allowed and not denied.

    The point of the Map­Generic­Mask function is to make life a little easier for the code that enforces security.

    On the other hand, the Map­Generic­Mask function is not particularly useful on the side that is requesting access. If you are requesting generic read access, just pass GENERIC_READ. The code that does the security check will convert the GENERIC_READ into the access masks that are specific to the object you are trying to access. (And it will most likely use the Map­Generic­Mask function to do it.)

    ¹ That extra phrase "or undefined bits" is contradicted by the subsequent sentence "If bits other than the generic bits are provided on input, the function does not clear them." The second sentence is correct; the extra phrase "or undefined bits" is incorrect and should be removed.

  • The Old New Thing

    Low-level hooks have thread affinity, so make sure you keep an eye on the thread

    • 4 Comments

    A customer was having a problem with their automated testing tool.

    We have an automation testing tool that, among other things, installs a low-level mouse hook. Sometimes, the hook takes too long to process an action, and it gets unhooked. We have a watchdog thread that tries to detect when this has happened, and in response, it kicks off a task on the thread pool to re-register the low-level hook. The call to register the low-level hook succeeds, but the hook apparently didn't get installed correctly because it never fires. What are we doing wrong?

    Recall that low-level hooks have thread affinity. This is spelled out in the documentation.

    This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

    So there are two mistakes here.

    First, the hook is installed from a thread pool task, which means that the hook is associated with the thread pool thread. One of the characteristics of the thread pool is that threads come and go based on demand. If there is no thread pool activity for a while, the thread pool will probably start trimming threads, and it it decides to get rid of the thread that installed the hook, and the hook disappears with it.

    The second mistake is that the hook is installed from a thread pool task. Sure, the hook registers successfully, but then when you return back to the thread pool, there's no guarantee that anybody on that thread is going to pump messages any time soon.

    Indeed, odds are that it won't.

    Tasks queued up on the thread pool tend not to be UI tasks, because, well, they're on the thread pool, not the UI thread. Therefore, there is no expectation that they will pump messages. Furthermore, if the thread goes idle, the thread pool is probably not going to pump messages; it's just going to put the thread to sleep until the next task is queued up.

    The customer thanked us for the explanation. I'm not sure what they are going to do about it, but I hope they're going to solve their problem not by patching up their watchdog thread but rather by fixing their low-level mouse hook so it doesn't exceeed the low-level hook timeout. For example, they could have the low-level hook post its events to another thread, then return immediately. That other thread can then do the expensive processing asynchronously. (This assumes that they are using the low-level hook only for monitoring the mouse rather than trying to intercept and block it.)

  • The Old New Thing

    Why don't you forward WM_GETMINMAXINFO and clamp the results?

    • 4 Comments

    In my illustration of how to make a window resizable in only one direction, commenter Josua asks, "Why don't you forward WM_GET­MIN­MAX­INFO and clamp the results?"

    I'm going to assume the question is really "Why don't you forward WM_GET­MIN­MAX­INFO before clamping the results?" rather than "Why did you bother writing all this code in the first place? Why not simply forward WM_GET­MIN­MAX­INFO and clamp the results?"¹

    The answer is that forwarding WM_GET­MIN­MAX­INFO doesn't do anything. As noted in the documentation, the incoming MIN­MAX­INFO structure already has the default values on entry. The default handler for the WM_GET­MIN­MAX­INFO message returns without doing anything, since all the default handler does is accept the defaults.

    So sure, you could forward the message, and then clamp the results, but the forwarding doesn't accomplish anything.

    ¹ In case the question really was "Why did you bother writing all this code in the first place...": Go ahead and delete all the changes aside from the initial version of the On­Get­Min­Max­Info handler. You'll see the problems called out in the text: The resize arrows appear when the mouse hovers over the corners and the left and right edges. And if you maximize the window onto a secondary monitor, and that monitor's height is different from the height of the primary monitor, it maximizes to the wrong height.

  • The Old New Thing

    How does Task Manager compute Up Time, and why doesn't it agree with GetTickCount?

    • 25 Comments

    Task Manager shows a piece of information called "Up time". How is this value calculated, and why doesn't it agree with the value reported by Get­Tick­Count/Get­Tick­Count64?

    Task Manager calculates "up time" by subtracting the system boot time from the current time. In other words, it is misnamed; it really should be called time since system was started. It doesn't subtract out the time when the computer was in sleep or hibernation.

    The tick count, on the other hand, counts only time that elapses while the computer is on.

  • The Old New Thing

    Can I run a service executable from a network location?

    • 10 Comments

    A customer liaison wanted to know whether it is possible to run a service executable from a network location. The customer was doing so and running into problems, and they wanted to know whether it is a legal scenario.

    Running a service from a network location is a bad idea. If the computer lose network connectivity momentarily, the service may die with STATUS_IN_PAGE_ERROR. (You can try to mitigiate this with /SWAPRUN:NET.) Plus there is a security issue here, because your computer is now trusting code that is coming from another computer. If somebody attacks your network and masquerades as the other computer, they can inject code into your computer with system privileges. If that other computer becomes compromised, then the attacker can inject code onto any computer that is running a service from the compromised computer.

    But even though it's a bad idea, it is nevertheless technically legal, in the same way that it is technically legal to use strcpy or to park your car and leave the windows open and the key on the front seat.

    But if you run into problems, all everybody is going to tell you is, "Don't do that."

    (The MSDN documentation advises against putting the service executable on another computer, which is already a step up from the traditional MSDN approach of merely providing facts and leaving you to develop your own guidance. But it can't bring itself to say that doing so is a bad idea; it merely says that "It is best to use a local file.")

  • The Old New Thing

    Documentation creates contract, which is why you need to be very careful what you document

    • 40 Comments

    A person with a rude name asks, "Why does MS not document the system metrics used by classic/pre-uxtheme windows and common controls? This image is really useful and I wish all of this was actually documented."

    Actually, that picture explains why it isn't documented.

    Suppose such a picture existed in the Windows 2000 documentation. I don't know what it would say exactly, so suppose, for the purpose of discussion, that it said that the caption buttons are exactly SM_CX­FRAME pixels from the right-hand edge of the window, and that the buttons are exactly SM_CX­SIZE pixels wide, with exactly SM_CX­EDGE pixels of padding between the buttons, and the buttons are exactly SM_CY­SIZE pixels tall, with SM_CY­EDGE pixels between the top of the button and the top of the window.

    Once that picture existed in the documentation, the picture you linked to could never exist.

    The picture from Windows 2000 doesn't include the SM_CX­PADDED­BORDER or the the SM_CY­PADDED­BORDER. It can't, because those metrics didn't exist in Windows 2000. Since the diagram is part of the documentation, it is contractual, and it would not be possible to alter the layout of the window caption (say, by incorporating a new metric like SM_CX­PADDED­BORDER), because that would break existing code.

    For example, a program may have looked at the diagram and concluded, "Okay, so if I want to programmatically click the Close button, I can go to the upper right corner of the window, move down SM_CY­FRAME + 1 pixels, move left move down SM_CX­FRAME + 1 pixels, and click there, and it will hit the button."

    And then Windows Vista shows up, adds some SM_CX­PADDED­BORDER between the Close button and the right edge, and the program stops working.

    Publishing the redlines would force the visual layout to be locked in stone. Windows 95 could not have added the Close button. Windows Vista could not have added extra padding around the buttons.

    Note that changing the visual layout of the caption does not break programs which draw their own caption bar. They will continue to draw the caption bar their own custom way. If they tried to mimic the Windows 2000 caption bar, then they will continue to mimic the Windows 2000 caption bar, even on Windows Vista. But nobody gets hurt, because the application is doing both the drawing and the hit-testing, so it remains in sync with itself.

Page 4 of 453 (4,523 items) «23456»