Windows (x86) Assembly Append Null Terminator To Inputted String - windows

I am currently trying to append a null terminator to an(a?) user inputted string:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
buff DB 100h DUP(?)
stdInHandle DWORD 0
bytesRead DWORD ?
.code
start:
;read string from stdin
INVOKE GetStdHandle, -10
MOV stdInHandle, eax
INVOKE ReadFile, stdInHandle, BYTE PTR[buff], 100, ADDR bytesRead, 0
;append null terminator on CR,LF
MOV eax, bytesRead
MOV edx, BYTE PTR[buff]
SUB eax, 2
AND BYTE PTR [eax+edx], 0
RET
END start
It refuses to assemble at MOV edx, BYTE PTR[buff] and gives me an error:
error: Invalid combination of opcode and operands (or wrong CPU setting).
So I'm assuming I cannot MOV the value of BYTE PTR[buff] into register edx. So I can't even begin to test if this method of trying to apply a NULL terminator to a string will even work.
My question is, what is wrong with the above code (should I use a different register instead of edx?)
What is the best way to apply a NULL terminator to the string?

You can't move a byte value into a dword sized register. You either need to use a byte sized register such as dl, or zero-extend it with movzx. As you are working with bytes, I suggest you go with the first option.

When I had to create methods for strings without using anything from good ole Irvine, I got the length of the string, incremented what the length returned as (you need to include an extra +1 for the null-terminator) by 1, and then added 0h to the end of the string where the pointer was where the counter is.
MOV EAX, SIZEOF lpSourceString + 1 ; Get the string length of string, add 1 to include null-terminator
INVOKE allocMem, EAX ; Allocate memory for a target to copy to
LEA ESI, [lpSourceString] ; put source address in ESI
MOV EDI, EAX ; copy the dest address to another register we can increment
MOV ECX, SIZEOF lpSourceString ; Set up loop counter
We have the size of the string. Now we can add the null-terminate to it. To do that, we need to make sure that we have a pointer looking at the end of the string. So if we have a method that returns a string in EAX, EAX needs to point to the start of the string (so we leave the allocMem unmodified, instead incrementing a copy in EDI). Let's say that we are putting characters in a string:
nextByte: ; Jump label, get the next byte in the string until ECX is 0
MOV DL, [ESI] ; Get the next character in the string
MOV [EDI], DL ; Store the byte at the position of ESI
INC ESI ; Move to next char in source
INC EDI ; INCrement EDI by 1
loop nextByte ; Re-loop to get next byte
MOV byte ptr[EDI], 0h ; Add null-terminator to end of string
; EAX holds a pointer to the start of the dynamically-allocated
; 0-terminated copy of lpSourceString
MOV requires the byte ptr size specifier because neither the [EDI] memory operand nor the 0 immediate operand would imply a size for the operation. The assembler wouldn't know if you meant a byte, word, or dword store.
I have this in my MASM, but I use a String_length stdcall method I had written due to a class requirement.

This is so common that the MASM32 runtime supplies this functionality as part of its runtime. All you need to do is include the relevant code:
include \masm32\include\masm32rt.inc
Then use the StripLF function as so:
invoke StripLF, addr buff
To fix your current problem (if you want to do it manually) , you need to move the address of buff to edx instead.
mov edx, offset buff

Related

How to find out the age of a file in ASM?

Greetings to all the geniuses of the digital age
Yesterday's task is still on the agenda: "Use the GetOpenFileName function to select a file. Check if the file is less than 3 days old, execute it. Otherwise, display a dialog asking to delete the file. If the user needs it, wipe." (Note: If a task is told to use a structure, it must be placed in dynamically allocated memory)"
I figured out how to open the file and now everything works like a Swiss watch. But another trouble arose.
How to determine the age of a file?
In general, I first thought to use GetFileTime to extract all data about the file time, then use FileTimeToLocalFileTime to convert it to local time, and using FileTimeToSystemTime - to system time. Then subtract one from the other using sub, and so on as per the task.
Here, the FileTimeToLocalFileTime function requires a FILETIME structure with the following parameters:
DWORD dwLowDateTime;
DWORD dwHighDateTime;
And the FileTimeToSystemTime function requires a SYSTEMTIME structure with the following parameters:
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
And how to be then? How to find the age of a file? Is there any alternative way? And if my method works, then what exactly and from what should I take it?
File.inc
include WINDOWS.inc
include user32.inc
include kernel32.inc
include comdlg32.inc
includelib user32.lib
includelib kernel32.lib
includelib comdlg32.lib
.data
Time_title db ' Lab_3',0
format db 'More than 3 days. Delete file?', 0
buf db 255 dup(0)
hFile dd 0
readed dd 0
hmem dd 0
File.asm
.386
.model flat,STDCALL
option casemap :none ;case sensitive
include Third.inc
include RADbg.inc
Mem_Alloc PROC Buf_Size:DWORD
add Buf_Size,4
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,Buf_Size
push eax
invoke GlobalLock,eax
pop [eax]
add eax,4
Mem_Alloc endp
Mem_Free PROC DATA:DWORD
mov eax,DATA
sub eax,4
mov eax,[eax]
push eax
push eax
call GlobalUnlock
call GlobalFree
Mem_Free endp
.code
Begin:
call main
invoke ExitProcess,NULL
main proc
LOCAL ftCreate, ftLocale: FILETIME;
LOCAL stUTC, stLocal: SYSTEMTIME;
invoke Mem_Alloc, 1000h
mov hmem, eax
invoke Mem_Alloc, sizeof OPENFILENAME
mov edi, eax
assume edi: ptr OPENFILENAME
xor eax, eax
mov [edi].lStructSize, sizeof OPENFILENAME
mov [edi].lpstrFile, offset buf
mov [edi].nMaxFile, 255
invoke GetOpenFileName, edi
invoke CreateFile, [edi].lpstrFile, GENERIC_READ,\
FILE_SHARE_READ, NULL, OPEN_EXISTING,\
FILE_ATTRIBUTE_NORMAL, NULL
mov hFile,eax ;
invoke GetFileTime, hFile, addr ftCreate, NULL, NULL
invoke FileTimeToLocalFileTime, addr ftCreate, addr ftLocale
invoke FileTimeToSystemTime, addr ftCreate, addr stUTC
cmp eax, 1
jz l1
invoke ReadFile, hFile, hmem, 1000h, addr readed, 0
invoke MessageBox, 0, hmem, addr Time_title, MB_OKCANCEL
jmp l2
l1:
invoke MessageBox, 0, addr format, addr Time_title, MB_OKCANCEL
cmp eax, IDOK
jne l2
invoke DeleteFile, addr [edi].lpstrFile
l2:
assume edi: dword
invoke CloseHandle, hFile
invoke Mem_Free, hmem
invoke Mem_Free, edi
ret
main endp
end Begin
As FILETIME and RtlTimeToSecondsSince1970 said, You should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member.
So, subtract the 64-bit value in the ULARGE_INTEGER structure initialized with the file time from the 64-bit value of the ULARGE_INTEGER structure initialized with the current system time.

FASM write Hello World to console with NO includes or dependencies at all

I've seen
How to write hello world in assembler under Windows?
and
Writing hello,world to console in Fasm with DOS
How to write to the console in fasm?
I've tried / seen code like this MASM example from this answer
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
(to which I get an error "Illegal instruction" on windows 64 bit extrn MessageBoxA:PROC because FASM doesn't understand that MASM directive.)
also this FASM example from this question
; Example of 64-bit PE program
format PE64 GUI
entry start
section '.text' code readable executable
start:
sub rsp,8*5 ; reserve stack for API use and make stack dqword aligned
mov r9d,0
lea r8,[_caption]
lea rdx,[_message]
mov rcx,0
call [MessageBoxA]
mov ecx,eax
call [ExitProcess]
section '.data' data readable writeable
_caption db 'Win64 assembly program',0
_message db 'Hello World!',0
section '.idata' import data readable writeable
dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0
kernel_table:
ExitProcess dq RVA _ExitProcess
dq 0
user_table:
MessageBoxA dq RVA _MessageBoxA
dq 0
kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0
_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0
but it displays a message box and also has external dependencies "kernel32.dll" and "user32.dll"
also tried this example from the FASM forum
format pe console
include 'win32ax.inc'
entry main
section '.data!!!' data readable writeable
strHello db 'Hello World !',13,10,0
strPause db 'pause',0
section '.txt' code executable readable
main:
; you can use crt functions or windows API.
cinvoke printf,strHello
cinvoke system,strPause; or import getc()
; or
; invoke printf,srtHello
; add esp, 4
; or use WriteFile and GetStdHandle APIs
push 0
call [ExitProcess]
section '.blah' import data readable
library kernel32,'kernel32.dll',\
msvcrt,'msvcrt.dll' ;; C-Run time from MS. This is always on every windows machine
import kernel32,\
ExitProcess,'ExitProcess'
import msvcrt,\
printf,'printf',\
system,'system'
but it depends on win32ax.inc and other imports
also
format PE console
include 'win32ax.inc'
.code
start:
invoke WriteConsole,<invoke GetStdHandle,STD_OUTPUT_HANDLE>,"Hello World !",13,0
invoke Sleep,-1
.end start
but requires "win32ax.inc" import
closest I could find without the win32ax from the FASM forum:
format pe64 console
entry start
STD_OUTPUT_HANDLE = -11
section '.text' code readable executable
start:
sub rsp,8*7 ; reserve stack for API use and make stack dqword aligned
mov rcx,STD_OUTPUT_HANDLE
call [GetStdHandle]
mov rcx,rax
lea rdx,[message]
mov r8d,message_length
lea r9,[rsp+4*8]
mov qword[rsp+4*8],0
call [WriteFile]
mov ecx,eax
call [ExitProcess]
section '.data' data readable writeable
message db 'Hello World!',0
message_length = $ - message
section '.idata' import data readable writeable
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
user_name db 'USER32.DLL',0
_ExitProcess db 0,0,'ExitProcess',0
_GetStdHandle db 0,0,'GetStdHandle',0
_WriteFile db 0,0,'WriteFile',0
but still requires the kernel32.dll and user32.dll
Any way to do this without any external DLLs at all? I know just the program fasm itself does it, and prints to the console, doesn't it?
Any way to do this without any external DLLs at all?
Under Windows: Definitely no!
Windows uses some methods (probably syscall) to enter the operating system, however, there are no official entry points.
This means that it is (unlikely but) possible that exactly the same program that shows the "Hello world" message box in the current Windows version will do something completely different after the next Windows update!
Because Microsoft is assuming that every Windows program is only calling the OS by using the .dll files that match the kernel version, they can do this.
I don't know about Windows 10, but an older Windows version (I don't remember if it was XP, Vista or 7) even simply assumed that an .exe file returns at once if it does not use any .dll file: The program was not even started in this case!
I know just the program fasm itself does it, and prints to the console
That is not the case, fasm is also using the kernel32 APIs.
FWIW kernel32 is loaded into the memory space of every process in Windows, so there is no penalty or overhead in using the kernel32 APIs.
You may like this Windows example in €ASM, which doesn't explicitly mention any DLL and doesn't require other external libraries.
Just save the source as "bluej.asm", assemble and link with euroasm bluej.asm and run as bluej.exe.
Nevertheless, you won't get away without using API functions imported from the default Windows system library "kernel32.dll".
bluej PROGRAM Format=PE, Entry=Start:
IMPORT GetStdHandle,WriteFile,ExitProcess
Start: PUSH -11 ; Param 1: standard output handle identificator.
CALL GetStdHandle; Return StdOutput handle in EAX.
PUSH 0 ; Param 5: no overlap.
PUSH Written ; Param 4: Address of a variable to store number of written bytes.
PUSH MsgSize ; Param 3: Number of bytes to write.
PUSH Msg ; Param 2: Address of text.
PUSH EAX ; Param 1: Output file handle.
CALL WriteFile ; System call.
PUSH 0 ; Errorlevel.
CALL ExitProcess ; System call.
Written DD 0
Msg DB "Hello, world!"
MsgSize EQU $ - Msg
ENDPROGRAM
What constitures as "dependency" to you? If you want to avoid even operating system DLL's, then you're probably out of luck. You can't rely on syscall numbers alone.
"no dependencies" can also mean "just using existing OS DLL's", such as ntdll, kernel32, etc., but without using 3rd party DLL's that may not be present, such as a specific version of the C runtime.
One method I would like to show is retrieving function pointers from the PEB. This is code that I've written and that I personally use, if I want to have shellcode that has no import section.
PebGetProcAddress works similarly to GetProcAddress, except that the DLL name and function name must be a hash, and the DLL must be loaded by using LoadLibrary.
This may not answer your question exactly, but I hope it gets you somewhat closer to your goal or help others who read it.
PebApi.asm
proc PebGetProcAddress ModuleHash:DWORD, FunctionHash:DWORD
local FirstEntry:DWORD
local CurrentEntry:DWORD
local ModuleBase:DWORD
local ExportDirectory:DWORD
local NameDirectory:DWORD
local NameOrdinalDirectory:DWORD
local FunctionCounter:DWORD
; Get InMemoryOrderModuleList from PEB
mov eax, 3
shl eax, 4
mov eax, [fs:eax] ; fs:0x30
mov eax, [eax + PEB.Ldr]
mov eax, [eax + PEB_LDR_DATA.InMemoryOrderModuleList.Flink]
mov [FirstEntry], eax
mov [CurrentEntry], eax
; Find module by hash
.L_module:
; Compute hash of case insensitive module name
xor edx, edx
mov eax, [CurrentEntry]
movzx ecx, word[eax + LDR_DATA_TABLE_ENTRY.BaseDllName.Length]
test ecx, ecx
jz .C_module
mov esi, [eax + LDR_DATA_TABLE_ENTRY.BaseDllName.Buffer]
xor eax, eax
cld
.L_module_hash:
lodsb
ror edx, 13
add edx, eax
cmp al, 'a'
jl #f
sub edx, 0x20 ; Convert lower case letters to upper case
##: dec ecx
test ecx, ecx
jnz .L_module_hash
; Check, if module is found by hash
cmp edx, [ModuleHash]
jne .C_module
; Get module base
mov eax, [CurrentEntry]
mov eax, [eax + LDR_DATA_TABLE_ENTRY.DllBase]
mov [ModuleBase], eax
; Get export directory
mov eax, [ModuleBase]
add eax, [eax + IMAGE_DOS_HEADER.e_lfanew]
mov eax, [eax + IMAGE_NT_HEADERS32.OptionalHeader.DataDirectoryExport.VirtualAddress]
add eax, [ModuleBase]
mov [ExportDirectory], eax
; Get name table
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfNames]
add eax, [ModuleBase]
mov [NameDirectory], eax
; Get name ordinal table
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
add eax, [ModuleBase]
mov [NameOrdinalDirectory], eax
; Find function in export directory by hash
mov [FunctionCounter], 0
.L_functions:
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.NumberOfNames]
cmp eax, [FunctionCounter]
je .E_functions
; Compute hash of function name
xor edx, edx
mov esi, [NameDirectory]
mov esi, [esi]
add esi, [ModuleBase]
xor eax, eax
cld
.L_function_hash:
lodsb
test al, al
jz .E_function_hash
ror edx, 13
add edx, eax
jmp .L_function_hash
.E_function_hash:
; Check, if function is found by hash
cmp edx, [FunctionHash]
jne .C_functions
; Return function address
mov eax, [ExportDirectory]
mov eax, [eax + IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
add eax, [ModuleBase]
mov ebx, [NameOrdinalDirectory]
movzx ebx, word[ebx]
lea eax, [eax + ebx * 4]
mov eax, [eax]
add eax, [ModuleBase]
ret
.C_functions:
add [NameDirectory], 4
add [NameOrdinalDirectory], 2
inc [FunctionCounter]
jmp .L_functions
.E_functions:
; Function not found in module's export table
xor eax, eax
ret
.C_module:
; Move to next module, exit loop if CurrentEntry == FirstEntry
mov eax, [CurrentEntry]
mov eax, [eax + LIST_ENTRY.Flink]
mov [CurrentEntry], eax
cmp eax, [FirstEntry]
jne .L_module
; Module not found
xor eax, eax
ret
endp
PebApi.inc
macro pebcall modulehash, functionhash, [arg]
{
common
if ~ arg eq
reverse
pushd arg
common
end if
stdcall PebGetProcAddress, modulehash, functionhash
call eax
}
Example
PEB_User32Dll = 0x63c84283
PEB_MessageBoxW = 0xbc4da2be
; pebcall translates to a call to PebGetProcAddress and the call to the returned function pointer
pebcall PEB_User32Dll, PEB_MessageBoxW, NULL, 'Hello, World!', NULL, MB_OK
How to generate hashes for module names and function names
#define ROTR(value, bits) ((DWORD)(value) >> (bits) | (DWORD)(value) << (32 - (bits)))
DWORD ComputeFunctionHash(LPCSTR str)
{
DWORD hash = 0;
while (*str)
{
hash = ROTR(hash, 13) + *str++;
}
return hash;
}
DWORD ComputeModuleNameHash(LPCSTR str, USHORT length)
{
DWORD hash = 0;
for (USHORT i = 0; i < length; i++)
{
hash = ROTR(hash, 13) + (str[i] >= 'a' ? str[i] - 0x20 : str[i]);
}
return hash;
}

How to fix: (cannot have implicit far jump or call to near label) and (use a register assumed to ERROR)

I'm trying to create dll using VS 2017.
The dll will have one proc: symbol_count.
It asks to enter the string and then set symbol what is needed to count.
.def file
LIBRARY name
EXPORTS
symbol_count
Code:
.586
.model flat, stdcall
option casemap: none
include C:\masm32\include\windows.inc
include C:\masm32\include\user32.inc
include C:\masm32\include\msvcrt.inc
includelib C:\masm32\lib\msvcrt.lib
includelib C:\masm32\lib\user32.lib
.data
msg_string db 'Enter string: ', 0
msg_symbol db 'Enter symbol: ', 0
result db 'Count = %d', 0
str_modifier db '%s', 0
sym_modifier db '%c', 0
.data
string db ?
symbol db ?
DllEntry PROC hInstDLL:DWORD, reason:DWORD, reserved:DWORD
mov eax, 1
ret
DllEntry ENDP
symbol_count PROC
invoke crt_printf, OFFSET msg_string
invoke crt_scanf, OFFSET str_modifier, OFFSET string
invoke crt_printf, OFFSET msg_symbol
invoke crt_scanf, OFFSET sym_modifier, OFFSET symbol
xor esi, esi
xor ecx, ecx
mov ebx, OFFSET string
mov ecx, eax
mov al, symbol
loop1: <------------------------------------------ A2108
cmp byte ptr [ebx + ecx], 0
je endloop <------------------------------ A2107
cmp al, byte ptr [ebx + ecx]
jne next <-------------------------------- A2107
inc esi
next: <------------------------------------------- A2108
inc ecx
jmp loop1 <------------------------------- A2107
endloop: <---------------------------------------- A2108
invoke crt_printf, OFFSET result, esi
ret
symbol_count ENDP
End DllEntry
Here is the list of error messages, what a compiler gives to me: (
in the code, I marked the places where the compiler swears)
A2108 use of register assumed to ERROR
A2108 use of register assumed to ERROR
A2108 use of register assumed to ERROR
A2107 cannot have implicit far jump or call to near label
A2107 cannot have implicit far jump or call to near label
A2107 cannot have implicit far jump or call to near label
procedure argument or local not referenced : hInstDLL } all this points
procedure argument or local not referenced : reason } to DllEntry ENDP
procedure argument or local not referenced : reserved }
"You put your code into the .data section which may or may not cause some of the errors. The last 3 should just be warnings as you don't use the arguments." – #Jester

Why syscall doesn't work?

I'm on MAC OSX and I'm trying to call through assembly the execve syscall..
His opcode is 59 .
In linux I have to set opcode into eax, then parameters into the others registers, but here I have to put the opcode into eax and push parameters into the stack from right to left.
So I need execve("/bin/sh",NULL,NULL), I found somewhere that with assembly null=0, so I put null into 2nd and 3rd parameters.
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
pop ebx ;stringa
push 0x0 ;3rd param
push 0x0 ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
int 0x80
string:
call main
db '/bin/sh',0
When I try to execute it say:
Bad system call: 12
32-bit programs on BSD (on which OS/X is based) requires you to push an extra 4 bytes onto the stack if you intend to call int 0x80 directly. From the FreeBSD documentation you will find this:
By default, the FreeBSD kernel uses the C calling convention. Further, although the kernel is accessed using int 80h, it is assumed the program will call a function that issues int 80h, rather than issuing int 80h directly.
[snip]
But assembly language programmers like to shave off cycles. The above example requires a call/ret combination. We can eliminate it by pushing an extra dword:
open:
push dword mode
push dword flags
push dword path
mov eax, 5
push eax ; Or any other dword
int 80h
add esp, byte 16
When calling int 0x80 you need to adjust the stack pointer by 4. Pushing any value will achieve this. In the example they just do a push eax. Before your calls to int 0x80 push 4 bytes onto the stack.
Your other problem is that add eax,0x3b for example requires EAX to already be zero which is almost likely not the case. To fix that add an xor eax, eax to the code.
The fixes could look something like:
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
xor eax, eax ;zero EAX
pop ebx ;stringa
push 0x0 ;3rd param
push 0x0 ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
push eax ;Push a 4 byte value after parameters per calling convention
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
push eax ;Push a 4 byte value after parameters per calling convention
; in this case though it won't matter since the system call
; won't be returning
int 0x80
string:
call main
db '/bin/sh',0
Shellcode
Your code is actually called the JMP/CALL/POP method and is used for writing exploits. Are you writing an exploit or did you just find this code online? If it is intended to be used as shell code you would need to avoid putting a 0x00 byte in the output string. push 0x00 will encode 0x00 bytes in the generated code. To avoid this we can use EAX which we are now zeroing out and push it on the stack. As well you won't be able to NUL terminate the string so you'd have to move a NUL(0) character into the string. One way after zeroing EAX and popping EBX is to move zero to the end of the string manually with something like mov [ebx+7], al. Seven is the index after the end of the string /bin/sh. Your code would then look like this:
global start
section .text
start:
jmp string
main:
; 59 opcode
; int execve(char *fname, char **argp, char **envp);
xor eax, eax ;Zero EAX
pop ebx ;stringa
mov [ebx+7], al ;append a zero onto the end of the string '/bin/sh'
push eax ;3rd param
push eax ;2nd param
push ebx ;1st param
add eax,0x3b ;execve opcode
push eax
int 0x80 ;interupt
sub eax,0x3a ; exit opcode
push eax
int 0x80
string:
call main
db '/bin/sh',1
You are using a 64 bit syscall numbers and a 32 bit instruction to jump to the syscall. That is not going to work.
For 32 bit users:
opcode for Linux/MacOS execve: 11
instruction to call syscall: int 0x80
For 64 bit users:
opcode for Linux execve: 59 (MacOS 64-bit system calls also have a high bit set).
instruction to call syscall: syscall
The method for passing args to system calls is also different: 32-bit uses the stack, 64-bit uses similar registers to the function-calling convention.

Piping into SET /P fails due to uninitialised data pointer?

Supposing we have got a text file sample.txt:
one
two
...
Now we want to remove the first line:
two
...
A quick way to do that is to use input redirection, set /P and findstr1 (I know there are other ways using more or for /F, but let us forget about them for now):
#echo off
< "sample.txt" (
set /P =""
findstr "^"
)
The output is going to be as expected.
However, why is the output empty when I replace the input redirection < by type and a pipe | :
#echo off
type "sample.txt" | (
set /P =""
findstr "^"
)
When I replace set /P ="" by pause > nul, the output is what I expect -- the input file is output but with the first character of the first line missing (as it is consumed by pause). But why does set /P seem to consume everything instead of only the first line like it does with the redirection < approach? Is that a bug?
To me it looks like set /P fails to adequately initialise the reading pointer to the piped data.
I watched that strange behaviour on Windows 7 and on Windows 10.
It becomes even more weird: when calling the script containing the pipe multiple times, for instance by a loop like for /L %I in (1,1,1000) do #pipe.bat, and the input file contains about fifteen lines or more, sometimes (a few times out of thousand) a fragment of the input file is returned; that fragment is exactly the same each time; it seems that there are always 80 bytes missing at the beginning.
1) findstr hangs in case the last line is not terminated by a line-break, so let us assume such is there.
When retrieving data, the set /p tries to fill a 1023 character buffer (if they are available) with data from stdin. Once this read operation has ended, the first end of line is searched and once it has been found (or the end of the buffer has been reached), the SetFilePointer API is called to reposition the input stream pointer after the end of the read line. This way the next read operation will start to retreive data after the read line.
This works flawlessly when a disk file is associated with the input stream, but as Microsoft states in the SetFilePointer documentation
The hFile parameter must refer to a file stored on a seeking device;
for example, a disk volume. Calling the SetFilePointer function with a
handle to a non-seeking device such as a pipe or a communications
device is not supported, even though the SetFilePointer function may
not return an error. The behavior of the SetFilePointer function in
this case is undefined.
What is happening is that, while not generating any error, the call to reposition the read pointer fails when stdin is associated with a pipe, the pointer is not moved back and the 1023 bytes (or the number of available read bytes) keep read.
edited in response to Aacini request
The set command is processed by the eSet function, who calls SetWork to determine which type of set command will be executed.
As it is a set /p the SetPromptUser function is called and from this function the ReadBufFromInput function is called
add esp, 0Ch
lea eax, [ebp+var_80C]
push eax ; int
push 3FFh ; int
lea eax, [ebp+Value]
push eax ; int
xor esi, esi
push 0FFFFFFF6h ; nStdHandle
mov word ptr [ebp+Value], si
call edi ; GetStdHandle(x) ; GetStdHandle(x)
push eax ; hFile
call _ReadBufFromInput#16 ; ReadBufFromInput(x,x,x,x)
it requests 3FFh (1023) characters from standard input handle (0FFFFFFF6h = -10 = STD_INPUT_HANDLE)
ReadBufFromInput uses the GetFileType API to determine if it should read from the console or from a file
; Attributes: bp-based frame
; int __stdcall ReadBufFromInput(HANDLE hFile, int, int, int)
_ReadBufFromInput#16 proc near
hFile= dword ptr 8
; FUNCTION CHUNK AT .text:4AD10D3D SIZE 00000006 BYTES
mov edi, edi
push ebp
mov ebp, esp
push [ebp+hFile] ; hFile
call ds:__imp__GetFileType#4 ; GetFileType(x)
and eax, 0FFFF7FFFh
cmp eax, 2
jz loc_4AD10D3D
and, as in this case it is a pipe (GetFileType returns 3) the code jumps to the ReadBufFromFile function
; Attributes: bp-based frame
; int __stdcall ReadBufFromFile(HANDLE hFile, LPWSTR lpWideCharStr, DWORD cchWideChar, LPDWORD lpNumberOfBytesRead)
_ReadBufFromFile#16 proc near
var_C= dword ptr -0Ch
cchMultiByte= dword ptr -8
NumberOfBytesRead= dword ptr -4
hFile= dword ptr 8
lpWideCharStr= dword ptr 0Ch
cchWideChar= dword ptr 10h
lpNumberOfBytesRead= dword ptr 14h
This function will call the ReadFile API function to retrive the indicated number of characters
push ebx ; lpOverlapped
push [ebp+lpNumberOfBytesRead] ; lpNumberOfBytesRead
mov [ebp+var_C], eax
push [ebp+cchWideChar] ; nNumberOfBytesToRead
push edi ; lpBuffer
push [ebp+hFile] ; hFile
call ds:__imp__ReadFile#20 ; ReadFile(x,x,x,x,x)
The returned buffer is iterated in search of an end of line, and once it is found, the pointer in the input stream is moved after the found poisition
.text:4AD06A15 loc_4AD06A15:
.text:4AD06A15 cmp [ebp+NumberOfBytesRead], 3
.text:4AD06A19 jl short loc_4AD06A2D
.text:4AD06A1B mov al, [esi]
.text:4AD06A1D cmp al, 0Ah
.text:4AD06A1F jz loc_4AD06BCF
.text:4AD06A25
.text:4AD06A25 loc_4AD06A25:
.text:4AD06A25 cmp al, 0Dh
.text:4AD06A27 jz loc_4AD06D14
.text:4AD06A2D
.text:4AD06A2D loc_4AD06A2D:
.text:4AD06A2D movzx eax, byte ptr [esi]
.text:4AD06A30 cmp byte ptr _DbcsLeadCharTable[eax], bl
.text:4AD06A36 jnz loc_4AD12018
.text:4AD06A3C dec [ebp+NumberOfBytesRead]
.text:4AD06A3F inc esi
.text:4AD06A40
.text:4AD06A40 loc_4AD06A40:
.text:4AD06A40 cmp [ebp+NumberOfBytesRead], ebx
.text:4AD06A43 jg short loc_4AD06A15
.text:4AD06BCF loc_4AD06BCF:
.text:4AD06BCF cmp byte ptr [esi+1], 0Dh
.text:4AD06BD3 jnz loc_4AD06A25
.text:4AD06BD9 jmp loc_4AD06D1E
.text:4AD06D14 loc_4AD06D14:
.text:4AD06D14 cmp byte ptr [esi+1], 0Ah
.text:4AD06D18 jnz loc_4AD06A2D
.text:4AD06D1E
.text:4AD06D1E loc_4AD06D1E:
.text:4AD06D1E mov eax, [ebp+var_C]
.text:4AD06D21 mov [esi+2], bl
.text:4AD06D24 sub esi, edi
.text:4AD06D26 inc esi
.text:4AD06D27 inc esi
.text:4AD06D28 push ebx ; dwMoveMethod
.text:4AD06D29 push ebx ; lpDistanceToMoveHigh
.text:4AD06D2A mov [ebp+cchMultiByte], esi
.text:4AD06D2D add esi, eax
.text:4AD06D2F push esi ; lDistanceToMove
.text:4AD06D30 push [ebp+hFile] ; hFile
.text:4AD06D33 call ds:__imp__SetFilePointer#16 ; SetFilePointer(x,x,x,x)
The short summarize of a long discussion at dostips (mentioned already by Aacini
set /p problems with pipes).
Reading with set /p from a redirect, reads always to the end of the line and removes the \r\n characters.
Reading with set /p from a pipe, reads up to 1023 bytes from the pipe buffer.
It doesn't stop at any \r or \n characters but it drops all content after a \n.
After closing the pipe on the left side, a set /p on the right side will read empty lines.

Resources