How to convert int to string asm win32 - winapi

So I'm trying to convert a number to a string .
How can i parse a integer value to string using asm win32?

strNumber db 80 dup(0), 0
szFormat db '%ld', 0
dwTheNumber dw 101020
PUSH dwTheNumber
PUSH OFFSET szFormat
PUSH OFFSET strNumber
CALL wsprintfA ; ANSI version
ADD ESP, 4*3 ; wsprintfA uses the C-calling convention
And that's on 32bit

Related

Accessing cmdline arguments on 32-bit assembly

So I'm currently trying to get the command line arguments using masm, here is what I've done so far:
.386
.MODEL FLAT
includelib kernel32.lib
includelib msvcrt.lib
__getmainargs PROTO C :DWORD
printf PROTO C :DWORD
.data
str_argv db "argv[1]: %s",0
.fardata?
argc dd ?
argv db 255 DUP(?)
env dd ?
.code
START:
push 0
push OFFSET env
push OFFSET argv
push OFFSET argc
call __getmainargs
add esp, 4*4 ;4 args
push [edi]
push OFFSET str_argv
call printf
add esp, 4 * 2 ;2 args
ret
END START
However this returns me a garbage string that does not correspond to the cmdline argument, in this case the module name.
Any ideas why this doesn't work? -> Also are there any other alternatives for accessing cmdline args?
Thanks in advance
You're pushing [edi] without having put the correct value into edi.
Change the declaration of argv to argv dd ?.
Then change the push [edi] to:
mov edi,argv
push dword ptr [edi+4]
And make sure you use the /SUBSYSTEM:CONSOLE option when linking.

Assembly - Readings strings with scanf in loop only reads one string

I need to read a bunch of strings from command line in assembly, however only one call to scanf seems to take place. I'm pretty sure the problem is related to the scanf format. If I replace what I've currently got with a simple "%s" it works fine, thing is I have to read whole lines including spaces, so "%s" won't do. "%[^c]s" should keep reading characters until it encounters c, but there's 2 problems with this:
I actually have to input the characters \ and n for the scanning to stop.
As I said, it only reads one string. After that, all the prompts for the remaining strings get instantly printed at the program ends.
I've seen that people usually suggest using fread, however I'm not really sure how to access stdin in assembly.
Here's my code:
bits 32
global start
extern exit, scanf, printf
import exit msvcrt.dll
import scanf msvcrt.dll
import printf msvcrt.dll
segment data use32 class=data
msg DB "Enter a value for n", 13, 10, 0
s_msg DB "Enter a string", 13, 10, 0
n_format DB "%d", 0
s_format DB "%[^\n]s", 0
segment bss use32 class=bss
n DD 0
s RESB 1000
segment code use32 class=code
start:
push dword msg
call [printf]
add ESP, 4 * 1
push dword n
push dword n_format
call [scanf]
add ESP, 4 * 2
mov ECX, [n]
read_strings:
pushad
push dword s_msg
call [printf]
add ESP, 4 * 1
push dword s
push dword s_format
call [scanf]
add ESP, 4 * 2
popad
loop read_strings
push dword 0
call [exit]

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.

Hard Disk handling using 32-bit system call in assembly language

friends, I need help regarding Harddisk handling using 32-bit system call. I am new to assembly language and I am using MASM assembler. I have tried some example codes but they are in 16-bit mode, and also i gives me error, while compling. I want to write in 32-bit. and i also read in a book that 32-bit is complicated, Is there any another procedure for 32-bit system call.
Example Code!
; This program calls INT 21h Function 7303h, to get free space information
; on a FAT-type drive volume. It displays both the volume size and free space.
; Runs under Windows 95/98/Me, but not under Windows NT/2000/XP.
; Last update: 12/11/01
INCLUDE Irvine16.inc
.data
buffer ExtGetDskFreSpcStruc <>
driveName BYTE "C:\",0
str1 BYTE "Volume size (KB): ",0
str2 BYTE "Free space (KB): ",0
str3 BYTE "Function call failed.",0dh,0ah,0
.code
main PROC
mov ax,#data
mov ds,ax
mov es,ax
mov buffer.Level,0 ; must be zero
mov di, OFFSET buffer ; ES:DI points to buffer
mov cx, SIZEOF buffer ; buffer size
mov dx, OFFSET DriveName ; ptr to drive name
mov ax, 7303h ; Get disk free space
int 21h
jc error ; Failed if CF = 1
mov dx,OFFSET str1 ; volume size
call WriteString
call CalcVolumeSize
call WriteDec
call Crlf
mov dx,OFFSET str2 ; free space
call WriteString
call CalcVolumeFree
call WriteDec
call Crlf
jmp quit
error:
mov dx,OFFSET str3
call WriteString
quit:
exit
main ENDP
;-------------------------------------------------------------------
CalcVolumeSize PROC
; Calculate and return the disk volume size, in kilobytes.
; Receives: buffer variable, a ExtGetDskFreSpcStruc structure
; Returns: EAX = volume size
; Remarks: (SectorsPerCluster * 512 * TotalClusters) / 1024
;--------------------------------------------------------------------
mov eax,buffer.SectorsPerCluster
shl eax,9 ; mult by 512
mul buffer.TotalClusters
mov ebx,1024
div ebx ; return kilobytes
ret
CalcVolumeSize ENDP
;-------------------------------------------------------------------
CalcVolumeFree PROC
; Calculate and return the number of available kilobytes on the
; given volume.
; Receives: buffer variable, a ExtGetDskFreSpcStruc structure
; Returns: EAX = available space, in kilobytes
; Remarks: (SectorsPerCluster * 512 * AvailableClusters) / 1024
;--------------------------------------------------------------------
mov eax,buffer.SectorsPerCluster
shl eax,9 ; mult by 512
mul buffer.AvailableClusters
mov ebx,1024
div ebx ; return kilobytes
ret
CalcVolumeFree ENDP
END main
Trying to assemble this program...
also i gives me error
Firstly, it cannot assemble because the struct ExtGetDskFreSpcStruc in the line
buffer ExtGetDskFreSpcStruc <>
is not defined before - not in this file and not in (the only) include file(s), in this case "Irvine16.inc", which doesn't contain the definition. Therefore all attempted accesses to "buffer.xxx" will throw errors.
Secondly, if you are trying to assemble this program for 32-bit, you are including a 16-bit include file in a 32-bit assembly file. You should use the 32-bit version "Irvine32.inc", because otherwise all indirect addressing like mov al, [si](16-bit) in the subroutines will fail.
Thirdly, you are calling DOS-legacy-interrupts, which are available only in Win95/98/Me, because their kernels are based on DOS. The newer NT kernel in Win2000 and above does not provide them, because it was a different OS architecture/codebase without/with reduced legacy code. The DOS-interrupt(21h) is 16-bit, because DOS was 16-bit. I don't know if there are implemented 32-bit versions of old DOS-interrupts in Win95/98/Me. A quick search yielded no indications of this having been realized. The BIOS interrupts used in "Irvine16.inc" are surely 16-bit and therefore unusable(without very complicated workarounds) in a 32-bit executable probably crashing the program.
Is there any another procedure for 32-bit system call[?]
Yes. Use the Win32-API, which is available in Win95 till Win8/10(?).
The easiest way to do this would be using the MASM-package by Hutch found at MOVSD.COM and then include kernel32.inc/lib from it. Then you can call the GetFreeDiskSpace function to get the desired result with a line similar to this:
invoke GetFreeDiskSpace,
offset driveName,
offset buffer.lpSectorsPerCluster, ; adjust to actual buffer layout names
offset buffer.lpBytesPerSector, ; "
offset buffer.lpNumberOfFreeClusters, ; "
offset buffer.lpTotalNumberOfClusters ; "

Assembly and Win32API input output

I am trying to figure this out but am stumped a bit. What I am trying to do is to use the ReadConsole/WriteConsole functions from the win32 lib and got it to work a degree but just not there. I am having trouble getting the second write console working correctly. I don't think I am sending the buffer to the variable right. I must be missing something here and I dont know what it is.
Here is what I have so far
TITLE MASM Template (main.asm)
; Description:
;
; Revision date:
INCLUDE Irvine32.inc
BufSize = 80
.data
endl EQU <0dh,0ah> ; end of line sequence
;variable holders
firstN db ?
fNSize db ($-firstN)
;messages for getting input
fName LABEL BYTE
BYTE "Enter your first name", endl
fNameSize DWORD ($-fName)
;output handlers
consoleHandle HANDLE 0 ; handle to standard output device
bytesWritten DWORD ? ; number of bytes written
;input handlers
buffer BYTE BufSize DUP(?)
stdInHandle HANDLE ?
bytesRead DWORD ?
.code
main PROC
; Get the console output handle:
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov consoleHandle,eax
; Write a string to the console:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR fName, ; string pointer
fNameSize, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used
; Get handle to standard input
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle,eax
; Wait for user input
INVOKE ReadConsole, stdInHandle, ADDR buffer,
BufSize, ADDR bytesRead, 0
;cheack to see if read consol worked
mov esi, OFFSET buffer
mov ecx, bytesRead
mov ebx, TYPE buffer
call DumpMem
;move the input into the variable
mov firstN, TYPE buffer
; Write a string to the console:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR firstN, ; string pointer
fNSize, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used
INVOKE ExitProcess,0
main ENDP
END main
Thanks for any help :)
firstN and fNSize are each a single byte and that's not what you want. Simply do this for the second WriteConsole call:
INVOKE WriteConsole,
consoleHandle, ; console output handle
ADDR buffer, ; string pointer
bytesRead, ; string length
ADDR bytesWritten, ; returns num bytes written
0 ; not used

Resources