I'm working on a program written in assembly:
xor eax, eax ; make eax equal to 0
push eax ; pushes null
push 0x68732f2f ; pushes /sh (//)
push 0x6e69622f ; pushes /bin
mov ebx, esp ; passes the first argument
push eax ; empty third argument
mov edx, esp ; passes the third argument
push eax ; empty second argument
mov ecx, esp ; passes the second argument
mov al, 11 ; execve system call #11
int 0x80 ; makes an interrupt
When compiled using nasm
as a flat-form binary, I am seeing extraneous f
characters in the hex representation of the program. I am expecting to see:
0000000: 31c0 5068 2f2f 7368 682f 6269 6e89 e350 1.Ph//shh/bin..P
0000010: 89e2 5089 e1b0 0bcd 80 ..P......
but actually see:
0000000: 6631 c066 5066 682f 2f73 6866 682f 6269 f1.fPfh//shfh/bi
0000010: 6e66 89e3 6650 6689 e266 5066 89e1 b00b nf..fPf..fPf....
0000020: cd80 ..
Oddly, when I try to compile my program using nasm
in another format such as ELF-32, I see the hex representation I am expecting (albeit lots of other hex I probably shouldn't include in my solution):
0000000: 7f45 4c46 0101 0100 0000 0000 0000 0000 .ELF............
0000010: 0100 0300 0100 0000 0000 0000 0000 0000 ................
0000020: 4000 0000 0000 0000 3400 0000 0000 2800 @.......4.....(.
0000030: 0500 0200 0000 0000 0000 0000 0000 0000 ................
0000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000060: 0000 0000 0000 0000 0100 0000 0100 0000 ................
0000070: 0600 0000 0000 0000 1001 0000 1900 0000 ................
0000080: 0000 0000 0000 0000 1000 0000 0000 0000 ................
0000090: 0700 0000 0300 0000 0000 0000 0000 0000 ................
00000a0: 3001 0000 2100 0000 0000 0000 0000 0000 0...!...........
00000b0: 0100 0000 0000 0000 1100 0000 0200 0000 ................
00000c0: 0000 0000 0000 0000 6001 0000 3000 0000 ........`...0...
00000d0: 0400 0000 0300 0000 0400 0000 1000 0000 ................
00000e0: 1900 0000 0300 0000 0000 0000 0000 0000 ................
00000f0: 9001 0000 1000 0000 0000 0000 0000 0000 ................
0000100: 0100 0000 0000 0000 0000 0000 0000 0000 ................
0000110: 31c0 5068 2f2f 7368 682f 6269 6e89 e350 1.Ph//shh/bin..P
0000120: 89e2 5089 e1b0 0bcd 8000 0000 0000 0000 ..P.............
0000130: 002e 7465 7874 002e 7368 7374 7274 6162 ..text..shstrtab
0000140: 002e 7379 6d74 6162 002e 7374 7274 6162 ..symtab..strtab
0000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000170: 0100 0000 0000 0000 0000 0000 0400 f1ff ................
0000180: 0000 0000 0000 0000 0000 0000 0300 0100 ................
0000190: 0073 6865 6c6c 7370 6177 6e2e 6173 6d00 .shellspawn.asm.
For what I'm trying to accomplish I think I must use a flat-form binary.
My question: where is this f
character coming from and what does it mean; how do i remove it?
NASM version 2.10.09 compiled on Dec 29 2013
xxd V1.10 27oct98 by Juergen Weigert
nasm -f bin
sets the default mode to 16-bit. In that mode, 32-bit operand-size instructions (like xor eax,eax
or push eax
) have to be encoded with a 0x66
operand-size prefix. See this table of modes vs. prefixes for operand-size and address-size. (f
is 0x66
in ASCII). See also links to x86 manuals in the x86 tag wiki. See also how to disassemble flat binaries in 16, 32, or 64-bit mode.
-f elf
is a synonym for -felf32
, so its targeting 32-bit mode. -felf64
targets 64-bit mode (where push eax
is not encodeable).
See section 6.1 in the NASM manual: BITS 32
tells the assembler to assembler for 32-bit mode, overriding the default based on the output file format. IDK if there's a command-line option that makes flat binaries with 32-bit code. I don't see one in the man page or --help. If for some reason you really didn't want to change your sources, you could use -felf
and use ld --oformat binary
to link flat binaries. See How to generate plain binaries like nasm -f bin with the GNU GAS assembler?
Ah, the docs imply that BITS 32
is the only way:
The most likely reason for using the BITS directive is to write 32-bit or 64-bit code in a flat binary file;
code review of your actual code:
If you just want to pass pointers to NULL as the 2nd and 3rd args, why not have them both point to first push eax
result (which is also the string terminator)? i.e. xor-zero / push / mov edx, esp
/ mov ecx, esp
.
Also, the man page says you can actually pass a argv=NULL and envp=NULL (but warns that it's not portable and don't depend on it). So you could just xor edx,edx
/ push edx
/ ... / mov ecx,edx
/ lea eax, [edx+11]
.