Resolving power button issues in Mac OS X Mavericks

Posted
Comments 33

It always amused me how Apple is capable of producing so quality hardware and has so bright ideas in design, but makes so awful lot of questionable decisions in software. I have quite a number of questions on the usability of Mac OS X, but recent update to Mavericks was the last drop. I spend a lot of time in the text editor and I press delete key several hundreds times a day. The problem is, I have a MacBook Air and delete key is only 3mm apart from power key and I mishit it from time to time.

In the past versions of OSX, pressing power key would result in shutdown dialog, which could be closed by esc key in a wink, no harm done. In Mavericks, power key puts system in sleep, screen goes black, and I need to press power key again, in 2-3 seconds system would boot up back, after that I need another couple of seconds to enter my password — 5 seconds in total, which is quite disturbing when you are concentrated. On top of that, this behavior is not customizable, that effectively cuts MacBook Air with Mavericks usability for programming or writing texts.

Let’s put aside the question why someone would decide to implement such a ridiculous feature — it was implemented, everyone is unhappy, and Apple seems to have more important tasks to do than to fix it back. Unfortunately MacBook is currently my primary instrument, and I could not just put in on the shelf until better times, so naturally I started to seek a solution. There was not much — hilarious Apple support post that advised to press power key for 1.5 seconds to get shutdown dialog and reddit post that advised to change powerd config file.

When you apply suggested fix, screen goes black on power key, but the system doesn’t fall asleep anymore, and you could wake it up momentarily, that saves you several seconds. And if you don’t want to lose another couple of seconds on password input, you can go to Security & Privacy in System Preferences and change password requirement from “Immediately” to “5 seconds”. Now you don’t lose any time, but as for me, screen blackout is still pretty damn disturbing, so I decided to investigate this issue further.

What do we have: if power key is released in less than 1.5 seconds, system falls asleep, if key is pressed for 1.5 seconds, shutdown dialog appears, and if it is pressed for 5+ seconds, system powers off. Third case is usually implemented in hardware, but the first two cases are software in nature and there must be a key handler somewhere, so our goal is to find it and fix it. We also have two leads — one is that powerd config contains “Sleep on power button” option, and another is the shutdown dialog that had to be linked to some piece of code.

I decided to start with shutdown dialog and searched the whole system disk for the phrase from it:

$ sudo find / -type f -print0 | xargs -0 fgrep "Are you sure you want to shut down your" 2>/dev/null

Actually it was a long shot because dialog resources could be encrypted or compressed, or string could be in Unicode, so I was already prepared to dump and examine memory, but luckily grep found matching string in two files:

Binary file /System/Library/CoreServices/loginwindow.app/Contents/Resources/English.lproj/PowerButton.nib matches
Binary file /System/Library/CoreServices/loginwindow.app/Contents/Resources/English.lproj/ShutDown.nib matches

As we can see, both of them are part of loginwindow application, and the name PowerButton.nib looks quite promising, huh? And if we dig it even deeper, we can figure out that PowerButton.nib is a dialog resource for power key, and ShutDown.nib is a dialog resource for Apple -> Shutdown…:

$ cd /System/Library/CoreServices/loginwindow.app/Contents/Resources/English.lproj/
$ fgrep "Restart" PowerButton.nib ShutDown.nib
Binary file PowerButton.nib matches
$ fgrep "If you do nothing, the computer will shut down" PowerButton.nib ShutDown.nib
Binary file ShutDown.nib matches

Anyway, now we had two suspects — loginwindow.app and powerd. /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow and /System/Library/CoreServices/powerd.bundle/powerd, to be precise.

I fired up IDA and loaded powerd in it. Quick look around discovered a whole lot of strings with “sleep” substring, imported IOPMSleepSystemWithOptions from IOKit and several exported symbols with “sleep” substring, but actually nothing that would instantly catch my eye. And no hits for “powerbutton” substring.

So I switched to loginwindow, but it looked all gibberish. That is when I remembered that Apple uses code signing and encryption. So I ended up dumping processes memory anyway. Quick searching on the internet discovered tool named readmem, that did the trick:

$ ps -A | fgrep loginwindow
   59 ??         0:02.31 /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow console
  436 ttys000    0:00.00 fgrep loginwindow
$ sudo ./readmem -p 59 -m -o loginwindow.dmp
---------------------------------
Readmem v0.6 - (c) 2012, 2013 fG!
---------------------------------
[DEBUG] Found main binary mach-o image @ 0x10acf7000!
[DEBUG] Executing get_image_size
[DEBUG] Executing dump_binary
[DEBUG] Dumping __TEXT at 10acf7000 with size 99000 (buffer:200000)
[DEBUG] Dumping __DATA at 10ad90000 with size 1d000 (buffer:299000)
[DEBUG] Dumping __CGPreLoginApp at 10adad000 with size 0 (buffer:2b6000)
[DEBUG] Dumping __RESTRICT at 10adad000 with size 0 (buffer:2b6000)
[DEBUG] Dumping __LINKEDIT at 10adad000 with size 15cc0 (buffer:2b6000)
[OK] Full binary dumped to loginwindow.dmp!

Now it looked fine in IDA, so I started to look for “sleep”, “powerbutton”, “power button” in there and almost instantly discovered the following strings:

__cstring:00000001000769F4 0000002F C -[ApplicationManager checkPowerButtonTimeout:]
__cstring:0000000100077140 0000002E C -[ApplicationManager handlePowerButtonEvent:]

Each string had several cross-references from the __text section, it was natural to assume that these places were all parts of two ApplicationManager methods, checkPowerButtonTimeout and handlePowerButtonEvent. I created these functions in IDA and now we were getting somewhere. Original strings turned out to be a part of logging system that was enabled by the condition:

lea     r12, qword_1000B5F18
test    byte ptr [r12+2], 2
jz      no_log

Of course, in the original source code it was something like this:

if (qword_1000B5F18 & 0x20000) log(…)

So I went back to readmem and enabled the logging:

$ sudo ./readmem -p 59 -a `python -c "print hex(0x10acf7000 + 0xb5f18)"` -s 8
---------------------------------
Readmem v0.6 - (c) 2012, 2013 fG!
---------------------------------
Memory protection: rw-/rwx
0x10adacf18 00 00 00 00 00 00 00 00                         |........|
$ sudo ./readmem -p 59 -a `python -c "print hex(0x10acf7000 + 0xb5f18)"` -s 8 -w -b 20000
---------------------------------
Readmem v0.6 - (c) 2012, 2013 fG!
---------------------------------
-[ Memory before writing... ]-
Memory protection: rw-/rwx
0x10adacf18 00 00 00 00 00 00 00 00                         |........|
-[ Memory after writing... ]-
Memory protection: rw-/rwx
0x10adacf18 00 00 02 00 00 00 00 00                         |........|

After which I did two tests. First, I held power button for 1.5 seconds. Here is what I got in the syslog via Console.app:

31/12/13 10:24:24,596 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | entered, keyDown:1
31/12/13 10:24:24,597 loginwindow[59]: FaceTimeNotificationCenter | -[FaceTimeNotifictionCenterSupport callIsRinging] | returning:0
31/12/13 10:24:24,597 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |      No call is ringing
31/12/13 10:24:24,597 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |     NO shield window showing
31/12/13 10:24:24,597 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | power button pressed, start timer
31/12/13 10:24:26,098 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager checkPowerButtonTimeout:] | entered.
31/12/13 10:24:26,099 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager checkPowerButtonTimeout:] |      not already handled
31/12/13 10:24:26,099 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager checkPowerButtonTimeout:] |      is not terminating apps and power button held for > 1.5 seconds, show powerbutton dialog
31/12/13 10:24:26,903 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | entered, keyDown:0
31/12/13 10:24:26,903 loginwindow[59]: FaceTimeNotificationCenter | -[FaceTimeNotifictionCenterSupport callIsRinging] | returning:0
31/12/13 10:24:26,903 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |      No call is ringing
31/12/13 10:24:26,903 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |     NO shield window showing

Second, I pressed and released power button momentarily, forcing the system to sleep, and pressed it again in about 5 seconds to wake it up:

31/12/13 10:27:47,682 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | entered, keyDown:1
31/12/13 10:27:47,683 loginwindow[59]: FaceTimeNotificationCenter | -[FaceTimeNotifictionCenterSupport callIsRinging] | returning:0
31/12/13 10:27:47,683 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |      No call is ringing
31/12/13 10:27:47,683 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |     NO shield window showing
31/12/13 10:27:47,683 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | power button pressed, start timer
31/12/13 10:27:47,842 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | entered, keyDown:0
31/12/13 10:27:47,842 loginwindow[59]: FaceTimeNotificationCenter | -[FaceTimeNotifictionCenterSupport callIsRinging] | returning:0
31/12/13 10:27:47,842 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |      No call is ringing
31/12/13 10:27:47,842 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] |     NO shield window showing
31/12/13 10:27:47,842 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager handlePowerButtonEvent:] | powre button released before 1.5 seconds, sleep the system.
31/12/13 10:27:47,843 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | __RegisterSleepWakeCallback_block_invoke | IOPMScheduleUserActiveChangedNotification received:0
31/12/13 10:27:47,843 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock userActivityChanged:] | entered.  isActive:0, shieldWindowShowing:0, lockRequestInProgress:0
31/12/13 10:27:47,847 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock(Private) userIsActiveCheck] | entered.
31/12/13 10:27:47,847 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock(Private) userIsActiveCheck] | returning: 0
31/12/13 10:27:49,185 loginwindow[59]: FaceTimeNotificationCenter | -[ApplicationManager checkPowerButtonTimeout:] | entered.
31/12/13 10:27:52,705 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | __RegisterSleepWakeCallback_block_invoke | IOPMScheduleUserActiveChangedNotification received:1
31/12/13 10:27:52,705 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock userActivityChanged:] | entered.  isActive:1, shieldWindowShowing:1, lockRequestInProgress:0
31/12/13 10:27:52,705 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock userActivityChanged:] | user event received, start an unlock with 'active user' as the reason
31/12/13 10:27:52,705 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock(Private) userIsActiveCheck] | entered.
31/12/13 10:27:52,706 loginwindow[59]: FaceTimeNotificationCenter | kLWDBLogScreenLockAndPower | -[LWScreenLock(Private) userIsActiveCheck] | returning: 1

Clearly, our initial suspicions about handlePowerButtonEvent and checkPowerButtonTimeout were right, these are the two functions responsible for the whole mess, so I restored their logic:

When power button is pressed:
  if facetime call is ringing, notify facetime about pressed powerbutton and do nothing.
  else if shield window (login form for current user) is active, simulate esc keystroke, effectively putting the system to sleep.
  else start timer for 1.5 seconds
When power button is released:
  if timer didn’t fire yet, put system to sleep.
When timer fires up:
  if button is still pressed, and the system is not in kiosk and the system is not powering down, show dialog.

Everything seems to be pretty straightforward. Now, we want to get rid of unwanted unacknowledged sleeping and we want to restore original behavior of showing shutdown options dialog. First task is pretty easy — basically placing mov rax, 1; retn in the beginning of handlePowerButtonEvent will do the trick. Second task is somewhat more ambiguous — we can either call ApplicationManager::postPowerButtonDialogRequest from handlePowerButtonEvent when keyDown is 1, or we can reduce timeout from 1.5 seconds to 0.001 seconds, or we can just replace handlePowerButtonEvent call with postPowerButtonDialogRequest and hope that multiple calls won’t break anything.

I personally consider second way is the least destructive — all we do is change a constant, no intervention in the program logic, so I focused on it.

Timer setup code looks like this:

10004D07A   48 8B 35 37 D6 05 00      mov     rsi, cs:off_1000AA6B8
10004D081   48 8B 0D 00 EF 05 00      mov     rcx, cs:off_1000ABF88
10004D088   48 8B 3D C1 FF 05 00      mov     rdi, cs:off_1000AD050
10004D08F   F2 0F 10 05 A1 81 04 00   movsd   xmm0, cs:qword_100095238
10004D097   4C 89 FA                  mov     rdx, r15
10004D09A   45 31 C0                  xor     r8d, r8d
10004D09D   45 31 C9                  xor     r9d, r9d
10004D0A0   FF 15 52 C4 04 00         call    cs:_objc_msgSend_ptr
10004D0A6   49 89 04 1F               mov     [r15+rbx], rax

Timer constant is loaded into xmm0 in the fourth line. The naïve approach is to simply update qword_100095238 value, but unfortunately that constant is used outside the handlePowerButtonEvent, so we could unwillingly alter behavior of other parts of loginwindow if mess with it. Therefore we would rather update the instruction so it points not to 100095238, but somewhere else.

We don’t see any direct reference to address 100095238 in the instruction, but it is common for x86 processor family to incorporate relative addresses, where effective address is calculated as next instruction address + offset. 100095238 - 10004D097 gives us 481A1, which is exactly the value of second dword of movsd instruction. So now our entire job is to find another, smaller value, recalculate offset to it, and replace old offset with it.

We could of course look for small values all over the memory, but that wouldn’t be exactly wise — most memory areas change from time to time, and if we find some small value now, it could easily change to enormous value or even be not valid memory place in the future. So the correct approach here is to look for small values only in the code segment of loginwindow, which is guaranteed to be intact in normal operation. I wrote a simple Python script for that matter:

def find_small_double(image, from, to=None):
	for i in xrange(0x18, 0x74):
		pattern = chr(i) + '\x3f'
		pos = image.find(pattern, from)
		if pos != -1:
			return (pos-6, struct.unpack('d',image[pos-6:pos+2])[0])
	return None

It in fact finds a lot of byte sequences that could be interpret as small double values around the __text section, so I just updated the offset to the first of them:

$ sudo ./readmem -p 59 -a `python -c "print hex(0x10acf7000 + 0x4D093)"` -s 4 -w -b 8533
---------------------------------
Readmem v0.6 - (c) 2012, 2013 fG!
---------------------------------
-[ Memory before writing... ]-
Memory protection: rw-/rwx
0x10ad44093 A1 81 04 00                                     |....|
-[ Memory after writing... ]-
Memory protection: rw-/rwx
0x10ad44093 33 85 00 00                                     |3...|

… and my power button was fixed.

Understanding that it is quite a big deal to fix it by hand all the time, I wrote a simple utility based on the readmem that tries to fix loginwindow process. Download it, build it (you will likely need XCode), run it. Alternatively, you can download and run binary version.

Of course, it has several limitations:

  • I have only tested it on my loginwindow version, so it is not guaranteed to work on any other machine. Please report on how it works for you.
  • The utility works only on 64bit platform but that shouldn’t be a problem, considering Mavericks only runs on 64bit.
  • The utility must be run from superuser. Probably you could chmod +s it and autolaunch it on system start or in cron, I haven’t tested it.
  • The fix will only work until system is rebooted or user is logged out. The fix will not work for any newly logged it users.

But still it should be handy. Have a happy coding in the New Year!

Donations are welcome at 1G1RKjYazp8TjxKTC6YpWADZzejQaiCeEc or LKqD7vAfWkfDTSzta1YUdGqWkBj1RMf654.

P.S.: Oh but wait, what about powerd and “Sleep on power button” config option? Nothing, actually. All the sleeping-waking magic is performed by IOKit, and powerd merely loads the config and applies it to IOKit. I guess just another option would be to modify IOKit and disable screen blackout, but I sticked to loginwindow fix.

Author
Categories reverse engineering, osx

Comments

  1. Tom

    “Let’s put aside the question why someone would decide to implement such a ridiculous feature…”

    Momentary presses of the power button do nothing on my Macbook Air with 10.9.1.

  2. Alan

    Your first sentence is in direct contradiction with your other sentences. If the problem is (as you say it is, and that it sounds like) that the power button is only 3mm from the delete key, that’s a hardware problem, not a software problem.

    In previous versions of OS X, this flaw was mitigated to an extent by being able to press “esc”, but I think we can all agree that not having to press “esc” all day would have been much better.

    My car doesn’t have its horn located 3mm from the radio’s volume knob, and if it did, I wouldn’t call it “quality hardware” with a “questionable decision in software”, nor would I consider it acceptable if it gave me an “are you sure?” dialog box before sounding the horn each time. That’s a hardware design issue, plain and simple.

  3. binchewer (Author)

    Tom, as we empirically found, duration threshold is around 0.07 sec, which is ~1/15 of a second. Maybe I press my keys too lazy, but for me it is quite common to press power button (thinking that I am pressing the delete key) for 0.07+ sec, thus activating it.

    Alan, hardware quality is perfectly fine. Location of a key is a hardware design issue, and, I agree, the source of the problem is location of a key. But what’s done is done, I bought this car, and I have to put up with it. But you can bypass a lot of hardware issues with proper software, and you would expect the vendor to do so.

    As for Apple, they, instead of fixing this issue with software, made it even bigger. I’m sorry if my sentencing didn’t make it clear the first time:
    * Apple hardware quality is very good,
    * Apple hardware design is generally good with several exceptions,
    * Apple interface design is good with a lot of exceptions,
    * Apple software quality is not bad, but it brings couple of issues that make you want to kill yourself.

    The entire post is about managing one of the latter issues.

  4. Ted

    I have experienced this on my MBA many times. Very frustrating. Of course havin dinosaur hands doesn’t help

  5. Mosselman

    @Alan

    It is obviously not true what you are saying. You are using @binchewer’s (equally flawed) solution to argue that the hardware (locaiton of power button) is wrong, while all you are saying is that a shutdown dialog isn’t what you’d want when you slightly press it.

    Not matter the location of the power button, I don’t want tapping it to result in immediate shutdown. The solution is to do what was done with the DVD eject button on the Macbook Pro; pressing it slightly longer 1 second versus slight tap, will trigger its functionality -> software fixed.

    The location of the power button is fine actually.

  6. Ben

    Just wanted to say awesome post and I learned a lot thanks for that! And to other commentators please guys just focus on what is really important here, small hint it is not the keyboard/hardware layout wink :)

    Regards,
    Ben

  7. Richard Bradshaw

    Neat write up, nice detail and very clear. It’s interesting to note that on the Macbooks I have (rMBP, older MBP, both on 10.9.1), this isn’t an issue – tapping the power button doesn’t power the machine off. If I hold it for a short amount of time (a slightly long tap) it does, but tapping it again it comes on instantly. (so, a taaap, tap = screen black for less than 1 second). I have a password required after 5 seconds, so that helps.

    I wonder if Apple’s logic is that the process is so quick, that it doesn’t matter. Interesting change of behaviour nonetheless.

  8. Ankur

    What is highly annoying is using booting to Windows and hitting the key while playing games.

  9. Eterna

    I’m just here to say that I sincerely hope all this extreme geeking and nerding gets you laid somehow, some day. You deserve it!

  10. user

    this really is a great article (and workaround) .. thanks!

  11. Criação

    This issue was driving me crazy too! Thanks so much for this fix!

  12. Dan

    Excellent read, it’s nice to see an article like this that actually ‘shows working out’, so to speak.

  13. Matt Mower

    I use a 2013 13” MBA and confess that I’ve never experienced this problem but I wanted to leave a comment to say how impressed I am with how you analysed and fixed the problem. I’m 99% certain I would have given up at the readmem stage, even had I known about it! Kudos to you.

  14. Kevin

    A good hack. Congrats

  15. Sammy

    great work! I’ve needed the ability to repurpose my power key to a forward delete key and now I finally have it. Thanks a million.

  16. Rosyna

    I am saddened by what you did. Very saddened. There’s no reason whatsoever to even get a disassembly of the loginwindow (class-dump is your friend here). The act of using memory addresses directly or thinking about using them makes me a sad panda.

    (not to mention patching loginwindow is extremely dangerous from a stability point of view as it controls all GUI).

    Better way:

    Make an NSBundle project (Cocoa Bundle) in Xcode that does all your patching in the +load method of your class.
    Compile that bundle and stick it somewhere. Embed it in a command line tool or something, if that floats your goat.
    From your command line tool running as root, use +[NSBundle bundleWithURL:] with the file URL to your bundle.
    On the resulting NSbundle instance, call -load. It’ll automatically run your +load code.

    For the +load code, do something like this.

    Get the old IMP of the target function using the objective-c runtime and save it somewhere.
    Create a new implementation of the function using imp_implementationWithBlock() from within that new IMP block, call the original IMP if you need to. Remember to recreate the second argument when you call the original.
    Use method_setImplementation() to set the new implementation.
    Rejoice.

    I do it with a different method as posted on

    https://gist.github.com/Rosyna/87017e661d5593acb733

    I used it to debug the actual “something” being passed around.
    Rejoice more.

  17. sean

    Thanks!! This shit was driving me crazy… besides the problem you stated, i work 100% of my time logged in to my office openvpn server when the power button is pressed besides the black screen (i hate it) i get automatically disconnected from the vpn server.

    So,

    tl:dr your 5 seconds of work disruption becomes 30-45 seconds to me (because of the vpn cut of).

    So,

    Thanks buddy. Great hack.

  18. Dave Barr

    Pro tip: you should never have to reach up and hit delete in a text editor/textbox. Ctrl-H is your friend. Keeps your fingers on the home row, especially if you map caps lock to control. You have remapped caps lock, right? Or do you murder babies too?

  19. me

    I have a 17” unibody MBP with 10.9.1 and it doesn’t work.
    I even was desperate enough to try logging in as root and running it.
    it has no effect.
    I am desperate to restore my power button to the popup dialog as it was before Mavericks. (God Apple is stupid!)

  20. binchewer (Author)

    Thank you all for your comments.

    Mosselman, yes, my fix just reverts it from “really bad” to “not so good”. Increasing the duration threshold is a clever solution, I’ll try to do it.

    Eterna, thank you. I hope so too.

    Rosyna, great comment. As you can see, I don’t know much about Objective-C and OSX internals, and this post was my first scratch on this subject. But, my incompetence taken into account, I still can’t agree with what you said.

    First, we absolutely need to disassembly the program — class hierarchy and declarations is not enough to understand how it works. Second, you are overdramatizing about danger of messing with loginwindow. I crashed it a dozen times while debugging my fix, and it’s not scary at all — when loginwindow crashes, you just get logged out and need to relogin, that’s all. Also my patch does a lot of checks not to screw it up.

    Third, your suggestion of replacing old method with new one is exactly the approach I discarded in the post, because I consider it far more dangerous than to mess with a constant — if you don’t know how method works (and you don’t because class-dump won’t tell you that), you risk breaking down application logic, which can lead to far more funny consequences than plain application crash.

    Anyway, your patching-bundle approach is very clever, and I will try to incorporate it in the future. Thank you.

    Dave Barr, I seem to murder babies :(

    Finally, the last commentator, please email me the details (my program output, loginwindow version, and probably loginwindow dump made with readmem). I can’t help you without this information.

  21. JPC

    Hi,
    Very good job, I like/use it !
    Another challenge for you : since Lion, can’t turn on the screen with mouse move or trackpad swipe, only with mouse clic, trackpad clic, or keyboard key.
    Can you investigate this ;-)
    WARNING: I am speaking about DISPLAY SLEEP state, not the full COMPUTER SLEEP state for which this behavior is correct.
    Thanks.

  22. Stefan

    Excellent work and analysis. Thanks a lot!
    I actually had the problem with the unreliable wake-up when opening the lid (depending on whether the battery is empty or not). So I tend to press the power button to speed things up or check the state “manually”, which under Mavericks tends to sleep the machine exactly when it wakes up due to the lid switch. Drove me nuts. So thanks again for the therapy.

    Stefan

  23. stino

    Very interesting to read how you analyse the problem. I never heard of that readmem tool before. I will give it a try at the weekend when I have more time.

    I wondering if it is possible to replace the the hole “movsd xmm0,cs:[adress]” opcode by an “xorps xmm0,xmm0” opcode to set the SSE register to zero? If the “xorps” opcode uses less bytes than “movsd” opcode you can fill the not needed bytes with some “nop” opcodes.
    It could be an alternative to finding an small double somewhere in mem and patching the relative jump address.
    But I have no idea if the next function call can handle an timer of 0.0 until we try it.

    Thanks for sharing your hack!

  24. gurn

    Thanks for this fix! It took me a while to figure out how to get this to run automatically at boot/login, but I finally got a .plist written for launchd, and it works flawlessly:

    <?xml version=“1.0” encoding=“UTF-8”?>
    <!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
    <plist version=“1.0”>
    <!—
    File name: com.binchewer.power_fixer.plist
    Placed in /Library/LaunchDaemons/
    Ensure plist file and program are both owned by root and executable
    —>
    <dict>
    <key>Label</key>
    <string>com.binchewer.power_fixer</string>
    <key>Program</key>
    <string>/usr/local/power_fixer/bin/power_fixer</string>
    <key>RunAtLoad</key>
    <true/>
    </dict>
    </plist>

  25. stino

    It was possible with an good disassembler like “hopper” to disassemble the loginwindow binary and this means the binary is not encrypted. But if you try to patch loginwindow in hopper directly and try to create a new binary from it, hopper warn you that the old binary was using code signing. This means the system will detect if the binary is changed in the file.

    But just for analysis there is no needed to grab a dump from memory. Disassembling the loginwindow file on your HD or SSD works also fine.

    But if we try to patch loginwindow we need to do this in the memory with the same technic that binchewer already uses in his power_fixer program.

    I change the source code of power_fixer a little bit to try out my idea from yesterday. This patched version of power_fixer not longer search for that small double as I suggested. It only replaces the pattern F20F1005A1810400 (“movsd xmm0,cs:[adress]”) with the pattern 0F57C09090909090 (“xorps xmm0,xmm0” and five times “nop”). I try this patched power_fixer program and it does the job as well.

    It is just great that I will be no longer disturbed by that annoying standby screen when accidentally hit the power button. :) I’m still wondering who had this ludicrous idea at apple?

    Anyway, thank you very much for your patch binchewer!

  26. stino

    Found another interesting way to patch loginwindow.
    The code where the sleep function is triggered (sub_10003dcb5)m when power key was released before the 1.5 sec are gone is found here:
    10004d036 E87A0CFFFF call sub_10003dcb5

    Just replace E87A0CFFFF by 9090909090 (5 nop as before) and than pressing the power button shorter than 1.5 sec make nothing. You have to press it longer than 1.5 sec to show the power button dialog.

  27. man

    Rosyna, you have convinced me women shouldn’t be working in tech, it’s bad enough already with males who’ve been emasculated.

  28. Todd

    While the tech is cool, what a waste of time and effort, learn to type better :) Submit bug reports to Apple and have them fix it properly. Of course that is just my lowly opinion.

  29. Jason

    Todd, you’re a dick.

  30. Joshua Ochs

    Looks like 10.9.2 broke this approach, or at least the binary no longer does its magic. Is there a way to generalize the approach so it works across new releases, or did Apple block this for good?

  31. #

    Can we get a fix for 10.9.2 please?

  32. Peter

    10.9.2 issue:
    https://github.com/binchewer/power_fixer/issues/9

  33. #

    Any idea when it’ll be fixed? Either stino’s or the original power_fixer? Anything beats the default 10.9.2 function…

Comment

Enter your comment below. Fields marked * are required. You must preview your comment first before finally posting.





← Older Newer →