1

I have a Linux system which is running in an embedded system. For various reasons I can't get into (or I'll get fired), I don't have direct access to this system through normal means like a keyboard, or SSH. I know, I know, it's evil to change an executing file, but please trust that if I had an alternative, I would take it.

On this system, which is built around an ARM CPU, there is an executable which is pure ARM machine code (compiled from C++). A bug has been found in this code. I found that the bug can be fixed by replacing a UXTB instruction with a UXTH instruction. Luckily for me, that requires changing an opcode byte from 0xEF to 0xFF. This patch can be performed by simply running the following command:

printf '\xff' | dd of=path/to/executable bs=1 seek=$((0x01ce22)) conv=notrunc

The byte being modified is part of a function that only gets called when this embedded system receives a particular command. I can absolutely guarantee that this command will not be sent while I am performing this patch. Therefore, there are no dangers involving differing versions of code in RAM and storage.

Unfortunately, the program that needs to be changed (which, again, initiates on system startup) is also the program I am relying on that allows me to have the little access I do to this system. So I can't kill that process, lest I lose access.

Is there any possibility I could modify this one byte of the executable, this single little bitty byte that isn't directly being used?

Maybe the best solution would be to use a shell script which kills the main process, changes the byte, then activates a reboot? Ideally I'd like for the system to stay alive, such that I can see that the change succeeded.

I have a test case script running on an identical system, which I do have direct SSH access into. The test script is a C++ script which just outputs a value to a file 1000 times, in 0.1 second increments. I disassembled it and found the byte which holds that constant value, and similarly to the above printf | dd command, I can modify that constant - but only when the program is not running. An ideal solution to me would be one where I can modify that constant on-the-fly, so that the output file holds 500ish of the as-made-in-C++ value, and 500ish of the value I have clobbered into the proper byte.

Thanks for any help or suggestions you can provide.

4
  • Please edit your question and explain what kind of access (or what means to modify which parts of the system) you do have, if you don't have ssh or something similar. – dirkt Dec 30 '20 at 13:13
  • I have access over a UART which is interpreted by a running script. All I need to know is whether it is possible in any fashion to work around the error dd: failed to open 'executable_file': Text file busy. That's the error I get when I run the command I listed in the original post, while the executable is running. – Murphy Dec 30 '20 at 16:29
  • "Text file busy" means the executable file is being executed at that moment, so you can't write to it. And if you can't do it with dd, you can't do it with anything else. So it won't work this way, unless your script allows other things (like executing a debugger to attach to the running process), or you can modify other things through the script. And maybe that's a good thing, because besides "fixing" executables, you can of course also "hack" them (and this will get you fired for sure). – dirkt Dec 30 '20 at 17:18
  • You might be able to use dd with of=/proc/XXXX/mem to update the in-memory copy of the running program where XXXX is the PID of the running process. You will need a different offset from the one you have calculated. /proc/XXXX/maps is a text file that will help you calculate the new offset. – icarus Jan 1 at 9:54
0

Linux and most other Unix operating systems don't permit you to actually modify the binary that is being executed. If you attempt to open such a file for write, you'll get an ETXTBSY error (Text file busy). That's because the binary may be memory mapped and modifying the file would modify the binary, almost certainly in an undesired way. The kernel also may not gracefully handle this case.

However, you can copy the file to the side, modify it there, and then call rename(2) (or something that uses it, like mv(1)) to rename the new binary over the old one. This works because the old binary is still on disk but is inaccessible by any name of the file system, and remains so until the last user closes it. If you re-exec the binary, then it will pick up the new version.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.