Courses/Computer Science/CPSC 601.29.ISSA/20110204CodeSession

We first executed a slight modification (for output purposes only) of the Red Pill:

[michael@proton redpill]$ gcc -Wall -g -O0 -o redpill redpill.c [michael@proton redpill]$ execstack -s redpill [michael@proton redpill]$ ./redpill idt base: 0xc0805000 (3229634560) idt limit: 0x7ff (2047) m[0] = 0xff m[1] = 0x07 m[2] = 0x00 m[3] = 0x50 m[4] = 0x80 m[5] = 0xc0 IDTR: ff 07 00 50 80 c0 Not in Matrix [michael@proton redpill]$

We also executed the 'nopill', which tested the GDT and LDT in addition to the IDT, and did it using inline assembly, e.g.:

static unsigned char loc[6]; inline idt idtcheck {   __asm__("sidt %0\n" :"=m"(loc) : ); //... }

For an explanation of inline assembly (not great, but a start), see: http://www.ibm.com/developerworks/library/l-ia.html

Keep in mind little-endian nature of output:

[michael@proton redpill]$ ./nopill IDTR: ff 07 00 50 80 c0 GDTR: ff 00 00 c0 00 c2 LDTR: 00 00 00 c0 00 c2 native machine detected [michael@proton redpill]$

The above execution within a VMware Fusion VM fails to "detect" the VM. We then attempted to see if the nopill or redpill would operate "properly" on a native machine (in this case, Mac OS X). We first need a build environment, so in our Makefile, we have the following target:

rp: rp.asm nasm -f macho rp.asm ld -o rp -e _start rp.o

Making system calls on Mac OS X is a bit different than Linux. This tutorial was helpful: http://michaux.ca/articles/assembly-hello-world-for-os-x

So, we start to write out code. We want to capture information from the IDTR using the SIDT instruction and store it to memory. We can store it to our data area or store it on the stack, or both. We then need to output it somehow, so we issue a write(2) system call to place the bytes on stdout. Note that one of the first things we do is some stack manipulation (not for any real good reason except for a few instructions that save space on the stack for use by SIDT later, but we will easily spot these effects in GDB later).

BITS 32 GLOBAL _start SECTION .data ;; declare space for storing IDTR value m32    db 0x00,0x00,0x00,0x00,0x00,0x00 ;6 bytes, lower 2=limit; upper 4=base m64    db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 SECTION .text _start: xor ecx, ecx           ;clear ECX push ecx               ; \0 null byte push 0xDEAD push 0xBEEF push ecx               ; 0 push 0x0a              ; \n push ecx               ; 4 bytes push ecx               ; 4 bytes push ecx               ; 4 bytes (12 bytes to store 2+8 in) ;; now esp points to a part of memory that has 6 open bytes sidt [m64]             ;one instruction is all it takes sidt [esp]             ;store it here, too: we made space... push dword 0x0a        ;write 10 bytes (10 of IDTR) push dword m64         ;IDTR push dword 0x01        ;stdout mov eax, 0x4           ;write sub esp, 4             ;BSD space on stack int 0x80               ;issue syscall add esp, 16            ;clean up stack push eax               ;write's return value mov eax, 0x01          ; sys_exit sub esp, 4             ; ? int 0x80

Running our assembly implementation of Red Pill and passing the output to hexdump produces:

[michael@xorenduex code]$ ./rp | hexdump 0000000 01 10 00 40 56 7a 00 00 00 00 000000a [michael@xorenduex code]$

These values change for various subsequent invocations; each processor has its own IDT.

For a closer look at the executing binary (and as a way of coming full circle to use a program (gdb) that uses a facility (ptrace) that in turn uses the IDT (INT 3) to inspect another process), we run rp in gdb:

[michael@xorenduex code]$ gdb ./rp GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries. done (gdb) info reg The program has no registers now.

The program has no registers because we haven't asked gdb to run it. GDB is giving us the opportunity to instrument the program first. We ask gdb to stop execution at the address "start" (a symbol we defined in our assembly program). GDB agrees, and kindly reports the actual address rather than the label name.

(gdb) break start Breakpoint 1 at 0x1fac

We then ask GDB to show us what the assembly code at start looks like (this should match what we explicitly wrote above):

(gdb) disassemble start Dump of assembler code for function start: 0x00001fac :	xor   %ecx,%ecx 0x00001fae :	push  %ecx 0x00001faf :	push  $0xdead 0x00001fb4 :	push  $0xbeef 0x00001fb9 :	push  %ecx 0x00001fba :	push  $0xa 0x00001fbf :	push  %ecx 0x00001fc0 :	push  %ecx 0x00001fc1 :	push  %ecx 0x00001fc2 :	sidtl 0x201d 0x00001fc9 :	sidtl (%esp) 0x00001fcd :	push  $0xa 0x00001fd2 :	push  $0x201d 0x00001fd7 :	push  $0x1 0x00001fdc :	mov   $0x4,%eax 0x00001fe1 :	sub   $0x4,%esp 0x00001fe7 <start+59>:	int   $0x80 0x00001fe9 <start+61>:	add   $0x10,%esp 0x00001fef <start+67>:	push  %eax 0x00001ff0 <start+68>:	mov   $0x1,%eax 0x00001ff5 <start+73>:	sub   $0x4,%esp 0x00001ffb <start+79>:	int   $0x80 End of assembler dump.

This output has the nice side effect of giving us some opportunities for inserting other breakpoints. We had a discussion in class here about the limited support for runtime, at-speed process inspection facilities available on x86, and how this is a gaping mismatch between the expectations of security policies, monitoring, and analysis and the actual hardware primitives for a trapping model (point to work with Sean and Sergey at Dartmouth).

(gdb) break 0x1fc2 Function "0x1fc2" not defined. Make breakpoint pending on future shared library load? (y or [n]) n

The problem exists between the keyboard and chair on this one. GDB thinks I'm asking for a breakpoint at symbol (e.g., a function name). I need to give the correct syntax to indicate that I want a breakpoint at a specific address. I continue to set up breakpoints before each SIDT instruction and before the write system call gets dispatched.

(gdb) break *0x1fc2 Breakpoint 2 at 0x1fc2 (gdb) break *0x1fc9 Breakpoint 3 at 0x1fc9 (gdb) break *0x1fcd Breakpoint 4 at 0x1fcd (gdb) break *0x1fe7 Breakpoint 5 at 0x1fe7

I can ask for the register values again, but the program still isn't running. But I don't have to type `info reg', I can abbreviate.

(gdb) i r   The program has no registers now.

Well, let's run it.

(gdb) run Starting program: /Users/michael/data/cvs/Calgary/teaching/ISSA/2011/code/rp Breakpoint 1, 0x00001fac in start

OK, now can I ask for the register values? Yes! Note that EIP is pointing to the next instruction to be executed, and that instruction happens to be the first instruction because GDB interrupts control before executing an instruction.

(gdb) i r eax           0x1fac	8108 ecx           0x603c2a4f	1614555727 edx           0x0	0 ebx           0x1000	4096 esp           0xbffff3f0	0xbffff3f0 ebp           0x0	0x0 esi           0x0	0 edi           0x0	0 eip           0x1fac	0x1fac eflags        0x296	662 cs            0x17	23 ss            0x1f	31 ds            0x1f	31 es            0x1f	31 fs            0x0	0 gs            0x37	55

Well, nothing much to see here. Let's keep moving along with the "continue" command. This command tells GDB to let the program go away and execute instructions until the next breakpoint.

(gdb) cont Continuing. Breakpoint 2, 0x00001fc2 in start

Let me just ask for a subset of "interesting" registers for now.

(gdb) i r eax ebx ecx edx eip esp eax           0x1fac	8108 ebx           0x1000	4096 ecx           0x0	0 edx           0x0	0 eip           0x1fc2	0x1fc2 <start+22> esp           0xbffff3d0	0xbffff3d0

Hmmmm. The value in ESP is the top of the stack, so let's examine memory there using the `x' command.

(gdb) x/16 esp No symbol table is loaded. Use the "file" command. (gdb) x/16 %esp A syntax error in expression, near `%esp'.

Again, PEBKAC. Consult the gdb manual for syntax! Once we know how to speak to gdb, we see that our stack has all the results of pushing \n, deadbeef, and the cleared ecx.

(gdb) x/16 $esp 0xbffff3d0:	0x00000000	0x00000000	0x00000000	0x0000000a 0xbffff3e0:	0x00000000	0x0000beef	0x0000dead	0x00000000 0xbffff3f0:	0x00000001	0xbffff4cc	0x00000000	0xbffff507 0xbffff400:	0xbffff576	0xbffff592	0xbffff5bc	0xbffff5c7 (gdb) cont Continuing. Breakpoint 3, 0x00001fc9 in start

We just executed the SIDT instruction involving the store to m64, our memory location in .data. Perhaps we can look at it?

(gdb) x/16 m64 Value can't be converted to integer.

Well, we actually know the address.

(gdb) x/16 0x201d 0x201d :	0x30001002	0x00007a77	0x00000000	0x00000000 0x202d:	0x00000000	0x00000000	0x00000000	0x00000000 0x203d:	0x00000000	0x00000000	0x00000000	0x00000000 0x204d:	0x00000000	0x00000000	0x00000000	0x00000000 (gdb) cont Continuing. Breakpoint 4, 0x00001fcd in start

After the next SIDT instruction, we should see the result on the stack. We do see a result, but it differs from what is in m64. What's going on?

(gdb) x/16 $esp 0xbffff3d0:	0xf0001003	0x00007a8b	0x00000000	0x0000000a 0xbffff3e0:	0x00000000	0x0000beef	0x0000dead	0x00000000 0xbffff3f0:	0x00000001	0xbffff4cc	0x00000000	0xbffff507 0xbffff400:	0xbffff576	0xbffff592	0xbffff5bc	0xbffff5c7 (gdb) cont Continuing. Breakpoint 5, 0x00001fe7 in start

Let's look at the stack before executing the system call. Looks like we are going to write 10 bytes (0x0000000a) starting at 0x0000201d to stdout (0x00000001).

(gdb) x/16 $esp 0xbffff3c0:	0x00000000	0x00000001	0x0000201d	0x0000000a 0xbffff3d0:	0xf0001003	0x00007a8b	0x00000000	0x0000000a 0xbffff3e0:	0x00000000	0x0000beef	0x0000dead	0x00000000 0xbffff3f0:	0x00000001	0xbffff4cc	0x00000000	0xbffff507 (gdb) cont Continuing. 0wz Program exited with code 012.

Looks like our output (remember, we're writing m64, not what was stored on esp) translates to ASCII 0wz (recall we passed this directly to hexdump before). The program also reports that it printed 012 characters. Remember in the assembly we saved the return value of write(2), which is the number of bytes written. This should be 10. It is -- note that 012 is octal notation, and that translates to 10 decimal. We're done here.

(gdb) exit Undefined command: "exit". Try "help".

It is always useful to know how to get out of some environment.

(gdb) quit [michael@xorenduex code]$