What is a code cave, and is there any legitimate u

2019-03-09 13:30发布

问题:

I encountered this word for the first time in the StackOverflow question "C# Theoretical: Write a JMP to a codecave in asm." I see that according to Wiktionary, a code cave is:

an unused block of memory that someone, typically a software cracker, can use to inject custom programming code to modify the behavior of a program.

Did I find the correct definition? If so, is there any legitimate use for a code cave?

回答1:

I've used them, although I'd never heard the term code cave until today. The Wiktionary definition suggests that a code cave is something the cracker finds in the executable he or she is attempting to crack. The question you cite doesn't use it that way. Instead, it suggests the code cave is being allocated with VirtualAllocEx to create a brand new block of memory in the target process. That removes the need to search for unused space in the target, and it guarantees you'll have enough space to put all your new code.

Ultimately, I think a "code cave" is just a place to store run-time-generated code. There doesn't have to be any nefarious purpose to that code. And at that point, the question of what a code cave is becomes entirely uninteresting. The interesting parts are what reasons there are for generating code at run time, and what techniques there are for making sure that new code gets run when you want it.



回答2:

One might wish to intentionally create a code cave as a part of using self-modifying code.

Assuming, of course, that one is insane.



回答3:

Code caves are usually created by compilers for alignment and are often located between functions in copious amounts. There should also be code caves between structures and jumps (in some architectures), but usually not in any significant amounts.

You also might search for a block of zeroed memory, but there's no guarantee that the program won't use them.

I suppose theoretically, if you lost your source code, you could patch your buggy program by using them, and your program wouldn't grow in size.

Edit

To those of you suggesting code caves are only for run-time generated code: that is an incomplete definition. Many times I have written a data structure in a "code cave" and updated pointers to point there, and I suspect I am not the only person to do so.



回答4:

some legitimate uses: patching live OS binaries without a reboot (MS does this), hooking low level OS functionality (filesystem, network) for firewall and antivirus, extending an application when you don't have source code (like scraping low level OS calls to DrawText so you can read them aloud for blind people)



回答5:

The way it's described here reminds me of patchpoints -- a legit use.



回答6:

Unfamiliar with the term but hot-patching mechanisms could use reserved space to store code patches. You hook into the defective function and redirect it to the new-improved function. It can be done on-the-fly without taking down critical equipment (large telecom switches).



回答7:

It can be used to inject code at runtime. It can be used to write self-modifying code in static languages assuming that the OS lets you (NX bit not set, etc). There are uses for it, but it's not something you should be thinking about in your typical business app.



回答8:

That sounds like the correct definition to me.

As for a legitimate use, let me say this: Don't do it unless you are simply experimenting for the sake of experimenting, and are willing to accept the consequences.

There is no way that this type of thing should ever go into production code:

  1. It is an enormous potential security problem. If it is possible to inject code into memory and then execute it, a malicious attacker can theoretically do, well, whatever they like.
  2. It is a code maintenance nightmare and debugging nightmare. If the code that ends up being run can change during runtime, it becomes almost impossible to track down errors and bugs.


回答9:

Self-modifying code should not be considered lightly, but can sometimes bring big performance gains. If you've been programming for very long, you've probably used it without realizing it.

Prior to the widespread use of the 486 and higher, many PCs did not include hardware floating support. This left people writing programs involving floating point with a dilemma. If they compiled their program to use in-line floating point instructions it would run fast on a machine with a floating point processor, and not at all on machines without one. If they compiled their program with software floating point emulation, it would run on all machines, but slowly even on machines with hardware floating point.

Many compilers libraries used an interesting trick with self-modifying code. The default behavior was to put a trap instruction where a floating point operation was needed. The trap handler would either emulate the instruction in software, or if it detected it was running on a machine with floating point hardware, it would modify the code by replacing the trap instruction with the appropriate hardware floating point instruction and execute it. The result was software that ran on all machines, and ran almost as fast on a machine with floating point hardware as if the code had been compiled to use floating point hardware directly (since most floating point intensive operations occur in loops that are executed many times).