Summerschool Aachen 2004/Malware Lab

From C4 Wiki
Jump to: navigation, search

Notes about Presentation

ELF Tools and others

Notes about Lab Session

more elf tools

  • elfsh - elf shell

small quiz

There is a really small quiz consisting of just one question here.

The Quiz, Question 1

The perl scripts execute the system call with the number 4, sys_write(), supplying a file descriptor of "1", which denotes stdout, the standard address of the ELF header of the binary (probably the perl interpreter) being executed (increased by 1 to skip the leading 0x7f) and an output length of "3". The perl script outputs "ELF" on my Linux box.

The Quiz, Question 2

I found out that the "yourtoy" file was a UPX - compressed file pretty fast. But trying to uncompress it with the upx utility didn't succeed as the file seemed to be corrupt.
I then tried upx'ing two other files, creating hexdumps of them and then doing a "diff3" on the hexdumps. I noticed that there were some areas where the other files matched but differed from "yourtoy" so I tried overwriting the corresponding areas in "yourtoy" with a hexeditor with the values found in the other files, but this did not work out.
After that i downloaded the source code for upx and ucl (the library upx uses) and used ddd to debug upx. I traced through several function calls until I found the one that finally returned the information "this is not a valid upx file". That function just searched the to-be-uncompressed file for some magic string, which it didn't find in "yourtoy". I then had a look at the other files I had created to find out that those contained the string twice whereas "yourtoy" only contained it once and instead of a second occurence contained another magic string of bovine origin. I replaced that with the correct string and was finally able to uncompress "yourtoy".

-- Lutz Böhne

I too had no problem finding the UPX header information in the packed binary. I tried to understand the UPX header format in order to be able to find bugs in the yourtoy compressed executable. After starring at it for a while and not knowing why the four bytes I thought were the version number were not at all what I expected, I tried to find the origin of the NotPackedException (btw. you only get it if you do a "upx -d yourtoy"). But after like five files of C++ code I can only barely read I gave up about this. I then upx'ed another binary and compared it to the provided one in order to find differences. But I only had a look at the top of the file b/c that's where I thought the header resided. Of course I had no luck with this either, so I jumped back into the source, finally finding a comment which explained the file layout. Now that I knew I had to look at the bottom, things were pretty straightforward. By changing only three bytes you could make the UPX file actually behave like it was supposed to...

-- Ernest Hammerschmidt

I did things a bit different. When I noticed that *someone* had messed up the upx header (or is it footer ?) I tried to look for documentation on the upx site. I didn't find any decent documentation on their site and didn't feel like looking at the source code because experiece has told me that such a thing can take a while (and we only have a couple of hours for the labsession). After some playing around with a hexeditor (to try and figure out what got changed) I got bored with the hexeditor and started looking at the manual file of upx. It said something interesting:


       How it works:

         Because Linux is a real operating system, the in-place in-memory
         decompression scheme used in the other executable formats doesn't
         work here.

         Instead we must use temporary decompression to disk. Interestingly -
         because of the good memory management of the Linux kernel - this
         often does not introduce a noticable delay, and in fact there
         will be no disk access at all if you have enough free memory as
         the entire process takes places within the filesystem buffers.

         A compressed executable consists of the UPX stub and an overlay
         which contains the original program in a compressed form.

         The UPX stub is a statically linked ELF executable and does
         the following at program startup:

           1) decompress the overlay to a temporary location in /tmp

Hm, so it gets decompressed in some temp file. To test this I made a test user and used the strace utility to see if this was true:

test@%m:%~% strace -i -s 10  ./yourtoy 
[????????] execve("./yourtoy", ["./yourtoy"], [/* 32 vars */]) = 0
[08048296] getpid()                     = 1664
[080482cf] open("/proc/1664/exe", O_RDONLY) = 3
[080482f1] lseek(3, 1468, SEEK_SET)     = 1468
[08048232] read(3, "\27\4`\341"..., 12) = 12
[08048351] gettimeofday({1097073253, 115757}, NULL) = 0
[0804837c] unlink("/tmp/upxBXX3ARQABUA") = -1 ENOENT (No such file or directory)
[0804839d] open("/tmp/upxBXX3ARQABUA", O_WRONLY|O_CREAT|O_EXCL, 0700) = 4
[080483aa] ftruncate(4, 15996)          = 0
[080483bc] old_mmap(NULL, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40000000
[08048232] read(3, "|>\0\0\315"..., 8)  = 8
[08048232] read(3, "\177?d\371"..., 5837) = 5837
[0804846d] write(4, "\177ELF\1\1"..., 15996) = 15996
[0804858b] unlink("/tmp/upxBXX3ARQABUA") = 0
[08048590] _exit(134518160)             = ?

Aha ! so it just gets uncompressed and stored in some file in /tmp. I then fired up my debugger, set a breakpoint at 0x08048589 (right before the unlink()) and ran it. at this point it was uncompressed and not deleted yet. Then I ran file to see if that is the real binary:

test@%m:%~% ls -alhp *upxB* -rwx------ 1 test users 16K Oct 6 12:39 upxBXX3ARQABUA test@%m:%~% file upxBXX3ARQABUA upxBXX3ARQABUA: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped test@%m:%~%

I found what I needed to solve the second question. hooray :)

-- Ilja van Sprundel

I tried to find errors in the ELF header, but it looked alright. In desperation i ran strace against the binary and discovered the tempfile. Grabbing tempfiles is quite easy...

# first term
while true; do ./yourtoy; done 
# other term
cd tmp; while true; do cp upx* old.`date +%H%M%S` 2>/dev/null; done

After a minute i stopped the loops and used "file" to discover a working copy.

--MM 17:22, 6 Oct 2004 (CEST)