Thursday, February 25, 2021

Password Checking Function in x86 Assembly

I recently came across this programming assignment that someone posted on the Internet. The task was to convert the following x86 assembly language into C source code.
proc near
push sPassword
call _strlen
pop ecx
mov esi, eax
mov ebx, offset sMyPassword
push ebx
call _strlen
pop ecx
cmp esi, eax
jz short loc_4012B2
xor eax, eax
jmp short end_proc
loc_4012B2:
push esi
push ebx
push sPassword
call _strcmp
add esp, 8
test eax, eax
jnz short loc_4012CC
mov eax, 1
jmp short end_proc
loc_4012CC:
xor eax, eax
end_proc:
pop esi
pop ebx
pop ebp
retn
endp
Well, tasks and assignments like these often get asked on online programming forums, so I googled "loc_4012B2". Sure enough, it was on stackoverflow and several other websites. The stackoverflow link is now dead though, and those sites don't really show you the process, only the result. So here's my take on this problem:
; eax = retval
; esi = a
; assume we start with an empty stack

proc  near                      ; void checkPassword() // start of function, let's give it a meaningful name

push  sPassword                 ; // stack: sPassword
call  _strlen                   ; int retval = strlen(sPassword);
pop   ecx                       ; // stack:
mov   esi, eax                  ; int a = retval;

mov   ebx, offset sMyPassword   ; // because we cannot push a value from memory to the stack
push  ebx                       ; // stack: sMyPassword
call  _strlen                   ; retval = strlen(sMyPassword);
pop   ecx                       ; // stack:
cmp   esi, eax                  ; if (a == retval)
jz    short loc_4012B2          ;   goto loc_4012B2;

xor   eax, eax                  ; retval = 0;
jmp   short end_proc            ; goto end_proc;

loc_4012B2:
push  esi                       ; // stack: esi
push  ebx                       ; // stack: sMyPassword
push  sPassword                 ; // stack: sPassword, sMyPassword, esi
call  _strcmp                   ; retval = strcmp(sPassword, sMyPassword);
add   esp, 8                    ; // stack: esi
test  eax, eax                  ; if (retval != 0)
jnz   short loc_4012CC          ;     goto loc_4012CC;
mov   eax, 1                    ; retval = 1;
jmp   short end_proc            ; goto end_proc;

loc_4012CC:
xor   eax, eax                  ; retval = 0;

end_proc:
pop   esi                       ; // stack:
pop   ebx                       ; // must have been pushed to the stack before
pop   ebp                       ; // and this one too
retn                            ; return retval;
endp                            ; // end of function
If we remove all the comments, we get:
void checkPassword() {
    int retval = strlen(sPassword);
    int a = retval;
    retval = strlen(sMyPassword);
    if (a == retval)
        goto loc_4012B2;
    retval = 0;
    goto end_proc;
loc_4012B2:
    retval = strcmp(sPassword, sMyPassword);
    if (retval != 0)
        goto loc_4012CC;
    retval = 1;
    goto end_proc;
loc_4012CC:
    retval = 0;
    return retval;
}
We can simplify the code like this:
void checkPassword() {
    int retval;
    int a = strlen(sPassword);
    if (a == strlen(sMyPassword))
        goto loc_4012B2;
    return 0;
loc_4012B2:
    if (strcmp(sPassword, sMyPassword) != 0)
        goto loc_4012CC;
    return 1;
loc_4012CC:
    return 0;
}
We can actually insert else statements to make the code easier to refactor:
void checkPassword() {
    if (strlen(sPassword) == strlen(sMyPassword))
        goto loc_4012B2;
    else
        return 0;

loc_4012B2:
    if (strcmp(sPassword, sMyPassword) != 0)
        goto loc_4012CC;
    else
        return 1;

loc_4012CC:
    return 0;
}
Now we can remove all the goto statements and simplify a bit more:
void checkPassword() {
    if (strlen(sPassword) == strlen(sMyPassword))
        if (strcmp(sPassword, sMyPassword))
            return 0;
        else
            return 1;
    else
        return 0;
}
It looks like a jumbled-up mess, though. Remember the else statements we added? We can do this instead:
void checkPassword() {
    if (strlen(sPassword) != strlen(sMyPassword))
        return 0;

    if (strcmp(sPassword, sMyPassword))
        return 0;

    return 1;
}
It turned out to be a simple function. This reminds me why I love C: it allows us to do anything we want, and at the same time it doesn't make the code overly complicated like assembly.

Wednesday, December 30, 2020

Install YouTube Vanced without Root on MIUI Devices

On non-MIUI devices, we can use Vanced Manager to seamlessly install YouTube Vanced and its accompanying microG.

On MIUI, it's a bit more cumbersome -- we need to disable MIUI optimizations before we can install YouTube Vanced.

There is actually another way if you have a laptop with adb.

  1. Download and install Vanced Manager.
  2. Open Vanced Manager, install microG and Vanced. This will fail for both apps, just choose "Close" each time.
  3. Open a file manager, and go to /sdcard/Android/data/com.vanced.manager/files
  4. There is a microg folder, install the apk file inside this folder.
  5. There is a vanced folder, copy all the apk files inside this folder to your laptop, for example into ~/vanced
  6. Now you can uninstall Vanced Manager if you want.
  7. On your device, sign in to your Mi account.
  8. Enable Developer options
  9. Enable USB debugging
  10. Enable Install via USB
  11. On your laptop, navigate to the folder ~/vanced and execute this command: adb install-multiple *.apk
If the last step is successful, now you have YouTube Vanced installed on your phone.

Tuesday, August 11, 2020

Enable Wakelock Detector without Root

Instead of installing a Chrome extension, just do the following:

  1. Enable USB debugging.
  2. Enable USB debugging (Security settings).
  3. Connect the phone to a laptop and grant BATTERY_STATS permission to WLD:
    adb shell pm grant com.uzumapps.wakelockdetector.noroot android.permission.BATTERY_STATS


Sunday, June 7, 2020

Enable Video Streaming from Google Drive

If you have trouble playing videos directly on Google Drive, the solution is actually simple. Just add google.com and youtube.com to the whitelist. This will also enable playing videos directly inside Google Slides.

To do so, open this link in your Chrome or Chromium browser: chrome://settings/content/cookies

Then click the "Add" button on the "Allow" section, and add these entries:
  • [*.]google.com
  • [*.]youtube.com
This might seem to enable cookies for something like fakedomaingoogle.com & fakedomainyoutube.com, but for now it works.

Thursday, February 13, 2020

Installing Windows 10 on a Modern Laptop or PC with a USB Flash Drive

It turns out that it is easy to install Windows 10 on a modern laptop or PC with EFI support. In this case, we will be using a USB flash drive so that installation is fast. Note that everything I put on this blog post is 100% legal.

  1. Download Windows 10 ISO 64-bit version from Microsoft: https://www.microsoft.com/en-us/software-download/windows10ISO
  2. Unpack the ISO file, then separate it into two folders: one for the FAT32 boot partition and another one for the NTFS data partition. More on this later.
  3. (Optional) Add an autounattend.xml file to the boot partition.
  4. Insert a USB flash drive, delete all partitions on it, re-initialize the partition table with GPT, then make two partitions: the first one has to be a FAT32 partition at least 600MB in size, and the second one as an NTFS partition with at least 4.8GB in size. We can do this even in Linux, there is no need to install any boot loader.
  5. Copy the files we prepared earlier accordingly, the contents of each folder copied into the corresponding partitions.
  6. Reboot, enter the BIOS/EFI, enable EFI boot, and choose the USB flash drive as the boot media. Then save your settings and reboot again.
Now, about the two folders for the two separate partitions:
  1. First, extract the ISO file.
  2. Make two directories, let's name them 1-fat32 and 2-ntfs.
  3. Move the sources/ folder into 2-ntfs.
  4. Move everything else into 1-fat32.
  5. Make a new folder sources/ inside 1-fat32, and move sources/boot.wim from 2-ntfs into this newly created folder.
Explanation:
  1. EFI can boot from a USB flash drive without a dedicated boot loader.
  2. EFI cannot boot from an NTFS partition. However, the file sources/install.wim is too large for a FAT32 partition.
  3. Therefore, the solution is to create a FAT32 partition and put all the boot files in it. Then create an NTFS partition and put all the installation files in it.
  4. Boot files include, at least these files: bootmgr, bootmgr.efi, everything inside boot/ and efi/, setup.exe for installation, everything inside support/, and also sources/boot.wim (that's why we need to move it).
  5. Installation files include everything inside sources/ except for the file named boot.wim.

Sunday, April 7, 2019

Linux Mint Laptop Brightness Bug

I'm using Linux Mint on a ThinkPad T420s. There is this strange bug whereby the Brightness Up/Down keys sometimes behave erratically. On classic ThinkPads like mine, the key combination is Fn+Home and Fn+End. This problem is at least partly caused by the different algorithms of the power manager of the desktop environment (Cinnamon or MATE) and the laptop firmware. The power manager calculates the steps in linear steps, but the laptop doesn't do that.


This behaviour is different between Linux Mint 19.1 Cinnamon and MATE. It is also different in Ubuntu 18.04.1.

In the Live DVD (thus more or less the default install), we can observe this. In the Live DVD of Linux Mint 19.1 MATE, this problem manifests itself as erratic brightness key behaviour. For example, when we press Brightness Up and then Brightness Down, sometimes the brightness does not go back to the original value. Also, when we dial down the brightness to the minimum and then press Brightness Down again, the screen briefly turns off and then on again.

This problem is not observed in the Live DVDs of Linux Mint 19.1 Cinnamon and Ubuntu 18.04.1. I have not investigated Ubuntu 18.04.1, but in Linux Mint 19.1 Cinnamon, it is because of this default setting:


$ gsettings get org.cinnamon.settings-daemon.plugins.power backlight-helper-preference-order
org.cinnamon.settings-daemon.plugins.power backlight-helper-preference-order ['firmware', 'platform', 'raw']


csd-power reads this setting, and then it calls csd-backlight-helper with those values. For example, with the setting above, csd-power will call csd-backlight-helper like this:

/usr/lib/x86_64-linux-gnu/cinnamon-settings-daemon/csd-backlight-helper --get-brightness -b firmware -b platform -b raw

Upon receiving that command, csd-backlight-helper looks for the brightness file with the type firmware, then if it's not found it looks for a brightness file with the type platform, and if it's also not found then it looks for a brightness file with the type raw. The way it does this is by asking for the list of backlight devices:

csd_backlight_helper_get_best_backlight (gchar** preference_list)
{
        GList *devices;
        GUdevClient *client;
        client = g_udev_client_new (NULL);
        devices = g_udev_client_query_by_subsystem (client, "backlight");
...

And then looking for one that matches the type specified in the command line. And the way it does that, is by querying the type file in the sysfs device directory:

csd_backlight_helper_get_type (GList *devices, const gchar *type)
{
        const gchar *type_tmp;
        GList *d;
        for (d = devices; d != NULL; d = d->next) {
                type_tmp = g_udev_device_get_sysfs_attr (d->data, "type");
...

What it essentially does it, it looks in the directory /sys/class/backlight, then for each subdirectory, it reads the file <subdir>/type, then checks its contents. If it matches the requested type, then proceed. On my laptop, there are two subdirectories (actually, links to other sysfs directories): acpi_video0 and intel_backlight. /sys/class/backlight/acpi_video0/type contains firmware, and /sys/class/backlight/intel_backlight contains raw. Both of these subdirectories contain a brightness file, which can be used to set the brightness. There is also an actual_brightness file, which is read-only, but so far it seems that actual_brightness and brightness always contain the same value. I might be wrong, so please comment if you have more information.
Now, the problem is that both the power manager and the laptop's firmware set the brightness. They really do this twice. And they sometimes have different ideas. If we tell csd-backlight-helper to use the firmware control method, all is fine because on this laptop, the brightness values exposed by the firmware is 0 through 15 and is linear. For example, if the current brightness is 8 and we press the Brightness Up key, then csd-power reads the maximum brightness and current brightness, calculates the next step, and sets the brightness to 9. It then verifies what it's done by reading the maximum brightness and current brightness again, and shows the change with the OSD.
If we use the platform control method, the OSD doesn't show up because on this laptop there is no backlight device with the platform control method.
However, if we use the raw control method, there is a problem. The laptop itself sets the brightness with these values: (the numbers on the left column are the corresponding brightness values obtained via the firmware backlight device)

15  4437
14  3567
13  2871
12  2262
11  1775
10  1392
 9  1096
 8  853
 7  626
 6  470
 5  348
 4  261
 3  191
 2  139
 1  104
 0  70
We can see that the steps are not linear. However, using the raw interface, we can manually set the brightness to any value.
This is what happens to the raw brightness value when we use the raw method:

4437 --> the original, maximum brightness value corresponding to 15 on the firmware's reported brightness

4216 --> the original brightness value minus 221
3567 --> the brightness value set by the laptop itself, corresponding to brightness level 14

3346 --> 3567 minus 221
2871 --> brightness value corresponding to level 13

2650 --> 2871 minus 221
2262 --> brightness value corresponding to level 12

2041 --> 2262 minus 221
1775 --> brightness value corresponding to level 11

1554 --> 1775 minus 221
1392 --> brightness value corresponding to level 10

1171 --> 1392 minus 221
1096 --> brightness value corresponding to level 9

875  --> 1096 minus 221
853  --> brightness value corresponding to level 8

632  --> 853 minus 221
626  --> brightness value corresponding to level 7

405  --> 626 minus 221
470  --> brightness value corresponding to level 6

249  --> 470 minus 221
348  --> brightness value corresponding to level 5, NOTE THAT the brightness actually increased

127
261  --> brightness value corresponding to level 4

40
191  --> brightness value corresponding to level 3

0
139  --> brightness value corresponding to level 2

0
104  --> brightness value corresponding to level 1

0
70   --> brightness value corresponding to level 0

0
70   --> brightness value corresponding to level 0

... and so on. Also note that 4437 = 221 x 20 + 17, and 221 = 17 x 13.
So this is why with the raw method, the brightness jumps around somewhat. This also happens in MATE, because mate-power-backlight-helper always uses the intel_backlight interface. This code snippet is from mate-power-manager/src/gpm-backlight-helper.c:

 /* available kernel interfaces in priority order */
 static const gchar *backlight_interfaces[] = {
  "gmux_backlight",
  "nv_backlight",
  "nvidia_backlight",
  "intel_backlight",
  "dell_backlight",
  "asus_laptop",
  "toshiba",
  "eeepc",
  "eeepc-wmi",
  "thinkpad_screen",
  "acpi_video1",
  "mbp_backlight",
  "acpi_video0",
  "fujitsu-laptop",
  "sony",
  "samsung",
  NULL,
 };

I also found some kind of workaround. In MATE, if we set /sys/module/video/parameters/brightness_switch_enabled to N, the brightness doesn't jump around, but there is a bug that resets the brightness when we plug or when we unplug the ac adapter. The alternative is to chmod /sys/class/backlight/intel_backlight/brightness to 444, so mate-power-backlight-helper can't modify the brightness and it just lets the laptop to set its own brightness, without the need to set /sys/module/video/parameters/brightness_switch_enabled to N.
The laptop does the brightness adjustment by means of ACPI events. In drivers/acpi/acpi_video.c,

static void brightness_switch_event(struct acpi_video_device *video_device,
        u32 event)
{
 if (!brightness_switch_enabled)
  return;

 video_device->switch_brightness_event = event;
 schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10);
}
Looking at that code, it seems that the event being handled with a delay. This means there is a possible race condition with csd-power / gsd-power / mate-power-manager. Also, it seems that the acpi event modifies the brightness after the power manager does, maybe because of the delayed work. Therefore, with the chmod workaround, the OSD still shows up, but it's delayed. When we turn up the brightness to maximum (15 on firmware and 4437 on raw), the OSD still shows an incomplete (not full) brightness bar. This is because the power manager manages to get priority execution and reads the brightness value before the video acpi module changes the value.










Thursday, January 3, 2019

Cat 6 Cables

The other time I needed to connect two offices located inside one industrial complex, but located quite far from each other. Then I also needed to rewire some cables at home, so it was the perfect opportunity to test cable quality.

Here is the data:

Belden Cat 6 Solid Copper wire, Original product (I have to say this because there are many fake Belden products, so we need to specify which product we were testing)
  • 196m 100Mbps 

Telebit Cat 6 Solid CCA wire, I'm not aware of fake Telebit cables
  • 215m 10Mbps (FTP ~ 1.1 MB/s)
  • Initially the link went up at 100Mbps, but it renegotiated the speed and came down to 10Mbps instead 
  • 170m 100Mbps (FTP ~ 11 MB/s) 
  • 120m & 90m 1000Mbps (FTP ~ 100MB/s) 

I will update the post with more data when I test some more cables.

Saturday, November 19, 2005