MASM, output from some memory point - memory

reader of this question.
I'm not new with assembly. But I'm new with MASM. (in fact, I was using that hardcore clean tasm stuff for about 8 years without even a single minute of using a single macros, he-he).
Now, I've got to make a simple program. I already did it's main logic. But there is some trouble with output.
When I use
output <some-variable-name>
it makes the thing - it outputs characters.
But now I want to begin output not from the very beginning of some variable but from a specific address in memory. Now I do:
lea eax, <some-variable-name>
mov esi, eax
... manipulations with address in esi, like 'add esi, ebx' and so on...
output esi
But that won't work.
Compiler says 'error A2070: invalid instruction operands'.
I use Microsoft Macro Assembler version 6.11.
Thanks in advance.
Sorry for my broken English.
UPD: defenition of 'output' macros, taken from included 'io.h' file:
output MACRO string,xtra ;; display string
IFB <string>
.ERR <missing operand in OUTPUT>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in OUTPUT>
EXITM
ENDIF
push eax ;; save EAX
lea eax,string ;; string address
push eax ;; string parameter on stack
call outproc ;; call outproc(string)
pop eax ;; restore EAX
ENDM

The soulution in this situation is use following:
lea eax, <some-variable-name>
mov esi, eax
... manipulations with pointer, like 'add esi, edx' and so on ...
push esi
call outproc

Related

How do I translate DOS assembly targeted for the small memory model to the large memory model?

I'm somewhat new to assembly language and wanted to understand how it works on an older system. I understand that the large memory model uses far pointers while the small memory model uses near pointers, and that the return address in the large model is 4 bytes instead of two, so the first parameter changes from [bp+4] to [bp+6]. However, in the process of adapting a graphics library from a small to a large model, there are other subtle things that I don't seem to understand. Running this code with a large memory model from C is supposed to clear the screen, but instead it hangs the system (it was assembled with TASM):
; void gr256cls( int color , int page );
COLOR equ [bp+6]
GPAGE equ [bp+8]
.MODEL LARGE,C
.186
public C gr256cls
.code
gr256cls PROC
push bp
mov bp,sp
push di
pushf
jmp skip_1
.386
mov ax,0A800h
mov es,ax
mov ax,0E000h
mov fs,ax
CLD
mov al,es:[bp+6]
mov ah,al
mov bx,ax
shl eax,16
mov ax,bx
cmp word ptr GPAGE,0
je short cls0
cmp word ptr GPAGE,2
je short cls0
jmp short skip_0
cls0:
mov bh,0
mov bl,1
call grph_cls256
skip_0:
cmp word ptr GPAGE,1
je short cls1
cmp word ptr GPAGE,2
je short cls1
jmp short skip_1
cls1:
mov bh,8
mov bl,9
call grph_cls256
skip_1:
.186
popf
pop di
pop bp
ret
.386
grph_cls256:
mov fs:[0004h],bh
mov fs:[0006h],bl
mov cx,16384
mov di,0
rep stosd
add word ptr fs:[0004h],2
add word ptr fs:[0006h],2
mov cx,16384
mov di,0
rep stosd
add word ptr fs:[0004h],2
add word ptr fs:[0006h],2
mov cx,16384
mov di,0
rep stosd
add word ptr fs:[0004h],2
add word ptr fs:[0006h],2
mov cx,14848 ;=8192+6656
mov di,0
rep stosd
;; Freezes here.
ret
gr256cls ENDP
end
It hangs at the ret at the end of grph_256cls. In fact, even if I immediately ret from the beginning of the function it still hangs right after. Is there a comprehensive list of differences when coding assembly in the two modes, so I can more easily understand what's happening?
EDIT: To clarify, this is the original source. This is not generated output; it's intended to be assembled and linked into a library.
I changed grph_256cls to a procedure with PROC FAR and it now works without issue:
grph_cls256 PROC FAR
...
grph_cls256 ENDP
The issue had to do with how C expects functions to be called depending on the memory model. In the large memory model, all function calls are far. I hadn't labeled this assumption on the grph_256cls subroutine when trying to call it, so code that didn't push/pop the right values onto/off the stack was assembled instead.

Understanding calling convention and stack pointer

I want to understand how should I use local variables and how to pass arguments to function in x86. I read a lot of guides, and they all wrote that the first parameter should be at [ebp+8], but it isn't here :/ WHat am I missing? What am I not understanding correctly?
number byte "724.5289",0
.code
main PROC
mov ebx,offset number ;making so that [ebp] = '7' atm
push ebx ;I push it on stack so I can access it inside the function
call rewrite
main ENDP
rewrite PROC
push ebp ; push ebp so we can retrieve later
mov ebp, esp ; use esp memory to retrieve parameters and
sub esp, 8 ; allocate data for local variable
lea ebx, [ebp-8]
lea eax, [ebp+8] ; i think here ebp+8 should point to the same now to which ebx did
;before function, but it does not, writechar prints some garbage ascii character
call writechar
call crlf
rewrite ENDP
END main
You pass a pointer as argument to rewrite, and then pass its address on to writechar. That is you take the address twice. That is one too many :)
You want mov eax, [ebp+8] instead of lea eax, [ebp+8]
Also, you need to clean up the stack after yourself, which you don't do. Furthermore, make sure your assembler automatically emits a RET for the ENDP directive, otherwise you will be in trouble. You might want to write it out explicitly.

Change the value at an absolute word address

How do you perform operations like change the value at an absolute word address?
Say you have some value at 5DAh and you want to count the number of zeros on that address, or move a value from one absolute address to another. How can one do that?
Short Answer: You Can't
You might have a trick question in front of you (no clue, just my guess).
The physical architecture of the 8086 chip did not have that instruction.
As for your two specific questions...
"...you want to count the number of zeros on that address..."
That's somewhat ambiguous, in fact so vague that I can't understand it.
"...move a value from one absolute address to another..."
Good question. We'll do this in 32 bit, no, 16 and then 32 bit.
16 bit example
Push Si ;source index register
Push Di ;destination index register
Push Ax ;We'll use this for the transfer
Lea Si, Where_The_Number_Is_Now ;You'll define this, somehow
Lea Di, Where_We_Want_It_To_Go ;You'll define this also, same thing
Mov Ax, Ds:[Si] ;The "Ds:" may or may not be needed, be safe
Mov Ds:[Di], Ax ;Probably do need "Ds:" for this instruction
Pop Ax ;Do pay attention to the reverse order
Pop Di ;...of popping the registers in exact
Pop Si ;...opposite of how they were pushed
; And you are done
32 bit example
Push Esi ;source index register
Push Edi ;destination index register
Push Eax ;We'll use this for the transfer
Lea Esi, Where_The_Number_Is_Now ;You'll define this, somehow
Lea Edi, Where_We_Want_It_To_Go ;You'll define this also, same thing
Mov Eax, Ds:[Esi] ;The "Ds:" may or may not be needed, be safe
Mov Ds:[Edi], Eax ;Probably do need "Ds:" for this instruction
Pop Eax ;Do pay attention to the reverse order
Pop Edi ;...of popping the registers in exact
Pop Esi ;...opposite of how they were pushed
; And you are done
To change a value at an absolute word address:
mov byte ptr [5dah], 0
...or...
mov word ptr [5dah], 0
To move a value from one absolute word address to another:
mov al, byte ptr [5dah]
mov byte ptr [1234h], al
...or...
mov ax, word ptr [5dah]
mov word ptr [1234h], ax
As for the other question, the one that asked how to count the number of zeros on that address, you were a little to vague.

Read command line in assembly

First time I play with ds, si and strings related instructions in assembly. I am trying to read the command line arguments char by char and this is how my code looks like now:
GetCommandLine:
push ebp
mov ebp, esp
push edi
push esi
call GetCommandLineW
mov edi, eax
mov esi, ebp
Parse:
lodsw
cmp ax, 0dh ; until return is found
jne Parse
pop esi
pop edi
pop ebp
ret
So, the GetCommandLineW function returns a correct pointer to the string. The problem is that the Parse section loops forever and I can't see the AX register being loaded with the correct next byte from the string. I think the EDI:ESI is not correctly loaded or something
esi and edi are different pointers. ebp is used for saving the old stack pointer, and for saving/loading local variables. GetCommandLineW will return the pointer in eax, which you should then put into esi. Since you're only using lodsw (and not stos*), you don't need to touch edi.
Why do you think that 0x0d is used in the commandline? A normal C string is returned, so you should look for a 0 byte.

Modifying a byte in memory using shellcode

I have been trying to create a simple chunk of shell code that allows me to modify a string by doing something simple like changing a letter, then print it out.
_start:
jmp short ender
starter:
xor ecx, ecx ;clear out registers
xor eax, eax
xor ebx, ebx
xor edx, edx
pop esi ;pop address of string into esi register
mov byte [esi+1], 41 ;try and put an ASCII 'A' into the second letter of the string
;at the address ESI+1
mov ecx, esi ;move our string into the ecx register for the write syscall
mov al, 4 ;write syscall number
mov bl, 1 ;write to STDOUT
mov dl, 11 ;string length
int 0x80 ;interrupt call
ender:
call starter
db 'hello world'
It's supposed to print out "hallo world". The problem occurs (segfault) when I try and modify a byte of memory with a mov command like so.
mov byte [esi+1], 41
I ran the program though GDB and the pop esi command works correctly, esi is loaded with the address of the string and everything is valid. I can't understand why I cant modify a byte value at the valid address though. I am testing this "shellcode" by just running the executable generated by NASM and ld, I am not putting it in a C program or anything yet so the bug exists in the assembly.
Extra information
I am using x64 Linux with the following build commands:
nasm -f elf64 shellcode.asm -o shellcode.o
ld -o shellcode shellcode.o
./shellcode
I have pasted the full code here.
If I had to guess, I'd say dbhello world` is being compiled in as code, rather than data, and as such has read and execute permissions, but not write ones. So you're actually falling foul of page protection.
To change this, you need to place the string in a section .data section and use nasm's variable syntax to find it. In order to modify the data as is, you're going to need to make a mprotect call to modify the permissions on your pages, and write to them. Note: these won't persist back to the executable file - mmap()'s MAP_PRIVATE ensures that's the case.

Resources