

push ebp<br />mov ebp, esp<br />sub esp, XX<br />While these are technically enough bytes to create a signature based on the opcodes, such a signature would be a really bad idea. What we have there, in fact, is just a pretty standard function entry point.
mov edi, edi<br />push ebp<br />mov ebp, esp<br />sub esp, $STACKSIZE<br />[optional trash]<br />push eax (*)<br />push edx (*)<br />push edi (*)<br /><br /><br />(*) note, the registers are chosen randomly among the 32 bit general purpose registers except esp and ebp<br /><br />[optional trash]<br />call $DELTA<br />Here we are inside ”$DELTA”..
[optional trash]<br />mov register, [ebp-stacksize]<br />[optional trash]<br />ret<br />
jmp local_var<br />or
push local_var<br />ret<br />
seek(begin_of_the_code_section, SEEK_SET);<br />cur = file_find_limit("\x55\x89\xe5\x83\xec", 5, end_of_the_code_section);<br />if(cur < 0) return 0; Then we set ourselves in a disassembly loop and we check if we got what we expect. Something along the lines of:while(1) {<br /> struct DIS_fixed d;<br /> int next = DisassembleAt(&d, cur, space_remaining);<br /> if(next -1) break; /* disasm error */<br /> cur = next; /* cur now points at the next op */<br /> [here we check the op]<br />}<br /></pre><br />As for the actual opcode matching, here are a few examples. The first thing we are interested in is the 3 pushes. In terms of bytecode we need to check that:<br /><br />1. the opcode is OP_PUSH<br />2. the argument is a register<br />3. the register is one of (eax, ebx, ecx, edx, esi, edi)<br /><br />In BC that'd be:<br /><pre>d.x86_opcode OP_PUSH
d.arg0.access_type ACCESS_REG<br />d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_EAX || d.arg0.u.reg REG_ECX || d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_EDX || d.arg0.u.reg REG_EBX || d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_ESI || d.arg0.u.reg REG_EDI<br /></pre>Altogether:<br /><pre>if(d.x86_opcode OP_PUSH && d.arg0.access_type ACCESS_REG && (d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_EAX || d.arg0.u.reg REG_ECX || d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_EDX || d.arg0.u.reg REG_EBX || d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.reg REG_ESI || d.arg0.u.reg REG_EDI))<br /></pre>Then we need to check for the call $DELTA. In other words we check that:<br /><br />1. the opcode is a call<br />i.e.: d.x86_opcode OP_CALL
2. the argument is an immediate relative value
i.e.: d.arg0.access_type ACCESS_REL<br /><br />Then we pick the call target and we "jump" to it, not before saving the return address:<br /><pre>int32_t target_address, return_address;<br />seek(cur-4, SEEK_SET); /* we position onto the call argument */<br />read(&target_address, sizeof(target_address)); /* we read the relative jump value */<br />target_address = le32_to_host(target_address); /* we handle big endian machines */<br />retaddr = cur; /* we save the address to return to */<br />target_address = cur + target_address; /* we compute the addres to jump to */<br /></pre><br />Another interesting example is the trash code parser. There can be 3 types or trash ops:<br /><br />A. Arithmetic or logic operation on a stack allocated DWORD based on an immediate or register value. Eg:<br /><pre>mov [ebp-xx], immed<br />add [ebp-xx], register<br /></pre>B. Arithmetic or logic operation on a 32bit register based on a stack allocated DWORD or an immediate value. Eg:<br /><pre>mov register, [ebp-xx]<br />sub register, other_register<br /></pre>C. A jump to the next chunk of code.Eg:<br /><pre>jmp next_chunk<br /></pre>More in details, for case A we check that:<br /><br />1. d.x86_opcode is one of (OP_ADD, OP_ADC, OP_AND, OP_MOV, OP_OR, OP_SBB, OP_SUB, OP_XOR), i.e.: <pre>d.x86_opcode OP_ADD || d.x86_opcode OP_ADC || d.x86_opcode OP_AND || d.x86_opcode OP_MOV || d.x86_opcode OP_OR || d.x86_opcode OP_SBB || d.x86_opcode OP_SUB || d.x86_opcode OP_XOR</pre><br />2. the dest argument is a mem region: <pre>d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.access_type ACCESS_MEMd.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.access_size SIZED</pre><br />4. the dest argument is in the form [ebx-displacement]: <pre>d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.scale_reg REG_EBP && d.arg0.u.mem.scale 1 && d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.add_reg REG_INVALID
d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.displacement <= -4 && d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.displacement >= -(int32_t)stacksize
d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.access_type ACCESS_REG</pre><br />2a. The src arg is either another reg: <pre>d.arg<sup><a href="#fn7399445164f37e71aeab87">1</a></sup>.access_type ACCESS_REG
d.arg<sup><a href="#fn7399445164f37e71aeab87">1</a></sup>.access_type ACCESS_IMM</pre><br />2c. Or it is a stack based DWORD: <pre>d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.access_type ACCESS_MEM && d.arg0.u.mem.access_size SIZED && d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.scale_reg REG_EBP && d.arg0.u.mem.scale 1 && d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.u.mem.add_reg REG_INVALID && d.arg0.u.mem.displacement <= -4 && d.arg0.u.mem.displacement >= -(int32_t)stacksize
d.x86_opcode OP_JMP</pre><br />2. Check that it's got an immediate argument: <pre>d.arg<sup><a href="#fn15783949824f37e71aea87b">0</a></sup>.access_type ACCESS_REL
int32_t rel;<br />seek(cur-4, SEEK_SET); /* move onto the jmp argument <strong>/<br />read(&rel, sizeof(rel)); /</strong> read it <strong>/<br />rel = le32_to_host(rel); /</strong> make it big endian safe <strong>/<br />cur += rel; /</strong> "jump" to it */<br />
Mon Oct 10 14:41:48 CEST 2011 (tk)
----------------------------------
freshclam/manager.c: fix error when compiling without DNS support (bb#3056)
Sat Oct 8 12:19:49 EEST 2011 (edwin)
-------------------------------------
libclamav/pdf.c: flag and dump PDF objects with /Launch (bb #3514)
Sat Oct 8 12:10:13 EEST 2011 (edwin)
-------------------------------------
libclamav/bytecode.c,bytecode_api.c: fix recursion level crash (bb #3706).
Tue Aug 2 17:03:33 CEST 2011 (tk)
----------------------------------
docs: clarify behavior of <del>-scan</del><strong>/Scan</strong> options (bb#3134)
Mon Jul 25 16:09:19 EEST 2011 (edwin)
-------------------------------------
libclamav/bytecode_vm.c: fix opcode 20 error (bb #3100)
Thu Sep 15 14:44:11 CEST 2011 (tk)
----------------------------------
freshclam: fix pidfile removal (bb#3499)
Sun Aug 21 17:05:24 EEST 2011 (edwin)
-------------------------------------
libclamav/pdf.c: fix incorrect blocking of some encrypted PDF with empty user passwords. (bb #3364)
Wed Aug 3 15:41:28 CEST 2011 (tk)
----------------------------------
sigtool/sigtool.c: fix calculation of max signature length



<span>USERPROFILE</span>\Local Settings\Application Data (for example: C:\Documents and Settings\username\Local Settings\Application Data) with a random, three letter name – like dpx.exe. It also adds some keys to the registry to make sure it will be started upon boot and it also adds a key that makes sure that it will be started as soon as you start a program on you Computer. So much for the self defense.“Overall, one out of every six or seven consumer machines is infected, according to new malware statistics gathered from Sourcefire’s software-based ClamAV and cloud-based Immunet customers during the first three weeks of July.”Head on over to the above link for the full article.
Thu Jun…