flat assembler
Message board for the users of flat assembler.

Index > Examples and Tutorials > [Linux32] vDSO, auxv, vsyscall, int 0x80, calling the kernel

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


Joined: 24 Aug 2004
Posts: 16861
Location: In your JS exploiting you and your system
revolution
[Linux32] vDSO, auxv, vsyscall, int 0x80, calling the kernel

In 32-bit Linux calling the kernel can be done using int 0x80. There are also other, more efficient ways to call kernel services and functions.

Linux maps into every process a kernel interface page called the virtual dynamic shared object (vDSO).
http://man7.org/linux/man-pages/man7/vdso.7.html
What this gives us is a function to call the kernel using either the syscall or the sysenter instruction. This is called the vsyscall entry. So depending upon which instruction the CPU supports Linux figures it out and makes it available to us in the vDSO.

There are at least three ways to find the entry point of vsyscall

The first and easiest is the AT_SYSINFO value available from the auxv table.
Code:
format ELF executable 0 at 1 shl 16
entry main

AT_NULL                 = 0
AT_SYSINFO              = 32
SYS_EXIT                = 1
SYS_WRITE               = 4
STD_OUTPUT              = 1

struc Elf32_auxv_t {
        .a_type         rd 1
        .a_val          rd 1
}
virtual at 0
        Elf32_auxv_t            Elf32_auxv_t
        sizeof.Elf32_auxv_t     = $
end virtual

segment executable

default_sys_call:
        ;if the search fails we use this to call the kernel
        int     0x80
        retn

main:
        mov     eax,[esp]                       ;argument count (argc)
        lea     ebx,[esp + 4 + (eax + 1) * 4]   ;skip the args and the final null
    .skip_environment:
        cmp     dword[ebx],0                    ;last entry in environment?
        lea     ebx,[ebx + 4]                   ;next entry in environment
        jnz     .skip_environment
    .scan_auxv:
        mov     eax,[ebx + Elf32_auxv_t.a_type]
        add     ebx,sizeof.Elf32_auxv_t         ;next auxv entry
        cmp     eax,AT_NULL                     ;end of auxv table?
        jz      .auxv_done
        cmp     eax,AT_SYSINFO
        jnz     .scan_auxv
        mov     eax,[ebx - sizeof.Elf32_auxv_t + Elf32_auxv_t.a_val]
        mov     [sys_call],eax
    .auxv_done:
        mov     ecx,vdso_at
        mov     edx,[sys_call]
        call    write_hex
        mov     eax,SYS_WRITE
        mov     ebx,STD_OUTPUT
        mov     ecx,hello_world
        mov     edx,hello_world_len
        call    [sys_call]
        mov     eax,SYS_EXIT
        xor     ebx,ebx
        call    [sys_call]

write_hex:
        ;ecx = address
        ;edx = value
    .next_nibble:
        mov     eax,edx
        shr     eax,28
        cmp     al,10
        sbb     al,0x69
        das
        mov     [ecx],al
        inc     ecx
        shl     edx,4
        jnz     .next_nibble
        retn

segment readable writeable

align 4
sys_call dd default_sys_call

hello_world:    db      'vdso at 0x'
vdso_at         db      '00000000',10
hello_world_len =       $ - hello_world    
Note that vsyscall uses the system call convention, so all arguments are passed in registers the same as for int 0x80. A few sample runs gives ths
Code:
vdso at 0xF7772C80
vdso at 0xF77C3C80
vdso at 0xF77F9C80
vdso at 0xF771DC80
vdso at 0xF775FC80
vdso at 0xF77A2C80
vdso at 0xF77D4C80
vdso at 0xF77BAC80
vdso at 0xF7790C80
vdso at 0xF7799C80    
So we can see that the location is not fixed and we can't hardcode the address.

However there is this note
Quote:
For some architectures, there is also an AT_SYSINFO tag. This is used only for locating the vsyscall entry point and is frequently omitted or set to 0 (meaning it's not available). This tag is a throwback to the initial vDSO work (see History below) and its use should be avoided.
So another easy way to find the vsyscall entry point is the AT_SYSINFO_EHDR value and simply getting the ELF entry point.
Code:
format ELF executable 0 at 1 shl 16
entry main

AT_NULL                 = 0
AT_SYSINFO_EHDR         = 33
Elf32_Ehdr.e_entry      = 0x18
SYS_EXIT                = 1
SYS_WRITE               = 4
STD_OUTPUT              = 1

struc Elf32_auxv_t {
        .a_type         rd 1
        .a_val          rd 1
}
virtual at 0
        Elf32_auxv_t            Elf32_auxv_t
        sizeof.Elf32_auxv_t     = $
end virtual

segment executable

default_sys_call:
        ;if the search fails we use this to call the kernel
        int     0x80
        retn

main:
        mov     eax,[esp]                       ;argument count (argc)
        lea     ebx,[esp + 4 + (eax + 1) * 4]   ;skip the args and the final null
    .skip_environment:
        cmp     dword[ebx],0                    ;last entry in environment?
        lea     ebx,[ebx + 4]                   ;next entry in environment
        jnz     .skip_environment
    .scan_auxv:
        mov     eax,[ebx + Elf32_auxv_t.a_type]
        add     ebx,sizeof.Elf32_auxv_t         ;next auxv entry
        cmp     eax,AT_NULL                     ;end of auxv table?
        jz      .auxv_done
        cmp     eax,AT_SYSINFO_EHDR
        jnz     .scan_auxv
        mov     ecx,[ebx - sizeof.Elf32_auxv_t + Elf32_auxv_t.a_val]
        mov     eax,[ecx + Elf32_Ehdr.e_entry]  ;get program entry
        add     eax,ecx
        mov     [sys_call],eax
    .auxv_done:
        mov     ecx,vdso_at
        mov     edx,[sys_call]
        call    write_hex
        mov     eax,SYS_WRITE
        mov     ebx,STD_OUTPUT
        mov     ecx,hello_world
        mov     edx,hello_world_len
        call    [sys_call]
        mov     eax,SYS_EXIT
        xor     ebx,ebx
        call    [sys_call]

write_hex:
        ;ecx = address
        ;edx = value
    .next_nibble:
        mov     eax,edx
        shr     eax,28
        cmp     al,10
        sbb     al,0x69
        das
        mov     [ecx],al
        inc     ecx
        shl     edx,4
        jnz     .next_nibble
        retn

segment readable writeable

align 4
sys_call dd default_sys_call

hello_world:    db      'vdso at 0x'
vdso_at         db      '00000000',10
hello_world_len =       $ - hello_world    
But this method, while easy, is undocumented and probably not trustworthy. It works on my system, today, but perhaps tomorrow after an update it will fail.

So there is a third method. Do a lookup of the ELF symbol table and find the entry for __kernel_vsyscall. Full code for this is below. Using this method is more flexible and gives us access to other functions also. For example my system provides a ccall function for __vdso_clock_gettime which allows faster access to the high resolution timer. If you need high precision timing then this might be useful.
Code:
;stack pointer->argc            dword = number of args (n)
;               argv 0          dword = program name
;               argv 1          dword
;               argv ...        dwords
;               argv n - 1      dword
;               argv NULL       dword = end of args
;               envp 0          dword
;               envp 1          dword
;               envp ...        dwords
;               envp NULL       dword = end of environment
;               auxv 0          Elf32_auxv_t
;               auxv 1          Elf32_auxv_t
;               auxv ...        Elf32_auxv_t
;               auxv NULL       Elf32_auxv_t = AT_NULL vector

format ELF executable 0 at 1 shl 16
entry main

AT_NULL                 = 0
AT_SYSINFO              = 32
AT_SYSINFO_EHDR         = 33
EI_NIDENT               = 16
SHT_STRTAB              = 3
SHT_DYNSYM              = 11
SYS_EXIT                = 1
SYS_WRITE               = 4
SYS_TIME                = 13
SYS_CLOCK_GETTIME       = 265
STD_OUTPUT              = 1
CLOCK_MONOTONIC         = 1
TIMESPEC_SCALE          = 1000000000
TEST_ITERATIONS         = 10000000
DOWN_SCALE              = 1000

struc Elf32_auxv_t {
        .a_type         rd 1
        .a_val          rd 1
}

struc e_ident {
        .ei_mag0        rb 1
        .ei_mag1        rb 1
        .ei_mag2        rb 1
        .ei_mag3        rb 1
        .ei_class       rb 1
        .ei_data        rb 1
        .ei_version     rb 1
        .ei_osabi       rb 1
        .ei_abiversion  rb 1
        .ei_pad         rb EI_NIDENT - $ + .ei_mag0
}

struc Elf32_Ehdr {
        .e_ident        e_ident
        .e_type         rw 1
        .e_machine      rw 1
        .e_version      rd 1
        .e_entry        rd 1
        .e_phoff        rd 1
        .e_shoff        rd 1
        .e_flags        rd 1
        .e_ehsize       rw 1
        .e_phentsize    rw 1
        .e_phnum        rw 1
        .e_shentsize    rw 1
        .e_shnum        rw 1
        .e_shstrndx     rw 1
}

struc Elf32_Shdr {
        .sh_name        rd 1
        .sh_type        rd 1
        .sh_flags       rd 1
        .sh_addr        rd 1
        .sh_offset      rd 1
        .sh_size        rd 1
        .sh_link        rd 1
        .sh_info        rd 1
        .sh_addralign   rd 1
        .sh_entsize     rd 1
}

struc Elf32_Sym {
        .st_name        rd 1
        .st_value       rd 1
        .st_size        rd 1
        .st_info        rb 1
        .st_other       rb 1
        .st_shndx       rw 1
}

struc timespec {
        .tv_sec         rd 1
        .tv_nsec        rd 1
}

struc symbol_scan name {
        .address        rd 1
        .name           dd name + 0
}

struc table_info {
        .address        rd 1
        .size           rd 1
}

struc string_header value {
        .length db value + 0    ;if you need strings longer than 255 bytes then set this to "dw"
}

irp structure, e_ident, Elf32_auxv_t, Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, timespec, symbol_scan, table_info {
        virtual at 0
                structure               structure
                sizeof.#structure       = $
        end virtual
}

virtual at -sizeof.string_header
        string_header           string_header
        sizeof.string_header    = $ - $$
end virtual

segment executable

default_sys_call:
        ;if the search fails we use this to call the kernel
        int     0x80
        retn

main:
        mov     eax,[esp]                       ;argument count (argc)
        lea     ebx,[esp + 4 + (eax + 1) * 4]   ;skip the args and the final null
    .skip_environment:
        cmp     dword[ebx],0                    ;last entry in environment?
        lea     ebx,[ebx + 4]                   ;next entry in environment
        jnz     .skip_environment
    .scan_auxv:
        mov     eax,[ebx + Elf32_auxv_t.a_type]
        add     ebx,sizeof.Elf32_auxv_t         ;next auxv entry
        cmp     eax,AT_NULL                     ;end of auxv table?
        jz      .auxv_done
        cmp     eax,AT_SYSINFO_EHDR
        jz      .examine_ELF
        cmp     eax,AT_SYSINFO
        jnz     .scan_auxv
        mov     eax,[ebx - sizeof.Elf32_auxv_t + Elf32_auxv_t.a_val]
        mov     [sys_call_AT_SYSINFO],eax
        push    eax message_found0
        call    print_format
        jmp     .scan_auxv
    .examine_ELF:
        mov     edi,[ebx - sizeof.Elf32_auxv_t + Elf32_auxv_t.a_val]
        push    edi message_elf_header
        call    print_format
        mov     eax,[edi + Elf32_Ehdr.e_entry]  ;get program entry
        add     eax,edi
        mov     [sys_call_Elf32_Ehdr.e_entry],eax ;vsyscall address from program entry
        push    eax message_found1
        call    print_format
        push    edi
        call    find_dynsym
        ;search the dynamic symbol table for the named symbols
        push    edi symbol_scan_table
        call    scan_symbols
        jmp     .scan_auxv
    .auxv_done:
        mov     eax,[vsyscall]                  ;trusted if present
        mov     ebx,[sys_call_AT_SYSINFO]       ;trusted if present
        mov     ecx,[sys_call_Elf32_Ehdr.e_entry];untrusted and not documented
        test    eax,eax
        jnz     .first_entry_address_okay
        mov     eax,ebx
    .first_entry_address_okay:
        test    eax,eax
        jz      .no_trusted_entry_found
        mov     [sys_call],eax                  ;set the new vsyscall address
        cmp     eax,ecx
        jnz     .e_entry_fail
        mov     ecx,message_success
        xor     ebx,ebx                         ;result code
    .done:
        push    ecx
        call    print_format
        call    tests
        mov     eax,SYS_EXIT
        call    [sys_call]
    .e_entry_fail:
        mov     ecx,message_e_entry_failed
        mov     ebx,1                           ;result code
        jmp     .done
    .no_trusted_entry_found:
        test    ecx,ecx
        jz      .no_address_found
        mov     [sys_call],ecx                  ;try this untrusted value and see what happens
        mov     ecx,message_untrusted_only
        mov     ebx,2                           ;result code
        jmp     .done
    .no_address_found:
        mov     ecx,message_none_found
        mov     ebx,3                           ;result code
        jmp     .done

tests:
        call    time_stamp
        mov     esi,TEST_ITERATIONS
    .loop_int_0x80:
        mov     eax,SYS_TIME
        xor     ebx,ebx
        int     0x80
        dec     esi
        jnz     .loop_int_0x80
        call    time_stamp
        mov     ecx,DOWN_SCALE
        div     ecx
        push    eax message_int_0x80
        call    print_format
        ;
        cmp     [vsyscall.address],0
        jz      .done_vsyscall
        call    time_stamp
        mov     esi,TEST_ITERATIONS
    .loop_vsyscall:
        mov     eax,SYS_TIME
        xor     ebx,ebx
        call    [vsyscall.address]              ;system call function
        dec     esi
        jnz     .loop_vsyscall
        call    time_stamp
        mov     ecx,DOWN_SCALE
        div     ecx
        push    eax message_vsyscall
        call    print_format
    .done_vsyscall:
        ;
        cmp     [time.address],0
        jz      .done_vdso
        call    time_stamp
        mov     esi,TEST_ITERATIONS
    .loop_vdso:
        push    0
        call    [time.address]                  ;ccall function
        add     esp,4
        dec     esi
        jnz     .loop_vdso
        call    time_stamp
        mov     ecx,DOWN_SCALE
        div     ecx
        push    eax message_vdso
        call    print_format
    .done_vdso:
        retn

time_stamp:
        ;return edx:eax = nanoseconds since last call to time_stamp
        mov     ecx,timer
        mov     ebx,CLOCK_MONOTONIC
        mov     eax,SYS_CLOCK_GETTIME
        call    [sys_call]
        mov     eax,TIMESPEC_SCALE
        mul     [timer.tv_sec]
        add     eax,[timer.tv_nsec]
        adc     edx,0
        mov     ecx,dword[prev_time_stamp + 0]
        mov     dword[prev_time_stamp + 0],eax
        sub     eax,ecx
        mov     ecx,dword[prev_time_stamp + 4]
        mov     dword[prev_time_stamp + 4],edx
        sbb     edx,ecx
        retn

find_dynsym:    ;arg1 = ELF_header
        ;find the dynamic symbol table and its associated string table
        mov     edx,[esp + 4]                   ;edx = ELF_header
        xor     ecx,ecx                         ;ecx = section number
        ;find the SHT_DYNSYM section
    .next_section:
        inc     ecx
        cmp     cx,[edx + Elf32_Ehdr.e_shnum]
        jae     .not_found
        call    .compute_header_pointer
        cmp     [eax + Elf32_Shdr.sh_type],SHT_DYNSYM
        jnz     .next_section
        ;save the details
        mov     edx,DYNSYM
        call    .initialise_table_info
        ;check the linked symbol table is valid and of type SHT_STRTAB
        mov     edx,[esp + 4]                   ;edx = ELF_header
        mov     ecx,[eax + Elf32_Shdr.sh_link]
        movzx   eax,[edx + Elf32_Ehdr.e_shnum]
        cmp     ecx,eax
        jae     .not_found
        call    .compute_header_pointer
        cmp     [eax + Elf32_Shdr.sh_type],SHT_STRTAB
        jnz     .not_found
        mov     edx,STRTAB
        call    .initialise_table_info
    .done:
        retn    4
    .not_found:
        xor     eax,eax
        mov     [DYNSYM.address],eax
        jmp     .done
    .compute_header_pointer:
        ;ecx = section number
        ;edx = ELF_header
        movzx   eax,[edx + Elf32_Ehdr.e_shentsize]
        imul    eax,ecx
        add     eax,[edx + Elf32_Ehdr.e_shoff]  ;eax = section header offset
        add     eax,edx                         ;eax = section header pointer
        retn
    .initialise_table_info:
        ;eax = section header
        ;edx = table info
        mov     ecx,[eax + Elf32_Shdr.sh_addr]
        add     ecx,[esp + 4 * 2]               ;add in the ELF_header
        mov     [edx + table_info.address],ecx
        mov     ecx,[eax + Elf32_Shdr.sh_size]
        mov     [edx + table_info.size],ecx
        retn

scan_symbols:   ;arg1 = scan table, arg2 = VDSO offset
        ;given a list of symbol names, find their corresponding addresses in the VDSO
        push    esi
        mov     esi,[esp + 4 * 2]               ;esi = symbol scan table
    .loop_symbol:
        mov     eax,[esi + symbol_scan.name]
        test    eax,eax
        jz      .done_scan
        push    eax
        call    find_symbol
        test    eax,eax
        jz      .next_symbol
        add     eax,[esp + 4 * 3]               ;add the VDSO offset
        mov     [esi + symbol_scan.address],eax ;store the addresss
        push    [esi + symbol_scan.name] eax message_symbol_found
        call    print_format
    .next_symbol:
        add     esi,sizeof.symbol_scan
        jmp     .loop_symbol
    .done_scan:
        pop     esi
        retn    8

find_symbol:    ;arg1 = symbol name
        ;return eax = offset of symbol if found, zero if not
        push    esi edi
        mov     edx,[DYNSYM.address]            ;edx = DYNSYM table
        test    edx,edx
        jz      .not_found
        xor     eax,eax                         ;eax = current symbol offset
    .loop_symbols:
        mov     esi,[edx + eax + Elf32_Sym.st_name]
        cmp     esi,[STRTAB.size]
        jae     .next_symbol
        add     esi,[STRTAB.address]
        mov     edi,[esp + 4 * 3]               ;edi = name to find
        movzx   ecx,[edi + string_header.length]
        cld
        repz    cmpsb
        jnz     .next_symbol
        cmp     byte[esi],0
        jz      .found_symbol
    .next_symbol:
        add     eax,sizeof.Elf32_Sym
        cmp     eax,[DYNSYM.size]
        jb      .loop_symbols
    .not_found:
        xor     eax,eax
        jmp     .done
    .found_symbol:
        mov     eax,[edx + eax + Elf32_Sym.st_value]
    .done:
        pop     edi esi
        retn    4

print_format:   ;arg1 = string, arg2 ... argN = values
        ; % expands to an unsigned decimal number
        ; # expands to an unsigned hexadecimal number
        ; $ expands to a string
        push    esi ebx edi ebp
        mov     esi,[esp + 4 * 5]               ;esi = string
        lea     ebx,[esp + 4 * 6]               ;ebx = values
        movzx   edi,[esi + string_header.length];edi = length
    .loop_char:
        test    edi,edi
        jz      .done
        mov     al,[esi]
        mov     ebp,16                          ;ebp = base 16
        cmp     al,'#'
        jz      .number
        mov     ebp,10                          ;ebp = base 10
        cmp     al,'%'
        jz      .number
        cmp     al,'$'
        jz      .string
        mov     ecx,esi
        mov     edx,1
    .write:
        call    .write_bytes
    .next_char:
        dec     edi
        inc     esi
        jmp     .loop_char
    .string:
        mov     ecx,[ebx]                       ;ecx = address
        movzx   edx,[ecx + string_header.length]
        add     ebx,4
        jmp     .write
    .number:
        .max_number_length = 12
        mov     edx,[ebx]                       ;edx = number
        mov     ecx,esp
        sub     esp,.max_number_length
    .next_digit:
        mov     eax,edx
        xor     edx,edx
        div     ebp
        xchg    edx,eax
        cmp     al,10
        sbb     al,0x69
        das
        dec     ecx
        mov     [ecx],al
        test    edx,edx
        jnz     .next_digit
        lea     edx,[esp + .max_number_length]
        sub     edx,ecx                         ;edx = length
        call    .write_bytes
        add     esp,.max_number_length
        add     ebx,4
        jmp     .next_char
    .done:
        mov     ecx,ebx
        pop     ebp edi ebx esi eax             ;eax = return address
        mov     esp,ecx
        push    eax
        retn
    .write_bytes:
        ;ecx = address
        ;edx = length
        test    edx,edx
        jz      .write_bytes_done
        push    ebx
        mov     eax,SYS_WRITE
        mov     ebx,STD_OUTPUT
        call    [sys_call]
        pop     ebx
    .write_bytes_done:
        retn

segment readable writeable

align 4
sys_call dd default_sys_call    ;all kernel calls pass through this

symbol_scan_table:
        vsyscall        symbol_scan vsyscall_name
        sigreturn       symbol_scan sigreturn_name
        rt_sigreturn    symbol_scan rt_sigreturn_name
        gettimeofday    symbol_scan gettimeofday_name
        time            symbol_scan time_name
        clock_gettime   symbol_scan clock_gettime_name
        dummy           symbol_scan 0

DYNSYM                          table_info
STRTAB                          table_info
timer                           timespec
sys_call_AT_SYSINFO             rd 1
sys_call_Elf32_Ehdr.e_entry     rd 1
prev_time_stamp                 rq 1

segment readable

struc string [chars] {
    common
        local ..length, ..dummy
        ..dummy string_header ..length
        .       db chars
        ..length = $ - .
}

vsyscall_name           string '__kernel_vsyscall'
sigreturn_name          string '__kernel_sigreturn'
rt_sigreturn_name       string '__kernel_rt_sigreturn'
gettimeofday_name       string '__vdso_gettimeofday'
time_name               string '__vdso_time'
clock_gettime_name      string '__vdso_clock_gettime'

message_elf_header      string '0x# VDSO ELF header',10
message_found0          string '0x# vsyscall from AT_SYSINFO',10
message_found1          string '0x# vsyscall from Elf32_Ehdr.e_entry',10
message_symbol_found    string '0x# $',10
message_success         string 'Address match for Elf32_Ehdr.e_entry okay',10
message_e_entry_failed  string 'Elf32_Ehdr.e_entry not matched',10
message_untrusted_only  string 'Only untrusted vsyscall address found',10
message_none_found      string 'No vsyscall address found',10
message_int_0x80        string 'int_0x80 time %',10
message_vsyscall        string 'vsyscall time %',10
message_vdso            string 'vdso     time %',10    
A sample run gave me this:
Code:
0xF7711C80 vsyscall from AT_SYSINFO
0xF7711000 VDSO ELF header
0xF7711C80 vsyscall from Elf32_Ehdr.e_entry
0xF7711C80 __kernel_vsyscall
0xF7711CA0 __kernel_sigreturn
0xF7711CB0 __kernel_rt_sigreturn
0xF7711AD0 __vdso_gettimeofday
0xF7711C40 __vdso_time
0xF7711820 __vdso_clock_gettime
Address match for Elf32_Ehdr.e_entry okay
int_0x80 time 4694864
vsyscall time 3032215
vdso     time 117856    
I call the time function in three different ways. The direct ccall version doesn't enter the kernel so it is the most efficient. Using the vsyscall (which on my CPU uses the syscall instruction) and more efficient than the traditional int 0x80. Note that the times are in microseconds, and I call the functions 10,000,000 times each. Also note that symbols prefixed with "__kernel" use kernel calling semantics, and symbols prefixed with "__vdso" use ccall calling semantics.
Post 23 Jan 2019, 10:08
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 1431
Furs
I think AT_SYSINFO is perfectly fine to use on 32-bit x86. It's not available on x86_64 but that's what they mean with that. They're not going to break applications that rely on it for 32-bit x86 and it's the easiest method.

BTW, you also need to do this if you write it in a exe or DLL file (under Wine) and want to call Linux kernel from within that Razz But you can't rely on any shared libraries in this case and if you're coding a DLL then you can't rely on the environment variable either.

However there's still a way: read from /proc/self/auxv with normal system calls (int 0x80) and get the vDSO from there. Yes, I use it so I know it works.

Then you can have your exe or DLL detect if it's running under Linux via Wine and use the Linux kernel for... stuff.
Post 23 Jan 2019, 21:43
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16861
Location: In your JS exploiting you and your system
revolution
I can't imagine a case where I need to detect and call the Linux kernel from a Windows exe. It is a neat trick though.

What is a reliable method to detect Linux anyhow? Execute int 0x80 and catch the exception?
Post 28 Jan 2019, 07: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-2019, Tomasz Grysztar.

Powered by rwasa.