Repository: guitmz/memrun Branch: master Commit: 4a5d8ca91eed Files: 8 Total size: 16.8 KB Directory structure: gitextract_cb4r4ys1/ ├── .gitattributes ├── LICENSE ├── README.md ├── assembly/ │ ├── README.md │ ├── memrun.asm │ ├── struct.inc │ └── utils.inc └── memrun.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ assembly/*.inc linguist-language=Assembly ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 Guilherme Thomazi Bonicontro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # memrun Small tool written in Golang to run ELF (x86_64) binaries from memory with a given process name. Works on Linux where kernel version is >= 3.17 (relies on the `memfd_create` syscall). # Usage Build it with `$ go build memrun.go` and execute it. The first argument is the process name (string) you want to see in `ps auxww` output for example. Second argument is the path for the ELF binary you want to run from memory. ``` Usage: memrun process_name elf_binary ``` ================================================ FILE: assembly/README.md ================================================ # memrun Small tool written in Assembly (FASM) to run ELF (x86_64) binaries from memory with a given process name. Works on Linux where kernel version is >= 3.17 (relies on the `memfd_create` syscall). # Usage Build it with `$ fasm memrun.asm` and execute it. The first argument is the path for the ELF binary you want to run from memory and the second argument is the process name (string) you want to see in `ps auxww` output for example. ``` Usage: memrun ``` ================================================ FILE: assembly/memrun.asm ================================================ format ELF64 executable 3 include "struct.inc" include "utils.inc" segment readable executable entry start start: ;----------------------------------------------------------------------------- ; parsing command line arguments ;----------------------------------------------------------------------------- pop rcx ; arg count cmp rcx, 3 ; needs to be at least two for the self program arg0 and target arg1 jne usage ; exit 1 if not add rsp, 8 ; skips arg0 pop rsi ; gets arg1 mov rdi, sourcePath push rsi ; save rsi push rdi call strToVar pop rsi ; restore rsi pop rdi mov rdi, targetProcessName pop rsi ; gets arg2 push rdi call strToVar ;----------------------------------------------------------------------------- ; opening source file for reading ;----------------------------------------------------------------------------- mov rdi, sourcePath ; loads sourcePath to rdi xor rsi, rsi ; cleans rsi so open syscall doesnt try to use it as argument mov rdx, O_RDONLY ; O_RDONLY mov rax, SYS_OPEN ; open syscall ; rax contains source fd (3) push rax ; saving rax with source fd ;----------------------------------------------------------------------------- ; getting source file information to fstat struct ;----------------------------------------------------------------------------- mov rdi, rax ; load rax (source fd = 3) to rdi lea rsi, [fstat] ; load fstat struct to rsi mov rax, SYS_FSTAT ; sys_fstat syscall ; fstat struct conntains file information mov r12, qword[rsi + 48] ; r12 contains file size in bytes (fstat.st_size) ;----------------------------------------------------------------------------- ; creating memory map for source file ;----------------------------------------------------------------------------- pop rax ; restore rax containing source fd mov r8, rax ; load r8 with source fd from rax mov rax, SYS_MMAP ; mmap number mov rdi, 0 ; operating system will choose mapping destination mov rsi, r12 ; load rsi with page size from fstat.st_size in r12 mov rdx, 0x1 ; new memory region will be marked read only mov r10, 0x2 ; pages will not be shared mov r9, 0 ; offset inside source file syscall ; now rax will point to mapped location push rax ; saving rax with mmap address ;----------------------------------------------------------------------------- ; close source file ;----------------------------------------------------------------------------- mov rdi, r8 ; load rdi with source fd from r8 mov rax, SYS_CLOSE ; close source fd syscall ;----------------------------------------------------------------------------- ; creating memory fd with empty name ("") ;----------------------------------------------------------------------------- lea rdi, [bogusName] ; empty string mov rsi, MFD_CLOEXEC ; memfd mode mov rax, SYS_MEMFD_CREATE syscall ; memfd_create mov rbx, rax ; memfd fd from rax to rbx ;----------------------------------------------------------------------------- ; writing memory map (source file) content to memory fd ;----------------------------------------------------------------------------- pop rax ; restoring rax with mmap address mov rdx, r12 ; rdx contains fstat.st_size from r12 mov rsi, rax ; load rsi with mmap address mov rdi, rbx ; load memfd fd from rbx into rdi mov rax, SYS_WRITE ; write buf to memfd fd syscall ;----------------------------------------------------------------------------- ; executing memory fd with targetProcessName ;----------------------------------------------------------------------------- xor rdx, rdx lea rsi, [argv] lea rdi, [fdPath] mov rax, SYS_EXECVE ; execve the memfd fd in memory syscall ;----------------------------------------------------------------------------- ; exit normally if everything works as expected ;----------------------------------------------------------------------------- jmp normal_exit ;----------------------------------------------------------------------------- ; initialized data ;----------------------------------------------------------------------------- segment readable writable fstat STAT usageMsg db "Usage: memrun ", 0xA, 0 sourcePath db 256 dup 0 targetProcessName db 256 dup 0 bogusName db "", 0 fdPath db "/proc/self/fd/3", 0 argv dd targetProcessName ================================================ FILE: assembly/struct.inc ================================================ ; Macroinstructions for defining data structures macro struct name { virtual at 0 define @struct field@struct equ name match child parent, name \{ restore field@struct field@struct equ child,fields@\#parent \} sub@struct equ struc db [val] \{ \common define field@struct .,db, \} struc dw [val] \{ \common define field@struct .,dw, \} struc du [val] \{ \common define field@struct .,du, \} struc dd [val] \{ \common define field@struct .,dd, \} struc dp [val] \{ \common define field@struct .,dp, \} struc dq [val] \{ \common define field@struct .,dq, \} struc dt [val] \{ \common define field@struct .,dt, \} struc rb count \{ define field@struct .,db,count dup (?) \} struc rw count \{ define field@struct .,dw,count dup (?) \} struc rd count \{ define field@struct .,dd,count dup (?) \} struc rp count \{ define field@struct .,dp,count dup (?) \} struc rq count \{ define field@struct .,dq,count dup (?) \} struc rt count \{ define field@struct .,dt,count dup (?) \} macro db [val] \{ \common \local anonymous define field@struct anonymous,db, \} macro dw [val] \{ \common \local anonymous define field@struct anonymous,dw, \} macro du [val] \{ \common \local anonymous define field@struct anonymous,du, \} macro dd [val] \{ \common \local anonymous define field@struct anonymous,dd, \} macro dp [val] \{ \common \local anonymous define field@struct anonymous,dp, \} macro dq [val] \{ \common \local anonymous define field@struct anonymous,dq, \} macro dt [val] \{ \common \local anonymous define field@struct anonymous,dt, \} macro rb count \{ \local anonymous define field@struct anonymous,db,count dup (?) \} macro rw count \{ \local anonymous define field@struct anonymous,dw,count dup (?) \} macro rd count \{ \local anonymous define field@struct anonymous,dd,count dup (?) \} macro rp count \{ \local anonymous define field@struct anonymous,dp,count dup (?) \} macro rq count \{ \local anonymous define field@struct anonymous,dq,count dup (?) \} macro rt count \{ \local anonymous define field@struct anonymous,dt,count dup (?) \} macro union \{ field@struct equ ,union,< sub@struct equ union \} macro struct \{ field@struct equ ,substruct,< sub@struct equ substruct \} } macro ends { match , sub@struct \{ restruc db,dw,du,dd,dp,dq,dt restruc rb,rw,rd,rp,rq,rt purge db,dw,du,dd,dp,dq,dt purge rb,rw,rd,rp,rq,rt purge union,struct irpv fields,field@struct \\{ restore field@struct \\common define fields@struct fields \\} match name tail,fields@struct, \\{ if $ display 'Error: definition of ',\\`name,' contains illegal instructions.',0Dh,0Ah err end if \\} match name=,fields,fields@struct \\{ restore @struct make@struct name,fields define fields@\\#name fields \\} end virtual \} match any, sub@struct \{ tmp@struct equ field@struct restore field@struct field@struct equ tmp@struct> \} restore sub@struct } macro make@struct name,[field,type,def] { common local define define equ name forward local sub match , field \{ make@substruct type,name,sub def define equ define,.,sub, \} match any, field \{ define equ define,.#field,type, \} common match fields, define \{ define@struct fields \} } macro define@struct name,[field,type,def] { common virtual db `name load initial@struct byte from 0 if initial@struct = '.' display 'Error: name of structure should not begin with a dot.',0Dh,0Ah err end if end virtual local list list equ forward if ~ field eq . name#field type def sizeof.#name#field = $ - name#field else label name#.#type rb sizeof.#type end if local value match any, list \{ list equ list, \} list equ list common sizeof.#name = $ restruc name match values, list \{ struc name value \\{ \\local \\..base match , @struct \\\{ define field@struct .,name, \\\} match no, @struct \\\{ label \\..base forward match , value \\\\{ field type def \\\\} match any, value \\\\{ field type value if ~ field eq . rb sizeof.#name#field - ($-field) end if \\\\} common label . at \\..base \\\} \\} macro name value \\{ match , @struct \\\{ \\\local anonymous define field@struct anonymous,name, \\\} match no, @struct \\\{ forward match , value \\\\{ type def \\\\} match any, value \\\\{ \\\\local ..field ..field = $ type value if ~ field eq . rb sizeof.#name#field - ($-..field) end if \\\\} common \\\} \\} \} } macro enable@substruct { macro make@substruct substruct,parent,name,[field,type,def] \{ \common \local define define equ parent,name \forward \local sub match , field \\{ match any, type \\\{ enable@substruct make@substruct type,parent,sub def purge make@substruct define equ define,.,sub, \\\} \\} match any, field \\{ define equ define,.\#field,type, \\} \common match fields, define \\{ define@\#substruct fields \\} \} } enable@substruct macro define@union parent,name,[field,type,def] { common virtual at parent#.#name forward if ~ field eq . virtual at parent#.#name parent#field type def sizeof.#parent#field = $ - parent#field end virtual if sizeof.#parent#field > $ - parent#.#name rb sizeof.#parent#field - ($ - parent#.#name) end if else virtual at parent#.#name label parent#.#type type def end virtual label name#.#type at parent#.#name if sizeof.#type > $ - parent#.#name rb sizeof.#type - ($ - parent#.#name) end if end if common sizeof.#name = $ - parent#.#name end virtual struc name [value] \{ \common label .\#name last@union equ forward match any, last@union \\{ virtual at .\#name field type def end virtual \\} match , last@union \\{ match , value \\\{ field type def \\\} match any, value \\\{ field type value \\\} \\} last@union equ field common rb sizeof.#name - ($ - .\#name) \} macro name [value] \{ \common \local ..anonymous ..anonymous name value \} } macro define@substruct parent,name,[field,type,def] { common virtual at parent#.#name forward local value if ~ field eq . parent#field type def sizeof.#parent#field = $ - parent#field else label parent#.#type rb sizeof.#type end if common sizeof.#name = $ - parent#.#name end virtual struc name value \{ label .\#name forward match , value \\{ field type def \\} match any, value \\{ field type value if ~ field eq . rb sizeof.#parent#field - ($-field) end if \\} common \} macro name value \{ \local ..anonymous ..anonymous name \} } ================================================ FILE: assembly/utils.inc ================================================ SYS_EXIT = 60 SYS_OPEN = 2 SYS_CLOSE = 3 SYS_WRITE = 1 SYS_READ = 0 SYS_STAT = 4 SYS_MEMFD_CREATE = 319 SYS_EXECVE = 59 SYS_FSTAT = 5 SYS_MMAP = 9 O_RDONLY = 0 MFD_CLOEXEC = 1 struct STAT st_dev dw ? ; ID of device containing file pad1 dw ? st_ino dd ? ; inode number st_mode dw ? ; protection st_nlink dw ? ; number of hard links st_uid dw ? ; user ID of owner st_gid dw ? ; group ID of owner st_rdev dw ? ; device ID (if special file) pad2 dw ? st_size dd ? ; total size, in bytes st_blksize dd ? ; block size st_blocks dd ? st_atime dd ? ; time of last access unused1 dd ? st_mtime dd ? ; time of last modification unused2 dd ? st_ctime dd ? ; time of last status change unused3 dd ? unused4 dd ? unused5 dd ? ends normal_exit: xor rdi, rdi ; exit code 0 mov rax, SYS_EXIT ; sys_exit syscall bad_exit: mov rdi, 1 mov rax, SYS_EXIT syscall usage: lea rdi, [usageMsg] call print jmp bad_exit strlen: ; rdi is the default search for scasb push rdi push rcx mov rcx, -1 xor eax, eax repne scasb not rcx mov rax, rcx pop rcx pop rdi ret print: push rsi push rdx push rdi call strlen mov rdx, rax mov rsi, rdi mov rdi, 1 mov rax, SYS_WRITE syscall pop rsi pop rdx pop rdi ret strToVar: mov al, [rsi] mov [rdi], al inc rsi inc rdi cmp byte [rsi], 0 ; Check for null terminator jne strToVar ; loop if not null ret ================================================ FILE: memrun.go ================================================ package main import ( "fmt" "io/ioutil" "os" "syscall" "unsafe" ) // the constant values below are valid for x86_64 const ( mfdCloexec = 0x0001 memfdCreate = 319 ) func runFromMemory(displayName string, filePath string) { fdName := "" // *string cannot be initialized fd, _, _ := syscall.Syscall(memfdCreate, uintptr(unsafe.Pointer(&fdName)), uintptr(mfdCloexec), 0) buffer, _ := ioutil.ReadFile(filePath) _, _ = syscall.Write(int(fd), buffer) fdPath := fmt.Sprintf("/proc/self/fd/%d", fd) _ = syscall.Exec(fdPath, []string{displayName}, nil) } func main() { lenArgs := len(os.Args) if lenArgs < 3 || lenArgs > 3 { fmt.Println("Usage: memrun process_name elf_binary") os.Exit(1) } runFromMemory(os.Args[1], os.Args[2]) }