www.main.lv
Don't think just code it

2012-05-10 Create small ELF file byte by byte

Creating smallest possible elf file.

Structure of ELF file:

Elf header
Program header
Code Part
Data Part


C structure of ELF header /usr/include/elf.h:
	typedef struct
	{
	  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
	  Elf64_Half	e_type;				/* Object file type */
	  Elf64_Half	e_machine;			/* Architecture */
	  Elf64_Word	e_version;			/* Object file version */
	  Elf64_Addr	e_entry;			/* Entry point virtual address */
	  Elf64_Off		e_phoff;			/* Program header table file offset */
	  Elf64_Off		e_shoff;			/* Section header table file offset */
	  Elf64_Word	e_flags;			/* Processor-specific flags */
	  Elf64_Half	e_ehsize;			/* ELF header size in bytes */
	  Elf64_Half	e_phentsize;		/* Program header table entry size */
	  Elf64_Half	e_phnum;			/* Program header table entry count */
	  Elf64_Half	e_shentsize;		/* Section header table entry size */
	  Elf64_Half	e_shnum;			/* Section header table entry count */
	  Elf64_Half	e_shstrndx;			/* Section header string table index */
	} Elf64_Ehdr;




Structure of Program header file /usr/include/elf.h:
	typedef struct
	{
	  Elf64_Word	p_type;			/* Segment type */
	  Elf64_Word	p_flags;		/* Segment flags */
	  Elf64_Off		p_offset;		/* Segment file offset */
	  Elf64_Addr	p_vaddr;		/* Segment virtual address */
	  Elf64_Addr	p_paddr;		/* Segment physical address */
	  Elf64_Xword	p_filesz;		/* Segment size in file */
	  Elf64_Xword	p_memsz;		/* Segment size in memory */
	  Elf64_Xword	p_align;		/* Segment alignment */
	} Elf64_Phdr;



This structures is all what we need to make our ELF file.
Now we will look inside kernel source and see that
we need only one program header for our program. All big programs
using usually two program headers one for code and one for data.

/linux-3.3.1/fs/binfmt_elf.c:605
	
	if (loc->elf_ex.e_phnum < 1 ||
		loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr))
		goto out;


Step by step there should be filled all
fields of the ELF header structure.

	typedef struct
	{
	  unsigned char	e_ident[EI_NIDENT];	/* default values of ELFMAG,ELFCLASS64,ELFDATA2LSB */
	  Elf64_Half	e_type;				/* we making executable then it would be ET_EXEC  */
	  Elf64_Half	e_machine;			/* Architecture is 0x3e(EM_X86_64) 
										 (not from elf header 
										 from /binutils/include/elf/common.h) */
	  Elf64_Word	e_version;			/* Object file version EV_CURRENT */
	  Elf64_Addr	e_entry;			/* Entry point virtual address points to
										 main function it is with label entrypoint */
	  Elf64_Off		e_phoff;			/* Program header table file offset */
										  offset of program header sizeof(Elf64_Ehdr)
	  Elf64_Off		e_shoff;			/* Section header table file offset 
											there is no section header */
	  Elf64_Word	e_flags;			/* No processor-specific flags 
											*/
	  Elf64_Half	e_ehsize;			/* ELF header size in bytes 
											0x40 sizeof(Elf64_Ehdr)
	  Elf64_Half	e_phentsize;		/* Program header table entry size 
											0x38 sizeof(Elf64_Phdr) */
	  Elf64_Half	e_phnum;			/* Program header table entry count 
											0x01 */
	  Elf64_Half	e_shentsize;		/* Section header table entry size 
											I put 0x40 */
	  Elf64_Half	e_shnum;			/* Section header table entry count 
											0x00 */
	  Elf64_Half	e_shstrndx;			/* There is no section header and 
										 string table index is 0x0 then */
	} Elf64_Ehdr;



With program header we will tell kernel how to load our file in memory
and with part of file will be mmaped to needed address. As our data
and code is placed in one address space and kernel ELF source says
that there is enough with 1 program header then we will use only 1.

	typedef struct
	{
	  Elf64_Word	p_type;			/* Segment type PT_LOAD */
	  Elf64_Word	p_flags;		/* Segment flags PF_X,PF_R,PF_W
									as our memory should be readable, writable and
									executable as it contains code and data */
	  Elf64_Off		p_offset;		/* Segment file offset 
										point to offset of entry point label offset
										in file */
	  Elf64_Addr	p_vaddr;		/* Segment virtual address 
										64bits programs is usually at 0x400000+code_file_offset*/
	  Elf64_Addr	p_paddr;		/* Segment physical address 
										same as above*/
	  Elf64_Xword	p_filesz;		/* Segment size in file 
										size of code and data if file */
	  Elf64_Xword	p_memsz;		/* Segment size in memory 
										same as above */
	  Elf64_Xword	p_align;		/* Segment alignment 
										same as all programs have on my PC*/
	} Elf64_Phdr;


Now everything is ready. Only thing that is left is code some small code
that uses data. And it would be hello world

mov eax, 1
mov edx, 12
mov rsi, qword 0x040009c ;address of string 
mov edi, 1
syscall

xor edi, edi
mov eax, 60
syscall

msg db 'Hello World',0xA


To calculate offsets of code and data labels is used macro:

macro doffset
{	
	bits = 16
    display ' 0x'
    repeat bits/4
        d = '0' + $ shr (bits-%*4) and 0Fh
        if d > '9'
            d = d + 'A'-'9'-1
        end if
        display d
    end repeat
    display 13,10
}


Total size of executable on 64bit system:
Program partSize
ELF header size0x40
Program header 0x38
Code size 0x24
Data size 0xc
Total: 168 bytes


If 32 bit system is used then need to find defintions of data structures
and retype some bytes. Also architecture variable need to be changed.

Future plans:
Add some shared libs and compile smallest possible program using
SDL graphics lib.

Code:
Source
Code is written and tested on x86_64.

Links:
[1] http://refspecs.freestandards.org/elf/elf.pdf

2011-12-15 List ELF section names

Every ELF (Executable Linux Format) file has standard structure.
There is section names that used to identify purpose of section.

Here is example how to write all names of all ELF sections.

Here is steps that we have taken:
1. Find String Table Section
2. Get all section names from string table section
3. Run trough all section an get names of sections

First of all we need get ELF header (Elf32_Ehdr) from position 0.
ELF header have offset of section headers (Elf32_Ehdr.e_shoff).

Sting table section have attributes with help us to recognize it:
1. string table section header address in memory (Elf32_Shdr.sh_addr) is 0
2. its type (Elf32_Shdr.sh_type) is SHT_STRTAB = 3
3. and it is first section with such attributes

To get trough all sections we make for cycle. We can get number
of sections from (Elf32_Ehdr.e_shnum) .
we run all trough all sections and checking for 3 string table section
rules.

for ( iter_s=0; iter_s < ELFheader.e_shnum; iter_s++  )
	{
		fseek( f, ELFheader.e_shoff+(ELFheader.e_shentsize*iter_s), SEEK_SET);
		fread( &STRheader, ELFheader.e_shentsize, 1, f );
		if ((STRheader.sh_type == SHT_STRTAB) && 
			(STRheader.sh_addr == 0x00000000))
		{
			//some code
			iter_s=ELFheader.e_shnum+1; //this is to exit from for cycle
		}
	}


String table section has all section names as strings. Section name
is in (Elf32_Shdr.sh_name) as position number of strings first symbol.

All string table values we read inside buffer

fseek( f, STRheader.sh_offset, SEEK_SET);
fread( STR_buffer, STRheader.sh_size, 1, f);


Now we can get section name with

printf("%s\n", STR_buffer+ITERheader.sh_name);


This is example code to get some info from ELF file. There is allot other
info that can be gained from ELF file.

2011-10-30 C inline assembler

There is long time since wanted to learn "creepy" gcc inline assembly.
Looking at manuals its not so hard and "creepy". Using it is more
interesting and dissambly of compiled code is very nice looking.

volatile puts our asm code where it is and don't optimize it without
volatile it can optimize.

What to write in __asm__ directive looks like this

__asm__ __volatile__("our_code":output:input:used)


as code to convert to inline asm we will use last post [2].

There is only one instruction that we using and it usage was

get_timer:
	rdtsc
	ret


its not very optimal and for 1 instruction writing whole function
its not beautiful. We remember that returning result of this function is
saved in eax register.

__asm__ __volatile__("rdtsc":"=a"(x)::)


code looks like this. But we can make it as define function

#define get_timer(X) __asm__ __volatile__("rdtsc":"=a"(X)::)


This code works fine and give 70058 ticks on cycle
When adding option -O2 then result becomes wherry strange.

As we remember that rdtsc return result in edx:eax then we add to
used registers(clobber) %edx.

#define get_timer(X) __asm__ __volatile__("rdtsc":"=a"(X)::"%edx")


And also we can rewrite everything as
inline function.

static inline unsigned int get_timeri()
{
	unsigned int i;
	__asm__ __volatile__("rdtsc":"=a"(i)::);
	return i;
}


Now this two functions works fine with -O options.
When empty cycle is optimized then it becomes empty and resulting
tick number is 32 for both inline function and define macro.
It not working for his main purpose. When no optimization switched
then get_timer works for some ticks faster then get_timeri.

We can add attribute always inline and we will win some ticks
and function will always inline regards optimization level

__attribute__((always_inline)) unsigned int get_timeri() 


Too fix test cycle for our measurement we make it as object file
and it will compiled without options.

void fixed_cycle()
{
	int i;
	for (i=0;i<10000;i++)
	{
	}
}


Now everything looks quite good and also inline assembly works as expected.

For reference about inline asm you can go to [1]

Source

Links
[1]http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
[2]http://main.lv/post/linux-antidebug-5

2011-09-28 Linux antidebug 5

2011-09-15 Linux antidebug 4

2011-08-10 Embeding Lua in C

2011-07-01 AVR disassembler

2011-05-30 Phase space for chaos

2011-04-21 Hooking interrupt descriptor table

2011-03-13 Sauerbraten patching and cheating

« Previous 123456789