4 ms·
Self-modifying code using GCC (2011)
- Zambyte 3y agoWhat would a practical application of something like this be? Maybe a JIT compiler that takes advantage of the C stack?
- onesphere 3y agoComputation itself can be seen as self-modifying. Browser loading JS, OS loading DLLs, closures, VMs. It's how "high up the abstraction" you want to go. I never got into this but "GNU lightning is a free-software library for generating assembly language code at run-time." https://en.wikipedia.org/wiki/GNU_lightning https://en.wikipedia.org/wiki/GNU_lightning https://onesphere.hashnode.dev/upstart https://onesphere.hashnode.dev/upstart And for some reason: https://news.ycombinator.com/item?id=36976878 https://news.ycombinator.com/item?id=36976878
- throwaway073123 3y ago- JIT / optimizing for the host device - hot patching - making sure sysadmins have healthy sense of panic available to them at all times
- planede 3y agoNone, this is wildly undefined behavior, even considering GCC's extension and its documentation. I doubt that GCC implementers would be interested in defining the behavior here. edit: There might be room for some other extension here, but as an other commenter already wrote: 1. functions might not be contiguous in memory 2. the code that you are moving should better be position independent So any such extension should handle these issues one way or an other.
- countWSS 3y agoInstead of if( condition) then code1: else code2, computed goto will just switch the branch to unconditional jump to either code1/code2, which bypasses branch misprediction penalty and is generally more elegant.
- CarVac 3y agoDoes that not actually cause a mispredict if the speculative execution happened before the code change?
- messe 3y agoWorse. It's more than likely to cause a cache miss, and waiting on memory is going to be even slower than a mispredicted branch.
- monocasa 3y agoIt could be even worse. I've seen x86 cores where the icache/dcache consistency logic ended up internally being most of a page fault and recovery once noticed by the processor.
- messe 3y agoOof on that note: at least in the example in the article, it's going to cost a TLB miss as page permissions are getting changed. So that's a page-table walk which means %cr3 -> PML4 -> PDPT -> PD -> PT -> the actual address you want to access; potentially up to 5 memory accesses (6 if your system has more than 256TB of RAM and you're using 5-level paging). That being said, in a loop you'd only take this hit on the first run. You'd be back to cache misses after that.
- slaymaker1907 3y ago> One of my research topics last year was self-modifying code mainly for *obfuscation*. I think obfuscation is generally a really bad idea, but that was brought up in the article. One practical application for self-modifying code is hotpatching. Sometimes you really don't want to stop the process but want to change the implementation for some function.
- Borg3 3y agoHold on, How you can actually do hotpatching on x86 protected mode? code is usualy executable but read only. data + stack is usualy NX but writable.
- slaymaker1907 3y agoYou do the same thing JIT does and change the permissions on the page to NX, apply whatever update you want, then remove the write permission and make it executable again. Even though it seems like it doesn't make a difference, it's much more difficult for an attacker to change the page permissions than it is for the hotpatcher/JIT. I think this could still fail though depending on how strict your OS is in which case you might need to use explicit function pointers which are obviously writable. Some systems apparently allow you to add executable without removing write as that is what the OP does with "mprotect(page, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);". However,
- metadat 3y agoWhy is it more difficult for an attacker to change the code compared the JIT?
- matheusmoreira 3y agoAttackers love overflowing buffers but since that memory is not executable they can't put code in there directly. The JIT compiler is almost always the only component which writes to executable pages so they need to somehow trick it into emitting the code they want. It's my understanding that JIT spray attacks are harder to develop.
- o11c 3y agoBetter hope the compiler generated contiguous PIC.
- Animats 3y ago> mainly for obfuscation. Right. It stopped being a useful optimization decades ago. One of the few architectural mistakes von Neumann made back in 1945 is that he didn't think of index registers. He was addressing arrays by storing into the address part of instructions. By 1949, the index register (the "B Box") had been invented, and storing into instructions was mostly obsolete.
- Nevermark 3y agoWould calculating algorithms that can be passed to a JIT-wise compiler callable directly, returning a pointer to object code that called can be called immediately count? Turns out going from calculating an algorithm, optimized for whatever specialization is needed for performance, functionality & formats; to object code; to execution, with the simplest syntax imaginable, is pretty useful. And fun Cough, Forth, cough!