flat assembler
Message board for the users of flat assembler.
Index
> Main > Is handwritten asm more dangerous than compiled C code? Goto page Previous 1, 2, 3 Next |
Author |
|
Furs 24 Sep 2018, 20:51
ACP wrote: Be so kind and reread all my above posts please - you will find exactly the same statement except not a single example taken out of context. Honestly speaking I fail to see how: This problem is obviously made worse by incompetent people who use "int" or signed types where they shouldn't be signed or even "int" in the first place (e.g. array indices on arbitrary input), because they follow some stupid Google "coding style" garbage. Signed types are just evil and should be avoided unless you *need* them to be signed. And yes, this goes against the crap spewed by non-C programmers on stack overflow which tell you to use signed everywhere. Even C++ is infected with that mentality. ACP wrote: In the first case the author admits that he had used uninitialized boolean variable thus resulting in this strange behavior. In asm it translates to something like this: ACP wrote: Using uninitialized variables is clearly wrong and it is considered a software defect that can lead to software vulnerabilities. So while we have UB here it was error in the source code in the first place that resulted in wrong code generation. You can make exactly the same wrong assumption in asm as well as exactly the same mistake. ACP wrote: Every source code defect should be handled by proper change at source code level. But we are not living in ideal world. People do introduce defects Like I said, the problem is between chair and keyboard. ACP wrote: Going your path we should disable all WAFs since they are just protecting vulnerable code from attacks. That is not how security works. |
|||
24 Sep 2018, 20:51 |
|
DimonSoft 24 Sep 2018, 22:36
ACP wrote:
I’ll just start here to avoid citing half of the standard. Just so that you know the direction to dive deeper. The size of char type is not 8 bits. It is only at least CHAR_BIT bits and CHAR_BIT should be at least 8. There’re platforms with 9 bits, 16 bits, etc. short int is not guaranteed to use two’s complement representation. That’s why the range of values is [–32767; 32767], lower bound is not –32768 as you might expect. And relying on the value being inside the type range is stepping into the UB land. If a compiler notices, it is free to perform any changes to the code. Emphasis: any. BTW, the range is only the minimal range. If you somehow rely on short being 2 bytes in size and allocate memory for it dynamically, congratulations, you’ve just introduced a potential security bug. Want to write perfectly valid C code that will never break when compiled for another platform? Don’t forget that radix of exponent representation in floating point types is FLT_RADIX, which is at least 2. I can list this stuff almost infinitely. Now tell me this language can be used to write safe code. ACP wrote: Using uninitialized variables is clearly wrong and it is considered a software defect that can lead to software vulnerabilities. So while we have UB here it was error in the source code in the first place that resulted in wrong code generation. You can make exactly the same wrong assumption in asm as well as exactly the same mistake. I predicted this answer: DimonSoft wrote: And your demand for secure C/C++ code with unwanted software defect is either a trick to later say “Ha-ha! It’s not a valid/secure C/C++ code since it has undefined behaviour!” or… If we define “valid C/C++ program” as “bugless C/C++ program”, then you’re right. Oops, but that applies to any other language, including assembly. But we’ve been talking about which language makes it easier to avoid security vulnerabilities. If a silly mistake becomes a security vulnerability, I’d prefer to avoid such a language/compiler for any production code. Like I said (and Furs has already doubled that), in assembly you won’t get (p) and (!p) both true at the same time. Because it interprets your program as is, without trying to be smarter than you. UB in C/C++ is basically a way to achieve amazing performance by allowing the optimizer to rewrite your code whenever you haven’t proved well enough that you know what you’re doing. It quickly turns compiler from being an instrument that assists in programming to being an opponent in a strange chess game where a tiny mistake might look like a valid reason to optimize and change your program’s behaviour in some corner case that will be detected only after the nuclear station explodes. ACP wrote: As for assemblers inserting some code during assembly process please check out A86 assembler. It had some interesting optimizations (like using mov offset instead of lea) and executable code watermarking. Now what? FASM also does that (say, choosing a shorter instruction). Does that change the program logic arbitrarily? How does that compare to inserting pieces of code that sometimes even perform calls to separate procedures? I’m OK with x div 2 being replaced with x shr 1 if that’s applicable for the operand type and doesn’t change the logic. Should I be OK with introducing code that’s not under my control and that involves operations on the stack thus changing the structure of a stack frame? Should I be OK when it turns my media player into a calculator? When should I start complaining? ACP wrote: If safeguards would make software secure we wouldn't be talking about software security in this thread - would we? The multi layer security model isn't anything new and it should not be surprising that compilers are following same path. The multiple layers model comes from the true belief that every safeguard can fail so adding another layer may decrease the risk of successful attack. Yet you need a good balance, adding too any layers or adding another layer doing the same does not work obviously. But I am sure you already know it. Shouldn’t it then insert checks for pointer parameters that are dereferenced inside functions for not being NULL pointers? Why? Quote: When stack protection techniques were designed buffer overflows were the most popular and most exploited type of software defects. That is why C compilers do deal with them. I wonder what language had most problems with buffer overflows. Maybe some language that doesn’t have String as First-Class Citizen? Some language that doesn’t have Array as First-Class Citizen? Or some language that pretends to have String (std::string) but fails to implement concatenation when the first operand is a string literal? Some language that still pretends to be a high-level cross-platform language? Some language that is still considered to be low-level compared to others? Some language in which it is quite painful to debug because of tons of junk code (safeguards) that differs between compilers? ACP wrote: I think you are missing crucial point in what safeguard purpose is in the first place, hence the whole discussion. Going your path we should disable all WAFs since they are just protecting vulnerable code from attacks. That is not how security works. I do understand the role of safeguards. I just absolutely disgust the solutions that do not really solve the problem (or solve its easy part) but just make one think (s)he is safe with them, also getting in the way from time to time. And I also can’t agree that having such a feature makes a language safer. It just makes a programmer feel safer. Which is bad. Quote: who actually deal with secure coding on assembly level and so I am hoping to learn something new. What I’m trying to say here is that secure coding is language-independent. Language is just a way to express what a program should do. Custom implementations are just dialects. Since the nature of buffer overflow or any other kind of vulnerability stays the same, their prevention is basically the same in all languages, just expressed with different words. |
|||
24 Sep 2018, 22:36 |
|
DimonSoft 24 Sep 2018, 22:51
Furs wrote:
Well, to play fair I should insert a note here that in assembly you actually can have UB. Kind of. For example, most flags are explicitly said to have undefined values after an integer division. There’re lots of cases. The difference is that an assembly compiler (assembler) is not given right to make arbitrary changes to the code whenever you hit such a case. Well, to be even more precise, such cases are not undefined behaviour. In terms of C/C++ it would be called “implementation-defined behaviour” or “unspecified behaviour”. In C/C++ these two do not make the program invalid, unlike UB. In fact, a program with UB is not considered to be a valid C/C++ program even though it’s written with the C/C++ syntax. I find it quite funny to divide programs written in a language into valid and invalid based on whether there’s a logical error in it. Then you can say it’s impossible to write a buggy program in your language, because any program having a bug doesn’t count as C/C++ program. |
|||
24 Sep 2018, 22:51 |
|
ACP 25 Sep 2018, 09:03
I will quickly recap since my main point is lost in all those rants. Assembly language is not more secure than other language. Take look at first example with boolean variable: the only thing that stops you from writing code similar to the one generated by C compiler is knowledge, not the language itself. End of story. If you don't understand this fact you should not be talking about secure programming at all because you are becoming part of FUD movement.
To recap some points: 1. I find it really odd that someone who doesn't know what WAF (Web Application Firewall) is talking about secure coding. 2. I find it even more strange when I hear that C compiler safeguards results in bloated code. At least in case of GCC and Visual Studio compilers you can disable all mentioned safeguards including those introduced by the linker to exploit operating system security properties. Maybe there is another C/C++ compiler that does not allow it, if so I would like to learn it's name and version. As for those 2 compilers repeating "bloated code" mantra just means that the programmer can't handle correctly tools he is using or he is criticizing. 3. Security is about thinking about out-of-the-box. You guys select simple cases that fits your way of thinking. As for using Code: db ? https://media.blackhat.com/bh-us-11/Vuksan/BH_US_11_VuksanPericin_PECOFF_Slides.pdf and https://docplayer.net/34839119-Pe-specification-vs-loader.html |
|||
25 Sep 2018, 09:03 |
|
Tomasz Grysztar 25 Sep 2018, 10:46
DimonSoft wrote: Well, to play fair I should insert a note here that in assembly you actually can have UB. Kind of. For example, most flags are explicitly said to have undefined values after an integer division. There’re lots of cases. |
|||
25 Sep 2018, 10:46 |
|
Furs 25 Sep 2018, 14:18
ACP wrote: 1. I find it really odd that someone who doesn't know what WAF (Web Application Firewall) is talking about secure coding. ACP wrote: 2. I find it even more strange when I hear that C compiler safeguards results in bloated code. At least in case of GCC and Visual Studio compilers you can disable all mentioned safeguards including those introduced by the linker to exploit operating system security properties. Maybe there is another C/C++ compiler that does not allow it, if so I would like to learn it's name and version. As for those 2 compilers repeating "bloated code" mantra just means that the programmer can't handle correctly tools he is using or he is criticizing. ACP wrote: 3. Security is about thinking about out-of-the-box. You guys select simple cases that fits your way of thinking. As for using I mean what's next? You "assume" the target is x86 family and thus code is wrong cause it won't compile for ARM? ACP wrote: You also assumes that OS loader works the same on the same (like it never gets updated for example) and different platforms and that the code will also always run in the same, non-hostile environment which is clearly wrong assumption. There two great presentation on that topic for PE format: Zero-initialization is defined behavior. It won't "change in the future" because it will break compatibility. That's like worrying about them changing the format of PE itself which would break any program anyway. It's not just PE either. Honestly, you remind me of people who "don't trust the API or system calls" and then make rigorous checks after them "just to be safe" even if they're documented in a certain way. Or maybe also save all the registers before calling an API, you can't trust it to save the callee-saved registers after all right? Let's not assume it will save them and cause security vulnerabilities. (and yes, there ARE people who think that way) |
|||
25 Sep 2018, 14:18 |
|
revolution 25 Sep 2018, 14:34
The OS has full control over your app so there is little to be gained by not trusting it. Since the OS could simply nullify all attempts to try and trick it. Your app would never know what happened.
Trust your OS and its APIs. They are there to help you. If you don't trust the OS then you might as well not run it. I'm looking at you Win10. |
|||
25 Sep 2018, 14:34 |
|
DimonSoft 25 Sep 2018, 20:05
ACP wrote: I will quickly recap since my main point is lost in all those rants. Assembly language is not more secure than other language. … but certain languages make it easier to mess things up unintentionally. ACP wrote: Take look at first example with boolean variable: the only thing that stops you from writing code similar to the one generated by C compiler is knowledge, not the language itself. End of story. If you don't understand this fact you should not be talking about secure programming at all because you are becoming part of FUD movement. The example is about making a mistake unintentionally, and the consequences of doing so in different languages. If you don’t understand how a language that makes it possible to have b and !b being true at the same time breaks code safety, think about b being a security check. Then think about the possibility of having similar situations in more tricky cases, like those Raymond Chen talks about. The Standard doesn’t even list all of them! UB is the topic that most people who love C/C++ are not aware of. Talking about this language feature is not FUD, it is spreading information about something that might (and does!) screw up software reliability and security. Is it FUD to talk about nuclear weapons being available to everyone? Quote: 1. I find it really odd that someone who doesn't know what WAF (Web Application Firewall) is talking about secure coding. I find it really odd that someone who doesn’t know about the variability of C/C++ types and consequences of triggering UB in these languages is talking about them. You see my point, right? My master degree dissertation was about applying static analysis to SQL-injection vulnerabilities’ detection, and I’ve obviously seen and analyzed firewall-style techniques in this field, but I personally haven’t seen this acronym to be widely used in this field (which is exactly in the sphere of web-application security). From what I can tell, it is more frequently used in “non-technical” discussions of security, i.e. discussions where prevention measures are discussed without going into serious details of attack mechanisms. I guess, Furs is from quite different field of programming which doesn’t prevent him to hve knowledge about security stuff related to his field. Besides, you don’t have to be a cow to tell that milk is spoiled. Quote: 2. I find it even more strange when I hear that C compiler safeguards results in bloated code. At least in case of GCC and Visual Studio compilers you can disable all mentioned safeguards including those introduced by the linker to exploit operating system security properties. Maybe there is another C/C++ compiler that does not allow it, if so I would like to learn it's name and version. As for those 2 compilers repeating "bloated code" mantra just means that the programmer can't handle correctly tools he is using or he is criticizing. You disable them and now you’re debugging a completely different version of your program. Let’s talk about software reliability and its formal verification? Sadly, not all bugs can be fixed without looking at disassembly of your program, unless you write some simple stuff. Skipping safeguards and stuff like that quickly becomes a nightmare. Quote: 3. Security is about thinking about out-of-the-box. You guys select simple cases that fits your way of thinking. As for using Nobody did. Reread the topic. And nobody said the author of the article expected the variable to be initialized to 0 or any other particular value. Well, it was you who assumed he did. The author was upset by the fact that the language allows two mutually exclusive situtations to be simultaneous just because of a small bug. Quote: How about good old COM format from MS-DOS? FYI you can use data directives in flat binaries as well for shellcode for example. You also assumes that OS loader works the same on the same (like it never gets updated for example) and different platforms and that the code will also always run in the same, non-hostile environment which is clearly wrong assumption. Could you please cite the posts where anyone assumed that? |
|||
25 Sep 2018, 20:05 |
|
wean_irdeh 25 Sep 2018, 23:19
Tomasz Grysztar wrote:
This is new to me. I have always assumed that assembly is WYSIWYG, now there are/is undefined behavior in assembly, is it good to code in asm as I try to avoid undefined behavior or should I go back to code in C? |
|||
25 Sep 2018, 23:19 |
|
revolution 26 Sep 2018, 01:21
For the x86 CPU there are instructions that have some undefined results, as already stated by others here. But this isn't necessarily true for all the other CPUs. Indeed I would suspect that the x86 CPUs are the exception here, most other CPUs precisely define the outcome of every instruction for all input values.
|
|||
26 Sep 2018, 01:21 |
|
Melissa 26 Sep 2018, 03:07
Tomasz Grysztar wrote:
You cannot create undefined behavior That is you can always predict what code will do no matter. |
|||
26 Sep 2018, 03:07 |
|
Melissa 26 Sep 2018, 03:16
Tomasz Grysztar wrote:
That's not undefined behavior. Undefined behavior is when compiler is free to do anything including completely unrelated things. famous example: Code: void f(char* p) { char tmp = *p; if(!p)/*do something*/ } compiler completely eliminated `if` because dereferencing p with value of NULL, causes undefined behavior. You can't do that in assembly. Actually programmer new that at address of NULL(in this case 0) is some special value that requires action. Thinking as assembly programmer he wanted to do something in that case. If he programmed in assembly everything would be fine. But alas in C, this is undefined behavior and his code was not executed causing code malfunction. This is why assmebly is safer then C. What's even worse program was probably tested in debug build, and error showed only in release build. Can't happen in assembly. |
|||
26 Sep 2018, 03:16 |
|
revolution 26 Sep 2018, 06:31
It is also possible to make assembly code that performs well and stresses the CPU more than some poorly optimised HLL code. So if the CPU overheats or has less than stellar manufacturing tolerances then the assembly code could trigger random behaviour where the HLL code doesn't.
Another example is the HCF instruction. HLL code never uses it so doesn't cause any problem. So in this case the assembly code can definitely be more "dangerous" than C code. |
|||
26 Sep 2018, 06:31 |
|
Tomasz Grysztar 26 Sep 2018, 07:07
revolution wrote: For the x86 CPU there are instructions that have some undefined results, as already stated by others here. But this isn't necessarily true for all the other CPUs. Indeed I would suspect that the x86 CPUs are the exception here, most other CPUs precisely define the outcome of every instruction for all input values. Another example, AVR architecture. These manuals do not use "unpredictable" term, only "undefined" one. Nevertheless, it lists many instructions that give undefined result, like: Code: LD r26, X+ LD r27, X+ LD r26, -X LD r27, -X Melissa wrote: You cannot create undefined behavior |
|||
26 Sep 2018, 07:07 |
|
revolution 26 Sep 2018, 07:19
Tomasz Grysztar wrote:
|
|||
26 Sep 2018, 07:19 |
|
wean_irdeh 26 Sep 2018, 11:14
revolution wrote:
How can I completely avoid undefined behavior? Is this even possible? |
|||
26 Sep 2018, 11:14 |
|
revolution 26 Sep 2018, 12:29
wean_irdeh wrote: How can I completely avoid undefined behavior? Is this even possible? |
|||
26 Sep 2018, 12:29 |
|
wean_irdeh 26 Sep 2018, 14:05
revolution wrote:
I mean in assembly, also there is a paper describing formal verification effort on ARMv8, does this mean the ARMv8 assembler would be free from undefined behavior? |
|||
26 Sep 2018, 14:05 |
|
fasmnewbie 26 Sep 2018, 18:33
It's not dangerous per se, but rather it is easier to make mistakes (or intentional 'mistakes') in ASM if one is not careful enough. A pseudo example;
Code: mov rdi,0x007ce0fffffffe ;a pointer to some string variable add edi,2 ;oops! Looks syntactically / arithmetically legit, but its a big no. You can give this bug any name you think fit because it fits into any types of bugs you can think of. This is no undefined behavior. It is simply being rude |
|||
26 Sep 2018, 18:33 |
|
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.