flat assembler
Message board for the users of flat assembler.

Index > Windows > NOOB Alert! - Trying to understand the basics

Goto page Previous  1, 2, 3  Next
Author
Thread Post new topic Reply to topic
Overclick



Joined: 11 Jul 2020
Posts: 670
Location: Ukraine
Overclick 11 Sep 2021, 18:42
You lost again. It is nothing about support. They can't change the rules all the time, especially at days some soft or windows still use them.
How do you imagine that? "Sorry guys, we don't support 7/8 so ALL SOFTWARE you know will stop working at all because we change the rule to call winapi. Install our new windows and wait for developers to recreate their soft for our new stupid rule" LOL
Post 11 Sep 2021, 18:42
View user's profile Send private message Visit poster's website Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 11 Sep 2021, 18:47
Overclick wrote:
"Sorry guys, we don't support 7/8 so ALL SOFTWARE you know will stop working at all because we change the rule to call winapi. Install our new windows and wait for developers to recreate their soft for our new stupid rule"
OffTop: You're right. This is what I am regularly offered in the Windows Update Center.

https://www.microsoft.com/en-us/microsoft-365/windows/end-of-windows-7-support

I've heard about the end of support for Windows 8, but I don't think they've decided yet.
Post 11 Sep 2021, 18:47
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 11 Sep 2021, 19:09
macomics wrote:
DimonSoft wrote:
Sorry, I was too focused on the parameter description and forgot to take a look at the function prototype itself which declares the only parameter as a pointer to const, so the question now is who would change the structure contents during the function call if the function itself is not supposed to?

It depends on the implementation of the API functions and the presence of an interception function.

If an interception function changes the behaviour in a way that is not compatible with the documentation of the original function, it is broken by definition and might render broken most programs that use the function. Function prototype is a contract, when one of the parties (caller/callee) breaks the rules the whole game is broken anyway, it’s just a matter of time to notice. If what’s documented for an OS function is broken, it’s not an application programmer’s fault.

macomics wrote:
DimonSoft wrote:
Yep. But my point was that storing and then taking the hInstance value from some WNDCLASSEX is a bad idea from the logical point of view in the first place.

And why store it at all, when it is possible to call GetModuleHandle(NULL) {GetWindowLong(hWnd,GWL_HINSTANCE) / GetClassLong(hWnd, GCL_HINSTANCE) } at any time. And WNDCLASS(EX) can be read by calling GetClassInfo(Ex).

Well, GetModuleHandle(NULL) may even be replaced with a literal, say, if one registers a class from an EXE, not a DLL, and it’s a 32-bit executable. For DLLs one still needs to store its hInstance somewhere since knowing the modules name to pass to GetModuleHandle gets trickier in such cases.

GetWindowLong and GetClassLong need a window to be created in the first place. And using them to retrieve hInstance is just another step towards attaching module-global value (hInstance) to particular window/window class. It definitely works, but from the architectural point of view it might only be OK for a few scenarios. When the number of windows created/classes registered becomes bigger it might create a mess in the project. Reading the whole WNDCLASSEX back to just get the value of a single field looks even less promising.

Actually, for many window classes having WNDCLASSEX initialized inside data section lets one have smaller executable and only requires a few writes, like, say, storing a valid cursor handle instead of processing WM_CURSOR which is far more convenient than filling the whole structure at runtime. Paying a few tens of bytes is OK here, since it saves time/code copying WNDCLASSEX back and forth if one needs it later. After all window classes are module-global, so storing window-class-related data in module’s global section is quite a valid decision, especially when it’s almost free.

But the question of storing/not storing WNDCLASSEX was not my point. My point was only about trying to solve a global problem (retrieving hInstance value) with a local solution (WNDCLASSEX of an arbitrary window class).
Post 11 Sep 2021, 19:09
View user's profile Send private message Visit poster's website Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 11 Sep 2021, 19:28
DimonSoft wrote:
If an interception function changes the behaviour in a way that is not compatible with the documentation of the original function, it is broken by definition and might render broken most programs that use the function. Function prototype is a contract, when one of the parties (caller/callee) breaks the rules the whole game is broken anyway, it’s just a matter of time to notice. If what’s documented for an OS function is broken, it’s not an application programmer’s fault.
I completely agree, but no one is talking about a violation. I want to point out to you once again that even in the example from MSDN, this structure is only temporary, does not require saving anywhere and should not contain up-to-date information on the class registered with it at any time after its application.
DimonSoft wrote:
Well, GetModuleHandle(NULL) may even be replaced with a literal, say, if one registers a class from an EXE, not a DLL, and it’s a 32-bit executable. For DLLs one still needs to store its hInstance somewhere since knowing the modules name to pass to GetModuleHandle gets trickier in such cases.
Code:
  format PE64 GUI DLL
  entry DLLEntry

. . .

section '.text' code . . .
DLLEntry:
  . . .

anyDllFunc:
   lea rax, [DLLEntry]
   xor ax, ax                   ;  rax = hInstance
    

How much harder is it?
DimonSoft wrote:
GetWindowLong and GetClassLong need a window to be created in the first place. And using them to retrieve hInstance is just another step towards attaching module-global value (hInstance) to particular window/window class. It definitely works, but from the architectural point of view it might only be OK for a few scenarios. When the number of windows created/classes registered becomes bigger it might create a mess in the project. Reading the whole WNDCLASSEX back to just get the value of a single field looks even less promising.
But these functions return the actual values. And by the way, they were mentioned only to show the inexpediency of storing an extra global variable, when you already have a global variable for the function of reading up-to-date information from the system.
Post 11 Sep 2021, 19:28
View user's profile Send private message Reply with quote
Overclick



Joined: 11 Jul 2020
Posts: 670
Location: Ukraine
Overclick 11 Sep 2021, 20:07
Quote:

OffTop: You're right. This is what I am regularly offered in the Windows Update Center.

It is not about some functionality bugs, call rules about ALL functionality, TOTALLY. To change this they need something most global like evolution from 32bit to 64bit. You will never receive that changes in Update Center, you don't understand what you talking about. That rules is fundamental basis, even if all 32bit winapi recreated/recompilled to true 64bit, that I never believe. It is too late to change the rule when tons of code already created for that.

They may provide some new sort of call rules for some new functions, theoretically. Name it like new generation or something this way. But old will work as is.
Post 11 Sep 2021, 20:07
View user's profile Send private message Visit poster's website Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 11 Sep 2021, 21:06
Overclick wrote:
Quote:

OffTop: You're right. This is what I am regularly offered in the Windows Update Center.

It is not about some functionality bugs, call rules about ALL functionality, TOTALLY. To change this they need something most global like evolution from 32bit to 64bit. You will never receive that changes in Update Center, you don't understand what you talking about. That rules is fundamental basis, even if all 32bit winapi recreated/recompilled to true 64bit, that I never believe. It is too late to change the rule when tons of code already created for that.

They may provide some new sort of call rules for some new functions, theoretically. Name it like new generation or something this way. But old will work as is.
You have been trying to convince me of something outside of this topic for a long time. It would be better to help the beginner understand and give an answer to one of his questions within the framework of his understanding.
Quote:
Just use it like that:
CS_HREDRAW = 2
CS_VREDRAW = 1

I think he will be able to read this in the source texts attached to fasm himself. But you don't want to explain to him why it should be done this way. Or maybe it would be more correct to do this:
Code:
CS_HREDRAW equ 2
CS_VREDRAW equ 1
    
or
Code:
CS_HREDRAW fix 2
CS_VREDRAW fix 1
    
or
Code:
define CS_HREDRAW 2
define CS_VREDRAW 1
    
or maybe like that
Code:
label CS_HREDRAW at 2
label CS_VREDRAW at 1
    
Take the trouble to at least explain this statement, and not argue with other participants in the topic.
Post 11 Sep 2021, 21:06
View user's profile Send private message Reply with quote
Overclick



Joined: 11 Jul 2020
Posts: 670
Location: Ukraine
Overclick 11 Sep 2021, 23:51
facepalm
People just run away from the FASM after your advice. IT IS NOT THE BASIC! Can you just read what he asking about? Do you even know what CS_HREDRAW is? So why you make it such complicated? For me it was enough to see how he trying to use it to guess what exactly he need.
Post 11 Sep 2021, 23:51
View user's profile Send private message Visit poster's website Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 12 Sep 2021, 04:03
Overclick wrote:
facepalm
People just run away from the FASM after your advice. IT IS NOT THE BASIC! Can you just read what he asking about? Do you even know what CS_HREDRAW is? So why you make it such complicated? For me it was enough to see how he trying to use it to guess what exactly he need.
First, learn to read English - these were rhetorical questions. Secondly, at least you read the name of the topic or you only had enough memory for the nearest answer. Third, if there is no desire to explain something, then go and write your programs in silence. Fourth, I have already run out of food for trolls.
Post 12 Sep 2021, 04:03
View user's profile Send private message Reply with quote
avidichard



Joined: 22 Mar 2021
Posts: 22
Location: Quebec/Canada
avidichard 12 Sep 2021, 05:39
macomics wrote:
Code:
        format PE64 GUI 6.0
        entry label_start

; include 'win64w.inc'

section '.idata' import data readable writeable
;  library kernel32,'KERNEL32.DLL',\
;          user32,  'USER32.DLL'

        dd RVA kernel32.lookup, 0, 0, RVA kernel32.label, RVA kernel32.address
        dd RVA user32.lookup, 0, 0, RVA user32.label, RVA user32.address
        dd 0, 0, 0, 0, 0
kernel32.label          db 'KERNEL32.DLL', 0
                        rb RVA $ and 1
user32.label            db 'USER32.DLL', 0
                        rb RVA $ and 1

;  import kernel32,\
;         GetModuleHandle,'GetModuleHandleA',\
;         ExitProcess,'ExitProcess'
kernel32.lookup:
                        dq RVA GetModuleHandle.label
                        dq RVA ExitProcess.label
                        dq 0
kernel32.address:
  GetModuleHandle       dq RVA GetModuleHandle.label
  ExitProcess           dq RVA ExitProcess.label
                        dq 0
GetModuleHandle.label   dw 0
                        db 'GetModuleHandleA', 0
                        rb RVA $ and 1
ExitProcess.label       dw 0
                        db 'ExitProcess', 0
                        rb RVA $ and 1

;  import user32,\
;         RegisterClassEx, 'RegisterClassExA',\
;         CreateWindowEx, 'CreateWindowExA',\
;         DefWindowProc, 'DefWindowProcA',\
;         GetMessage, 'GetMessageA',\
;         TranslateMessage, 'TranslateMessage',\
;         DispatchMessage, 'DispatchMessageA',\
;         ShowWindow, 'ShowWindow',\
;         PostQuitMessage, 'PostQuitMessage',\
;         LoadIcon, 'LoadIconA',\
;         LoadCursor, 'LoadCursorA'
user32.lookup:
                        dq RVA RegisterClassEx.label
                        dq RVA CreateWindowEx.label
                        dq RVA DefWindowProc.label
                        dq RVA GetMessage.label
                        dq RVA TranslateMessage.label
                        dq RVA DispatchMessage.label
                        dq RVA ShowWindow.label
                        dq RVA PostQuitMessage.label
                        dq RVA LoadIcon.label
                        dq RVA LoadCursor.label
                        dq 0
user32.address:
RegisterClassEx         dq RVA RegisterClassEx.label
CreateWindowEx          dq RVA CreateWindowEx.label
DefWindowProc           dq RVA DefWindowProc.label
GetMessage              dq RVA GetMessage.label
TranslateMessage        dq RVA TranslateMessage.label
DispatchMessage         dq RVA DispatchMessage.label
ShowWindow              dq RVA ShowWindow.label
PostQuitMessage         dq RVA PostQuitMessage.label
LoadIcon                dq RVA LoadIcon.label
LoadCursor              dq RVA LoadCursor.label
                        dq 0
RegisterClassEx.label   dw 0
                        db 'RegisterClassExA', 0
                        rb RVA $ and 1
CreateWindowEx.label    dw 0
                        db 'CreateWindowExA', 0
                        rb RVA $ and 1
DefWindowProc.label     dw 0
                        db 'DefWindowProcA', 0
                        rb RVA $ and 1
GetMessage.label        dw 0
                        db 'GetMessageA', 0
                        rb RVA $ and 1
TranslateMessage.label  dw 0
                        db 'TranslateMessage', 0
                        rb RVA $ and 1
DispatchMessage.label   dw 0
                        db 'DispatchMessageA', 0
                        rb RVA $ and 1
ShowWindow.label        dw 0
                        db 'ShowWindow', 0
                        rb RVA $ and 1
PostQuitMessage.label   dw 0
                        db 'PostQuitMessage', 0
                        rb RVA $ and 1
LoadIcon.label          dw 0
                        db 'LoadIconA', 0
                        rb RVA $ and 1
LoadCursor.label        dw 0
                        db 'LoadCursorA', 0
                        rb RVA $ and 1

section '.data' data readable writeable
  s_winTitle db "My program's window title", 0
  s_winClass db 'FASMWIN64', 0
  ;wc WNDCLASSEX ? ; struct - macro too
  wc:
  wc.cbSize             dd ?
  wc.style              dd ?
  wc.lpfnWndProc        dq ?
  wc.cbClsExtra         dd ?
  wc.cbWndExtra         dd ?
  wc.hInstance          dq ?
  wc.hIcon              dq ?
  wc.hCursor            dq ?
  wc.hbrBackground      dq ?
  wc.lpszMenuName       dq ?
  wc.lpszClassName      dq ?
  wc.hIconSm            dq ?
  wc.Length = $ - wc
  ; msg MSG ? ; struct - macro too
  msg:
  msg.hwnd              dq ?
  msg.message           dd ?
                        dd ?
  msg.wParam            dq ?
  msg.lParam            dq ?
  msg.time              dd ?
  msg.pt.x              dd ?
  msg.pt.y              dd ?
  l_hWnd dq ?
  l_hInstance dq ?

section '.text' code readable writeable executable
  label_start:
    xor rcx, rcx        ; instead: mov rcx, 0
    push rcx            ;          push rax
    call [GetModuleHandle]
    add rsp, 8
    mov [l_hInstance], rax
    mov [wc.hInstance], rax
    mov [wc.cbSize], wc.Length;sizeof.WNDCLASSEX
    mov [wc.style], 3; CS_HREDRAW or CS_VREDRAW
    mov [wc.lpfnWndProc], procWnd
    mov [wc.cbClsExtra], 0
    mov [wc.lpszClassName], s_WinClass
    lea rcx, [wc]       ; instead: mov rcx, wc
    push rcx
    call [RegisterClassEx]
    add rsp, 8
    ;invoke CreateWindowEx, 0, s_WinClass, s_WinTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL
    push 0      ; NULL
    push [l_hInstance]
    push 0      ; NULL
    push 0      ; NULL
    push 480
    push 640
    push 8000h  ; CW_USEDEFAULT
    push 8000h  ; CW_USEDEFAULT
    mov r9, 000CF0000h; WS_OVERLAPPEDWINDOW
    lea r8, [s_WinTitle] ; instead: mov r8, s_WinTitle
    lea rdx, [s_WinClass]; instead: mov rdx, s_WinClass
    xor rcx, rcx; instead: mov rcx, 0
    sub rsp, 32
    call [CreateWindowEx]
    add rsp, 32+64
    mov [l_hWnd], rax
    ;invoke ShowWindow, [l_hWnd], SW_SHOW
    mov rdx, 5  ; SW_SHOW
    mov rcx, rax
    sub rsp, 16
    call [ShowWindow]
    add rsp, 16
  label_msg_loop:
    ;invoke GetMessage, msg, NULL, 0, 0
    xor r9, r9          ; instead: mov r9, 0
    xor r8, r8          ; instead: mov r8, 0
    xor rdx, rdx        ; instead: mov rdx, 0
    lea rcx, [msg]      ; instead: mov rcx, msg
    sub rsp, 32
    call [GetMessage]
    add rsp, 32
    or rax, rax
    je label_end_prog
    ;invoke TranslateMessage, msg
    lea rcx, [msg]      ; instead: mov rcx, msg
    push rcx
    call [TranslateMessage]
    add rsp, 8
    ;invoke DispatchMessage, msg
    lea rcx, [msg]      ; instead: mov rcx, msg
    push rcx
    call [DispatchMessage]
    add rsp, 8
    jmp label_msg_loop
    
  label_end_prog:
    ;invoke ExitProcess, [msg.wParam]
    mov rcx, [msg.wParam]
    push rcx
    call [ExitProcess]
    add rsp, 8
    
;proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam
procWnd:
  push rbp
  mov rbp, rsp
  push rbx
  push rsi
  push rdi      ; instead: rsi
  mov [rbp+16], rcx
  mov [rbp+24], rdx
  mov [rbp+32], r8
  mov [rbp+40], r9
  cmp dword [rbp+24], 2; WM_DESTROY
  je label_destroy_wnd
  ;invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam]

; macro generated, redundant
  ; mov r9, [rbp+40]
  ; mov r8, [rbp+32]
  ; mov rdx, [rbp+24]
  ; mov rcx, [rbp+16]

  sub rsp, 32
  call [DefWindowProc]
  add rsp, 32
  jmp label_finish
  
  label_destroy_wnd:
    ;invoke PostQuitMessage,0
    xor rcx, rcx        ; instead: mov rcx, 0
    push rcx
    call [PostQuitMessage]
    add rsp, 8
    
  label_finish:
    ;ret - macro too
    lea rsp, [rbp-24]
    pop rdi     ; instead: rsi
    pop rsi
    pop rbx
    pop rbp
    retn
;endp
    

sorry for the typos, I typed in the browser

ADD: it seems that everything has been expanded


I decided to try and understand the basics to it's simplest form and go with the low end of basics following your code but adapting it as I understood it. But FASM gives me an error when compiling. It tells me that "call[printf]" is an illegal instruction. I tried to symply write hello world in console. I watched many Youtube videos but none go with the Windows operating system and all lean towards linux systems. On the other hand, I get other places who import and include files. As I want to understand ASM first before having fun with simplified FASM macros, I found your initial post interesting and more instructive. Here's my code to begin with:
Code:
; Define our program type/format
format pe console
; Define our starting point for executing our program
entry label_start
; Import the DLL functions
section '.idata' import data readable writeable
  ; Call the import process for the DLL and defined functions
  dd RVA msvcrt, 0, 0, dll_msvcrt, msvcrt_functions
  ; Import the defined functions
  msvcrt:
    dq RVA func_printf
    dq RVA func_system
    dq RVA func_exit
    dq 0
  ; Set our usable functions for coding later
  msvcrt_functions:
    printf dq RVA func_printf
    system dq RVA func_system
    exit dq RVA func_exit
    dq 0        
  ; Import the required DLL
  dll_msvcrt db 'msvcrt.dll', 0
             rb RVA $ and 1
  ; Define the functions to import from the DLL's list of functions
  func_printf dw 0
              db 'printf', 0
              rb RVA $ and 1
  func_system dw 0
              db 'system', 0
              rb RVA $ and 1
  func_exit dw 0
            db 'exit', 0
            rb RVA $ and 1
; Define our variables
section '.data' data readable writeable
  mess db 'Hello, world!', 0
  mess_len equ $-mess
; Execute the program (program's actual code)
section '.text' code readable writable executable
  label_start:
    push ebp
    mov ebp, esp
    ; This line invokes the write command which is defined by value 4
    sub ebp, 4
    mov dword [esp], mess
    ; Print's the message on screen
    call [printf]
    mov dword [esp], 0
    ; Exit the program
    call [exit]    

Now, I really don't know what RVA does and you seem to use VERY often. I tried to comment this as I understood it from your example. But yeah, I got this illegal intruction. I also followed the tutorial I found here: https://jakash3.wordpress.com/2010/07/23/fasm-tutorial-16-32-bit/

And I tried to mix it with yours but obviously, I missed something. And I cannot go more basic than this unless I wanted to run a com app on DOSBox which is not my objective. I'm on Windows 11 so I'd like to miniumum be able to show something in command line while using my basic Windows App to build on top of it adding menus, buttons, text boxes and more later.

And I kind of lost track of all of what other people were talking about in this thread. I even saw someone talk about cell phones which is way outside my question.
Post 12 Sep 2021, 05:39
View user's profile Send private message Reply with quote
Overclick



Joined: 11 Jul 2020
Posts: 670
Location: Ukraine
Overclick 12 Sep 2021, 07:29
avidichard, just open examples under FASM folder. Some simple templates has to be there.
Post 12 Sep 2021, 07:29
View user's profile Send private message Visit poster's website Reply with quote
avidichard



Joined: 22 Mar 2021
Posts: 22
Location: Quebec/Canada
avidichard 12 Sep 2021, 08:01
Overclick wrote:
avidichard, just open examples under FASM folder. Some simple templates has to be there.

The problem is most use includes and imports. I am AVOIDING this and I indeed checked a lot of those already.

I just want to know how to make this thing work because the pure ASM example we provided me also does not compile. I also checked the include files to understand what it generates and I know where the proposed code comes from, but still, the calls do not work.
Post 12 Sep 2021, 08:01
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 12 Sep 2021, 09:16
macomics wrote:
I completely agree, but no one is talking about a violation. I want to point out to you once again that even in the example from MSDN, this structure is only temporary, does not require saving anywhere and should not contain up-to-date information on the class registered with it at any time after its application.

My initial correction was about the probability of WNDCLASSEX having been changed. As for storing or not storing it, it a matter of a particular task. Generally people don’t tend to change their window classes a lot, so there’s no real winner strategy.

But, once again, my point was that saving hInstance in some WNDCLASSEX and taking it from there is not a recommended way to go. No matter whether the structure is passed from the stack of from the global variable.

macomics wrote:
How much harder is it?

Well, nobody said it really is noticeably harder, I just gave an example of a project where a simple $ - rva $ expression works at any line after the format directive. The difference is that EXEs are usually loaded at the base address specified in the headers while DLLs are not guaranteed to, so for DLLs the trick is one step longer as it requires the constants being fixed up by the loader, plus additional records in the fixups section. Not that it really is hard.
Post 12 Sep 2021, 09:16
View user's profile Send private message Visit poster's website Reply with quote
avidichard



Joined: 22 Mar 2021
Posts: 22
Location: Quebec/Canada
avidichard 12 Sep 2021, 09:29
Code:
; Define our program type/format
format pe console
; Define our starting point for executing our program
entry label_start
; Set our variables
section '.idata' import data readable writeable
  ; Import our DLL file
  dd rva msvcrt.functions
  dd 0
  dd 0
  dd rva msvcrt.dll
  dd rva msvcrt.functions
  dd 5 dup(0)
  msvcrt.dll db 'msvcrt.dll', 0
  ; Import the functions
  printf.function dw 0
                  db 'printf', 0
  exit.function dw 0
                db 'exit', 0
  msvcrt.functions:
    printf dq rva printf.function
    exit   dq rva exit.function
           dq 0
; Define our variables
section '.data' data readable writeable
  mess db 'Hello, world!', 0
; Execute the program (program's actual code)
section '.text' code readable writable executable
  label_start:
    ; Print's the message on screen
    push mess
    call [printf]
    push 0
    ; Exit the program
    call [exit]    

I tried again using another example I followed and I still have the illegal instruction on "call [printf]". If I remove the square brackets, then, it compiles. BUT, it returns nothing in the command line prompt, the message never appears.
Post 12 Sep 2021, 09:29
View user's profile Send private message Reply with quote
Overclick



Joined: 11 Jul 2020
Posts: 670
Location: Ukraine
Overclick 12 Sep 2021, 10:01
U work in 32bit mode.
Change dq to dd:
Code:
; Define our program type/format
format pe console
; Define our starting point for executing our program
entry label_start
; Set our variables
section '.idata' import data readable writeable
  ; Import our DLL file
  dd rva msvcrt.functions
  dd 0
  dd 0
  dd rva msvcrt.dll
  dd rva msvcrt.functions
  dd 5 dup(0)
  msvcrt.dll db 'msvcrt.dll', 0
  ; Import the functions
  printf.function dw 0
                  db 'printf',0
  getch.function dw 0
                 db '_getch',0
  exit.function dw 0
                db 'exit',0
  msvcrt.functions:
    printf dd rva printf.function
    getch  dd rva getch.function
    exit   dd rva exit.function
           dd 0
; Define our variables
section '.data' data readable writeable
  key  db '%s',0
  mess db 'Hello, world!', 0
; Execute the program (program's actual code)
section '.text' code readable writable executable
  label_start:
    ; Print's the message on screen
    push mess
    push key
    call [printf]
    call [getch]
    push 0
    ; Exit the program
    call [exit]     
Post 12 Sep 2021, 10:01
View user's profile Send private message Visit poster's website Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 12 Sep 2021, 13:09
avidichard wrote:
Now, I really don't know what RVA does and you seem to use VERY often. I tried to comment this as I understood it from your example. But yeah, I got this illegal intruction. I also followed the tutorial I found here:
RVA - stands for "relative virtual address". This calculates the value of the label in your program relative to its starting address in memory.
avidichard wrote:
And I kind of lost track of all of what other people were talking about in this thread. I even saw someone talk about cell phones which is way outside my question.
Don't worry about smartphones. This was my hint to return "Overclick" to the framework of the topic under discussion.
DimonSoft wrote:
My initial correction was about the probability of WNDCLASSEX having been changed. As for storing or not storing it, it a matter of a particular task. Generally people don’t tend to change their window classes a lot, so there’s no real winner strategy.

But, once again, my point was that saving hInstance in some WNDCLASSEX and taking it from there is not a recommended way to go. No matter whether the structure is passed from the stack of from the global variable.
I'm not agitating you for anything, it's just that my position differs from yours in that I don't see the point in storing these structures and values. But no one restricts you in this, because the assembler gives us complete freedom of action.
Quote:
Well, nobody said it really is noticeably harder, I just gave an example of a project where a simple $ - rva $ expression works at any line after the format directive. The difference is that EXEs are usually loaded at the base address specified in the headers while DLLs are not guaranteed to, so for DLLs the trick is one step longer as it requires the constants being fixed up by the loader, plus additional records in the fixups section. Not that it really is hard.
For movable modules of the DLL type, you will have to use 2 commands. When using $ - rva $, the base address used during compilation will be loaded into the register (a number, not an address). Two commands are needed to create and apply a fixup. Using any global variables in your program will generate a fix anyway. But if you need to get rid of them, you will have to sacrifice simplicity and speed.
Code:
call label
label:
  pop rax
  sub rax, rva label
    
I mean, both calling an external function and trying to save the value obtained in the parameters will also require generating corrections or you will have to manually resort to tricks to get rid of them.
Post 12 Sep 2021, 13:09
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 12 Sep 2021, 14:44
avidichard wrote:
I tried again using another example I followed and I still have the illegal instruction on "call [printf]". If I remove the square brackets, then, it compiles. BUT, it returns nothing in the command line prompt, the message never appears.
Overclick gave you a working example, but again he was too lazy to explain what the error was in your actions. When you remove the brackets, you are not calling a function whose address is in a variable, but this variable itself. Then the value of this variable begins to be decoded as commands to the processor. In the assembly language, there is no distinction between commands and data, but there are hardware limitations that do not allow explicitly declared data to start executing. Although if you mix code and data in one section, you may start executing data unintentionally. For example:
Code:
or rax, -1
dw 0x15FF                ; This and the next lines will be decoded into a command:
dd my_label-$-4      ; call [my_label]
mov [my_var], rax
dw 0xFE74                ; jz $   (preventing the execution of data in the "my_label" variable)
; but we completely suspend the current flow of command execution
my_label  dq my_function
my_function:
  xor rax, rax
  db $C3                     ; retn

my_var  dq ?    ; my_var = 0
    
In 32-bit code, the length of the variable containing the transition address should be 4-byte, not 8-byte. Therefore, you need to change the dq directives to dd. For example (32-bit code):
Code:
or eax, -1
dw 0x15FF                ; This and the next lines will be decoded into a command:
dd my_label-$-4      ; call [my_label]
mov [my_var], eax
dw 0xFE74                ; jz $   (preventing the execution of data in the "my_label" variable)
; but we completely suspend the current flow of command execution
my_label  dd my_function
my_function:
  xor eax, eax
  db $C3                     ; retn

my_var  dd ?    ; my_var = 0    
Again, by removing the brackets in the command call [var], you force the assembler to generate the correct address of this variable, no matter what size it is. But this does not mean that the program will be able to start executing data at this address in any case. For example (64-bit code):
Code:
or rax, -1
db 0xE8                ; This and the next lines will be decoded into a command:
dd my_label-$-4      ; call my_label    <- error
mov [my_var], rax
dw 0xFE74                ; jz $   (preventing the execution of data in the "my_label" variable)
; but we completely suspend the current flow of command execution
my_label  dq my_function  ; Even if you try to imagine the possible value of this variable: 0x000000007FF800CC
; The lowest byte will be executed as an int 3 command, and further execution will be stopped.
; But I just came up with the value of this variable (to simplify understanding).
; And you will be very lucky if the processor can chew the data that the address consists of without any problems.
my_function:
  xor rax, rax
  db $C3                     ; retn

my_var  dq 2    ; my_var = 2
    
Post 12 Sep 2021, 14:44
View user's profile Send private message Reply with quote
avidichard



Joined: 22 Mar 2021
Posts: 22
Location: Quebec/Canada
avidichard 12 Sep 2021, 21:45
Overclick wrote:
U work in 32bit mode.
Change dq to dd:

Well, THAT did the job. I literally spent 2 hours searching and trying different things. All that because of a "q" instead of a "d", the joys of programming. I did find the "%s" push in a few examples and you also supplied it. But without it, the program does run. So is the "push '%s'" really necessary? and if so, why?

Now, I did find 2 differences with the exact same output and I would like to know which one is the best way to work. One is simple:
Code:
; Print's the message on screen
push mess
call [printf]
push 0
; Exit the program
call [exit]    

And this one is a bit more complexe but again, results in the exact same thing.
Code:
; Print's the message on screen
push ebp
mov ebp, esp
sub esp, 4
mov dword[esp], mess
call [printf]
mov dword[esp], 0
; Exit the program
call [exit]    

macomics wrote:
Overclick gave you a working example, but again he was too lazy to explain what the error was in your actions. When you remove the brackets, you are not calling a function whose address is in a variable, but this variable itself. Then the value of this variable begins to be decoded as commands to the processor. In the assembly language, there is no distinction between commands and data, but there are hardware limitations that do not allow explicitly declared data to start executing. Although if you mix code and data in one section, you may start executing data unintentionally. For example:

Thank you for the precisions. I just easily get lost in your explanations though because it gives too many details in which I get lost into and not the exact answer to my question although you DO answer it, it's just a bit more difficult for me to easily spot my mistake. BUT, I DO read your explanations and I do learn from them, it's just a bit longer because of the details. BUT, I do recon that I may not be all that precise in my questions either. I indeed had an idea that calling with or without brackets had a very big impact and a difference and that the brackets WERE needed. I just find it VERY impressive that FASM actually detects errors in variable length variations compared to system type i/e 32 vs 64 bits. For such a small program, I am very impressed and I do love FASM for it's capacity and simplicity compared to MASM, NASM and YASM.

So now, my program works but yeah, I'd love a little explanation in the right way of implementing the simple lines of code I wrote above. As for you, macomics, I do have a question about if there is a way to implement the "xor" and "lea" inside my code and if it's considered, for you, to be better practice?
Code:
xor esp, esp
sub esp, 4
lea esp, [mess]
push esp
call [printf]
xor esp, esp
call [exit]    

Or something like that. I'm sure this will need to be corrected, but I am just wondering how those lines could be implemented and which one would be considered the fastest, althout it's a simple print request so optimising is not going to show that much. I also would love more details, NOOB vocabulary explanation on the "rva" because I did not find anything comprehenssive for me yet and I did search. The only logical explanation I seen to understand is that "rva" returns the value of a label content but I think I am pretty much off with this understanding.

Also, this in the ".idata" section:
Code:
; Import our DLL file
label_dll_import:
  dd rva msvcrt_functions
  dd 0
  dd 0
  dd rva msvcrt_dll
  dd rva msvcrt_functions
  dd 5 dup(0)
msvcrt_dll db 'msvcrt.dll', 0
; Import the functions
label_function_import:
  printf_function dw 0
                  db 'printf', 0, 0
  exit_function dw 0
                db 'exit', 0, 0
; Define functions
msvcrt_functions:
  printf dd rva printf_function
  exit   dd rva exit_function
         dd 0    

To me, this executes the code from up to down. does assembly stop executing the code once it meets another label? Logically, not, but practically, it actually does. for example, this portion:
Code:
  dd rva msvcrt_dll
  dd rva msvcrt_functions
  dd 5 dup(0)
msvcrt_dll db 'msvcrt.dll', 0    

the "dd rva msvcrt_dll" refers to the "msvcrt_dll db 'msvcrt.dll', 0" code which is executed, or read lower. In the case it does search for the reference and run it, once it went through the last line of the dd's "dd 5 dub(0)", it still executes the "msvcrt_dll db 'msvcrt.dll', 0" AND so on for the others bellow "msvcrt_functions" and "printf_function" and "exit_function". So I'm wondering how does the program logically treat this information? Because clearly, it does NOT run these lines of codes in the order we wrote them, it treats and executes them much differently and I'd like to know if someone can explain to me how the information coded is treated.

**EDIT:** Before I forget, a SINCERE and VERY HUGE thank you for you who helped me. macomics, your converted code made me have much better searches to understand. and all the others, the bits and pieces of information I got from your many different views and solutions gave me a lot of help and answers to many questions. I am very gratefull that you have been this patient with me and I really want you to recieve my gratitude on answering my numerous questions. I know noobs are not always well treated because most people refer them to manuals and searches, a lazy way to get their questions out of the way, but you did not and I really am gratefull for all of your support. so THANK YOU!!!
Post 12 Sep 2021, 21:45
View user's profile Send private message Reply with quote
avidichard



Joined: 22 Mar 2021
Posts: 22
Location: Quebec/Canada
avidichard 12 Sep 2021, 22:03
Code:
dd rva msvcrt.functions
dd 0
dd 0
dd rva msvcrt.dll
dd rva msvcrt.functions
dd 5 dup(0)    

I know this is also the same:
Code:
dd rva msvcrt.functions, 0, 0, rva msvcrt.dll, rva msvcrt.functions
dd 0, 0, 0, 0, 0    

But could these also be valid?
Code:
dd rva msvcrt.functions, 0, 0, rva msvcrt.dll, rva msvcrt.functions, 0, 0, 0, 0, 0
; OR
dd rva msvcrt.functions, 0, 0, rva msvcrt.dll, rva msvcrt.functions, 5 dup(0)    

Would those still work?
Post 12 Sep 2021, 22:03
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 12 Sep 2021, 22:19
avidichard wrote:
I did find the "%s" push in a few examples and you also supplied it. But without it, the program does run. So is the "push '%s'" really necessary? and if so, why?
The first parameter of this function is a pointer to the message formatting string. This line may contain a different number of formatting directives, and depending on their number, you will need a similar number of additional parameters for the function that are placed on the stack after the first parameter. For example: C
Code:
printf("My message %s, %2d-%2d-%4d", "Hello!", 13, 9, 2021);    
prints: My message Hello! 13-09-2021
Code:
push ebp
mov ebp, esp
push 2021
push 9
push 13
push my_message.hello
push format_string
call [printf]
mov esp, ebp
...

section '.data' ...
format_string db 'My message %s, %2d-%2d-%4d', 0
my_message.hello  db 'Hello!', 0    
it will print the same thing
avidichard wrote:
For such a small program, I am very impressed and I do love FASM for it's capacity and simplicity compared to MASM, NASM and YASM.
I also chose it for the same reason.
Quote:

xor esp, esp ;this will immediately corrupt the pointer to the top of the stack and should lead to an error at the first access to the address 0.
sub esp, 4
lea esp, [mess] ; <-- *
push esp
call [printf]
xor esp, esp ; error
call [exit]


*it is better not to touch the stack pointer in 32-bit mode at all, except for explicitly saving the stack address to fix the current block of parameters for the function. Unlike the 64-bit mode, where it is required to maintain alignment in the stack by 16 bytes, in the 32-bit mode, the stack alignment goes by 4 bytes and for this it is simply not worth touching the esp once again, but using push/pop commands
avidichard wrote:
Quote:
dd rva label_msvcrt.functions
dd 0
dd 0
dd rva msvcrt.dll
dd rva msvcrt.functions
dd 5 dup(0)

I know this is also the same:
Code:
dd rva msvcrt.functions, 0, 0, rva msvcrt.dll, rva msvcrt.functions
dd 0, 0, 0, 0, 0    

But could these also be valid?
Code:
dd rva msvcrt.functions, 0, 0, rva msvcrt.dll, rva msvcrt.functions, 0, 0, 0, 0, 0
; OR
dd rva [b]label_msvcrt.functions[/b], 0, 0, rva msvcrt.dll, rva msvcrt.functions, 5 dup(0)    

Would those still work?
Yes. Even that
Code:
dd rva label_msvcrt.functions,\
   0,\
   0,\
   rva msvcrt.dll,\
   rva msvcrt.functions,\
   5 dup(0)    
But! These declarations are actually separate structures of 20 bytes each and it is better not to mix them, but to declare them separately in general.
Code:
struc PE32.IMPORT_SECTION.LIBRARY LibName, RvaArray, NamesArray, TimeStamp, FwdChain {
  .Names  dd 0+NamesArray
  .TimeStamp dd 0+TimeStamp
  .Chain dd 0+FwdChain
  .Library  dd 0+LibName
  .Functions dd 0+RvaArray
}
mscvrt PE32.IMPORT_SECTION.LIBRARY rva mscvrt.lib_name, rva mscvrt.functions, rva mscvrt.names;, 0, 0
end_empty PE32.IMPORT_SECTION.LIBRARY; 0,0,0,0,0
    
The included macro "library" that's exactly what he does. According to the list of library names, it forms an array of similar structures, but also discards from this array those library names from which no functions are imported.
Post 12 Sep 2021, 22:19
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1062
Location: Russia
macomics 12 Sep 2021, 23:26
Add:
avidichard wrote:
Or something like that. I'm sure this will need to be corrected, but I am just wondering how those lines could be implemented and which one would be considered the fastest, althout it's a simple print request so optimising is not going to show that much. I also would love more details, NOOB vocabulary explanation on the "rva" because I did not find anything comprehenssive for me yet and I did search. The only logical explanation I seen to understand is that "rva" returns the value of a label content but I think I am pretty much off with this understanding.

Also, this in the ".idata" section:
Code:

; Import our DLL file
label_dll_import:
dd rva msvcrt_functions
dd 0
dd 0
dd rva msvcrt_dll
dd rva msvcrt_functions
dd 5 dup(0)
msvcrt_dll db 'msvcrt.dll', 0
rb RVA $ and 1 alignment
; Import the functions
label_function_import:
printf_function dw 0
db 'printf', 0
rb RVA $ and 1 alignment
exit_function dw 0
db 'exit', 0
rb RVA $ and 1 alignment
; Define functions
msvcrt_functions:
printf dd rva printf_function
exit dd rva exit_function
dd 0


To me, this executes the code from up to down. does assembly stop executing the code once it meets another label? Logically, not, but practically, it actually does. for example, this portion:
Code:

dd rva msvcrt_dll
dd rva msvcrt_functions
dd 5 dup(0)
msvcrt_dll db 'msvcrt.dll', 0


For some reason, you removed the alignment of ads. Just go back to using macros. It will be easier this way.

RVA: This fasm operator subtracts the base address from the label address
Code:
format PE GUI 5.0 at 0x00400000 ; <- base address
  entry main ; <- label main = 0x000402000      / rva main = 0x00002000
section '.idata' ...
...
section '.text' ...
main:
    
avidichard wrote:
the "dd rva msvcrt_dll" refers to the "msvcrt_dll db 'msvcrt.dll', 0" code which is executed, or read lower. In the case it does search for the reference and run it, once it went through the last line of the dd's "dd 5 dub(0)", it still executes the "msvcrt_dll db 'msvcrt.dll', 0" AND so on for the others bellow "msvcrt_functions" and "printf_function" and "exit_function". So I'm wondering how does the program logically treat this information? Because clearly, it does NOT run these lines of codes in the order we wrote them, it treats and executes them much differently and I'd like to know if someone can explain to me how the information coded is treated.
This information is just a block of data that the loader program of the operating system uses to determine the connections of your program with other modules. After loading the program into memory, the loader corrects the addresses if it was necessary to load the program at an address other than the one chosen by the compiler. Then it reads the information from the import and loads all the required dll modules into the address space of your program. After loading each dll module, the loader reads its dll-export section and matches the names of the functions exported by the module with the names listed in the exe-import section. If they match, the address of this function is written to the corresponding global variable in the exe-import section. Next, your program uses this global variable to call the imported function.This process is repeated recursively for all the required modules (exe/dll), until all of them are loaded into memory and all the functions are mapped to each other.

In fact, the process of loading into memory is even more complicated. I have simplified the explanations very much. Very long books are usually written on this topic. There is no way to fit into one answer.
Post 12 Sep 2021, 23:26
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3  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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.