flat assembler
Message board for the users of flat assembler.

Index > Linux > Use the fword to switch 32/64 bitness mode on the fly

Author
Thread Post new topic Reply to topic
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20460
Location: In your JS exploiting you and your system
revolution 22 Feb 2023, 21:19
It is possible to run both 32-bit and 64-bit code in the same process.
Code:
format elf executable at 1 shl 16       ; must start in 32-bit mode or we can't access memory after a 64 --> 32 switch

TRIALS=8 ; do some example trial runs

STDOUT_FILENO   = 1
SYS32_write     = 4
SYS32_exit      = 1
SYS64_write     = 1
SYS64_exit      = 60

entry $
        mov     ebp,TRIALS
    .32:
        use32
        mov     eax,SYS32_write
        mov     ebx,STDOUT_FILENO
        mov     ecx,text32
        mov     edx,len32
        int     0x80
        dec     ebp
        jz      .exit32
        mov     ecx,.64
        jmp     toggle_mode
    .exit32:
        mov     eax,SYS32_exit
        xor     ebx,ebx
        int     0x80

    .64:
        use64
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        lea     rsi,[text64]
        mov     edx,len64
        syscall
        dec     ebp
        jz      .exit64
        lea     ecx,[.32]
        jmp     toggle_mode
    .exit64:
        mov     eax,SYS64_exit
        xor     edi,edi
        syscall

toggle_mode:
        use64                   ; this is code for both modes
        mov     edx,.far_ptr    ; use absolute address only
        mov     eax,cs
        xor     eax,0x10        ; offset is +-16
        mov     [rdx],ecx
        mov     [rdx+4],ax
        jmp     fword[rdx]      ; jmp to ax:ecx
    .far_ptr    df ?

text32 db 'Hello from 32-bit code!',10
len32 = $ - text32
text64 db 'Hello from 64-bit code!',10
len64 = $ - text64

; See this comment at https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/segment.h
;
;/*
; * We cannot use the same code segment descriptor for user and kernel mode,
; * not even in long flat mode, because of different DPL.
; *
; * GDT layout to get 64-bit SYSCALL/SYSRET support right. SYSRET hardcodes
; * selectors:
; *
; *   if returning to 32-bit userspace: cs = STAR.SYSRET_CS,
; *   if returning to 64-bit userspace: cs = STAR.SYSRET_CS+16,
; *
; * ss = STAR.SYSRET_CS+8 (in either case)
; *
; * thus USER_DS should be between 32-bit and 64-bit code selectors:
; */
;
;#define GDT_ENTRY_DEFAULT_USER32_CS    4
;#define GDT_ENTRY_DEFAULT_USER_DS      5
;#define GDT_ENTRY_DEFAULT_USER_CS      6    
It is also possible to define a simple mode toggle for call to have 32/64 code call 64/32 functions.

There are some restrictions, of course. The most obvious would be:
  • All memory allocations should be done in 32-bit code through int 0x80 to ensure the addresses are <4G.
  • Using int 0x80 has an undefined effect on r8-r15, so those might be corrupted, and there is no way to save them in 32-bit code.
  • A debugger might not understand what is happening and go wonky.
Post 22 Feb 2023, 21:19
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2572
Furs 23 Feb 2023, 12:51
revolution wrote:
  • All memory allocations should be done in 32-bit code through int 0x80 to ensure the addresses are <4G.
You can also use MAP_32BIT for mmap in 64-bit code but that has the drawback that it's only 2G instead of 4G. Does 32-bit mmap handle full 4G?

I guess the "correct" way here to do it from 64-bit code is to do your own allocator like Wine does (since it also supports 32-bit on 64-bit processes recently), you'll need to specify the addresses for mmap in this case and handle failure or fragmentation.

But I guess allocating it in 32-bit code is easier.
Post 23 Feb 2023, 12:51
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20460
Location: In your JS exploiting you and your system
revolution 23 Feb 2023, 23:16
Using indirect calls allows for going 32-->64-->32 and back.
Code:
format elf executable at 1 shl 16

STDOUT_FILENO   = 1
SYS32_write     = 4
SYS32_exit      = 1
SYS64_write     = 1
SYS64_exit      = 60
CS_TOGGLE       = 0x10  ; offset is +-16

entry $
        ;initialise call pointers
        mov     eax,cs
        mov     word[print_hello_32+4],ax
        xor     eax,CS_TOGGLE
        mov     word[print_hello_64+4],ax
        call    [print_hello_64]
        mov     eax,SYS32_exit
        xor     ebx,ebx
        int     0x80

print_hello_32  df      0:_print_hello_32
_print_hello_32:
        use32
        mov     eax,SYS32_write
        mov     ebx,STDOUT_FILENO
        mov     ecx,text32
        mov     edx,len32
        int     0x80
        retf

print_hello_64  df      0:_print_hello_64
_print_hello_64:
        use64
        call    [print_hello_32]
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        lea     rsi,[text64]
        mov     edx,len64
        syscall
        retfd

text32 db 'Hello from 32-bit code!',10
len32 = $ - text32
text64 db 'Hello from 64-bit code!',10
len64 = $ - text64    
Post 23 Feb 2023, 23:16
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.