flat assembler
Message board for the users of flat assembler.

Index > Windows > I have the assembler, now what?

Goto page Previous  1, 2, 3, 4, 5, 6  Next
Author
Thread Post new topic This topic is locked: you cannot edit posts or make replies.
Trinitek



Joined: 06 Nov 2011
Posts: 257
Trinitek 29 Mar 2017, 03:43
C0deHer3tic wrote:
I have a possible ridiculous query. Is it possible to use stand alone assembly code to print stdout, and get stdin?

Or will I have to use C functions in the FASM framework?
Talking to STDIN and STDOUT will still require you to interface to OS libraries.

There's no real black magic happening in FASM; all the import macros are doing is writing data to the import table in the PE header. There is no "framework" or additional runtime that is appended to your executable. It's very raw and baremetal.
Post 29 Mar 2017, 03:43
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 29 Mar 2017, 04:17
C0deHer3tic wrote:
I have a possible ridiculous query. Is it possible to use stand alone assembly code to print stdout, and get stdin?

Or will I have to use C functions in the FASM framework?
You can use the Windows functions, no MSVCRT required..
Code:
proc printf_stdoutput c string,args
        locals
                buff    rb 1028
        endl
        invoke  wvsprintf,addr buff,[string],addr args
        stdcall write_stdoutput,addr buff,eax
        ret
endp

proc write_stdoutput source,bytes
        local   bytes_written:DWORD
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
        invoke  WriteFile,eax,[source],[bytes],addr bytes_written,0
        test    eax,eax
        jz      .done
        mov     eax,[bytes_written]
    .done:
        ret
endp    
Post 29 Mar 2017, 04:17
View user's profile Send private message Visit poster's website Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
C0deHer3tic 29 Mar 2017, 05:42
Thank you Trinitek and revolution.

Now when told to see the C assembly code by gcc -S -o... I get this:

Code:
        .file   "test1.c"
        .comm   number, 4, 2
        .def    __main; .scl    2;      .type   32;     .endef
        .section .rdata,"dr"
.LC0:
        .ascii "Enter a number:\11\0"
.LC1:
        .ascii "%d\0"
.LC2:
        .ascii "\12The number is %d!\12\0"
        .text
        .globl  main
        .def    main;   .scl    2;      .type   32;     .endef
        .seh_proc       main
main:
        pushq   %rbp
        .seh_pushreg    %rbp
        movq    %rsp, %rbp
        .seh_setframe   %rbp, 0
        subq    $32, %rsp
        .seh_stackalloc 32
        .seh_endprologue
        call    __main
        leaq    .LC0(%rip), %rcx
        call    printf
        leaq    number(%rip), %rax
        movq    %rax, %rdx
        leaq    .LC1(%rip), %rcx
        call    scanf
        leaq    number(%rip), %rax
        movl    (%rax), %eax
        movl    %eax, %edx
        leaq    .LC2(%rip), %rcx
        call    printf
        movl    $0, %eax
        addq    $32, %rsp
        popq    %rbp
        ret
        .seh_endproc
        .ident  "GCC: (tdm64-2) 4.8.1"
        .def    printf; .scl    2;      .type   32;     .endef
        .def    scanf;  .scl    2;      .type   32;     .endef
    


From the file test1.c:
Code:
#include <stdio.h>

int number;

int main()
{
        printf("Enter a number:\t");
        scanf("%d",&number);
        printf("\nThe number is %d!\n",number);
        return 0;
}
    


So then I tried to do this:
Code:
format PE console
entry start

include 'win32a.inc'
include 'dota.inc' ;holds my imports


section '.data' readable  writeable

prompt db "Enter a number:",9,9,0
result db 10,"The number is %d!",1010b,0

number db "%d",0

num dd 3

section '.main' code readable
start:
        push    ebp
        mov     esp, ebp
        sub     esp, 32
        lea     ecx, [prompt]
        call    [printf]
        lea     eax, [num]
        mov     eax, edx
        lea     ecx, [number]
        call    [scanf]
        lea     eax, [number]
        mov     eax,eax
        mov     eax, edx
        lea     ecx, [result]
        call    [printf]
        mov     eax, 0
        add     esp, 32
        pop     ebp
        ret  
    

Which crashes. What am I doing wrong? I tried to do the code exactly how it showed, and it failed, then I tried to change the registers from rsp to esp, rax, eax, etc.

Now that you have provided me with something new to look at, Revolution, I will study that while I also try to figure out my errors. I appreciate everything from you ladies and gentlemen.

- Pluggin away, C0deHer3tic

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 29 Mar 2017, 05:42
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257
Trinitek 29 Mar 2017, 05:52
AT&T syntax--the nightmare returns.

AT&T syntax swaps the left and right operands, so there's one of your problems, at least. Use the -masm=intel flag to get Intel syntax instead, which is what FASM uses.
Post 29 Mar 2017, 05:52
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
C0deHer3tic 29 Mar 2017, 07:20
Okay, so now I put got this from the masm=intel switch:

Code:
        .file   "test1.c"
        .intel_syntax noprefix
        .comm   number, 4, 2
        .def    __main; .scl    2;      .type   32;     .endef
        .section .rdata,"dr"
.LC0:
        .ascii "Enter a number:\11\0"
.LC1:
        .ascii "%d\0"
.LC2:
        .ascii "\12The number is %d!\12\0"
        .text
        .globl  main
        .def    main;   .scl    2;      .type   32;     .endef
        .seh_proc       main
main:
        push    rbp
        .seh_pushreg    rbp
        mov     rbp, rsp
        .seh_setframe   rbp, 0
        sub     rsp, 32
        .seh_stackalloc 32
        .seh_endprologue
        call    __main
        lea     rcx, .LC0[rip]
        call    printf
        lea     rax, number[rip]
        mov     rdx, rax
        lea     rcx, .LC1[rip]
        call    scanf
        lea     rax, number[rip]
        mov     eax, DWORD PTR [rax]
        mov     edx, eax
        lea     rcx, .LC2[rip]
        call    printf
        mov     eax, 0
        add     rsp, 32
        pop     rbp
        ret
        .seh_endproc
        .ident  "GCC: (tdm64-2) 4.8.1"
        .def    printf; .scl    2;      .type   32;     .endef
        .def    scanf;  .scl    2;      .type   32;     .endef
    


My assembly code is now:
Code:
format PE console
entry start

include 'win32a.inc'
include 'dota.inc'    ; imports


section '.data' readable  writeable

prompt db "Enter a number:",9,9,0        ;LC0
result db 10,"The number is %d!",1010b,0 ;LC2

number db "%d",0                         ;LC1

num dd 3

section '.main' code readable
start:
        push    ebp
        mov     ebp, esp

        sub     esp, 32



        lea     ecx, [prompt]
        call    printf
        lea     eax, [num]
        mov     edx, eax
        lea     ecx, [number]
        call    scanf
        lea     eax, [num]
        mov     eax, [eax]
        mov     edx, eax
        lea     ecx, [result]
        call    printf
        mov     eax, 0
        add     esp, 32
        pop     ebp
        ret
    


And this gets a blinking cursor, and then crashes. What is the issue? What am I not understanding, and how can I learn?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 29 Mar 2017, 07:20
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257
Trinitek 29 Mar 2017, 07:27
Issue #2 is that you've swapped the 64-bit registers with their 32-bit counterparts, but you've forgotten about the different calling conventions in use here.

GCC compiled your code into a 64-bit binary. Remember that 64-bit uses the fastcall convention. Since your assembly is 32-bit, you need to be using the 32-bit stdcall convention.

I have to agree, getting into calling conventions on day 1 probably wasn't a good idea. Laughing
Post 29 Mar 2017, 07:27
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
C0deHer3tic 29 Mar 2017, 07:34
Where would you recommend I start?

I am open to any task. I am a curious learner, can you guide me?
Post 29 Mar 2017, 07:34
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257
Trinitek 29 Mar 2017, 07:52
Well, let's go ahead and solve your issue here.

The first three instructions sets up some stack space to put local variables. Since you don't have any local variables, you can remove these 5 instructions:
Code:
push ebp
mov ebp, esp
sub esp, 32
; ...
add esp, 32
pop ebp    
The rest of your code involves maneuvering parameters. Instead of mov'ing and lea'ing your parameters into registers as GCC did it for 64-bit fastcall, you need to instead rewrite these to push the parameters onto the stack instead. Remember the examples at the beginning of the thread, where we wrote this for printf:
Code:
push Hello
call [printf]
add esp, 4 ; <-- only for variable-parameter functions like printf    
There's more issues after that, but let's handle one thing at a time.
Post 29 Mar 2017, 07:52
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
C0deHer3tic 29 Mar 2017, 08:12
Alright, this is what my assembly looks like now:
Code:
format PE console
entry start

include 'win32a.inc'
include 'dota.inc'


section '.data' readable  writeable

prompt db "Enter a number:",9,9,0
result db 10,"The number is %d!",1010b,0

number db "%d",0

num dd ? ; changed this to not have a set variable.

section '.main' code readable
start:
        push    prompt
        call    [printf]
        push    num
        mov     eax, edx
        push    number
        call    [scanf]
        push    number
        mov     eax,eax
        mov     eax, edx
        push    result
        call    [printf]
        mov     eax, 0
        ret
    


And this is the output:
Code:


Enter a number:         5

The number is 4202534!
    

I enter 5, and hit enter, it displays message and crashes.
Slowly but surely. Razz

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 29 Mar 2017, 08:12
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
C0deHer3tic 29 Mar 2017, 08:26
My internet is down for my pc. I am on a phone.

I fixed the problem of the crashing. But that ridiculous number is showing me that basically scanf is not getting the number I entered correctly.

Will keep on trying to get it though. Razz

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 29 Mar 2017, 08:26
View user's profile Send private message Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 29 Mar 2017, 09:58
Post 29 Mar 2017, 09:58
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 29 Mar 2017, 10:58
system error wrote:
That's because you're extemely mad at me for giving you some schooling on 64-bit programming.
Or maybe because in his opening post in this thread he said he is experienced with several languages and gave example in C, idiot. I didn't realize he was asking how to use C standard library functions like scanf because of that reason. Using that knowledge you must have given him such wonderful advice to do what he already knows from C, indeed. On the other hand, looks like he doesn't understand pointers in asm (see his latest attempt), so you can try to ridicule me all you want, at least I know I help him unlike you.

(btw about rax, shows how much of an airhead you are, most functions return a value in rax, and other functions use that value as first argument, plus rax is an extra register to use to pass parameters; this is what is called SUPERIOR DESIGN. I don't personally give a shit if YOU find it insignificant. It is objectively better as it avoids 1 mov instruction for many function calls and uses 1 more register as parameter, so go cry to your mommy for getting schooled -- on and lastly, optimizing the function CALL is much more important than the FUNCTION itself because 1 function is called at LEAST one time, but usually many MORE times than once; so placing the overhead into EACH call makes for more bloated code (callee cleans and other crap), less cache used, etc, dummy)

If varargs are your argument, those are a complete joke on x64 calling convention. The amount of extra bloat you have to do in your function is unimaginable to handle that properly. (and you cried for one 'and' instruction to align the stack pointer, LOL!!)


C0deHer3tic wrote:
Alright, this is what my assembly looks like now:
Code:
format PE console
entry start

include 'win32a.inc'
include 'dota.inc'


section '.data' readable  writeable

prompt db "Enter a number:",9,9,0
result db 10,"The number is %d!",1010b,0

number db "%d",0

num dd ? ; changed this to not have a set variable.

section '.main' code readable
start:
        push    prompt
        call    [printf]
        push    num
        mov     eax, edx
        push    number
        call    [scanf]
        push    number
        mov     eax,eax
        mov     eax, edx
        push    result
        call    [printf]
        mov     eax, 0
        ret
    
You need to think of it like in C. I assumed you knew some C since you said that in your opening post, and in this case scanf takes pointers to addresses where it still store values. Here's comments:

Code:
section '.main' code readable
start:
        push    prompt
        call    [printf]
        push    num         ; this is correct, this pushes the *address* of 'num' for scanf (which is what it expects)
        mov     eax, edx    ; this has no purpose at all (edx has unknown value to begin with)
        push    number
        call    [scanf]     ; this will put the number into 'num' (num as an address, a pointer, you pushed above)

;       push    number      ; this is the wrong part: you push 'number' which is the address (!) of the *string* "%d" above
        push    dword [num] ; instead, push this: this pushes the 32-bit (dword) *value* found at *num* (address); remember, we passed 'num' (address) to scanf, and it stored it there

        mov     eax,eax     ; useless instruction? I'm asking so I get to understand why you do this Razz it doesn't do anything
        mov     eax, edx    ; same as above, what is its purpose? 'edx' is unknown value after scanf, eax is scanf's return value before this
        push    result
        call    [printf]
        mov     eax, 0
        ret
    


Of course, you also need to clean the stack, as shown above with 'add esp, 8' or 'pop <dummy register>', that's why it crashes.

But at least now it should print ok.
Post 29 Mar 2017, 10:58
View user's profile Send private message Reply with quote
system error



Joined: 01 Sep 2013
Posts: 670
system error 29 Mar 2017, 11:26
Furs wrote:
Or maybe because in his opening post in this thread he said he is experienced with several languages and gave example in C, idiot. I didn't realize he was asking how to use C standard library functions like scanf because of that reason. Using that knowledge you must have given him such wonderful advice to do what he already knows from C, indeed. On the other hand, looks like he doesn't understand pointers in asm (see his latest attempt), so you can try to ridicule me all you want, at least I know I help him unlike you.

(btw about rax, shows how much of an airhead you are, most functions return a value in rax, and other functions use that value as first argument, plus rax is an extra register to use to pass parameters; this is what is called SUPERIOR DESIGN. I don't personally give a shit if YOU find it insignificant. It is objectively better as it avoids 1 mov instruction for many function calls and uses 1 more register as parameter, so go cry to your mommy for getting schooled -- on and lastly, optimizing the function CALL is much more important than the FUNCTION itself because 1 function is called at LEAST one time, but usually many MORE times than once; so placing the overhead into EACH call makes for more bloated code (callee cleans and other crap), less cache used, etc, dummy)

If varargs are your argument, those are a complete joke on x64 calling convention. The amount of extra bloat you have to do in your function is unimaginable to handle that properly. (and you cried for one 'and' instruction to align the stack pointer, LOL!!)


Looks like you're still extremely mad at me for that schooling thing. Well, angry people don't get no love from me Razz
Post 29 Mar 2017, 11:26
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 29 Mar 2017, 11:38
revolution wrote:
In any protected OS the zone below the stack is perfectly safe for user mode programs to use in regards to worrying about the OS clobbering it. The x86 CPU provides for 4 independent stack pointers, one for for each privilege level. But one does still need to be aware of certain things when using that stack zone, push and call will overwrite any data there.

It is also of note that you can use the stack pointer (ESP/RSP) as a general purpose computing register without causing any problem to the OS. Your stack pointer can even be 0x0000, or any other value you want, and the OS won't crash. But at some point you need to recover the original value before doing calls or pushes and that will usually require some global variable (and that often also precludes multi-threading).
So what is the purpose of the red zone then? This is what AMD says:
Quote:
The 128-byte area beyond the location pointed to by rsp is considered to be reserved and shall not be modified by signal or interrupt handlers. Therefore, functions may use this area for temporary data that is not needed across function calls. In particular, leaf functions may use this area for their entire stack frame, rather than adjusting the stack pointer in the prologue and epilogue. This area is known as the red zone.
And I found this article: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64

It says this: There is no concept of "red zone" whatsoever [in Windows ABI]. In fact, the ABI explicitly states that the area beyond rsp is considered volatile and unsafe to use. The OS, debuggers or interrupt handlers may overwrite this area.




@system error: You know your behavior is exactly that of a kid not getting his way in an argument, covering his ears while shouting the same thing over and over again, right?

Sigh, oh dear. If a hypothetical design required Bubble Sort on a huge data set, and I were to complain about it (because it doesn't use Quick Sort for example), system error would proudly come and claim "just because you don't know how to use Bubble Sort doesn't mean it sucks!"

Grasping at straws, aye. That's all you've been doing, if you look at it.

(and my main complaint was *because* we are forced to use this ABI to interact with library functions -- i.e. it's a bad design (in terms of waste and bloat) that escalates now, and into the future, for every compliant call -- including calls that use AVX which have to realign the stack anyway so you gain absolutely *nothing* from 16-byte alignment for future code, PERIOD)
Post 29 Mar 2017, 11:38
View user's profile Send private message Reply with quote
system error



Joined: 01 Sep 2013
Posts: 670
system error 29 Mar 2017, 11:54
revolution wrote:
It is also of note that you can use the stack pointer (ESP/RSP) as a general purpose computing register without causing any problem to the OS. Your stack pointer can even be 0x0000, or any other value you want, and the OS won't crash. But at some point you need to recover the original value before doing calls or pushes and that will usually require some global variable (and that often also precludes multi-threading).


That's actually the general wisdom of MS64 ABI. Your RSP isn't involved in any function 'stacking' until after the 5th arguments kicks in. It is giving an impression that as far as the first 4 arguments go, the stack is still as 'flat' as static memory area.

For example, theoritically, you can point to a static data area using RSP and saves you yet another pre-entry overhead, if you don't use more than 4 arguments. Example;

Code:
section '.data' bla bla
here:
    _rcx dq 0
    _rdx dq 0
    ...
    _r9 dq 0
    rb 32

section '.code' bla bla
main:
    mov rsp,here     ;hijacking the RSP to point to static data
    sub rsp,0x20
    push $+8
    jmp [aWinAPI]
    add rsp,0x20    


Looks quite hackish but I blame it on MS for creating an ABI which empowers people to be 'creative'. IMHO, it can pose serious security threats. This is even more threatening in C because unlike MS, RSP in C is 'linked' to C's internal processing while in MS it is 'allocated' instead.
Post 29 Mar 2017, 11:54
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 29 Mar 2017, 12:19
There are problem with pointing ESP/ESP to data areas. Exception handlers might not be able to be entered because the OS checks if ESP/RSP is inside a valid stack area. Also you should make sure there is enough space on the stack for the API to do its work. It is not until the kernel is entered that a new stack is used.

Furs: In a protected OS the stack use is at your leisure. Other non-protected OSes might not use different stacks for interrupts. So in those OSes you could get into trouble. Remember that AMD and Intel don't only support Windows and Linux, they also need to cover all situations.
Post 29 Mar 2017, 12:19
View user's profile Send private message Visit poster's website Reply with quote
system error



Joined: 01 Sep 2013
Posts: 670
system error 29 Mar 2017, 12:31
revolution wrote:
There are problem with pointing ESP/ESP to data areas. Exception handlers might not be able to be entered because the OS checks if ESP/RSP is inside a valid stack area. Also you should make sure there is enough space on the stack for the API to do its work. It is not until the kernel is entered that a new stack is used


Well, it's just a theory though. But bad things can still happen when the first few API data is well-exposed in the user's code.
Post 29 Mar 2017, 12:31
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 29 Mar 2017, 13:53
revolution wrote:
Furs: In a protected OS the stack use is at your leisure. Other non-protected OSes might not use different stacks for interrupts. So in those OSes you could get into trouble. Remember that AMD and Intel don't only support Windows and Linux, they also need to cover all situations.
AMD yes, but why MS ABI says to consider the area beyond/below rsp as volatile then? MS ABI applies only to Windows Confused
Post 29 Mar 2017, 13:53
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 29 Mar 2017, 14:03
Well if MS really does use the user program stack for system things then they have have broken the protection guarantees of the OS. In protected OSes no user code should ever be able to see system data, or another program's data in any memory it can access. Also no user program should even be able to tell that it was interrupted (in theory). So if a user program can simply examine the stack area for changes then the OS is not a protected OS.
Post 29 Mar 2017, 14:03
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2493
Furs 29 Mar 2017, 14:06
Well I doubt it is system data that it sees. It could be just user data from e.g. exceptions or for debugging. I don't know if Windows has Signal Handlers like Linux -- I'm not too fond of that low level stuff... Here more detail it seems: http://stackoverflow.com/questions/36489049/is-the-stack-only-preserved-above-the-stack-pointer

Even if it doesn't today maybe it's just a spec thing so it's never done in the future when it might be used for something. Still "unsafe" to use area below esp/rsp Smile

(it also seems to be unsafe when it triggers a page fault, since apparently Linux (not sure about Windows) only allocates more stack pages if it is >= esp and probably < start_of_stack)
Post 29 Mar 2017, 14:06
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic This topic is locked: you cannot edit posts or make replies.

Jump to:  
Goto page Previous  1, 2, 3, 4, 5, 6  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.