flat assembler
Message board for the users of flat assembler.

Index > Main > Self assembling asm file. ASM+shell script in one file

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


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 03 Feb 2023, 07:26
A polyglot ASM+shell script in a single file. Simplifying the process of packaging and documenting all of the build variants and source code.

By marking the .asm file as executable and taking advantage of the OS using the shell to run text files that don't have the #! identifier in the first line, it is possible to make a dual language file combing the source and build script together. See the description in the code for how it works. This example for bash+fasm builds 32-bit and 64-bit outputs and then runs them.
Code:
false : rept 0 {

# save this as a .asm file and chmod +x

# within the shell:
# Linux automatically runs the default shell when text files don't have the leading #! signature
# the shell then runs the "false" executable and the four arguments ": rept 0 {" are ignored
# use "exit" at the end to prevent the shell from trying to interpret the assembly code

# within fasm:
# fasm creates a label named "false" and then defines a dummy block around this text
# you can include closing "}"s inside this text if they are enclosed within quotes
# as a bonus false=0 within the assembly code, you just need to define true=1 to complete the boolean set

EXE_NAME="${0%.*}"      # strip the trailing extension ".asm"
                        # the closing "}" there is ignored by fasm because it is inside quotes
for BITS in 32 64 ; do
        fasm -DBITS=$BITS "$0" "$EXE_NAME" && "$EXE_NAME" && rm "$EXE_NAME" || exit $?
done
exit 0

} ; close the dummy block and begin the assembly code

match BITS, BITS {      ; BITS is defined on the command line
        elf32 equ elf
        format elf#BITS executable

        segment executable

        text            db      'Hello from ',`BITS,'-bit world!',10
        len             =       $ - text
}

STDOUT_FILENO   =       1
entry $
if BITS = 64
        SYS_write       = 1
        SYS_exit        = 60
        mov     eax, SYS_write
        mov     edi, STDOUT_FILENO
        lea     rsi, [text]
        mov     edx, len
        syscall
        mov     eax, SYS_exit
        xor     edi, edi
        syscall
else
        SYS_write       = 4
        SYS_exit        = 1
        mov     eax, SYS_write
        mov     ebx, STDOUT_FILENO
        mov     ecx, text
        mov     edx, len
        int     0x80
        mov     eax, SYS_exit
        xor     ebx, ebx
        int     0x80
end if    
[edit] See below for a different trick that avoids creating any extra labels.


Last edited by revolution on 05 Feb 2023, 14:49; edited 1 time in total
Post 03 Feb 2023, 07:26
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 03 Feb 2023, 08:52
Here is a c+shell script version. Naturally the c code is just a wrapper for the more important asm code. Smile
Code:
//bin/true '
/*'

NAME="${0%.*}"
for BITS in 32 64 ; do
        gcc -m$BITS -DBITS=$BITS -x c -masm=intel -o "$NAME" "${0}" && "$NAME" && rm "$NAME" || exit $?
done

exit 0

*/

#include <unistd.h>             // STDOUT_FILENO
#include <sys/syscall.h>        // SYS_write, SYS_exit
#define S_(v) #v
#define S(v) S_(v)              // convert macro into literal string

const char text[] = "Hello from "S(BITS)"-bit world!\n";

int main() {
        asm (
#if BITS == 64
        "       mov     eax, "S(SYS_write)"     \n"
        "       mov     edi, "S(STDOUT_FILENO)" \n"
        "       lea     rsi, %[str]             \n"
        "       mov     edx, %[len]             \n"
        "       syscall                         \n"
        "       mov     eax, "S(SYS_exit)"      \n"
        "       xor     edi, edi                \n"
        "       syscall                         \n"
#else
        "       mov     eax, "S(SYS_write)"     \n"
        "       mov     ebx, "S(STDOUT_FILENO)" \n"
        "       lea     ecx, %[str]             \n"
        "       mov     edx, %[len]             \n"
        "       int     0x80                    \n"
        "       mov     eax, "S(SYS_exit)"      \n"
        "       xor     ebx, ebx                \n"
        "       int     0x80                    \n"
#endif
        :
        :
        [str]   "m" (text),
        [len]   "i" (sizeof (text)-1)
        );
}    
Post 03 Feb 2023, 08:52
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 05 Feb 2023, 14:49
There is a way to eliminate the extraneous false label and leave no constraints on the assembly source.

Bash + fasm:
Code:
false equ ; if false ; then
restore false
rept 0 {
fi

#; save this as a .asm file and chmod +x

#; within the shell:
#; Linux automatically runs the default shell when text files don't have the leading #! signature
#; the shell then runs the "false" executable and the argument "equ" is ignored
#; then the if/then/fi block encloses two fasm lines
#; use "exit" at the end to prevent the shell from trying to interpret the assembly code

#; within fasm:
#; make "false" an equ and then restore it
#; use "rept 0" to create a dummy block around this text
#; you can include closing "}"s inside this text if they are enclosed within quotes

for BITS in 32 64 ; do
        EXE_NAME="${0%.*}.$BITS"        # strip the trailing extension ".asm"
                                        # the closing "}" there is ignored by fasm because it is inside quotes
        fasm -DBITS=$BITS "$0" "$EXE_NAME" && "$EXE_NAME" && rm "$EXE_NAME" || exit $?
done
exit $?

} ; close the dummy block and begin the assembly code

match BITS, BITS {      ; BITS is defined on the command line
        elf32 equ elf
        format elf#BITS executable
        text    db      'Hello from ',`BITS,'-bit world!',10
        len     =       $ - text
}

STDOUT_FILENO   =       1
entry $
if BITS = 64
        SYS_write       = 1
        SYS_exit        = 60
        mov     eax, SYS_write
        mov     edi, STDOUT_FILENO
        lea     rsi, [text]
        mov     edx, len
        syscall
        mov     eax, SYS_exit
        xor     edi, edi
        syscall
else
        SYS_write       = 4
        SYS_exit        = 1
        mov     eax, SYS_write
        mov     ebx, STDOUT_FILENO
        mov     ecx, text
        mov     edx, len
        int     0x80
        mov     eax, SYS_exit
        xor     ebx, ebx
        int     0x80
end if    
Post 05 Feb 2023, 14:49
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 07 Feb 2023, 05:48
Bash + Batch + Windows + Linux + fasm self assembling hybrid, just run it on whatever system you have.
Code:
echo equ >/dev/null ; if false ; then # 2>NUL >NUL & goto BATCH
restore echo
rept 0 {        ; open dummy block so fasm ignores the build scripts
fi                                                                                              #
                                                                                                #
#; save this with CR/LF line endings as a .bat file and chmod +x
#; it needs a .bat extension or Windows won't run it
#; it needs chmod +x or *nix won't run it
#; each *nix script line needs to have a # to comment out the CR
                                                                                                #
#; bash script portion
#; this assembles and runs the ELF parts
FORMAT=elf                                                                                      #
for BITS in 32 64 ; do                                                                          #
        EXE_NAME="${0%.*}.$BITS"        # strip the trailing extension ".bat"
        fasm -DFORMAT=$FORMAT$BITS "$0" "$EXE_NAME" && "$EXE_NAME" && rm "$EXE_NAME" || exit $? #
done                                                                                            #
exit $?                                                                                         #

:BATCH
rem cmd script portion
rem assembles and runs the PE parts
@echo off
set FORMAT=pe
set EXE_NAME=%~dpn0
for %%E in (32, 64) do (
        if errorlevel 1 goto :DONE
        fasm -DFORMAT=%FORMAT%%%E "%0" "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
        "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
        del "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
)
:DONE
exit /b %errorlevel%

} ; close the dummy block and begin the assembly code

STDOUT_FILENO = 1
STD_OUTPUT_HANDLE = -11
if FORMAT eq elf32
        format elf executable
        text db 'Hello from 32-bit ELF world!',10
        len = $ - text
        SYS_write       = 4
        SYS_exit        = 1
        entry $
        mov     eax,SYS_write
        mov     ebx,STDOUT_FILENO
        mov     ecx,text
        mov     edx,len
        int     0x80
        mov     eax,SYS_exit
        xor     ebx,ebx
        int     0x80
else if FORMAT eq elf64
        format elf64 executable
        text db 'Hello from 64-bit ELF world!',10
        len = $ - text
        SYS_write       = 1
        SYS_exit        = 60
        entry $
        mov     eax,SYS_write
        mov     edi,STDOUT_FILENO
        lea     rsi,[text]
        mov     edx,len
        syscall
        mov     eax,SYS_exit
        xor     edi,edi
        syscall
else if FORMAT eq pe32
        format pe console
        data import
                dd      0,0,0,rva kernel_name,rva kernel_table
                dd      0,0,0,0,0
        kernel_table:
                ExitProcess     dd rva _ExitProcess
                GetStdHandle    dd rva _GetStdHandle
                WriteFile       dd rva _WriteFile
                                dd 0
        kernel_name             db 'KERNEL32.DLL',0
        _ExitProcess            db 0,0,'ExitProcess',0
        _GetStdHandle           db 0,0,'GetStdHandle',0
        _WriteFile              db 0,0,'WriteFile',0
        end data
        text db 'Hello from 32-bit PE world!',13,10
        len = $ - text
        entry $
        push    STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        push    0
        mov     ecx,esp
        push    0
        push    ecx
        push    len
        push    text
        push    eax
        call    [WriteFile]
        push    0
        call    [ExitProcess]
else if FORMAT eq pe64
        format pe64 console
        data import
                dd      0,0,0,rva kernel_name,rva kernel_table
                dd      0,0,0,0,0
        kernel_table:
                ExitProcess     dq rva _ExitProcess
                GetStdHandle    dq rva _GetStdHandle
                WriteFile       dq rva _WriteFile
                                dq 0
        kernel_name             db 'KERNEL32.DLL',0
        _ExitProcess            db 0,0,'ExitProcess',0
        _GetStdHandle           db 0,0,'GetStdHandle',0
        _WriteFile              db 0,0,'WriteFile',0
        end data
        text db 'Hello from 64-bit PE world!',13,10
        len = $ - text
        entry $
        sub     rsp, 8 * 7
        mov     ecx,STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        mov     rcx,rax
        lea     rdx,[text]
        mov     r8d,len
        lea     r9,[rsp + 4 * 8]
        mov     qword[rsp + 4 * 8],0
        call    [WriteFile]
        xor     ecx,ecx
        call    [ExitProcess]
end if    


Last edited by revolution on 07 Feb 2023, 10:25; edited 1 time in total
Post 07 Feb 2023, 05:48
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
ProMiNick 07 Feb 2023, 07:25
features that could be added(if possible):
check presence of fasm (presence of it setup(value of INCLUDE environment variable, is in linux exist equivalent of environment var, is it reachable from script?))
download fasm if notexisted, setup its INCLUDE var
by the way only console apps could be created & executed this way ? will script wait until GUI executable will close to delete executable (by GUI I mean GUI for both windows & linux, may be executing one of them not reachable from script in principle)? could script hide console window for cases of GUI executables? could script determine console or GUI.
all question are related to potential functionality of scripts, not to current script.
if add these features fasm would become full featured interpreter environment, while it source files would become equaled to native executables.
at current stage with absence of INCLUDE and limitation to console only - fasm is only console limited interpreter environment.
realy impressive, even on current state.
Post 07 Feb 2023, 07:25
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 07 Feb 2023, 07:30
You have the entire power of the scripting engine of your system to use. Go for it. Add all of those things.

I only posted the simplest examples so as not to get bogged down with tricky details hiding the meat.
Post 07 Feb 2023, 07:30
View user's profile Send private message Visit poster's website Reply with quote
ProMiNick



Joined: 24 Mar 2012
Posts: 798
Location: Russian Federation, Sochi
ProMiNick 07 Feb 2023, 08:13
Go for it - how about 50/50? In batch I could try to realise its part. But in case of bash I`m zero.
Post 07 Feb 2023, 08:13
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 07 Feb 2023, 10:22
Adding " & rem ^" the the end of the first line can allow for formatting with just LF line endings. Some newer versions of CMD.EXE are okay with only LF terminations.
Code:
echo equ >/dev/null ; if false ; then # 2>NUL >NUL & goto BATCH & rem ^
;...    
It should work for both line endings, but if you need to support older CMD.EXEs then still format with CR+LF anyway.
Post 07 Feb 2023, 10:22
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 07 Feb 2023, 10:24
ProMiNick wrote:
Go for it - how about 50/50? In batch I could try to realise its part. But in case of bash I`m zero.
I'll try to help where I can. but if you want a full Linux GUI layer then you might be waiting a while.

Post your stuff we can see how it goes.
Post 07 Feb 2023, 10:24
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 07 Feb 2023, 10:50
It is possible to make common code that works in 32-bit and 64-bit. Eliminating some need to create different versions for each bit width. Then add only minimal code to give an OS interface.
Code:
echo equ >/dev/null ; if false ; then # 2>NUL >NUL & goto BATCH & rem ^
restore echo
rept 0 {        ; open dummy block so fasm ignores the build scripts
fi                                                                              #
                                                                                #
#; save this with CR/LF line endings as a .bat file and chmod +x
#; it needs a .bat extension or Windows won't run it
#; it needs chmod +x or *nix won't run it
#; each *nix script line needs to have a # to comment out the CR
                                                                                #
#; bash script portion
#; this assembles and runs the ELF parts
FORMAT=ELF                                                                      #
for BITS in 32 64 ; do                                                          #
        EXE_NAME="${0%.*}.$BITS"        # strip the trailing extension ".bat"
        fasm -DFORMAT=$FORMAT -DBITS=$BITS "$0" "$EXE_NAME" &&                  #
                "$EXE_NAME" && rm "$EXE_NAME" || exit $?                        #
done                                                                            #
exit $?                                                                         #

:BATCH
@echo off
rem cmd script portion
rem assembles and runs the PE parts
set FORMAT=PE
set EXE_NAME=%~dpn0
for %%E in (32, 64) do (
        if errorlevel 1 goto :DONE
        fasm -DFORMAT=%FORMAT% -DBITS=%%E "%0" "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
        "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
        del "%EXE_NAME%.%%E.exe"
        if errorlevel 1 goto :DONE
)
:DONE
exit /b %errorlevel%

} ; close the dummy block and begin the assembly code

; internally use STDCALL for 32-bit, and a dodgy version of STDCALL for 64-bit

; OS interfacing
if FORMAT eq ELF
        STDOUT_FILENO = 1
        if BITS eq 32
                format elf executable
                SYS_write       = 4
                SYS_exit        = 1
            write:
                push    ebx
                mov     eax,SYS_write
                mov     ebx,STDOUT_FILENO
                mov     ecx,[esp+12]    ;text
                mov     edx,[esp+8]     ;len
                int     0x80
                pop     ebx
                ret     8
            exit:
                mov     eax,SYS_exit
                mov     ebx,[esp+4]
                int     0x80
        else if BITS eq 64
                format elf64 executable
                SYS_write       = 1
                SYS_exit        = 60
            write:
                push    rsi rdi
                mov     eax,SYS_write
                mov     edi,STDOUT_FILENO
                mov     rsi,[rsp+0x20]  ;text
                mov     edx,[rsp+0x18]  ;len
                syscall
                pop     rdi rsi
                ret     0x10
            exit:
                mov     eax,SYS_exit
                mov     rdi,[rsp+0x8]
                syscall
        end if
else if FORMAT eq PE
        macro imports def {
                data import
                        dd      0,0,0,rva kernel_name,rva kernel_table
                        dd      0,0,0,0,0
                kernel_table:
                        ExitProcess     def rva _ExitProcess
                        GetStdHandle    def rva _GetStdHandle
                        WriteFile       def rva _WriteFile
                                        def 0
                kernel_name             db 'KERNEL32.DLL',0
                _ExitProcess            db 0,0,'ExitProcess',0
                _GetStdHandle           db 0,0,'GetStdHandle',0
                _WriteFile              db 0,0,'WriteFile',0
                end data
        }
        STD_OUTPUT_HANDLE = -11
        if BITS eq 32
                format pe console
                imports dd
            write:
                push    STD_OUTPUT_HANDLE
                call    [GetStdHandle]
                push    0
                mov     ecx,esp
                push    0
                push    ecx
                push    dword[esp+0x10] ;len
                push    dword[esp+0x18] ;text
                push    eax
                call    [WriteFile]
                add     esp,4
                ret     8
            exit:
                add     esp,4
                call    [ExitProcess]
        else if BITS eq 64
                format pe64 console
                imports dq
            write:
                mov     r12,rsp
                and     rsp,-0x10
                sub     rsp, 8 * 6
                mov     ecx,STD_OUTPUT_HANDLE
                call    [GetStdHandle]
                mov     rcx,rax
                mov     rdx,[r12+0x10]  ;text
                mov     r8,[r12+0x8]    ;len
                lea     r9,[rsp + 4 * 8]
                mov     qword[rsp + 4 * 8],0
                call    [WriteFile]
                mov     rsp,r12
                ret     0x10
            exit:
                mov     rcx,[rsp+8]
                and     rsp,-0x10
                sub     rsp, 8 * 4
                call    [ExitProcess]
        end if
        purge imports
end if

; create an alternate set of register names tax, tbx, ... tsp
match =32, BITS { irp reg,ax,bx,cx,dx,si,di,bp,sp \{ t\#reg equ e\#reg \} }
match =64, BITS { irp reg,ax,bx,cx,dx,si,di,bp,sp \{ t\#reg equ r\#reg \} }

; common code for all variants

text1   db      'Hello from MAX='
        len1 = $ - text1
text2   db      ' '
                match F,FORMAT{db `F}
        db      ' world!',13,10
        len2 = $ - text2

print_decimal:
        .buff_size = BITS
        mov     tax,[tsp+BITS shr 3]
        push    tsi tdi
        mov     tsi,tsp
        sub     tsp,.buff_size
        mov     ecx,10
    .loop:
        xor     edx,edx
        div     tcx
        dec     tsi
        add     dl,'0'
        mov     [tsi],dl
        test    tax,tax
        jnz     .loop
        lea     tdx,[tsp+.buff_size]
        sub     tdx,tsi
        push    tsi tdx
        call    write
        add     tsp,.buff_size
        pop     tdi tsi
        ret     (BITS shr 3) * 1

entry $
        lea     tax,[text1]
        push    tax len1
        call    write
        push    -1
        call    print_decimal
        lea     tax,[text2]
        push    tax len2
        call    write
        push    0
        call    exit    
Post 07 Feb 2023, 10:50
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 08 Feb 2023, 04:52
The extraneous first line echo in CMD can be eliminated by changing the first two lines:
Code:
@echo equ 2>/dev/null ; if false ; then # 2>NUL >NUL & goto BATCH & rem ^
restore @echo    
Bash complains that @echo is not found but the error message is thrown into null.


Last edited by revolution on 10 Feb 2023, 15:00; edited 1 time in total
Post 08 Feb 2023, 04:52
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 09 Feb 2023, 17:55
With the extreme permissiveness in Linux with filenames it turns out the trying to replace the extention portion is riddled with problems. The method I used first EXE_NAME="${0%.*} fails in many ways. Sad

I came up with this small function just_name and a few test cases. It "works" as far as I can tell. I'm probably missing an obvious, more robust, and more elegant, way to do this.
Code:
just_name () {
  PATH_=$(dirname -- "${1}")
  NAME=$(basename -- "${1}")
  EXT="${NAME##*.}"
  NAME=$(basename -- "${NAME}" ".${EXT}")
  EXE_NAME="${PATH_}/${NAME}"
  echo "${EXE_NAME}" ;
}
# some test vectors
declare -a a
a[0]="/path.to/me.ext"
a[1]="/path.to/me."
a[2]="/path.to/me"
a[3]="/path.to/.me"
a[4]="me.ext"
a[5]="me."
a[6]="me"
a[7]=".me"
a[8]="--me"
a[9]=".--me"
a[10]="m e.ext"
a[11]="m e."
a[12]="m e"
a[13]="m  e.ext"
a[14]="m  e."
a[15]="m  e"
a[16]="m "$'\n'" e"
for path in "${a[@]}" ; do
  just_name "${path}"
done    
Post 09 Feb 2023, 17:55
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 10 Feb 2023, 14:19
Why replace any generic extension? Just append to it, or replace a specific extension (e.g. .sh) if you want to. I would certainly be wary of a tool that tries to be too smart if I rename its filename to something else.

Anyway this is pretty awesome.
Post 10 Feb 2023, 14:19
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 10 Feb 2023, 15:13
Furs wrote:
Why replace any generic extension? Just append to it, or replace a specific extension (e.g. .sh) if you want to.
You might be right.

It's just that GenericAppName.bat.exe doesn't feel right to me. That is like something phishing emails do ImportantDocument.txt.exe.

So if one doesn't care about the final name then a more simple SOURCE_NAME=$(dirname -- "$0")/$(basename -- "$0") creates a "sanitised" name always starting with either dot or slash so no accidental dash to invoke trouble.
Post 10 Feb 2023, 15:13
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 11 Feb 2023, 05:15
Less than 1000 bytes source, 4 lines of preamble. A bit of code golf to show the bare minimum.
Code:
@echo equ 2>/dev/null ; if false ; then # 2>NUL >NUL & goto BATCH & rem ^
rept 0 { ; fi ; fasm -DFORMAT=elf "$0" "$0.32" && "$0.32" && rm "$0.32" ; exit $? #
:BATCH
@echo off & fasm -DFORMAT=pe "%0" & "%~dpn0" & del "%~dpn0.exe" & exit /b %errorlevel% & }
if FORMAT eq elf
        format elf executable
        mov     eax,4   ;SYS_write
        mov     ebx,1   ;STDOUT_FILENO
        mov     ecx,text
        mov     edx,len
        int     0x80
        mov     eax,1   ;SYS_exit
        xor     ebx,ebx
        int     0x80
else if FORMAT eq pe
        format pe console
        push    -11     ;STD_OUTPUT_HANDLE
        call    [GetStdHandle]
        lea     ecx,[esp-8]
        push    0 0 ecx len text eax
        call    [WriteFile]
        call    [ExitProcess]
        kernel_name     db 'KERNEL32.DLL',0
        _ExitProcess    db 0,0,'ExitProcess',0
        _GetStdHandle   db 0,0,'GetStdHandle',0
        _WriteFile      db 0,0,'WriteFile',0
        ExitProcess     dd rva _ExitProcess
        GetStdHandle    dd rva _GetStdHandle
        WriteFile       dd rva _WriteFile,0
        data import
                dd 0,0,0,rva kernel_name,rva ExitProcess,5 dup 0
        end data
end if
text db 'Hello world!',13,10
len = $-text    
Post 11 Feb 2023, 05:15
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 11 Feb 2023, 19:09
revolution wrote:
Furs wrote:
Why replace any generic extension? Just append to it, or replace a specific extension (e.g. .sh) if you want to.
You might be right.

It's just that GenericAppName.bat.exe doesn't feel right to me. That is like something phishing emails do ImportantDocument.txt.exe.

So if one doesn't care about the final name then a more simple SOURCE_NAME=$(dirname -- "$0")/$(basename -- "$0") creates a "sanitised" name always starting with either dot or slash so no accidental dash to invoke trouble.
That's fine, then just replace the .bat, and if someone renames it to something else, append instead. Most times, programs on Linux don't have an extension at all, since you launch them by name directly, without weird "default extensions" trying like Windows shell does.

I guess you need to make sure it's not named only .bat (i.e. starting with dot) cause that's a special case on Linux (hidden files).
Post 11 Feb 2023, 19:09
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20302
Location: In your JS exploiting you and your system
revolution 14 Feb 2023, 20:48
An auto-patching x32 executable.

fasm doesn't natively support x32 outputs. But it is easy to make an x32 executable.
Code:
false equ ; if false ; then
rept 0 { ; fi

        EXE_NAME="$0.x32"
        fasm "$0" "$EXE_NAME"                                                              || exit $?
        # patch byte at 0x12 (e_machine) from 0x03 (x86) to 0x3e (AMD x86-64)
        printf '\x3e' | dd of="$EXE_NAME" count=1 bs=1 seek=18 conv=notrunc 2>/dev/null    || exit $?
        "$EXE_NAME"                                                                        || exit $?
        rm "$EXE_NAME"                                                                     || exit $?
        exit $?

} restore false

format elf executable at 1 shl 16       ; normal 32 bit elf header that needs byte 0x12 patched
use64                                   ; x32 is 64-bit mode

; the syscall entry numbers have their own range
; see /usr/include/x86_64-linux-gnu/asm/unistd_x32.h
__X32_SYSCALL_BIT       = 0x40000000
SYSx32_write            = (__X32_SYSCALL_BIT + 1)
SYSx32_exit             = (__X32_SYSCALL_BIT + 60)

entry $
        mov     eax,SYSx32_write
        mov     edi,1           ; syscall registers are the same as 64-bit
        lea     esi,[message]   ; can use 32-bit addressing
        mov     edx,len         ; third arg is rdx
        ;mov    r10,4           ; fourth arg is r10
        ;mov    r8,5            ; fifth arg is r8
        ;mov    r9,6            ; sixth arg is r9
        syscall
        mov     eax,SYSx32_exit
        xor     edi,edi
        syscall
; yes
        add     r10,r15         ; can use 64-bit registers
        pxor    xmm15,xmm15     ; can use 16 xmm registers
; no
        ;push   eax             ; can't push 32-bit values
        ;daa                    ; can't use daa, das, ... etc.

message db 'Hello from x32 ELF World!',10
len = $ - message    
Post 14 Feb 2023, 20:48
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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.