On 07/25/2017 05:25 PM, Kevin Kofler wrote:
Patrick O'Callaghan wrote:
> Running sed on an executable is unlikely to work:
> $ file /usr/bin/kwrite
> /usr/bin/kwrite: ELF 64-bit LSB shared object, x86-64, version 1
> (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
> for GNU/Linux 2.6.32, BuildID[sha1]=3c378cb60be1e2a76f98
> 1ba5c15c1096f1b6a5b5, stripped
> Also, are you sure you mean 'getpid'?
OK, so let me explain how this hack works (*) (I wanted to let you try and
be amazed first :-p):
* The first thing to observe is that the replacement string has the same
length as the string being replaced. (In fact, I only replace one character
with another, but this does not even matter, as long as the length does not
change.) sed actually has no issues at all with operating on binary files.
The only problem is, if you change the length of the string, you break all
the offsets in the executable and it will stop working. So it is extremely
important that the replacement string also has 6 characters like "getuid".
* Now compare the prototypes of "getuid" and "getpid":
Notice that they are almost the same, only the return type looks different
at first glance. But both uid_t and pid_t are actually 32-bit integers
(technically, uid_t is unsigned and pid_t is signed, but that does not
matter at all at assembly level), so that does not matter. Therefore, it is
safe to call one function instead of the other.
* Symbol versioning might get in your way. But if you check, you will find
that the current symbol version of both "getuid" and "getpid" on
GLIBC_2.2.5, so that will not get in your way either.
* Now look at how the check for root actually works: it does something like:
if (getuid() == 0) fail;
My hack changes this to:
if (getpid() == 0) fail;
The interesting thing is, getpid() == 0 is always false! The PID is never
zero, PID 0 is reserved by the Linux kernel. So the whole check becomes a
no-op and kwrite will always run.
So, all in all, I just had to look for a libc function that has a 6-letter
name, a compatible prototype with getuid, and will never return 0. getpid
was the perfect match. (By the way, if upstream decides to change the check
to check for geteuid instead, which has 7 characters, then you can replace
that with getppid, which is also never 0.)
So next time you should at least try my command before claiming that it will
not work. :-) You should trust an experienced developer with assembly
knowledge like me more than you do. ;-)
(*) To be sure, I have now just tested it on the kwrite binary from
kwrite-17.04.1-1.fc26.x86_64.rpm, and yes, it does work – but I was almost
sure it would work even before testing it. :-) "I have only proved it
correct, not tried it." as Donald Knuth once wrote. ;-) But now I did try it
and it works indeed.
It did work indeed. Great work. Any similar "trick" to get konqueror to use
the --profile option again? :-) I know, of course not.
However, Can someone direct me to where I can find the source code for konqueror? Not
have profiles really cramps my productivity. Even worse that the above kwrite issue.
Enough to maybe actually do something about it.