Other

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Account vulnerable to Active Directory administrator

    • 45 Comments

    A security vulnerability report came in that went something like this:

    Disclosure of arbitrary data from any user

    An attacker can obtain arbitrary data from any user by means of the following steps:

    1. Obtain administrative access on the domain controller.
    2. Stop the XYZZY service.
    3. Edit the XYZZY.DAT file in a hex editor and changes the bytes starting at offset 0x4242 as follows:
    4. ...

    There's no point continuing, because the first step assumes that you are on the other side of the airtight hatchway. If you have compromised the domain controller, then you control the domain. From there, all the remaining steps are just piling on style points and cranking up the degree of difficulty.

    A much less roundabout attack is as follows:

    1. Obtain administrative access on the domain controller.
    2. Deploy a logon script to all users that does whatever you want.
    3. Wait for the user to log in next, and your script will DO ANYTHING YOU WANT.

    No, wait, I can make it even easier.

    1. Obtain administrative access on the domain controller.
    2. Change the victim's password.
    3. Log on as that user and DO ANYTHING YOU WANT.

    You are the domain administrator. You already pwn the domain. That you can pwn a domain that you pwn is really not much of a surprise.

    This is why it is important to choose your domain administrators carefully.

  • The Old New Thing

    The psychology of confirmation, or something, I don't know what to call it

    • 46 Comments

    There is probably a name for this phenomenon. I will illustrate it below.

    "Is there a way to configure the system to do X?"

    Go to the Y dialog and select Z.

    "It doesn't work."

    I just tried it. It works for me. I'm using ⟨configuration details⟩.

    "Thanks. It's working."

  • The Old New Thing

    Microspeak: Redlines

    • 30 Comments

    To the outside world, redline can mean to mark something for removal, or it could mean the maximum safe speed of an engine. But in the world of Microsoft design, the term redlines (pronounced as if it were written as the two words red lines, but the accent is on the red) refers to a diagram showing the exact position of visual elements. They typically take the form of a proposed screen shot, with arrows and lines superimposed to indicate the distances between items, which items align with each other, and so on. They also contain indications as to the exact colors to use for different elements.

    Originally the lines and arrows were actually red, hence the name. Here's an example of something that gives you the idea:

    These aren't real redlines because the diagram doesn't contain any indications about the colors to use, and more complete redlines would include diagrams showing the hover, pressed, and disabled states.

  • The Old New Thing

    How to view the stack of a user-mode thread when its kernel stack has been paged out

    • 4 Comments

    Suppose you have a machine that has crashed, and your investigation shows that the reason is that there is a critical section that everybody is waiting for. While waiting for that critical section, work piles up, and eventually the machine keels over. Suppose further that this crash is given to you in the form of a kernel debugger.

    In case it wasn't obvious, by "you" I mean "me".

    Okay, so the critical section that is the cause of the logjam is this one:

    1: kd> !cs CONTOSO!g_csDataLock
    -----------------------------------------
    Critical section   = 0x00007ff7f0ed2f68 (CONTOSO!g_csDataLock+0x0)
    DebugInfo          = 0x0000000022f2efd0
    LOCKED
    LockCount          = 0x5D
    WaiterWoken        = No
    OwningThread       = 0x0000000000004228
    RecursionCount     = 0x1
    LockSemaphore      = 0x17A0
    SpinCount          = 0x00000000020007cb
    

    "Great," you say. "I just need to look at thread 0x4228 to see why it is stuck.

    1: kd> !process -1 4
    PROCESS ffffe000047ae900
        SessionId: 1  Cid: 0604    Peb: 7ff74ecfa000  ParentCid: 05cc
        DirBase: 0eb07000  ObjectTable: ffffc000014c5680  HandleCount: 7003.
        Image: contoso.exe
    
            ...
            THREAD ffffe0000c136080  Cid 0604.4228  Teb: 00007ff74e94c000 Win32Thread: fffff90144edea60 WAIT
            ...
    

    Woo-hoo, there's the thread. Now I just need to switch to its context to see what it is stuck on.

    1: kd> .thread ffffe0000c136080
    Can't retrieve thread context, Win32 error 0n30
    

    Okay, that didn't work out too well. Now what?

    Even though the kernel stack is paged out, the user-mode stack may still be available.

    1: kd> !thread ffffe0000c136080
    THREAD ffffe0000c136080  Cid 0604.4228  Teb: 00007ff74e94c000
           Win32Thread: fffff90144edea60 WAIT: (UserRequest) UserMode Non-Alertable
        ffffe000077a7830  NotificationEvent
    Not impersonating
    DeviceMap                 ffffc00000e89c80
    Owning Process            ffffe000047ae900       Image:         contoso.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      12735890       Ticks: 328715 (0:01:25:36.171)
    Context Switch Count      75             IdealProcessor: 2
    UserTime                  00:00:00.000
    KernelTime                00:00:00.031
    Kernel stack not resident.
    

    The limits of the user-mode stack are kept in the Teb.

    2: kd> !teb 00007ff74e94c000
    TEB at 00007ff74e94c000
        ExceptionList:        0000000000000000
        StackBase:            00000001027d0000
        StackLimit:           00000001027c2000
        SubSystemTib:         0000000000000000
        FiberData:            0000000000001e00
        ArbitraryUserPointer: 0000000000000000
        Self:                 00007ff74e94c000
        EnvironmentPointer:   0000000000000000
        ClientId:             0000000000000604 . 0000000000004228
        RpcHandle:            0000000000000000
        Tls Storage:          000000010132dfc0
        PEB Address:          00007ff74ecfa000
        LastErrorValue:       1008
        LastStatusValue:      c0000034
        Count Owned Locks:    2
        HardErrorMode:        0
    

    We now use the trick we learned some time ago where we grovel the stack of a thread without knowing where its stack pointer is.

    In this case, the groveling is made easier because we already know that everybody is waiting on the data lock. The data lock is taken in only two functions, so it's a matter ot looking for any occurrences of one of those two functions. And here it is: Data­Wrapper::Verify­Data.

    00000001`027cef88  00007ffe`f1bbac9a NTDLL!NtWaitForSingleObject+0xa
    00000001`027cef90  00000000`00006ac8
    00000001`027cef98  00007ffe`ef1bd085 KERNELBASE!WaitForSingleObjectEx+0xa5
    00000001`027cefa0  00000000`00006ac8
    00000001`027cefa8  00000000`00000000
    00000001`027cefb0  00000000`026d0000
    00000001`027cefb8  00000000`00000000
    00000001`027cefc0  00000001`01739ee0
    00000001`027cefc8  00000000`00000001
    00000001`027cefd0  00000000`00000048
    00000001`027cefd8  00000001`00000001
    00000001`027cefe0  00000000`00000000
    00000001`027cefe8  00000000`00000000
    00000001`027ceff0  00000000`00000000
    00000001`027ceff8  00000000`00000000
    00000001`027cf000  00000000`00000000
    00000001`027cf008  00000000`00000000
    00000001`027cf010  00000000`00000000
    00000001`027cf018  00007ff7`eefe6540 FABRIKAM!Lock::IsInitialized+0xfc
    00000001`027cf020  00000000`00000000
    00000001`027cf028  00000000`3b803fa0
    00000001`027cf030  00000000`00006ac8
    00000001`027cf038  00007ff7`eeff3c43 FABRIKAM!AccessRequest::WaitTimeout+0x87
    00000001`027cf040  00000000`ffffffff
    00000001`027cf048  10f513ec`6a161fb8
    00000001`027cf050  00000000`00000000
    00000001`027cf058  00000000`00006ac8
    00000001`027cf060  00000000`3b803fb8
    00000001`027cf068  00007ff7`eeff3cc0 FABRIKAM!AccessRequest::Wait+0x18
    00000001`027cf070  00000000`8007000e
    00000001`027cf078  00000000`fd416ff0
    00000001`027cf080  4fe80c4a`51236583
    00000001`027cf088  00000000`3b803fb8
    00000001`027cf090  00000000`ffffffff
    00000001`027cf098  00000000`00000000
    00000001`027cf0a0  00000000`3b803fa0
    00000001`027cf0a8  00007ff7`da8375b7 FABRIKAM!DataAccess::RequestAccess+0x93
    00000001`027cf0b0  00000000`3b803fa0
    00000001`027cf0b8  00000000`3b803fb8
    00000001`027cf0c0  4fe80c4a`51236583
    00000001`027cf0c8  10f513ec`6a161fb8
    00000001`027cf0d0  00000000`00000076
    00000001`027cf0d8  00007ff7`f07a8619 CONTOSO!Widget::SetColor+0x9
    00000001`027cf0e0  000095dc`90897985
    00000001`027cf0e8  00000000`00000110
    00000001`027cf0f0  00000000`00000000
    00000001`027cf0f8  00000000`00000000
    00000001`027cf100  00007ff7`4dd8000c
    00000001`027cf108  00007ff7`f07a85e5 CONTOSO!Widget::UpdateColor+0x39
    00000001`027cf110  00000000`ffc03f90
    00000001`027cf118  00000001`027cf1e8
    00000001`027cf120  00000000`ffc03fc8
    00000001`027cf128  00000000`00000000
    00000001`027cf130  00000000`00000000
    00000001`027cf138  00007ff7`4dd8000c
    00000001`027cf140  00007ff7`da5bc420 FABRIKAM!DataAccess::`vftable'+0x18
    00000001`027cf148  00000000`ffc03f90
    00000001`027cf150  00000001`027cf260
    00000001`027cf158  00007ff7`f0b3459c CONTOSO!DataWrapper::VerifyData+0x428
    00000001`027cf160  00000000`3b803fa0
    00000001`027cf168  00007ff7`f0ed1d30 CONTOSO!g_DataManager
    00000001`027cf170  00000000`fe196f10
    00000001`027cf188  00000000`00000001
    00000001`027cf190  00000000`00000000
    00000001`027cf198  00000001`027cf270
    00000001`027cf1a0  00000001`027cf480
    00000001`027cf1a8  00007ff7`00000001
    00000001`027cf1b0  00000001`027cf220 
    00000001`027cf1b8  00000000`00000000 
    00000001`027cf1c0  00000000`00000000 
    

    I left the red herrings in place just to make things a little more interesting.

    The Data­Wrapper::Verify­Data method enters the critical section and then calls Data­Access::Request­Access via a virtual method call:

    00007ff7`f0b3458f mov     dword ptr [rsp+28h],eax
    00007ff7`f0b34593 mov     eax,dword ptr [rsi+10h]
    00007ff7`f0b34596 mov     dword ptr [rsp+20h],eax
    00007ff7`f0b3459a call    qword ptr [rdi] ←
    

    Let's disassemble the start of Data­Access::Request­Access to see how it sets up its stack. This will help us interpret the other values in the stack dump.

    0: kd> u 00007ff7`da8375b7-93
    FABRIKAM!DataAccess::RequestAccess
    ;; function prologue
    00007ff7`da837524 mov     rax,rsp
    00007ff7`da837527 mov     qword ptr [rax+8],rbx
    00007ff7`da83752b mov     qword ptr [rax+20h],r9
    00007ff7`da83752f mov     qword ptr [rax+18h],r8
    00007ff7`da837533 mov     qword ptr [rax+10h],rdx
    00007ff7`da837537 push    rbp
    00007ff7`da837538 push    rsi
    00007ff7`da837539 push    rdi
    00007ff7`da83753a push    r12
    00007ff7`da83753c push    r13
    00007ff7`da83753e push    r14
    00007ff7`da837540 push    r15
    00007ff7`da837542 sub     rsp,70h
    ;; function body
    00007ff7`da837546 lea     rsi,[rcx+18h]
    00007ff7`da83754a mov     rdi,rcx
    00007ff7`da83754d mov     rbp,r9
    00007ff7`da837550 mov     rcx,rsi
    00007ff7`da837553 call    qword ptr [FABRIKAM!_imp_EnterCriticalSection]
    00007ff7`da837559 xor     r13b,r13b
    00007ff7`da83755c mov     ebx,8007000Eh
    ...
    00007ffe`da8375b1 call    FABRIKAM!AccessRequest::Wait
    

    We can replay the above code in our head and annotate the stack trace accordingly. On entry to the function, the stack pointer is 00000001`027cf158 (the return address). The function stashes some registers in the caller-provided spill area and it pushes others onto the stack, and then it subtracts some space for local variables as well as for outbound parameters of functions it intends to call.

    /-00000001`027cf0b0  00000000`3b803fa0
    | 00000001`027cf0b8  00000000`3b803fb8
    | 00000001`027cf0c0  4fe80c4a`51236583
    | 00000001`027cf0c8  10f513ec`6a161fb8
    | 00000001`027cf0d0  00000000`00000076
    | 00000001`027cf0d8  00007ff7`f07a8619 CONTOSO!Widget::SetColor+0x9
    | 00000001`027cf0e0  000095dc`90897985
    | 00000001`027cf0e8  00000000`00000110
    | 00000001`027cf0f0  00000000`00000000
    | 00000001`027cf0f8  00000000`00000000
    | 00000001`027cf100  00007ff7`4dd8000c
    | 00000001`027cf108  00007ff7`f07a85e5 CONTOSO!Widget::UpdateColor+0x39
    | 00000001`027cf110  00000000`ffc03f90
    \-00000001`027cf118  00000001`027cf1e8
      00000001`027cf120  00000000`ffc03fc8 // VerifyData's r15
      00000001`027cf128  00000000`00000000 // VerifyData's r14
      00000001`027cf130  00000000`00000000 // VerifyData's r13
      00000001`027cf138  00007ff7`4dd8000c // VerifyData's r12
      00000001`027cf140  00007ff7`da5bc420 FABRIKAM!DataAccess::`vftable'+0x18 // VerifyData's rdi
      00000001`027cf148  00000000`ffc03f90 // VerifyData's rsi
      00000001`027cf150  00000001`027cf260 // VerifyData's rbp
      00000001`027cf158  00007ff7`f0b3459c CONTOSO!DataWrapper::VerifyData+0x428 ← ESP is here
      00000001`027cf160  00000000`3b803fa0 // VerifyData's rbx
      00000001`027cf168  00007ff7`f0ed1d30 CONTOSO!g_DataManager // VerifyData's rdx
      00000001`027cf170  00000000`fe196f10 // VerifyData's r8
      00000001`027cf188  00000000`00000001 // VerifyData's r9
      00000001`027cf190  00000000`00000000
      00000001`027cf198  00000001`027cf270
      00000001`027cf1a0  00000001`027cf480
      00000001`027cf1a8  00007ff7`00000001
      00000001`027cf1b0  00000001`027cf220 
      00000001`027cf1b8  00000000`00000000 
      00000001`027cf1c0  00000000`00000000 
    

    The region marked in brackets is the 0x70 bytes of space for local variables and outbound parameters. Notice that some red herring function pointers are in that space. Those are probably variables that haven't been initialized yet, and the memory happened previously to have been used to hold some return addresses.

    A reassuring observation is that the rdx coming from Verify­Data is the address of CONTOSO!g_Data­Manager. That is the second function parameter (or first, if you aren't counting the hidden this) to Request­Access.

    Another reassuring observation is that that Verify­Data's rdi points into the vtable for Data­Access, since that matches the code we saw at the call point: call qword ptr [rdi].

    The mov rdi, rcx instruction in the function body tells us that the function stashed its this pointer in rdi. That's good info to keep track of, because that will let us look at the Data­Access object once we figure out what is in rdi.

    The next function on the stack is Access­Request::Wait.

    FABRIKAM!AccessRequest::Wait:
    00007ff7`eeff3ca8 sub     rsp,38h
    00007ffe`eeff3cb3 mov     dword ptr [rsp+20h],0FFFFFFFFh
    00007ffe`eeff3cbb call    FABRIKAM!AccessRequest::WaitTimeout
    00007ffe`eeff3cc0 add     rsp,38h
    00007ffe`eeff3cc4 ret
    

    This function doesn't bother saving any registers; it just reserves space for local variables and outbound parameters. From inspection, you can see that this is a simple wrapper that passes all its parameters onward to Wait­Timeout, with an INFINITE tacked onto the end, so this function has no local variables at all. Everything is just for outbound parameters.

    We can annotate some more entries in our stack trace.

    00000001`027cf070  00000000`8007000e // spill space for WaitTimeout
    00000001`027cf078  00000000`fd416ff0 // spill space for WaitTimeout
    00000001`027cf080  4fe80c4a`51236583 // spill space for WaitTimeout
    00000001`027cf088  00000000`3b803fb8 // spill space for WaitTimeout
    00000001`027cf090  00000000`ffffffff // INFINITE parameter
    00000001`027cf098  00000000`00000000 // unused
    00000001`027cf0a0  00000000`3b803fa0 // unused
    00000001`027cf0a8  00007ff7`da8375b7 FABRIKAM!DataAccess::RequestAccess+0x93
    

    The next function on the list is Access­Request::Wait­Timeout.

    FABRIKAM!AccessRequest::WaitTimeout:
    00007ff7`eeff3bbc mov     qword ptr [rsp+8],rbx
    00007ff7`eeff3bc1 mov     qword ptr [rsp+10h],rbp
    00007ff7`eeff3bc6 push    rsi
    00007ff7`eeff3bc7 sub     rsp,20h
    00007ff7`eeff3bcb mov     ebx,edx
    00007ff7`eeff3bcd mov     rsi,rcx
    00007ff7`eeff3bd0 mov     edx,0Bh
    00007ff7`eeff3bd5 mov     rcx,r8
    

    This function stashes two registers in the parameter spill space, pushes one onto the stack, and reserves another 0x20 bytes for local use (outbound parameters).

    00000001`027cf040  00000000`ffffffff // spill space for WaitForSingleObjectEx
    00000001`027cf048  10f513ec`6a161fb8 // spill space for WaitForSingleObjectEx
    00000001`027cf050  00000000`00000000 // spill space for WaitForSingleObjectEx
    00000001`027cf058  00000000`00006ac8 // spill space for WaitForSingleObjectEx
    00000001`027cf060  00000000`3b803fb8 // Wait's rsi
    00000001`027cf068  00007ff7`eeff3cc0 FABRIKAM!AccessRequest::Wait+0x18
    00000001`027cf070  00000000`8007000e // Wait's rbx
    00000001`027cf078  00000000`fd416ff0
    00000001`027cf080  4fe80c4a`51236583
    00000001`027cf088  00000000`3b803fb8
    

    Notice that the stashed rbx value is 8007000E, which conveniently lines up with the mov ebx,8007000Eh instruction in Data­Access::Request­Access. That's a bit reassuring, since it's another sign that we're on the right track.

    Next up is Wait­For­Single­Object­Ex.

    0: kd> u 00007ffe`ef1bd085 -a5
    KERNELBASE!WaitForSingleObjectEx
    00007ffe`ef1bcfe0 mov     r11,rsp
    00007ffe`ef1bcfe3 mov     qword ptr [r11+8],rbx
    00007ffe`ef1bcfe7 mov     dword ptr [r11+18h],r8d
    00007ffe`ef1bcfeb push    rsi
    00007ffe`ef1bcfec push    rdi
    00007ffe`ef1bcfed push    r14
    00007ffe`ef1bcfef sub     rsp,80h
    00007ffe`ef1bcff6 mov     ebx,r8d
    

    Incorporating this prologue into our stack annotation yields

    /-00000001`027cefa0  00000000`00006ac8 // spill space for NtWaitForSingleObject
    | 00000001`027cefa8  00000000`00000000 // spill space for NtWaitForSingleObject
    | 00000001`027cefb0  00000000`026d0000 // spill space for NtWaitForSingleObject
    | 00000001`027cefb8  00000000`00000000 // spill space for NtWaitForSingleObject
    | 00000001`027cefc0  00000001`01739ee0
    | 00000001`027cefc8  00000000`00000001
    | 00000001`027cefd0  00000000`00000048
    | 00000001`027cefd8  00000001`00000001
    | 00000001`027cefe0  00000000`00000000
    | 00000001`027cefe8  00000000`00000000
    | 00000001`027ceff0  00000000`00000000
    | 00000001`027ceff8  00000000`00000000
    | 00000001`027cf000  00000000`00000000
    | 00000001`027cf008  00000000`00000000
    | 00000001`027cf010  00000000`00000000
    \-00000001`027cf018  00007ff7`eefe6540 FABRIKAM!Lock::IsInitialized+0xfc
      00000001`027cf020  00000000`00000000 // WaitTimeout's r14
      00000001`027cf028  00000000`3b803fa0 // WaitTimeout's rdi
      00000001`027cf030  00000000`00006ac8 // WaitTimeout's rsi
      00000001`027cf038  00007ff7`eeff3c43 FABRIKAM!AccessRequest::WaitTimeout+0x87
      00000001`027cf040  00000000`ffffffff // WaitTimeout's rbx
      00000001`027cf048  10f513ec`6a161fb8
      00000001`027cf050  00000000`00000000 // WaitTimeout's r8
      00000001`027cf058  00000000`00006ac8
    

    Ooh, another red herring function pointer got caught in the local variables.

    Putting everything together results in the following annotated stack, with red herrings removed.

    00000001`027cef88  00007ffe`f1bbac9a NTDLL!NtWaitForSingleObject+0xa
    00000001`027cef90  00000000`00006ac8
    00000001`027cef98  00007ffe`ef1bd085 KERNELBASE!WaitForSingleObjectEx+0xa5
    00000001`027cefa0  00000000`00006ac8
    00000001`027cefa8  00000000`00000000
    00000001`027cefb0  00000000`026d0000
    00000001`027cefb8  00000000`00000000
    00000001`027cefc0  00000001`01739ee0
    00000001`027cefc8  00000000`00000001
    00000001`027cefd0  00000000`00000048
    00000001`027cefd8  00000001`00000001
    00000001`027cefe0  00000000`00000000
    00000001`027cefe8  00000000`00000000
    00000001`027ceff0  00000000`00000000
    00000001`027ceff8  00000000`00000000
    00000001`027cf000  00000000`00000000
    00000001`027cf008  00000000`00000000
    00000001`027cf010  00000000`00000000
    00000001`027cf018  00007ff7`eefe6540
    00000001`027cf020  00000000`00000000 // WaitTimeout's r14
    00000001`027cf028  00000000`3b803fa0 // WaitTimeout's rdi
    00000001`027cf030  00000000`00006ac8 // WaitTimeout's rsi
    00000001`027cf038  00007ff7`eeff3c43 FABRIKAM!AccessRequest::WaitTimeout+0x87
    00000001`027cf040  00000000`ffffffff // WaitTimeout's rbx
    00000001`027cf048  10f513ec`6a161fb8
    00000001`027cf050  00000000`00000000 // WaitTimeout's r8
    00000001`027cf058  00000000`00006ac8
    00000001`027cf060  00000000`3b803fb8 // Wait's rsi
    00000001`027cf068  00007ff7`eeff3cc0 FABRIKAM!AccessRequest::Wait+0x18
    00000001`027cf070  00000000`8007000e // Wait's rbx
    00000001`027cf078  00000000`fd416ff0
    00000001`027cf080  4fe80c4a`51236583
    00000001`027cf088  00000000`3b803fb8
    00000001`027cf090  00000000`ffffffff // INFINITE parameter
    00000001`027cf098  00000000`00000000
    00000001`027cf0a0  00000000`3b803fa0
    00000001`027cf0a8  00007ff7`da8375b7 FABRIKAM!DataAccess::RequestAccess+0x93
    00000001`027cf0b0  00000000`3b803fa0
    00000001`027cf0b8  00000000`3b803fb8
    00000001`027cf0c0  4fe80c4a`51236583
    00000001`027cf0c8  10f513ec`6a161fb8
    00000001`027cf0d0  00000000`00000076
    00000001`027cf0d8  00007ff7`f07a8619
    00000001`027cf0e0  000095dc`90897985
    00000001`027cf0e8  00000000`00000110
    00000001`027cf0f0  00000000`00000000
    00000001`027cf0f8  00000000`00000000
    00000001`027cf100  00007ff7`4dd8000c
    00000001`027cf108  00007ff7`f07a85e5
    00000001`027cf110  00000000`ffc03f90
    00000001`027cf118  00000001`027cf1e8
    00000001`027cf120  00000000`ffc03fc8 // VerifyData's r15
    00000001`027cf128  00000000`00000000 // VerifyData's r14
    00000001`027cf130  00000000`00000000 // VerifyData's r13
    00000001`027cf138  00007ff7`4dd8000c // VerifyData's r12
    00000001`027cf140  00007ff7`da5bc420 FABRIKAM!DataAccess::`vftable'+0x18 // VerifyData's rdi
    00000001`027cf148  00000000`ffc03f90 // VerifyData's rsi
    00000001`027cf150  00000001`027cf260 // VerifyData's rbp
    00000001`027cf158  00007ff7`f0b3459c CONTOSO!DataWrapper::VerifyData+0x428
    00000001`027cf160  00000000`3b803fa0 // VerifyData's rbx
    00000001`027cf168  00007ff7`f0ed1d30 CONTOSO!g_DataManager // VerifyData's rdx
    00000001`027cf170  00000000`fe196f10 // VerifyData's r8
    00000001`027cf188  00000000`00000001 // VerifyData's r9
    00000001`027cf190  00000000`00000000
    00000001`027cf198  00000001`027cf270
    00000001`027cf1a0  00000001`027cf480
    00000001`027cf1a8  00007ff7`00000001
    00000001`027cf1b0  00000001`027cf220 
    00000001`027cf1b8  00000000`00000000 
    00000001`027cf1c0  00000000`00000000 
    

    From this, we can also suck out the this pointer passed to Data­Access::Request­Access. We saw that it was stashed in rdi. The Wait function doesn't use rdi (because if it did, it would have saved the old value), so its rdi is the same as Request­Access's rdi. Similarly, the Wait­Timeout function does not use rdi. Therefore, when Wait­For­Single­Object saves the rdi register, it is saving the value from Data­Access::Request­Access.

    00000001`027cf028  00000000`3b803fa0 // WaitTimeout DataAccess's rdi
    

    And that is the this pointer that lets us study the Data­Access object to figure out why its access request is not completing.

  • The Old New Thing

    Microspeak: Line of sight

    • 15 Comments

    I first encountered this term in a meeting I attended.

    Q: We would like to be able to reverse the polarity of the neutron flow without requiring a reboot.

    A: Yes, that is something we've been thinking about, but we don't have line of sight to having that feature before the end of the month.

    From context, having line of sight to a result means something like "Have made it part of our immediate plans to achieve that result."

    This appears to be extending the idiom on the horizon. Literally, something on the horizon. is at the edge of what can be seen. Figuratively, then, something that is on the horizon is at the edge of what can be predicted. And if something can be seen, then you have line of sight to it.

    There is another aspect of line of sight: The view to the object must be unobstructed. Taking the analogy further, then, having line of sight to a result means that there is a plan for achieving that result that is not dependent on work from another team.

    Note that I don't know if the "unobstructed" part of the analogy was intended by the speaker. All I have to work from is that one snippet of conversation.

    In an attempt to obtain better insight into the phrase line of sight, I searched the intranet, and the hits fell into a few categories.

    One category was people using the term literally, usually in the context of wireless communications.

    Another category appeared to use the phrase as a synonym for "insight obtained from information":

    Monthly tear sheets are improving line of sight.
    Teams were empowered to reallocate expenses within discretionary line items, but there was a lack of transparency into these changes. Forecasting was a challenge because we did not have line of sight into these reallocation decisions. We will address this by developing a pivot tool that provides management a consolidated line of sight into spend by resource.

    Note also the business jargony use of spend as a noun, meaning expenditure.

    The third category appears to be what I heard in that meeting, where it means something like "a path to a result":

    XYZ was impacted by ABC and DEF. We have line of sight to get back on track.

    And then I think I hit the jackpot: Somebody defined the term, sort of.

    Line of sight to ending year $XX under budget

    XYZ is at 99% pass, with line of sight to ending the year at 100% pass. ABC is $YY under budget, and is on track to end the year at $XX under budget.

    The value $XX was repeated both in the heading and in the body, which let me match the two statements. And one of the statements uses the phrase line of sight, whereas the other uses the more conventional phrase on track.

    I therefore conclude that the two are roughly synonyms. Line of sight to X means on track to X.

    Though this means that one of the citations above translates to "We are on track to get back on track," which sounds kind of eerily meta.

    The preferred emphatic form of line of sight appears to be clear line of sight.

  • The Old New Thing

    Why does misdetected Unicode text tend to show up as Chinese characters?

    • 34 Comments

    If you take an ASCII string and cast it to Unicode,¹ the results are usually nonsense Chinese. Why does ASCII→Unicode mojibake result in Chinese? Why not Hebrew or French?

    The Latin alphabet in ASCII lives in the range 0x41 through 0x7A. If this gets misinterpreted as UTF-16LE, the resulting characters are of the form U+XXYY where XX and YY are in the range 0x41 through 0x7A. Generously speaking, this means that the results are in the range U+4141 through U+7A7A. This overlaps the following Unicode character ranges:

    • CJK Unified Ideographs Extension A (U+3400 through U+4DBF)
    • Yijing Hexagram Symbols (U+4DC0 through U+4DFF)
    • CJK Unified Ideographs (U+4E00 through U+9FFF)

    But you never see the Yijing hexagram symbols because that would require YY to be in the range 0xC0 through 0xFF, which is not valid ASCII. That leaves only CJK Unified Ideographs of one sort of another.

    That's why ASCII misinterpreted as Unicode tends to result in nonsense Chinese.

    The CJK Unified Ideographs are by far the largest single block of Unicode characters in the BMP, so just by purely probabilistic arguments, a random character in BMP is most likely to be Chinese. If you look at a graphic representation of what languages occupy what parts of the BMP, you'll see that it's a sea of pink (CJK) and red (East Asian), occasionally punctuated by other scripts.

    It just so happens that the placement of the CJK ideographs in the BMP effectively guarantees it.

    Now, ASCII text is not all just Latin letters. There are space and punctuation marks, too, so you may see an occasional character from another Unicode range. But most of the time, it's a Latin letter, which means that most of the time, your mojibake results in Chinese.

    ¹ Remember, in the context of Windows, "Unicode" is generally taken to be shorthand for UTF-16LE.

  • The Old New Thing

    The grand ambition of giving your project the code name Highlander

    • 24 Comments

    Code name reuse is common at Microsoft, and there have been several projects at code-named Highlander, the movie with the tag line There can be only one. (Which makes the whole thing kind of ironic.)

    I was able to find a few of these projects. There are probably more that I couldn't find any records of.

    Two of the projects I found did not appear to be named Highlander for any reason beyond the fact that the person who chose the name was a fan of the movie.

    Another project code named Highlander was an internal IT effort to simplify the way it did something really full of acronyms that I don't understand. ("Reduce the architectural footprint of the XYZZY QX Extranet.") There used to be something like five different systems for doing this thing (whatever it is), and they wanted to consolidate them down to one.

    The project code named Highlander that people outside Microsoft will recognize is the one now known as Microsoft Account, but which started out as Passport.¹ Its goal was to provide single sign-on capability, so that you need to remember "only one" password.

    The last example is kind of complicated. There was a conflict between two teams. Team A was responsible for a client/server product and developed both the server back-end software as well as the client. Meanwhile, Team 1 wrote an alternative client with what they believed was a more user-friendly interface. A battle ensued between the two teams to write the better client, and management decided to go with Team 1's version.

    But Team A did not go down without a fight. Rather than putting their project to rest, Team A doubled down and tried to make an even more awesome client, which they code-named Highlander. The idea was that their project was engaged in an epic battle with Team 1, and the tag line There can be only one reflected their belief that the battle was to the death, and that their project would emerge victorious. This being back in the day when playing music on your Web page was cool, they even set up their internal Web site so that it played the Highlander theme music when you visited.

    They were correct in that there was ultimately only one.

    The bad news for them was that Team 1 was the winner of the second battle as well.

    To me, the moral of the story is to keep your project code name humble.

    Reminder: The ground rules for this site prohibits trying to guess the identity of a program whose name I intentionally did not reveal.

    ¹ The Wikipedia entry for Microsoft Account erroneously claims that the project was once known as Microsoft Wallet. That claim isn't even supported by the Web site they cite as a reference. The Web site says, "Microsoft Wallet has been updated to use Microsoft Passport technology." In other words, "Wallet now uses Passport for authentication." This is like seeing the sentence "Microsoft Active Directory uses Kerberos for authentication" and concluding "Kerberos was once named Microsoft Active Directory."

  • The Old New Thing

    Poor man's comments: Inserting text that has no effect into a configuration file

    • 34 Comments

    Consider a program which has a configuration file, but the configuration file format does not have provisions for comments. Maybe the program has a "list of authorized users", where each line takes the form allow x or deny x, where x is a group or user. For example, suppose we have access_list that goes like this:

    allow payroll_department
    deny alice
    allow personnel_department
    allow bob
    

    This is the sort of file that can really use comments because people are going to want to know things like "Why does Bob have access?"

    One way of doing this is to embed the comments in the configuration file in a way that has no net effect. You can do this to add separator lines, too.

    deny !____________________________________________________________
    allow payroll_department
    deny !alice_is_an_intern_and_does_not_need_access_to_this_database
    deny alice
    deny !____________________________________________________________
    allow personnel_department
    deny !____________________________________________________________
    deny !temporary_access_for_auditor
    deny !see_service_request_31415
    deny !access_expires_on_2001_12_31
    allow bob
    

    Assuming that you don't have any users whose names begin with an exclamation point, the extra deny !... lines have no effect: They tell the system to deny access to a nonexistent user.

    Sometimes finding the format of a line that has no effect can take some creativity. For example, if you have a firewall configuration file, you might use URLs that correspond to no valid site.

    allow nobody http://example.com/PAYROLL_DEPARTMENT/--------------------
    allow alice http://contoso.com/payroll/
    allow nobody http://example.com/PURCHASING_DEPARTMENT/-----------------
    allow bob http://contoso.com/purchasing/
    allow nobody http://example.com/SPECIAL_REQUEST/-----------------------
    allow ceo http://www.youtube.com/
    

    Of course, these extra lines create work for the program, since it will sit there evaluating rules that will never apply. You may have to craft them in a way so that they have minimum cost. In the example above, we assigned the comments to a user called nobody which presumably will never try to access the Internet. We definitely didn't want to write the comment like

    allow * http://example.com/PAYROLL_DEPARTMENT/-------------------------
    

    because that would evaluate the dummy rule for every user.

    If you are willing to add a layer of process, you can tell everybody to stop editing the configuration files directly and instead edit an alternate file that gets preprocessed into a configuration file. For example, we might have access_list.commented that goes

    //////////////////////////////////////////////////////////////////
    allow payroll_deparment
    
    deny alice // payroll intern does not need access to this database.
    
    //////////////////////////////////////////////////////////////////
    allow personnel_department
    
    //////////////////////////////////////////////////////////////////
    allow bob // Temporary access for auditor, see SR 31415. Expires 2001/12/31.
    

    Everybody agrees to edit the access_list.commented file, and after each edit they run a script that sends the file through the C++ preprocessor and puts the result in the access_list file. By using the C++ preprocessor, you enable features like #include directives and #define macros.

  • The Old New Thing

    A lie repeated often enough becomes the truth: The continuing saga of the Windows 3.1 blue screen of death (which, by the way, was never called that)

    • 36 Comments

    HN has been the only major site to report the history of the Windows 3.1 Ctrl+Alt+Del dialog correctly. But it may have lost that title due to this comment thread.

    I read here that Steve Ballmer wrote part of [the blue screen of death] too.

    The comment linked to one of may articles that erroneously reported that Steve wrote the blue screen of death.

    Somebody replied,

    Seriously?

    linking back to my article where I set the record straight.

    Undeterred, the original commenter wrote,

    LOL! so far only MSDN has been refuting the claim.

    and linked to two technology sites which reported the story incorrectly.

    Just goes to show that a lie repeated often enough becomes the truth.

    Oh, and by the way, the phrase "blue screen of death" did not really apply to the blue screen messages in Windows 3.1 or Windows 95. As we saw earlier, the Windows 3.1 fatal error message was a black screen of death, and in Windows 95, the blue screen message was more a screen of profound injury rather than death. (Windows 95 was sort of like the Black Knight, trying very hard to continue the fight despite having lost all of its limbs.)

    The phrase "blue screen of death" was generally attributed to the blue screen fatal error message of Windows NT. In Windows 95, we just called them "blue screen messages", without the "of death".

    I didn't expect this to become "blue screen week", though that's sort of what it turned into.

  • The Old New Thing

    It's a trap! Employment documents that require you to violate company policy

    • 20 Comments

    One of my colleagues had a previous job involving tuning spam filters and removing objectionable content. Before he could start, he was told that he had to sign a special release. The form said basically, "I understand that my job may require me to see pornography or other objectionable material, and I promise not to sue."

    He asked, "So where is the part that says I'm not going to be fired for doing that?"

    "What do you mean?"

    He explained, "This document protects the company from me. But where is the part that protects me from the company?"

    "I don't know what you're talking about."

    He spelled it out: "Company policy says that watching pornography at work is grounds for termination. This document does not actually say that it's okay for me to do so if it is done in the course of my job duties."

    "Look, you can either sign the release form or not, but you can't work until you sign it."

    My colleague sighed as he signed the form. "Whatever. Nevermind."

Page 1 of 94 (935 items) 12345»