3 ms·
What section is used eventually by the payload? Somehow the stack size feels like a red herring. These tools scan the executables without executing them, don't
by leni536 4y ago
What section is used eventually by the payload? Somehow the stack size feels like a red herring. These tools scan the executables without executing them, don't they? The payload is surely not on the stack yet.
- cxrfcg 4y ago> These tools scan the executables without executing them, don't they? No, modern AV software executes unknown binaries in an emulated system environment. Defender has an x86-to-safe-x86 JIT compiler built in to make this more performant.
- muststopmyths 4y agoThe payload for both approaches should be in the data segment I think. Which makes this strange. Edit : a map file should show the difference if any
- Karliss 4y agoHere a test in godbolt https://godbolt.org/z/rKao1ssb9 https://godbolt.org/z/rKao1ssb9 . All 3 compilers GCC, Clang and MVSC instead of placing the whole stack initialization value in rodata and then copying from there using memcpy, chose to initialize parts of array using `mov [stack_pointer] Literal_value` . Results might be slightly different with different sizes of constant and various other factors like optimization level. This breaks up the big constant array int smaller chunks which is probably why the AV didn't detect when just scanning file, and the whole constant is only assembled during execution on stack. Even if compiler didn't break up the constant, it shouldn't be difficult to achieve similar result by having an encrpyted version of payload in read only section, and then decrypting it to stack. Manual analysis would trivially defeat such encryption with key stored next to it, but for automated analysis the solution is to execute the binary in sandboxed environment and allowing it decrypt itself, but the problem here is that Windows defender doesn't properly notice the payload if it gets stored in unusually big stack and that's why the blogpost about it. As for why the compiler by default breaks up the constant. I assume it's because compiler heuristics are written with assumption that you wouldn't have 2MB constant initializing stack variable. And for more reasonable initial stack variable values, storing them as instruction literals can be more performant as that way it avoids additional memory loads. When array and constant is sufficiently big GCC and clang fully switches to rodata+memcpy strategy. But with optimizations disabled MSVC naively copies the values with "move [ptr], 1_byte_literal" one byte at a time even for very big arrays.
- muststopmyths 4y agoyes, I just tested with VC and was going to post that I found exactly what you said. Thanks for explaining in detail.
- Karliss 4y agoI guess that every byte being stored as `mov [stack_ptr], 0x12` is why executable with 2MB array takes 16MB of disk space.