Anti Virus 2.0 "Compilers in Disguise": Mihai G. Chiriac Bitdefender
Anti Virus 2.0 "Compilers in Disguise": Mihai G. Chiriac Bitdefender
Anti Virus 2.0 "Compilers in Disguise": Mihai G. Chiriac Bitdefender
0
“Compilers in disguise”
Mihai G. Chiriac
BitDefender
Talk outline
• AV History
• Emulation basics
• Compiler technology
– Intermediate Language
– Optimizations
– Code generation
• Conclusions
AV History!
• String searching
– Aho-Corasick, KMP, Boyer-Moore
– PolySearch
– Bookmarks (from top, tail, EP?)
– Hashes (B, ofs1, sz1, crc1, ofs2, sz2, crc2)
NYB.A
AV History (cont’d)
• Encrypted viruses
– Static decryption loop (signature)
– Simple encryption (xray-ing)
– Algorithmic detection
TPE.Giraffe.A
Emulation!
• Hardware
– Virtual CPU
– Virtual memory
– Virtual devices
• Software
– Partial OS simulation
• Bonus Goodies
– Fake IRC, SMTP, DNS, etc servers
Workflow
• Init the CPU / VM
• Init the virtual OS
– Modules
– Structures
• Map the file
• Start emulation from cs:eip
• Scan (when conditions are met)
• Quit (when conditions are met)
Sample
• Emulate!
• Easy, huh?
On average,
one every three instructions
references memory…
Memory accesses
• We have to virtualize the entire 4 GB
space….
• Every memory access needs:
– Segment access checks
– Linear address computation
– Page access checks
– Hardware debugging checks
– SMC checks!! (for memory writes)
Problems…
• Millions of instructions…
• Polymorphic decryption loops are full of
do-nothing, “garbage” code…
• Decompression loops are optimized for
size, not speed…
200000
400000
Parses 800000
0
1000000
1200000
1400000
1600000
0x00565577 ->…
0x005D1EF2 ->…
0x005D1F04 ->…
0x005D1F1C ->…
0x005D1F33 ->…
0x005D1F4F ->…
0x005D1F61 ->…
0x005D1F74 ->…
0x005D1F9A ->…
UPX decompression
0x005D1FC3 ->…
0x005D1FF6 ->…
0x005D201F ->…
0x7FF00C0E ->…
0x7FF80430 ->…
0x7FF80498 ->…
0x7FF804E8 ->…
0x7FF80521 ->…
0x7FF8055D ->…
Advantages
• Typically, an emulator spends the most
time in loops…
Compute_ZF (tm1)
mm0 = esi + edi Compute_SF (tm1)
tm0 = load32 (mm0) Compute_PF (tm1)
tm1 = tm0 ^ ebx
store32 (mm0, tm1) Compute_OF (OP_XOR, …)
Compute_AF (OP_XOR, …)
Compute_CF (OP_XOR, …)
Parite.A decryption (2)
• Decrypt:
• .420010 xor [esi+edi], ebx
• .420013 sub esi, 2
• .420016 sub esi, 2
• .420019 jnz Decrypt
Compute_ZF (esi)
Compute_SF (esi)
tm0 = esi Compute_PF (esi)
esi = esi – 2
Compute_OF (OP_SUB, …)
Compute_AF (OP_SUB, …)
Compute_CF (OP_SUB, …)
Parite.A decryption (3)
• Decrypt:
• .420010 xor [esi+edi], ebx
• .420013 sub esi, 2
• .420016 sub esi, 2
• .420019 jnz Decrypt
Compute_ZF (esi)
Compute_SF (esi)
tm0 = esi Compute_PF (esi)
esi = esi – 2
Compute_OF (OP_SUB, …)
Compute_AF (OP_SUB, …)
Compute_CF (OP_SUB, …)
Parite.A decryption (4)
int a, b, c; int a, b, c;
a = 5; a = 5;
b = 3; b = 3;
c = a + b + 3; c = a + b;
b = c + 1; c = c + 3;
b = c + 1;
SSA (cont’d)
Three-address code… SSA Form
a = 5; a[0] = cnst(5)
b = 3; b[0] = cnst(3)
c = a + b; c[0] = a[0]+b[0]
c = c + 3; c[1] = c[0]+cnst(3)
b = c + 1; b[1] = c[1]+cnst(1)
• A possible solution
– Perform these optimizations only after we’ve
gathered a set of run-time data…
Execution modes – 1
• No code generation!
• Simply simulate the micro-ops
• Advantages:
– Very portable
– Easy to profile
– Easy to debug
• Disadvantages:
– Slow
PSP
Execution modes – 2
• Trivial code generation…