User Tools

Site Tools


Sidebar

General

Namespaces

guides:windows:lenovo_bluetooth_and_windows_8.1

Lenovo, Bluetooth and Windows 8.1

Let's talk about Lenovo. In Lenovo, when you manufacture a notebook with a Bluetooth feature, you don't permit people enable that feature on their computers. Not obviously of course, you just “forget” to put such option to your management app. “Oh come on, Itachi, Bluetooth isn't such a big deal” - you could say that 15 years ago while sending danzel_-_pump_it_up.mp3 through IrDA for the 5th time. But now, it is really convenient to have Bluetooth. Okay, you have it, but you can't use it. Why? Ask Lenovo.

Some time ago I tried to install Bluetooth on my Lenovo Y580 notebook. It was enabled in BIOS, it was working on Windows 7 before, but when I tried to install drivers under freshly installed (and even genuine) Windows 8.1, this stubborn piece of schmitt was admitting that the device could not be found. Really? Well, the Bluetooth chip inside my laptop must have been an Illuminati's plot. I remembered that Bluetooth needed to be enabled in Lenovo Energy Management on Windows 7, but on it's younger brother I found nothing related to Bluetooth; but, hey, you can now “remove dust” from your fan!

I Googled my issue and finally stumbled upon a workaround that proposed installation of Lenovo Energy Management for Windows 7. I tried that, Windows 8.1 broke into tears because the application wasn't compatible with it, but it worked, I could enable Bluetooth now. Since I was not fully satisfied with such workaround, I reverted the appropriate version of LEM (yay, dust cleaning!), and started thinking.

Lenovo's developers are not exceptionally smart, but they thankfully follow the most well known paradigm: developers are lazy. Though the both versions of Lenovo Energy Management differ in UI, they stil use the same DLL for performing device oriented calls. This is convenient, instead of creating a whole different application for each OS, create one lib with functions and simply replace the UI part. Software developers - 1, UX designers - 0.

The DLL that is a core part of my solution was located under the Lenovo Energy Management directory and was named: LenovoEmExpandedAPI. It has “API” suffix, I like that. Let's check what functions it exports (oh boy, I'm excited like 9 year old on Christmas). To do that I used a very neat program: DLL Export Viewer.

Jackpot! Let see, what can we use… Ah… There it is! SetBluetooth!. This couldn't be more obvious. Although we can't peek (not directly) what arguments that function takes, developers, even the ones from Lenovo, think similar, so the “set” function probably takes a single argument which is a true or false. Okay, but how to quickly check that? We need to code a small program that loads this DLL and calls that function. When the question contains: “quickly” and “code” then the answer is: Python.

from ctypes import 
lib = cdll.LoadLibrary('LenovoEmExpandedAPI')
lib.SetBluetooth(1)

“You must be kidding Itachi…”, no, it's simple as that. If any of the Lenovo's developers read that, you have my permission to use my sophisticated algorithm for free.

Quick analyze

Since we've managed to walk this far, why don't have some fun? For example, let's read the Bluetooth state, there's a dedicated function for that: GetBluetoothStatus. If we try the same trick with Python as before, the only thing that will be returned is disappointment. Instead of the expected status, I was getting “0”, irrespective of the actual Bluetooth status. It looked like this was rather a return code, so the Bluetooth status must be returned in some other way, for example through the argument passed to that function. In order to be 100% sure, I decompiled the DLL and found the function's implementation:

signed __int64 GetBluetoothStatus(_DWORD *a1, int a2) {
  _DWORD *v2;
  int v3;
  signed __int64 result;
  HANDLE v5;
  void *v6;
  void *v7;
  _BYTE *v8;
  BOOL v9;
  DWORD BytesReturned;
 
  v2 = a1;
  v3 = a2;
  if (FindWindowW(L"EnergyCut_Window", 0i64)) {
    v5 = CreateFileW(L"\\\\.\\EnergyDrv", 0xC0000000, 0, 0i64, 2u, 0x80u, 0i64);
    if (v5 == (HANDLE) -1) {
      if (v3) {
        sub_180001390("EM Driver Create Failed.GetBluetoothStatus\r\n");
      }
 
      result = 4372i64;
    }
    else {
      v6 = operator new(0xCui64);
      *((_DWORD *)v6 + 1) = 1;
      *(_DWORD *)v6 = 2;
      v7 = v6;
      v8 = (char *)v6 + 8;
      BytesReturned = 0;
      v9 = DeviceIoControl(v5, 0x831020C4, v6, 4u, (char *)v6 + 8, 4 * *((_DWORD *)v6 + 1), &BytesReturned, 0i64);
      CloseHandle(v5);
      *v2 = v9 && *v8;
      operator delete(v7);
 
      result = 0i64;
    }
  }
  else {
    result = 4377i64;
  }
 
  return result;
}

Yep, I was right, the “0” I was getting is just a return code saying that the command executed successfully. The real Bluetooth state is a return value of DeviceIoControl function. The result is then stored in the pointer passed as a first argument of GetBlueoothStatus function. The second argument looks like a verbosity flag, and the function sub_180001390 must be some kind of logger. Not important to us.

So, now we're finally ready to get the Bluetooth status. We use Python again, and I suppose you still have your library loaded, if so, then do the following:

ret_val = c_int()
lib.GetBluetoothStatus(byref(ret_val), 0)
print(ret_val.value)

c_int() creates a C-like integer variable, and then it's passed by its address to the GetBluetoothStatus function. If you run this code, you should see the actual status of your Bluetooth. Simple? I know it was.

Hey, you know what? This DLL contains more functions. Just sayin'…

Bluedentist

I prepared a tiny program called Bluedentist (~180 KB) that can be used to turn the Bluetooth on or off. It's just a small window with two radio buttons that does the job.

Binary releases are here: https://github.com/ITachiLab/bluedentist/releases

Source code is here: https://github.com/ITachiLab/bluedentist

Before you use Bludentist, make sure you:

  • have Lenovo Energy Management installed on your computer,
  • downloaded version appropriate to your system's architecture.
guides/windows/lenovo_bluetooth_and_windows_8.1.txt · Last modified: 2019/08/10 00:59 by itachi