f.lux hotkeys modification

I’ve started using f.lux some time ago and now I cannot live without it. But there is one disadvantage considering my use case. Whenever I want to see a movie (which is usually at evening when f.lux is making everything reddish) I have to disable it manually. Through context menu. Because hotkey allows you to disable it only for one hour. And my movies usually are longer than that. So what can I do? Fire an IDA, of course.

f.lux debugging #1

Where to start? I’ve tried to find string that is shown after pressing these keys (ALT + END): “for an hour” and “f.lux is back”. Strings window found it at address 0x483850 and 0x483860 (f.lux v. 3.10 for Windows). IDA could find only one reference to these addresses in single function sub_458330. Great, lets put breakpoint at the beginning of this function and lets see what happen.

Breakpoint will hit frequently after the program starts. It must be some kind of message processor. Ok, lets put breakpoints on lines referenced to strings (0x4585D6 and 0x4585E2 – see picture on the left) instead of begginig of function. Now we can see that it hits only on hotkeys, but not on menu click. Great.

Looking around this place we could find an interesting value. At address 0x4585B9 there is label pointing to double float:

.rdata:00490240 dbl_490240 dq 3600.0

3600 which is number of seconds in hour. Coincidence? And what is this strange fld instruction? Probably some mov with float argument. Lets find it.

f.lux debugging #2

I’m not sure but it looks like this value is placed on the stack as argument to sub_452BD0 function. Lets break on this function and try to modify the value on the stack. I found online float to binary converter here http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html. I’ve tried to change this to 10 secs, which is 0x4024000000000000 (use double precision). It works, so all we need to do is to patch executable with value corresponding to 3 hour time or so and maybe change strings accordingly, right?

Why not “disable until sunrise”?

Why not just remap ALT + END to call this function? It has no shortcut whatsoever. Lets find this string. It is used at address 0x457DD0 as parameter to AppendMenuA function. But it is here registered, not executed. Maybe we should try different approach: lets find xrefs to sub_452BD0. We should find proper message processor associated with menu this way.

There is five of them. Lets break on four yet unexamined. This way we will detect the one called by menu. As we can see, it is 0x457FCF. But wait, there is similar code next to it.

f.lux debugging #3

Only difference is in timeout parameter passed to our function – it is -1 this time. Is it some special value to indicate this “until sunrise” mode? Lets find out. We already have breakpoint in here, so we only have to click this option from menu. And it breaks!

Finally our hack comes to modify this single value at address 0x4585B9 (hotkey handling function). Or I suggest to modify instruction to load value -1 from address 0x4901F8 instead to not affect other places where this value is used (and there is several such places). And maybe changing string “for an hour”.

Oh wait, “until sunrise” is too long to fit in there! What now?

Don’t worry, there are at least two possible solutions. We could use another string here. “Until sunrise” is presented at 0x483888. And if you want string that starts with lower case, you could use “Disable until sunrise” at 0x483724 but skipping the first word.

If you still couldn’t find any useful string, you could always add new one. At the end of .rdata section there is more than 400 bytes unused. You can put your string there. Don’t forget to update virtual size of this section in section header.

f.lux debugging

Unfortunately f.lux license forbids me to publish modified version. Instead, I would present patching instruction in form that it would be easy to patch with any hex editor.

Format:
address: original value -> new value
where address is file offset hexadecimal value.
"Until sunrise" patch:
579BB: 40 02 49 00 -> F8 01 49 00
579D7: 60 38 48 00 -> 2C 37 48 00
"3 hour" patch:
8F640: 00 00 00 00 00 20 AC 40 -> 00 00 00 00 00 18 C5 40
82C60: "for an hour" -> "for 3 hours"

Controlling Samsung TV adjustments

Samsung TV’s (series D and probably series C) are equipped with some feature called Rendering Control Service. It is simply network protocol useful to control some parameters related to audio and video options (e.g. volume level, brightness etc).

Protocol is based on HTTP and XML technology. Requests are sent by TCP port 52235 and looks like:

POST /upnp/control/RenderingControl1 HTTP/1.1
Content-Type: text/xml; charset="utf-8
SOAPACTION: "SoapAction:urn:schemas-upnp-org:service:RenderingControl:1#GetVolume"
Cache-Control: no-cache
Host: 192.168.1.102:52235
Content-Length: 354
Connection: Close

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ns0:GetVolume xmlns:ns0="urn:schemas-upnp-org:service:RenderingControl:1">
<InstanceID>0</InstanceID>
<Channel>Master</Channel>
</ns0:GetVolume>
</s:Body>
</s:Envelope>

SOAPACTION contains action name (GetVolume), rest of this string is constant. Host IP is, of course, our device address. Content-Length define payload data length (XML data). Rest of the headers above is rather self-explanatory.

Header lines are separated by two bytes CR+LF (carriage return 0x0D followed by new line symbol 0x0A). Between headers and payload there is one extra empty line – CR+LF+CR+LF.

XML data is almost entirely predefined constant. Only <ns0:Getvolume …>…</ns0:GetVolume> are customizable. GetVolume is action name and the subtags (InstanceID, Channel) are parameters with determined values. List of all valid actions, values and parameters are covered in http://upnp.org/specs/av/UPnP-av-RenderingControl-v1-Service.pdf. My TV does not support every actions defined in here.

TV response  will be similar to request:

HTTP/1.1 200 OK
CONTENT-LENGTH: 289
CONTENT-TYPE: text/xml; charset="utf-8"
DATE: Thu, 01 Jan 1970 03:25:13 GMT
EXT:
SERVER: Linux/9.0 UPnP/1.0 PROTOTYPE/1.0

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetVolumeResponse xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"><CurrentVolume>6</CurrentVolume></u:GetVolumeResponse></s:Body></s:Envelope>

I’m sure it require no comment.

We can of course set up parameters too. E.g. it is possible to set volume:

POST /upnp/control/RenderingControl1 HTTP/1.1
Content-Type: text/xml; charset="utf-8
SOAPACTION: "SoapAction:urn:schemas-upnp-org:service:RenderingControl:1#SetVolume"
Cache-Control: no-cache
Host: 192.168.1.102:52235
Content-Length: 389
Connection: Close

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ns0:SetVolume xmlns:ns0="urn:schemas-upnp-org:service:RenderingControl:1">
<InstanceID>0</InstanceID>
<Channel>Master</Channel>
<InstanceID>0</InstanceID>
<DesiredVolume>69</DesiredVolume>
</ns0:SetVolume>
</s:Body>
</s:Envelope>

I plan to release simply C++ classes to control Samsung TV with this protocol, and previously described Samsung Network Remote Control.

Samsung TV network remote control protocol

It happens, that I get my new 32″ Samsung TV – model LE32D550. Like most of new Samsung TV’s (if not everyone) it could be connected into the LAN. Of course, one of the first thing I do when the network cable was connected was port-scan.

C:\Users\Michal>nmap -p 1-65535 tv.lan

Starting Nmap 5.21 ( http://nmap.org ) at 2012-02-16 22:19 îrodkowoeuropejski czas stand.
Nmap scan report for tv.lan (192.168.1.102)
Host is up (0.0016s latency).
Not shown: 65531 closed ports
PORT      STATE SERVICE
52235/tcp open  unknown
52396/tcp open  unknown
55000/tcp open  unknown
55001/tcp open  unknown
MAC Address: 60:6B:BD:AB:FC:95 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 9.04 seconds

55000 is used for remote control over network. There is application for iPhone and Android smartphones (unfortunately only these created by Samsung) to control TV through WiFi. I did some research, and now I understand the protocol quite well.

1. Authentication

When connection on port 55000 is established, remote control must be authenticated. It sends datagram.

0000   00 13 00 69 70 68 6f 6e 65 2e 69 61 70 70 2e 73  ...iphone.iapp.s
0010   61 6d 73 75 6e 67 38 00 64 00 14 00 4d 54 6b 79  amsung8.d...MTky
0020   4c 6a 45 32 4f 43 34 78 4c 6a 45 77 4d 41 3d 3d  LjE2OC4xLjEwMA==
0030   10 00 5a 32 52 7a 4e 7a 4d 30 64 47 64 30 5a 41  ..Z2RzNzM0dGd0ZA
0040   3d 3d 0c 00 63 32 4d 77 64 48 6b 75 63 47 77 3d  ==..c2MwdHkucGw=

And the meaning of this bytes.

offset  value and description
------	---------------------
0x00   	0x00 - datagram type?
0x01	0x0013 - string length (little endian)
0x03	"iphone.iapp.samsung" - string content
0x16	0x0038 - payload size (little endian)
0x18	payload

I don’t know the meaning of the string above, my TV is accepting any string in here, but I suggest to use this particular one just for compatibility reason.

Payload starts with 2 bytes: 0x64 and 0x00, then comes 3 strings encoded with base64 algorithm. Every string is preceded by 2-bytes field containing encoded string length. These three strings are as follow:

  • remote control device IP,
  • unique ID – value to distinguish controllers,
  • name – it will be displayed as controller name.

TV reply us giving following datagram:

0000    02 0c 00 69 61 70 70 2e 73 61 6d 73 75 6e 67 06  ...iapp.samsung.
0010    00 0a 00 02 00 00 00                             .......

It means:

offset  value and description
------	---------------------
0x00   	don't know, it it always 0x00 or 0x02
0x01	0x000c - string length (little endian)
0x03	"iapp.samsung" - string content
0x0f	0x0006 - payload size (little endian)
0x11	payload

String content is always iapp.samsung or iphone.livingroom.iapp.samsung. Meaning of these strings is unclear, I suggest to not compare it with any specific value during response parsing (maybe other devices using another values).

Payload is one of the following:

  • 0x64, 0x00, 0x01, 0x00 – access granted, you can now send key codes and it will be executed by TV,
  • 0x64, 0x00, 0x00, 0x00 – access denied – user rejected your network remote controller,
  • 0x0A, 0x00, 0x02, 0x00, 0x00, 0x00 – waiting for user to grant or deny access for your app,
  • 0x65, 0x00 – timeout or cancelled by user.
Access is granted only during current TCP connection, when your app or TV disconnect, you have to repeat the authentication process.

 2. Sending key codes

Now you can send simple datagrams containing key codes.

0000    00 13 00 69 70 68 6f 6e 65 2e 69 61 70 70 2e 73  ...iphone.iapp.s
0010    61 6d 73 75 6e 67 11 00 00 00 00 0c 00 53 30 56  amsung.......S0V
0020    5a 58 31 5a 50 54 46 56 51                       ZX1ZPTFVQ

It means:

offset  value and description
------	---------------------
0x00   	always 0x00
0x01	0x0013 - string length (little endian)
0x03	"iphone.iapp.samsung" - string content
0x16	0x0011 - payload size (little endian)
0x18	payload

And the payload is:

offset  value and description
------	---------------------
0x18   	three 0x00 bytes
0x1b	0x000c - key code size (little endian)
0x1d	key code encoded as base64 string

TV response will be similar to authentication response, but with different payload data. I will not describe this data detailed because I wasn’t investigated it much.

Key codes list is published in SamyGO wiki: http://wiki.samygo.tv/index.php5/D-Series_Key_Codes

Useful information can be found also in SamyGO Android Remote sources.

[EDIT]

Benoit Dumasin created easy to use C++ class (using QT library) able to control Samsung TV: https://github.com/Bntdumas/SamsungIPRemote  (he also provided an example QT widget).

[EDIT]

Here is Wireshark protocol dissector create by Konstantin Salikhov (Koka58).

MSI Wind – making System Control Manager more likeable

System Control Manager is an MSI software designed to handle keyboard shortcuts with Fn key for Wind netbooks. Since I have Wind U115 with hybrid hard disc (8GB SSD drive for system and 160GB mechanical drive for data which can be turned off due to lower energy consumption) I am forced to use. IMHO it is very unreliable, uncomfortable and unstable piece of software.

Am I really forced to use it? Not if I know assembler 🙂

SCM have 2 main functions: showing the OSD (icons like WiFi turn on/off etc)  and to switch on and off HDD (when I type HDD I mean the mechanical drive to distinguish it from solid state drive – SSD).

What is wrong with SCM? It’s sometimes not loading properly or loading very long. There are inconvenience related to switching the HDD. And it is very ugly. When I using Fn+F10 to switch off the HDD the ugly window shows up and ask me for confirmation. Well, if I wouldn’t be sure that I want to turn that thing off, certainly I wouldn’t press the Fn+F10 right? But even worse is – this window often loose its focus and it shows up not on top. It’s annoying. OK, lets launch IDA Pro.

How does it work?

System Control Manager consist of 3 main files:

  • MGSysCtrl.exe – tray application,
  • MSIService.exe – service that actually do all the magic,
  • MSIWmiAcpi.dll – library that communicate with the service,
  • MGKBHook.dll – library to set the global hook to keyboard.

HDD off confirmation window are enclosed in MGSysCtrl. Interesting functions I’ve found:

set_hdd_off     equ 0x415290    ; BOOL __cdecl set_hdd_off()
set_hdd_on      equ 0x4156D0    ; BOOL __thiscall set_hdd_on(void *this)
set_hdd_state   equ 0x40E330    ; int __cdecl set_hdd_state(bool hdd_on)
show_hdd_window equ 0x415890    ; int __thiscall show_hdd_window(void *this)
endDialog       equ 0x42AF65    ; int __stdcall CDialog::EndDialog(int nResult)

Purpose of first three functions are obvious. Fourth one is called when the window is created. Last function is closing the confirmation window. We can use it to disable the confirmation window and to turn off the HDD without confirmation (just Fn+F10). To do that I’ve created some patch (nasm code):

set_hdd_state    equ 0x40E330
endDialog        equ 0x42AF65

use32

org 0x415890
    mov esi, ecx    ; need this ?
    push 1
    call endDialog

    push 0
    call set_hdd_state
    add esp, 4
    mov eax, 1
    ret

It changes show_hdd_window() function to call endDialog() and then set_hdd_state(1). I know it’s ugly solution (creating window and closing it instantly) but I couldn’t manage pretty way to do that. In theory it should be possible to disable function that shows up the window, but I was unable to do that, MSGSysCtrl always crash. My ugly solution is doing its job, and as they say – if it works, don’t touch it.

Now it works much better. But still there are things to improve. I actually consider to write my own app to replace the original SCM. But there is still much to reverse. Or maybe I’ll use original service and dlls to just write my own OSD + HDD controlling program?

MGSysCtrl-mod.rar