flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2, 3 Next |
Author |
|
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" 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. |
|||
![]() |
|
DimonSoft 11 Sep 2021, 19:09
macomics 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. macomics 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. 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). |
|||
![]() |
|
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. 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. |
|||
![]() |
|
Overclick 11 Sep 2021, 20:07
Quote:
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. |
|||
![]() |
|
macomics 11 Sep 2021, 21:06
Overclick wrote:
Quote: Just use it like that: 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 Code: CS_HREDRAW fix 2 CS_VREDRAW fix 1 Code: define CS_HREDRAW 2 define CS_VREDRAW 1 Code: label CS_HREDRAW at 2 label CS_VREDRAW at 1 |
|||
![]() |
|
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. |
|||
![]() |
|
macomics 12 Sep 2021, 04:03
Overclick wrote: facepalm |
|||
![]() |
|
avidichard 12 Sep 2021, 05:39
macomics wrote:
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. |
|||
![]() |
|
Overclick 12 Sep 2021, 07:29
avidichard, just open examples under FASM folder. Some simple templates has to be there.
|
|||
![]() |
|
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. |
|||
![]() |
|
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. |
|||
![]() |
|
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. |
|||
![]() |
|
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] |
|||
![]() |
|
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: 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. 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. 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. Code: call label label: pop rax sub rax, rva label |
|||
![]() |
|
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. 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 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 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 |
|||
![]() |
|
avidichard 12 Sep 2021, 21:45
Overclick wrote: U work in 32bit mode. 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!!! |
|||
![]() |
|
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? |
|||
![]() |
|
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? Code: printf("My message %s, %2d-%2d-%4d", "Hello!", 13, 9, 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 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. Quote:
*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:
Code: dd rva label_msvcrt.functions,\ 0,\ 0,\ rva msvcrt.dll,\ rva msvcrt.functions,\ 5 dup(0) 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 |
|||
![]() |
|
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. 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. 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. |
|||
![]() |
|
Goto page Previous 1, 2, 3 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.