/* * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * Copyright (C) 2007-2013 Sourcefire, Inc. * * Authors: Alberto Wu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* ** unsp.c ** ** 11/10/2k6 - Merge started. ** */ /* ** Plays around with NsPack compressed executables ** ** This piece of code is dedicated to Damian Put ** who I made a successful and wealthy man. ** ** Damian, you owe me a pint! */ /* ** TODO: ** ** - Investigate the "unused" code in NsPack ** - Fetch all the nspacked samples from the zoo and run extensive testing ** - Add bound checks ** - Test against the zoo again ** - Perform regression testing against the full zoo ** - check nested ** - look at the 64bit version (one of these days) ** */ /* FIXME: clean this rubbish init_and_check_dll_loadflags(); nsp1:004359FE add edi, [ebp-28Dh] nsp1:00435A04 mov ebx, edi nsp1:00435A06 cmp dword ptr [edi], 0 nsp1:00435A09 jnz short loc_435A15 nsp1:00435A0B add edi, 4 nsp1:00435A0E mov ecx, 0 nsp1:00435A13 jmp short loc_435A2B nsp1:00435A15 ; --------------------------------------------------------------------------- nsp1:00435A15 nsp1:00435A15 loc_435A15: ; CODE XREF: start+349EEj nsp1:00435A15 mov ecx, 1 nsp1:00435A1A add edi, [ebx] nsp1:00435A1C add ebx, 4 nsp1:00435A1F nsp1:00435A1F loc_435A1F: ; CODE XREF: start+34A3Dj nsp1:00435A1F cmp dword ptr [ebx], 0 nsp1:00435A22 jz short loc_435A5A nsp1:00435A24 add [ebx], edx nsp1:00435A26 mov esi, [ebx] nsp1:00435A28 add edi, [ebx+4] nsp1:00435A2B nsp1:00435A2B loc_435A2B: ; CODE XREF: start+349F8j nsp1:00435A2B push edi nsp1:00435A2C push ecx nsp1:00435A2D push edx nsp1:00435A2E push ebx nsp1:00435A2F push dword ptr [ebp-1D1h] ; VirtualFree nsp1:00435A35 push dword ptr [ebp-1D5h] ; alloc nsp1:00435A3B mov edx, esi nsp1:00435A3D mov ecx, edi nsp1:00435A3F mov eax, offset get_byte nsp1:00435A44 int 3 ; Trap to Debugger nsp1:00435A45 add eax, 5A9h nsp1:00435A4A call eax ; real_unpack ; edx=401000 nsp1:00435A4A ; ecx=436282 nsp1:00435A4C pop ebx nsp1:00435A4D pop edx nsp1:00435A4E pop ecx nsp1:00435A4F pop edi nsp1:00435A50 cmp ecx, 0 nsp1:00435A53 jz short loc_435A5A nsp1:00435A55 add ebx, 8 nsp1:00435A58 jmp short loc_435A1F nsp1:00435A5A ; --------------------------------------------------------------------------- nsp1:00435A5A nsp1:00435A5A loc_435A5A: ; CODE XREF: start+34A07j nsp1:00435A5A ; start+34A38j nsp1:00435A5A push 8000h */ #if HAVE_CONFIG_H #include "clamav-config.h" #endif #include #include "clamav.h" #include "others.h" #include "rebuildpe.h" #include "execs.h" #include "unsp.h" /* real_unpack(start_of_stuff, dest, malloc, free); */ uint32_t unspack(const char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, uint32_t base, uint32_t ep, int file) { uint8_t c = *start_of_stuff; uint32_t i,firstbyte,tre,allocsz,tablesz,dsize,ssize; uint16_t *table; char *dst = dest; const char *src = start_of_stuff+0xd; struct cli_exe_section section; if (c>=0xe1) return 1; if (c>=0x2d) { firstbyte = i = c/0x2d; do {c+=0xd3;} while (--i); } else firstbyte = 0; if (c>=9) { allocsz = i = c/9; do {c+=0xf7;} while (--i); } else allocsz = 0; tre = c; i = allocsz; c = (tre+i)&0xff; tablesz = ((0x300<>shft) + ((put&unpacked_so_far)<<(tre&0xff)); tpos *=3; tpos<<=8; if ((int32_t)damian>=4) { /* signed */ if ((int32_t)damian>=0xa) { /* signed */ damian -= 6; } else { damian -= 3; } } else { damian=0; } /* 44847E */ if (previous_bit) { if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1; ssize = (ssize&0xffffff00) | (uint8_t)dst[unpacked_so_far - backbytes]; /* FIXME! ssize is not static */ bielle = get_100_bits_from_tablesize(&table[tpos+0x736], &read_struct, ssize); previous_bit=0; } else { bielle = get_100_bits_from_table(&table[tpos+0x736], &read_struct); } /* unpack_one_byte - duplicated */ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], 1)) return 1; dst[unpacked_so_far] = bielle; unpacked_so_far++; if (unpacked_so_far>=dsize) return 0; continue; } else { /* got_mainbit */ bielle = previous_bit = 1; if (getbit_from_table(&table[damian+0xc0], &read_struct)) { if (!getbit_from_table(&table[damian+0xcc], &read_struct)) { tpos = damian+0xf; tpos <<=4; tpos += backsize; if (!getbit_from_table(&table[tpos], &read_struct)) { if (!unpacked_so_far) return bielle; /* FIXME: WTF?! */ damian = 2*((int32_t)damian>=7)+9; /* signed */ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1; bielle = (uint8_t)dst[unpacked_so_far - backbytes]; /* unpack_one_byte - real */ dst[unpacked_so_far] = bielle; unpacked_so_far++; if (unpacked_so_far>=dsize) return 0; continue; } else { /* gotbit_tre */ backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize); damian = ((int32_t)damian>=7); /* signed */ damian = ((damian-1) & 0xfffffffd)+0xb; /* jmp checkloop_and_backcopy (uses edx) */ } /* gotbit_uno ends */ } else { /* gotbit_due */ if (!getbit_from_table(&table[damian+0xd8], &read_struct)) { tpos = oldbackbytes; } else { if (!getbit_from_table(&table[damian+0xe4], &read_struct)) { tpos = old_oldbackbytes; } else { /* set_old_old_oldback */ tpos = old_old_oldbackbytes; old_old_oldbackbytes = old_oldbackbytes; } /* set_old_oldback */ old_oldbackbytes = oldbackbytes; } /* set_oldback */ oldbackbytes = backbytes; backbytes = tpos; backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize); damian = ((int32_t)damian>=7); /* signed */ damian = ((damian-1) & 0xfffffffd)+0xb; /* jmp checkloop_and_backcopy (uses edx) */ } /* gotbit_due ends */ } else { /* gotbit_uno */ old_old_oldbackbytes = old_oldbackbytes; old_oldbackbytes = oldbackbytes; oldbackbytes = backbytes; damian = ((int32_t)damian>=7); /* signed */ damian = ((damian-1) & 0xfffffffd)+0xa; backsize = get_n_bits_from_tablesize(&table[0x332], &read_struct, backsize); tpos = ((int32_t)backsize>=4)?3:backsize; /* signed */ tpos<<=6; tpos = get_n_bits_from_table(&table[0x1b0+tpos], 6, &read_struct); if (tpos>=4) { /* signed */ uint32_t s = tpos; s>>=1; s--; temp = (tpos & bielle) | 2; temp<<=(s&0xff); if ((int32_t)tpos<0xe) { temp += get_bb(&table[(temp-tpos)+0x2af], s, &read_struct); } else { s += 0xfffffffc; tpos = get_bitmap(&read_struct, s); tpos <<=4; temp += tpos; temp += get_bb(&table[0x322], 4, &read_struct); } } else { /* gotbit_uno_out1 */ backbytes = temp = tpos; } /* gotbit_uno_out2 */ backbytes = temp+1; /* jmp checkloop_and_backcopy (uses edx) */ } /* gotbit_uno ends */ /* checkloop_and_backcopy */ if (!backbytes) return 0; /* very_real_unpack_end */ if (backbytes > unpacked_so_far) return bielle; /* FIXME: WTF?! */ backsize +=2; if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], backsize) || !CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], backsize) ) { cli_dbgmsg("%p %x %p %x\n", dst, dsize, &dst[unpacked_so_far], backsize); return 1; } do { dst[unpacked_so_far] = dst[unpacked_so_far - backbytes]; unpacked_so_far++; } while (--backsize && unpacked_so_far=dsize) return 0; } /* got_mainbit ends */ } /* while true ends */ } uint32_t get_byte(struct UNSP *read_struct) { uint32_t ret; if (read_struct->src_curr >= read_struct->src_end) { read_struct->error = 1; return 0xff; } ret = *(read_struct->src_curr); read_struct->src_curr++; return ret&0xff; } int getbit_from_table(uint16_t *intable, struct UNSP *read_struct) { uint32_t nval; if (!CLI_ISCONTAINED((char *)read_struct->table, read_struct->tablesz, (char *)intable, sizeof(uint16_t))) { read_struct->error = 1; return 0xff; } nval = *intable * (read_struct->bitmap>>0xb); if (read_struct->oldvalbitmap = nval; nval = *intable; sval = 0x800 - nval; sval = CLI_SRS((int32_t)sval,5); /* signed */ sval += nval; *intable=sval; if (read_struct->bitmap<0x1000000) { /* unsigned */ read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct); read_struct->bitmap<<=8; } return 0; } read_struct->bitmap -= nval; read_struct->oldval -= nval; nval = *intable; nval -= (nval>>5); /* word, unsigned */ *intable=nval; if (read_struct->bitmap<0x1000000) { /* unsigned */ read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct); read_struct->bitmap<<=8; } return 1; } uint32_t get_100_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t ssize) { uint32_t count = 1; while (count<0x100) { uint32_t lpos, tpos; lpos = ssize&0xff; ssize=(ssize&0xffffff00)|((lpos<<1)&0xff); lpos>>=7; tpos = lpos+1; tpos<<=8; tpos+=count; tpos = getbit_from_table(&intable[tpos], read_struct); count=(count*2)|tpos; if (lpos!=tpos) { /* second loop */ while (count<0x100) count = (count*2)|getbit_from_table(&intable[count], read_struct); } } return count&0xff; } uint32_t get_100_bits_from_table(uint16_t *intable, struct UNSP *read_struct) { uint32_t count = 1; while (count<0x100) count = (count*2)|getbit_from_table(&intable[count], read_struct); return count&0xff; } uint32_t get_n_bits_from_table(uint16_t *intable, uint32_t bits, struct UNSP *read_struct) { uint32_t count = 1; uint32_t bitcounter; /* if (bits) { always set! */ bitcounter = bits; while (bitcounter--) count = count*2 + getbit_from_table(&intable[count], read_struct); /* } */ return count-(1<<(bits&0xff)); } uint32_t get_n_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t backsize) { if (!getbit_from_table(intable, read_struct)) return get_n_bits_from_table(&intable[(backsize<<3)+2], 3, read_struct); if (!getbit_from_table(&intable[1], read_struct)) return 8+get_n_bits_from_table(&intable[(backsize<<3)+0x82], 3, read_struct); return 0x10+get_n_bits_from_table(&intable[0x102], 8, read_struct); } uint32_t get_bb(uint16_t *intable, uint32_t back, struct UNSP *read_struct) { uint32_t pos = 1; uint32_t bb = 0; uint32_t i; if ((int32_t)back<=0) /* signed */ return 0; for (i=0;ibitmap>>=1; /* unsigned */ retv<<=1; if (read_struct->oldval>=read_struct->bitmap) { /* unsigned */ read_struct->oldval-=read_struct->bitmap; retv|=1; } if (read_struct->bitmap<0x1000000) { read_struct->bitmap<<=8; read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct); } } return retv; }