flat assembler
Message board for the users of flat assembler.
Index
> Linux > ELF executable + relocations/fixups for ASLR? Goto page 1, 2, 3, 4 Next |
Author |
|
Tomasz Grysztar 22 Jan 2019, 06:37
For address randomization in Linux you need PIE, which just like PIC requires code to be position-independent.
The ELF loader requires relocations to respect section permissions, so for a non-writeable code section you would not be able to apply relocations even if you tried. This is why you need to use PIC. |
|||
22 Jan 2019, 06:37 |
|
revolution 22 Jan 2019, 07:12
Tomasz Grysztar wrote: For address randomization in Linux you need PIE, which just like PIC requires code to be position-independent. Tomasz Grysztar wrote: The ELF loader requires relocations to respect section permissions, so for a non-writeable code section you would not be able to apply relocations even if you tried. This is why you need to use PIC. That means it is a lot of work to modify every line where memory is addressed. We lose one register in an already register starved architecture. And the rva operator doesn't seem to be active in executable output. Macros might come to save the day for us here, but is there another way to get the rva? Okay, so is there a magic flag setting that marks the file as moveable and a valid target for ASLR? "format elf executable 3 <magic_ASLR_flag>"? Section 2.2.4 of the fasm manual mentions nothing so I guess there is some other mechanism to tell the OS about ASLR validity. |
|||
22 Jan 2019, 07:12 |
|
Tomasz Grysztar 22 Jan 2019, 08:01
revolution wrote: That means it is a lot of work to modify every line where memory is addressed. We lose one register in an already register starved architecture. And the rva operator doesn't seem to be active in executable output. Macros might come to save the day for us here, but is there another way to get the rva? revolution wrote: Okay, so is there a magic flag setting that marks the file as moveable and a valid target for ASLR? "format elf executable 3 <magic_ASLR_flag>"? Section 2.2.4 of the fasm manual mentions nothing so I guess there is some other mechanism to tell the OS about ASLR validity. |
|||
22 Jan 2019, 08:01 |
|
revolution 22 Jan 2019, 08:47
I got this code running, but it doesn't relocate
Code: ; fasm <name>.asm && ld -m elf_i386 -e start -o <name> <name>.o && ./<name> format ELF SYS_EXIT = 1 SYS_WRITE = 4 STD_OUTPUT = 1 section '.data' hello_world db 'Hello Relocated World! Running at 0x' hello_world_len = $ - hello_world section '.text' executable public start sys_call: int 0x80 retn start: call @f @@: pop esi sub esi,rva @b lea ecx,[esi + rva hello_world] mov edx,hello_world_len call write_bytes mov eax,esi call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor ebx,ebx jmp sys_call write_hex: ;eax = value mov ecx,esp mov edx,eax sub esp,8 .next_nibble: mov eax,edx shr edx,4 and al,0xf cmp al,10 sbb al,0x69 das dec ecx mov [ecx],al cmp ecx,esp ja .next_nibble mov edx,8 call write_bytes add esp,8 retn write_char: ;al = char push eax mov ecx,esp mov edx,1 call write_bytes pop eax retn write_bytes: ;ecx = address ;edx = length push ebx mov eax,SYS_WRITE mov ebx,STD_OUTPUT call sys_call pop ebx retn Code: Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Hello Relocated World! Running at 0x080490D4 Code: Hello Relocated World! Running at 0x566210D4 Hello Relocated World! Running at 0x565F30D4 Hello Relocated World! Running at 0x5655D0D4 Hello Relocated World! Running at 0x566470D4 Hello Relocated World! Running at 0x5657C0D4 Hello Relocated World! Running at 0x566230D4 Hello Relocated World! Running at 0x5664E0D4 Hello Relocated World! Running at 0x565AA0D4 Hello Relocated World! Running at 0x565E80D4 Hello Relocated World! Running at 0x565B50D4 Hello Relocated World! Running at 0x565970D4 Hello Relocated World! Running at 0x5655F0D4 Hello Relocated World! Running at 0x565680D4 Hello Relocated World! Running at 0x5660F0D4 Hello Relocated World! Running at 0x5657E0D4 Hello Relocated World! Running at 0x565C90D4 Hello Relocated World! Running at 0x566120D4 Hello Relocated World! Running at 0x565F40D4 Hello Relocated World! Running at 0x5656C0D4 Hello Relocated World! Running at 0x565D30D4 But, yuck. Having to modify all the source code to be PIC. Hurrumph. |
|||
22 Jan 2019, 08:47 |
|
revolution 22 Jan 2019, 09:06
Curiously ld merges the data and text sections and marks it as readable and executable. The only way that I can find to make them separate sections is to mark the data section as writeable.
I can't find any way to make a segment that is only readable, and another segment that is only executable. I seems we always get readable and executable combined together when using ld. |
|||
22 Jan 2019, 09:06 |
|
revolution 22 Jan 2019, 09:31
So we can eliminate ld and do this directly with fasm and a single byte patch. But it still needs to be PIC.
Code: ; fasm <name>.asm && chmod +x <name> && printf "\x03" | dd of=<name> obs=1 seek=16 count=1 conv=notrunc && ./<name> format ELF executable 3 at 0 entry start SYS_EXIT = 1 SYS_WRITE = 4 STD_OUTPUT = 1 segment readable hello_world db 'Hello Relocated Executable World! Running at 0x' hello_world_len = $ - hello_world segment executable sys_call: int 0x80 retn start: call @f @@: pop esi sub esi,@b lea ecx,[esi + hello_world] mov edx,hello_world_len call write_bytes mov eax,esi call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor ebx,ebx jmp sys_call write_hex: ;eax = value mov ecx,esp mov edx,eax sub esp,8 .next_nibble: mov eax,edx shr edx,4 and al,0xf cmp al,10 sbb al,0x69 das dec ecx mov [ecx],al cmp ecx,esp ja .next_nibble mov edx,8 call write_bytes add esp,8 retn write_char: ;al = char push eax mov ecx,esp mov edx,1 call write_bytes pop eax retn write_bytes: ;ecx = address ;edx = length push ebx mov eax,SYS_WRITE mov ebx,STD_OUTPUT call sys_call pop ebx retn Code: Hello Relocated Executable World! Running at 0x5661B000 Hello Relocated Executable World! Running at 0x5658E000 Hello Relocated Executable World! Running at 0x565D2000 Hello Relocated Executable World! Running at 0x56649000 Hello Relocated Executable World! Running at 0x565A9000 Hello Relocated Executable World! Running at 0x56646000 Hello Relocated Executable World! Running at 0x565E4000 Hello Relocated Executable World! Running at 0x565BA000 Hello Relocated Executable World! Running at 0x565C1000 Hello Relocated Executable World! Running at 0x56603000 Hello Relocated Executable World! Running at 0x565EA000 Hello Relocated Executable World! Running at 0x565B1000 Hello Relocated Executable World! Running at 0x56573000 Hello Relocated Executable World! Running at 0x565EC000 Hello Relocated Executable World! Running at 0x5662D000 Hello Relocated Executable World! Running at 0x565DD000 Hello Relocated Executable World! Running at 0x56586000 Hello Relocated Executable World! Running at 0x565BA000 Hello Relocated Executable World! Running at 0x56608000 Hello Relocated Executable World! Running at 0x565AE000 Last edited by revolution on 22 Jan 2019, 09:50; edited 1 time in total |
|||
22 Jan 2019, 09:31 |
|
revolution 22 Jan 2019, 09:37
This line would be good IMO
Code: format ELF dynamic executable 3 at 0 Code: format ELF executable 3 dynamic at 0 Code: format ELF executable 3 at 0 dynamic Code: format ELF executable 3 dynamic |
|||
22 Jan 2019, 09:37 |
|
revolution 22 Jan 2019, 09:45
Sorry for spamming my own topic, but the "randomness" of ASLR is quite poor. After 22000 runs I never got more than 256 separate address:
Code: 0x56554000 ... 0x56653000 |
|||
22 Jan 2019, 09:45 |
|
revolution 22 Jan 2019, 10:35
64-bit code is easier to write
Code: ; fasm <name>.asm && chmod +x <name> && printf "\x03" | dd of=<name> obs=1 seek=16 count=1 conv=notrunc && ./<name> format ELF64 executable 3 at 0 entry start SYS_WRITE = 1 SYS_EXIT = 60 STD_OUTPUT = 1 segment readable hello_world db 'Hello Relocated Executable World! Running at 0x' hello_world_len = $ - hello_world hex_table db '0123456789ABCDEF' segment executable sys_call: syscall retn start: lea rsi,[hello_world] mov edx,hello_world_len call write_bytes lea rax,[rip - ($ + 7)] call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor edi,edi jmp sys_call write_hex: ;rax = value mov rsi,rsp sub rsp,16 lea rcx,[hex_table] .next_nibble: mov rdx,rax shr rax,4 and rdx,0xf mov dl,[rcx + rdx] dec rsi mov [rsi],dl cmp rsi,rsp ja .next_nibble mov edx,16 call write_bytes add rsp,16 retn write_char: ;al = char push rax mov rsi,rsp mov edx,1 call write_bytes pop rax retn write_bytes: ;rsi = address ;rdx = length mov eax,SYS_WRITE mov edi,STD_OUTPUT call sys_call retn Code: Hello Relocated Executable World! Running at 0x000055F715002000 Hello Relocated Executable World! Running at 0x0000555F98BE9000 Hello Relocated Executable World! Running at 0x000055B5B2F25000 Hello Relocated Executable World! Running at 0x0000562618645000 Hello Relocated Executable World! Running at 0x000055587E540000 Hello Relocated Executable World! Running at 0x000055DBFDBDF000 Hello Relocated Executable World! Running at 0x0000562A3E328000 Hello Relocated Executable World! Running at 0x000055A6B3F88000 Hello Relocated Executable World! Running at 0x000055DB88F12000 Hello Relocated Executable World! Running at 0x000055B0455F7000 Code: 0000555555643000 ... 000056555542E000 |
|||
22 Jan 2019, 10:35 |
|
revolution 22 Jan 2019, 15:26
I made some minor tweaks to my local copy of fasm.
Code: Index: SOURCE/FORMATS.INC ================================================================== --- SOURCE/FORMATS.INC +++ SOURCE/FORMATS.INC @@ -2921,12 +2921,17 @@ mov [edx+14h],al mov byte [edx+12h],3 mov byte [edx+28h],34h mov byte [edx+2Eh],28h mov [code_type],32 - cmp word [esi],1D19h + mov byte [edx+10h],2 ;ET_EXEC + cmp word [esi],1D19h ;executable + je format_elf_exe + mov byte [edx+10h],3 ;ET_DYN + cmp word [esi],021eh ;dynamic je format_elf_exe + mov byte [edx+10h],0 elf_header_ok: mov byte [edx+10h],1 mov eax,[additional_memory] mov [symbols_stream],eax mov ebx,eax @@ -2970,13 +2975,18 @@ mov byte [edx+4],2 mov byte [edx+12h],62 mov byte [edx+34h],40h mov byte [edx+3Ah],40h mov [code_type],64 - cmp word [esi],1D19h - jne elf_header_ok - jmp format_elf64_exe + mov byte [edx+10h],2 ;ET_EXEC + cmp word [esi],1D19h ;executable + je format_elf64_exe + mov byte [edx+10h],3 ;ET_DYN + cmp word [esi],021eh ;dynamic + je format_elf64_exe + mov byte [edx+10h],0 + jmp elf_header_ok elf_section: bt [format_flags],0 jc illegal_instruction call close_coff_section mov ebx,[free_additional_memory] @@ -3700,11 +3710,10 @@ cmp [value_type],0 jne invalid_use_of_symbol mov [image_base],eax pop edx elf_exe_base_ok: - mov byte [edx+10h],2 mov byte [edx+2Ah],20h mov ebx,edi mov ecx,20h shr 2 cmp [current_pass],0 je init_elf_segments @@ -3768,11 +3777,10 @@ jne invalid_use_of_symbol mov [image_base],eax mov [image_base_high],edx pop edx elf64_exe_base_ok: - mov byte [edx+10h],2 mov byte [edx+36h],38h mov ebx,edi mov ecx,38h shr 2 cmp [current_pass],0 je init_elf64_segments Code: format ELF dynamic ... format ELF64 dynamic ... |
|||
22 Jan 2019, 15:26 |
|
Tomasz Grysztar 22 Jan 2019, 16:27
You could also set up "labels type" to make labels require relocation (not available in this format) and thus enforce use of relative offsets only in code. But then you would have to write your code in a different way. Well, then perhaps that is not a good option for you...
|
|||
22 Jan 2019, 16:27 |
|
revolution 22 Jan 2019, 16:58
Tomasz Grysztar wrote: You could also set up "labels type" to make labels require relocation (not available in this format) and thus enforce use of relative offsets only in code. But then you would have to write your code in a different way. Well, then perhaps that is not a good option for you... |
|||
22 Jan 2019, 16:58 |
|
Tomasz Grysztar 22 Jan 2019, 17:59
I made a proof of concept with fasmg's ELF executable formatter: https://github.com/tgrysztar/fasmg/commit/4aa9d12c807e40951702b4fe4798cef3355ccb7a
Your example programs look like this after necessary tweaks: Code: include 'format/format.inc' format ELF dynamic ELFOSABI_LINUX at 0 entry start SYS_EXIT = 1 SYS_WRITE = 4 STD_OUTPUT = 1 segment readable hello_world db 'Hello Relocated Executable World! Running at 0x' hello_world_len = $ - hello_world segment executable sys_call: int 0x80 retn start: call .here .here: pop esi sub esi,RVA .here lea ecx,[esi + RVA hello_world] mov edx,hello_world_len call write_bytes mov eax,esi call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor ebx,ebx jmp sys_call write_hex: ;eax = value mov ecx,esp mov edx,eax sub esp,8 .next_nibble: mov eax,edx shr edx,4 and al,0xf cmp al,10 sbb al,0x69 das dec ecx mov [ecx],al cmp ecx,esp ja .next_nibble mov edx,8 call write_bytes add esp,8 retn write_char: ;al = char push eax mov ecx,esp mov edx,1 call write_bytes pop eax retn write_bytes: ;ecx = address ;edx = length push ebx mov eax,SYS_WRITE mov ebx,STD_OUTPUT call sys_call pop ebx retn Code: include 'format/format.inc' format ELF64 dynamic ELFOSABI_LINUX at 0 entry start SYS_WRITE = 1 SYS_EXIT = 60 STD_OUTPUT = 1 segment readable hello_world db 'Hello Relocated Executable World! Running at 0x' hello_world_len = $ - hello_world hex_table db '0123456789ABCDEF' segment executable sys_call: syscall retn start: lea rsi,[hello_world] mov edx,hello_world_len call write_bytes lea rax,[rip - (RVA .here)] .here: call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor edi,edi jmp sys_call write_hex: ;rax = value mov rsi,rsp sub rsp,16 lea rcx,[hex_table] .next_nibble: mov rdx,rax shr rax,4 and rdx,0xf mov dl,[rcx + rdx] dec rsi mov [rsi],dl cmp rsi,rsp ja .next_nibble mov edx,16 call write_bytes add rsp,16 retn write_char: ;al = char push rax mov rsi,rsp mov edx,1 call write_bytes pop rax retn write_bytes: ;rsi = address ;rdx = length mov eax,SYS_WRITE mov edi,STD_OUTPUT call sys_call retn This kind of error catching is nice when adapting an existing program - the errors are going to show what places in code need to be changed for PIE (with fasmg you can use an option like -e100). |
|||
22 Jan 2019, 17:59 |
|
revolution 22 Jan 2019, 18:23
Thanks. I can use that for checking any mistakes before I release to the customer.
|
|||
22 Jan 2019, 18:23 |
|
revolution 22 Jan 2019, 18:44
revolution wrote: Thanks. I can use that for checking any mistakes before I release to the customer. |
|||
22 Jan 2019, 18:44 |
|
Tomasz Grysztar 22 Jan 2019, 18:50
revolution wrote:
|
|||
22 Jan 2019, 18:50 |
|
Furs 22 Jan 2019, 23:56
revolution wrote: I was dreading that this might be the case. I see a lot of information about relocations for binding .so files. So what if two .so files are based at the same address? I guess this means all .so files must be PIC or bad things happen. Not gonna lie, ELF loader sounds like a pretty dumb one here, but it's dumb in many other aspects. |
|||
22 Jan 2019, 23:56 |
|
revolution 23 Jan 2019, 02:19
Furs wrote: Did you try to see how GCC does it with -fno-PIC on shared objects? |
|||
23 Jan 2019, 02:19 |
|
revolution 23 Jan 2019, 06:12
Some simple macros make the 32-bit conversion a bit easier:
Code: ;... irp reg,eax,ebx,ecx,edx,esi,edi,ebp { if used mov_#reg#_eip mov_#reg#_eip: mov reg,[esp] retn end if } macro addr reg,offset { call mov_#reg#_eip lea reg,[reg + offset - $] ;use lea to avoid changing the flags } start: addr ecx,hello_world mov edx,hello_world_len call write_bytes addr eax,0 call write_hex mov al,10 call write_char mov eax,SYS_EXIT xor ebx,ebx jmp sys_call ;... |
|||
23 Jan 2019, 06:12 |
|
Goto page 1, 2, 3, 4 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.