I’m always on the look-out for interesting code techniques used by malware, so thought I’d share this experience from last week.
A file came in flagged as a probable fake anti-virus (so much of what we see at the moment is related to that now), so I opened it up in my disassembler and started analysis.
Very boringly this sets up the stack and then does a call to the address 0x407A0A
. What’s interesting is what you find at that location – nothing. The file is set up in such a way that the address isn’t specified – the PE headers set the first section from 0x401000
to 0x4060ED
, and the second section from 0x408000
to 0x419D16
, and no other section covers that intermediary gap – 0x407A0A
falls between the sections. By calling it, the code jumps off a cliff into the unknown.
That’s fine, I thought, it’s a broken sample … but then I looked at what happened when the file ran in a test environment and saw this:
The sample very clearly isn’t broken. And yet I could see it plunging head-first into the abyss. I looked for alternate entry points but there were none, I looked for exception handlers but it hadn’t set up any – I couldn’t see it using any sort of parachute whatsoever.
Debugging the file in a live environment showed that 0x407A0A
was full of zero bytes – not surprising in hindsight, since the Windows loader fills that uninitialised memory with zeros. But “00 00” is actually a valid opcode, if not one you see executed very often, so even though these zero bytes don’t live in any section the file continues to run happily.
Here’s an example of what the code looks like when it eventually makes its way to the second section at 0x408000
:
Riveting stuff, I know, and we’ve had to run through several hundred similar instructions just to get here. But we’ve reached a section finally, and shortly afterwards we find some real initialised data:
Before it executed the call to the zeros, the code pointed EAX to the stack. Now it moves that to ESI, steps back 4 bytes (so ESI now points to the return address from that call), then adds 0x2B
to it via EDX and finally executes a retn. End result – we end up back near the entry code, only 0x2B
bytes later than before.
You watch the malware jump off a cliff, then turn around and suddenly it’s standing right in front of you, back at the top of the cliff. A nifty trick, but it won’t stop us from detecting it.