Other

  • The Old New Thing

    Wow, they really crammed a lot into those 410 transistors

    • 22 Comments

    A colleague of mine pointed out that in yesterday's Seattle Times, there was an article about Moore's Law. To illustrate the progress of technology, they included some highlights, including the following piece of trivia:

    The Core 2 Duo processor with 410 transistors made its debut in 2002.

    You can see the photo and caption in the online version of the article if you go to the slide show and look at photo number three.

    This is an impressive feat. Intel managed to cram a Core 2 Duo into only an eighth as many transistors as the 6502.

    On the other hand, it does help to explain why the chip has so few registers. There weren't any transistors left!

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Invalid parameters from one security level crashing code at the same security level (yet again)

    • 23 Comments

    It's the bogus vulnerability that keeps on giving. This time a security researcher found a horrible security flaw in Sys­Alloc­String­Len:

    The Sys­Alloc­String­Len function is vulnerable to a denial-of-service attack. [Long description of reverse-engineering deleted.]

    The Sys­Alloc­String­Len does not check the length parameter properly. If the provided length is larger than the actual length of the buffer, it may encounter an access violation when reading beyond the end of the buffer. Proof of concept:

    SysAllocStringLen(L"Example", 0xFFFFFF);
    

    Credit for this vulnerability should be given to XYZ Security Labs. Copyright © XYZ Security Labs. All rights reserved.

    As with other issues of this type, there is no elevation. The attack code and the code that crashes are on the same side of the airtight hatchway. If your goal was to make the process crash, then instead of passing invalid parameters to the Sys­Alloc­String­Len function, you can launch the denial of service attack much more easily:

    int __cdecl main(int, char**)
    {
        ExitProcess(0);
    }
    

    Congratulations, you just launched a denial-of-service attack against yourself.

    In order to trigger an access violation in the Sys­Alloc­String­Len function, you must already have had enough privilege to run code, which means that you already have enough privilege to terminate the application without needing the Sys­Alloc­String­Len function.

    Once again, we have a case of MS07-052: Code execution results in code execution

    Earlier in the series:

    Bonus bogus vulnerability report:

    The Draw­Text function is vulnerability to a denial-of-service attack because it does not validate that the lpchText parameter is a valid pointer. If you pass NULL as the second parameter, the function crashes. We have found many functions in the system which are vulnerable to the same issue.

    ¹ Now, of course, if there were some way you could externally induce a program into passing invalid parameters to the Sys­Alloc­String­Length function, then you'd be onto something. But even then, the vulnerability would be in the program that is passing the invalid parameters, not in the Sys­Alloc­String­Length function itself.

  • The Old New Thing

    The details of the major incident were not clearly articulated, but whatever it is, it's already over

    • 15 Comments
    When a server is taken offline, be it a planned unplanned outage or an unplanned unplanned outage or something else, the operations team send out a series of messages alerting customers to the issue.

    Some time ago, I received a notification that went like this:

    From: Adam Smith
    Subject: Nosebleed Service : Major Incident Notification - Initial
    Date: mm/dd/yyyy 1:16AM

    Major Incident Notification

    dfdsfsd

    Affected Users

    fdfsdfsdf

    Start: mm/dd/yyyy 12:00AM Pacific Standard Time
    mm/dd/yyyy 8:00AM UTC
    End: No ETA at this time.

    Incident Duration: 1 hour 15 minutes

    Impact

    fsdfdsfsdf

    Continued Notifications

    fdsfsdf

    Information & Support

    • Other Support: Please send questions or feedback to

    Thank you,

    Adam Smith
    IT Major Incident Management

    Well that clears things up.

    Curiously, the message includes an incident duration but doesn't have an ETA. Thankfully, the message was sent one minute after the incident was over, so by the time I got it, everything was back to normal.

  • The Old New Thing

    Finding the constructor by scanning memory for the vtable

    • 5 Comments

    In Looking for leaked objects by their vtable, we used the object's constructor to locate the vtable, and then scanned the heap for the vtable to find the leaked object. But you can run this technique in reverse, too.

    Suppose you found an object and you want to find its constructor. This is not a problem if you have the source code, but if you are doing some reverse-engineering for application compatibility purposes, you don't have the luxury of the application source code. You may have figured out that the application fails because the byte at offset 0x50 is zero, but on the previous version of Windows, it was nonzero. You want to find out who sets the byte at offset 0x50, so that you can see why it is setting it to zero instead of a nonzero value.

    If the object has a vtable, you can scan the code segments for a copy of the vtable. It will show up in an instruction like

    mov dword ptr [reg], vtable_address
    

    This is almost certainly the object's constructor, setting up the object vtable as part of construction. You can set a breakpoint here to break when the object is constructed, and then you can set a write breakpoint on offset 0x50 to see where its value is seto.

  • The Old New Thing

    Sure, we have RegisterWindowMessage and RegisterClipboardFormat, but where are DeregisterWindowMessage and DeregisterClipboardFormat?

    • 23 Comments

    The Register­Window­Message function lets you create your own custom messages that are globally unique. But how do you free the message format when you're done, so that the number can be reused for another message? (Similarly, Register­Clipboard­Format and clipboard formats.)

    You don't. There is no Deregister­Window­Message function or Deregister­Clipboard­Format function. Once allocated, a registered window message and registered clipboard format hangs around until you log off.

    There is room for around 16,000 registered window messages and registered clipboard formats, and in practice exhaustion of these pools of numbers is not an issue. Even if every program registers 100 custom messages, you can run 160 unique programs before running into a problem. And most people don't even have 160 different programs installed in the first place. (And if you do, you almost certainly don't run all of them!) In practice, the number of registered window messages is well under 1000.

    A customer had a problem with exhaustion of registered window messages. "We are using a component that uses the Register­Window­Message function to register a large number of unique messages which are constantly changing. Since there is no way to unregister them, the registered window message table eventually fills up and things start failing. Should we use Global­Add­Atom and Global­Delete­Atom instead of Register­Window­Message? Or can we use Global­Delete­Atom to delete the message registered by Register­Window­Message?"

    No, you should not use Global­Add­Atom to create window messages. The atom that comes back from Global­Add­Atom comes from the global atom table, which is different from the registered window message table. The only way to get registered window messages is to call Register­Window­Message. Say you call Global­Add­Atom("X") and you get atom 49443 from the global atom table. Somebody else calls Register­Window­Message("Y") and they get registered window message number 49443. You then post message 49443 to a window, and it thinks that it is message Y, and bad things happen.

    And you definitely should not use Global­Delete­Atom in a misguided attempt to deregister a window message. You're going to end up deleting some unrelated atom, and things will start going downhill.

    What you need to do is fix the component so it does not register a lot of window messages with constantly-changing names. Instead, encode the uniqueness in some other way. For example, instead of registering a hundred messages of the form Contoso user N logged on, just register a single Contoso user logged on message and encode the user number in the wParam and lParam payloads. Most likely, one or the other parameter is already being used to carry nontrivial payload information, so you can just add the user number to that payload. (And this also means that your program won't have to keep a huge table of users and corresponding window messages.)

    Bonus chatter: It is the case that properties added to a window via Set­Prop use global atoms, as indicated by the documentation. This is an implementation detail that got exposed, so now it's contractual. And it was a bad idea, as I discussed earlier.

    Sometimes, people try to get clever and manually manage the atoms used for storing properties. They manually add the atom, then access the property by atom, then remove the properties, then delete the atom. This is a high-risk maneuver because there are so many things that can go wrong. For example, you might delete the atom prematurely (unaware that it was still being used by some other window), then the atom gets reused, and now you have a property conflict. Or you may have a bug that calls Global­Delete­Atom for an atom that was not obtained via Global­Add­Atom. (Maybe you got it via Global­Find­Atom or Enum­Props.)

    I've even seen code that does this:

    atom = GlobalAddAtom(name);
    
    // Some apps are delete-happy and run around deleting atoms they shouldn't.
    // If they happen to delete ours by accident, things go bad really fast.
    // Prevent this from happening by bumping the atom refcount a few extra
    // times so accidental deletes won't destroy it.
    GlobalAddAtom(name);
    GlobalAddAtom(name);
    

    So we've come full circle. There is a way to delete an unused atom, but people end up deleting them incorrectly, so this code tries to make the atom undeletable. Le Chatelier's Principle strikes again.

  • The Old New Thing

    Microspeak: Headcount, req, and related personnel terms

    • 16 Comments

    For some reason, there are a lot of Microspeak terms related to personnel. (Maybe you folks can tell me how common these terms are outside Microsoft.)

    We start with a term that is not actually used much outside the personnel world: The Position Control Number, or PCN. The PCN represents a place where an employee could be hired. If somebody is actually hired for the position, then the PCN is filled; if not, then it is unfilled.

    The term you are likely to hear outside of the personnel world is headcount. (Pronounced as the two words head count, accent on the first word.) This is a filled PCN, and it is often abbreviated to just head.

    Another term you are likely to hear is a req, short for requisition, and pronounced like the word wreck. A req is a requisition to recruit; in other words, it is permission to look for somebody to fill a position.

    We have an open req to find somebody to frob the whatsit so it can futz the doodad.

    An open req is a req that has not yet been filled. This sounds redundant to me, because a req by definition is unfilled, isn't it?

    Yet another personnel term you may encounter is backfill. This refers to hiring someone to take over a position that has been vacated by somebody who left the team. You will sometimes hear the term used in a metaphorical context.

    Who is the backfill for Bob while he is on vacation?

    Bob has not actually left the team; the person merely wants to know who is covering Bob's responsibilities while he is on vacation.

    The last term I'm going to expose you to is the ROP, or Recruiting Only Position. A ROP is permission to interview someone for a position that doesn't exist yet. You open a ROP with a particular person in mind, and once obtained, you have permission to interview them. You can think of a ROP as unapproved headcount, since if you decide to hire the person, you still have to find a PCN to put them in. And if you decide not to hire the person after you interviewed them, you close the ROP.

    I have no idea how useful these terms are for people not in the personnel world, but I figured I'd write them down for my own benefit, so I have something to refer to when I run across them.

  • The Old New Thing

    Debugging walkthrough: Access violation on nonsense instruction, episode 2

    • 17 Comments

    A colleague of mine asked for help debugging a strange failure. Execution halted on what appeared to be a nonsense instruction.

    eax=0079f850 ebx=00000000 ecx=00000113 edx=00000030 esi=33ee06ef edi=74b9b8ad
    eip=00c0ac74 esp=0079f82c ebp=0079f86c iopl=0         nv up ei pl zr na pe nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
    00c0ac74 0000            add     byte ptr [eax],al          ds:002b:0079f850=74
    

    If you've been debugging x86 code for a while, you immediately recognize this instruction as "executing a page of zeroes". If you haven't been debugging x86 code for a while, you can see this from the code bytes in the second column.

    So how did we end up at this nonsense instruction?

    The instruction is not near a page boundary, so we didn't fall through to it. We must have jumped to it or returned to it.

    Since debugging is an exercise in optimism, let's assume that we jumped to it via a call instruction, and the return address is still on the stack.

    0:000> dps esp l2
    0079f82c  74b9b8b1 user32!GetMessageW+0x4
    0079f830  008f108b CONTOSO!MessageLoop+0xe7
    0:000> u user32!GetMessageW l3
    USER32!GetMessageW:
    74b9b8ad cc              int     3
    74b9b8ae ff558b          call    dword ptr [ebp-75h]
    74b9b8b1 ec              in      al,dx
    

    Well, that explains it. The code bytes for the Get­MessageW function were overwritten, causing us to execute garbage, and one of the garbage instructions was a call that took us to page of zeroes.

    But look more closely at the overwritten bytes.

    The first byte is cc, which is a breakpoint instruction. Hm...

    Since Windows functions begin with a MOV EDI, EDI instruction for hot patching purposes, the first two bytes are always 8b ff. If we unpatch the cc to 8b, we see that the rest of the code bytes are intact.

    USER32!GetMessageW:
    74b9b8ad 8bff            mov     edi,edi
    74b9b8af 55              push    ebp
    74b9b8b0 8bec            mov     ebp,esp
    

    After a brief discussion, we were able to piece together what happened:

    Somebody was trying to debug the CONTOSO application, so they connected a user-mode debugger to the application. Meanwhile, they set a breakpoint on user32!GetMessageW from the kernel debugger. Setting a breakpoint in a debugger is typically performed by patching an int 3 at the point where you want the breakpoint. When the int 3 fires, the debugger regains control and says, "Oh, thanks for stopping. Let me unpatch all the int 3's I put in the program to put things back the way they were."

    When the breakpoint hit, it was caught by the user-mode debugger, but since the user-mode debugger didn't set that breakpoint, it interpreted the int 3 as a hard-coded breakpoint in the application. At this point, the developer saw a spurious breakpoint, didn't know what it meant, and simply resumed execution. This executed the second half of the MOV EDI, EDI instruction as the start of a new instruction, and havoc ensued.

    That developer then asked his friend what happened, and his friend asked me.

    TL;DR: Be careful if you have more than one debugger active. Breakpoints set by one debugger will not be recognized by the other. If the breakpoint instruction is caught by the wrong debugger, things will go downhill fast unless you take corrective action. (In this case, it would be restoring the original byte.)

  • The Old New Thing

    Dubious security vulnerability: Copying a program and running the copy

    • 30 Comments

    This wasn't an actual security vulnerability report, but it was inspired by one. "If you take the program XYZ.EXE and you rename it or copy it to a new name that contains the letters XYX, then you can trigger a buffer overflow in the renamed/copied version of XYZ.EXE due to a bug in the way it parses its own file name in order to generate the names of its auxiliary files."

    While that's a bug, and thanks for pointing it out, it is not a security issue because there is no elevation of privilege. Sure, you could rename or copy the program and run it, but if you have permission to do that, you may as well do it the easy way: Instead of copying XYZ.EXE and running it, just copy pwnz0rd.exe and run it! Either way, it's just a case of you attacking yourself. You did not gain any privileges.

    Renaming or copying a file requires FILE_ADD_FILE permission in the destination directory, and if you have permission to add files to a directory, why stop at just adding files that are copies of existing files? You can add entirely new files!

    In other words, instead of copy XYZ.EXE XYX.EXE, just do copy pwnz0rd.exe XYX.EXE.

    This is a variation of the dubious vulnerability known as Code execution results in code execution.

    Now, this would be an actual vulnerability if you could somehow redirect attempts by other people to run XYZ.EXE from the original to your alternate XYX.EXE instead. But that would be attacking the redirection code, not attacking XYZ.EXE itself. Because if you can fool somebody into running XYX.EXE instead of XYZ.EXE, then you may as well fool them into running pwnz0rd.exe. It's not like the Create­Process function performs a hard drive scan looking for a program whose name is similar to the one you requested and running that other program instead.

  • The Old New Thing

    The more times you use the word "simply" in your instructions, the more I suspect you don't know what that word means

    • 49 Comments

    I was helping somebody look up how to enable frobbing for widgets, and I found one set of instructions on a blog somewhere. To be honest, this happened long enough ago that I forgot what it was exactly, but here's something that captures the general spirit:

    First, check whether your widget supports frobbing. To do this, simply run this command

    magic ppg=q-40 id=voodoo xyzzy:42
    

    where voodoo is the voodoo code for your widget. It will say "frob supported" if your widget supports frobbing.

    If you don't know your widget's voodoo code, you can get a list of the voodoo codes and enchantment numbers for all the widgets connected to your computer by simply typing

    yoda PHASERS=warp10
    

    and then using the voodoo code in the first command line above.¹

    Once you have confirmed that your widget supports frobbing, you can enable it by simply editing the widget configuration file abc and adding frob="1" to the attributes of the appropriate entry. (If there is an existing frob="0", then simply change the 0 to a 1.)

    The changes will take effect at the next reboot. To make them take effect immediately, simply run the command

    episkey GANDALF.color=black DRADIS=pikachu
    

    My reaction was "Wow, this is really complicated. I have no idea how a normal human being is expected to know how to do this." And each time the next step in the process was revealed, my bewilderment increased.

    What struck me more was that the instructions used the word "simply" a lot. It became clear that the person writing the article was living in a world different from me. To me, the simple way to accomplish the task would have been if frobbing were enabled automatically if the hardware supported it. If there is some downside to frobbing, say, because it makes the widget run slower or use more power, then the simple way would have been to check a checkbox somewhere saying "Enable frobbing".

    But this person lived in a world where dropping to a command prompt, running a magic command, extracting the right voodoo code from the cryptic output, running a second magic command, then editing a configuration file, and then running a third magic command for the changes to take effect is a perfectly simple operation.

    I have to confess that I am guilty of this as well, where I dismiss various Win32 concepts as obvious, but my excuse is that my intended audience is developers who are already familiar with Win32, and for whom these sorts of things should be simple and obvious, because I'm trying to move past the basic concepts and discuss something more advanced.

    I do have entries with a non-technical audience in mind. Those entries are typically tagged Tips/Support and usually come out on Tuesdays. In those entries, I try to remember to dial things back. I suspect I don't always succeed.

    ¹ If there is more than one widget connected to your computer, then there will be more than one voodoo code. The instructions didn't say how to tell which voodoo code corresponds to which widget. Perhaps it was so simple it didn't need to be explained.

  • The Old New Thing

    Why does the mouse cursor jump a few pixels if you click on the very bottom row of pixels on the taskbar?

    • 31 Comments

    ABCDSchuetze discovered that if you click on the very bottom row of pixels of the taskbar, the mouse cursor jumps up a few pixels. Why is that?

    In order to take advantage of Fitts's Law, the bottom-most row of pixels on a bottom-docked taskbar are clickable. Even though they are technically on the dead border of the window, the taskbar redirects the click to the button immediately above the border. But then you have this problem:

    • User clicks on the border pixel between the button and the edge of the screen.
    • The taskbar remaps the click to the button, thereby activating the button.
    • The button takes capture because that's what buttons do when you click on them. This allows you to drag off the button to cancel the click.
    • But wait: Since the mouse is on the border, it is already outside the button.
    • Result: The button cancels immediately.

    The short version: Clicking on the Fitts's edge causes the button to be pressed and then immediately canceled.

    The fix is to nudge the mouse back inside the button when the click begins.

Page 1 of 96 (955 items) 12345»