One of my Favorite "Workarounds"
Sep 26, 2013
2 minute read

The back story

Today’s AMD Catalyst Linux beta driver removes the long-standing “Testing use only” watermark:

watermark

watermark_four

Congratulations to the voice of reason!

Last year I needed to use the beta driver for a while until a bug was fixed in the next release. It’s obnoxious to have translucent watermarks on top of everything you’re doing, so I asked AMD support how to disable it. They recommended a small script from a third-party site as a workaround. Let’s discuss how it works!

The Script

    #!/bin/sh
    DRIVER=/usr/lib/fglrx/xorg/modules/drivers/fglrx_drv.so
    for x in $(objdump -d $DRIVER|awk '/call/&&/EnableLogo/{print "\\x"$2"\\x"$3"\\x"$4"\\x"$5"\\x"$6}'); do
       sed -i "s/$x/\x90\x90\x90\x90\x90/g" $DRIVER
    done

The first line sets a convenient variable to the absolute path of the driver:

DRIVER=/usr/lib/fglrx/xorg/modules/drivers/fglrx_drv.so

We then loop over the output of a compound command:

objdump -d $DRIVER |awk '/call/&&/EnableLogo/{print "\\x"$2"\\x"$3"\\x"$4"\\x"$5"\\x"$6}'

objdump -d disassembles the binary, yielding ~90 megabytes of output like this:

...
 3717c0:     48 83 ec 08     sub $0x8,%rsp
 3717c4:     49 89 f0        mov %rsi,%r8
 3717c7:     48 89 f9        mov %rdi,%rcx
...

This is x86 (x86_64) assembly – on the left is the address, the bytes in the middle are the encoding of the instructions, and on the right is the assembly representation.

This is piped into an awk command that does several things. First it filters for lines that contain “call” and “EnableLogo”; these commands are equivalent:

objdump -d $DRIVER |awk '/call/&&/EnableLogo/{print $0}'
objdump -d $DRIVER |grep call |grep EnableLogo

If you grep the driver’s disassembly like this, you’ll see twenty something calls to the atiddxEnableLogo() function:

cat fglrx.objd |grep call |grep EnableLogo
 381548:     e8 f3 d8 fd ff     callq 35ee40 <atiddxEnableLogo@plt>
 3ae624:     e8 17 08 fb ff     callq 35ee40 <atiddxEnableLogo@plt>
 3ae9e7:     e8 54 04 fb ff     callq 35ee40 <atiddxEnableLogo@plt>
...

From these matching lines, the original awk command selects whitespace-delimited columns 2-5 (the encoding bytes), formats and prints them :

cat fglrx.objd |awk '/call/&&/EnableLogo/{print "\\x"$2"\\x"$3"\\x"$4"\\x"$5"\\x"$6}'
\xe8\xf3\xd8\xfd\xff
\xe8\x17\x08\xfb\xff
\xe8\x54\x04\xfb\xff

With the compound command complete, each of these formatted lines is then passed to the following sed command:

sed -i "s/$x/\x90\x90\x90\x90\x90/g" $DRIVER

This simply replaces one binary sequence with another within the file. All occurrences of the given sequence (e.g. 0xE8F3D8FDFF) turn into 0x9090909090. This turns the five-byte call instruction into five one-byte no-op instructions.

This is a shotgun approach that risks inadvertently replacing the same sequence elsewhere – it may stomp on code or data elsewhere in the binary. In this case it works.

TL;DR

This tiny “workaround” script disassembles the driver binary, finds all the calls to EnableLogo(), and patches them out.