; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ; ÚÄ Benny's Compression Engine for Win32 Ä¿ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; ³ by ³ ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄ Benny / 29A ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ ; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ ; ; ; ;Hello everybody, ; ;let me introduce my second compression engine for Win32 enviroment (u can ;find my first engine in Win32.Benny and Win98.Milennium). This engine ;worx on "compressin' bit groups" base. When I started to write this stuff, ;i wanted to write engine, that would work on Huffmann base. Then I decided ;it's not needed to implement this complicated algorithm here, coz I wanna ;be this engine small and effective. ; ;Not only this is truth. This engine is very fast, very small (only 478 bytes) ;and has implemented my special compression algorithm, that is simple and has ;very, ehrm, let's call it "interesting" compression ratio X-D. ; ; ; ;So how does it work ? ;====================== ; ;I said, this engine worx on "compressin' bit groups" base. What does it mean ? ;Bit group (as I call it) is group of two bits. U know, every byte has 8 bits. ; ;Example: byte 9Ah group0 group1 group2 group3 ; 10011010 ===> 10 10 01 10 ; ;As u can see, every byte has 4 bit groups and I said, it compresses ;bit groups. Heh, u think i'm crazy when im tryin' to compress ;two bits, yeah :?) ; ; ;This engine will (on the beginnin') calculate, which bit group has ;the biggest count of repetency, which second biggest, etc... ; ;Example: group count ; 00 ===> 74 ; 01 ===> 32 ; 10 ===> 12 ; 11 ===> 26 ; ; ;That's not all. It has to sort items to know, which group has the biggest ;count. I decided it's best to use "bubble sort algorithm". Then there isn't ;any problem to use "our algorithm". ;Look at this table, when in first column r sorted groups and in second ;comlumn r bits, which will represent new compressed data. ; ;Sorted by count: 1. ===> 1 ; 2. ===> 00 ; 3. ===> 010 ; 4. ===> 011 ; ;Finally, engine will replace bit groups with these bits. ;Gewd thing on this algorithm is that there aren't needed same bytes to have ;good compression ratio, but only some bits. ;So now u know whole secret of my compression algorithm. U also know, why ;I said, it has "interesting compression ratio". Look at the table and u will ;see, what type of files can we strongly compress. They r both of binaries ;and texts, but not every binaries or texts can be compressed as well as otherz. ;We can compress some binaries again with the same or better ratio. Why ? ;Imagine, u have file with 1000x 0x0s. After compression we have 125x 0xFFs, that ;can be compressed again. Some files can be after compression (negative even - ;file is bigger) compressed again with positive compression (file is smaller). ;Heh, crazy, isn't it ? X-DDD. ; ; ; ;How can I use BCE32 in my virus ? ;================================== ; ;BCE32 is placed in two procedures called BCE32_Compress and BCE32_Decompress. ; ; ;a) BCE32_Compress: ;------------------- ;Input state: ; 1) ESI register - pointer to data, which will be compressed ; 2) EDI register - pointer to memory, where will be placed compressed data ; 3) ECX register - number of bytes to compress + 1 (do not forget "+ 1" !) ; 4) EBX register - work memory (16 bytes) ; 5) EDX register - work memory (16 bytes). MUST NOT be same as EBX ! ; ; call BCE32_Compress ; ;Output state: ; 1) EAX register - new size of compressed data ; 2) CF set, if negative compression ; 3) Other registers r preserved (except FLAGS) ; ; ;b) BCE32_Decompress: ;--------------------- ;Input state: ; 1) ESI register - pointer to compressed data ; 2) EDI register - pointer to memory, where will be placed decompressed data ; 3) ECX register - number of bytes to decompress (EAX value returned by ; BCE32_Compress) - 1 (do not forget "- 1" !) ; ; call BCE32_Decompress ; ;Output state: ; 1) All registers r preserved ; ; ;WARNING: Be sure, u have enought memory for case of negative compression. ;NOTE: U can compress (in some special cases) already compressed data. ; For this purpose exists output parameters EAX and CF. ; ; ; ;Do u like this (or my another work) ? ;====================================== ; ;Gimme know. If u have some notes or commentz for this, for another work, ;or if u simply like it, mail me to benny@post.cz. Thanx. ; ; ; ;Don't u like it ? ;================== ; ;Fuck u. ; ; ; ;(c) by Benny/29A May 1999. BCE32_Compress Proc ;compression procedure pushad ;save all regs ;stage 1 pushad ;and again create_table: push ecx ;save for l8r usage push 4 pop ecx ;ECX = 4 lodsb ;load byte to AL l_table:push eax ;save it xor edx, edx ;EDX = 0 and al, 3 ;this stuff will separate and test je st_end ;bit groups cmp al, 2 je st2 cmp al, 3 je st3 st1: inc edx ;01 jmp st_end st2: inc edx ;10 inc edx jmp st_end st3: mov dl, 3 ;11 st_end: inc dword ptr [ebx+4*edx] ;increment count in table pop eax ror al, 2 ;next bit group loop l_table pop ecx ;restore number of bytes loop create_table ;next byte push 4 ;this will check for same numbers pop ecx ;ECX = 4 re_t: cdq ;EDX = 0 t_loop: mov eax, [ebx+4*edx] ;load DWORD inc dword ptr [ebx+4*edx] ;increment it cmp eax, [ebx] ;test for same numbers je _inc_ ;... cmp eax, [ebx+4] ;... je _inc_ ;... cmp eax, [ebx+8] ;... je _inc_ ;... cmp eax, [ebx+12] ;... jne ninc_ ;... _inc_: inc dword ptr [ebx+4*edx] ;same, increment it inc ecx ;increment counter (check it in next turn) ninc_: cmp dl, 3 ;table overflow ? je re_t ;yeah, once again inc edx ;increment offset to table loop t_loop ;loop popad ;restore regs ;stage 2 pushad ;save all regs mov esi, ebx ;get pointer to table push 3 pop ebx ;EBX = 3 mov ecx, ebx ;ECX = 3 rep_sort: ;bubble sort = the biggest value will ;always "bubble up", so we know number ;steps push ecx ;save it mov ecx, ebx ;set pointerz mov edi, edx ;... push edx ;save it lodsd ;load DWORD (count) mov edx, eax ;save it sort: lodsd ;load next cmp eax, edx ;is it bigger jb noswap ;no, store it xchg eax, edx ;yeah, swap DWORDs noswap: stosd ;store it loop sort ;next DWORD mov eax, edx ;biggest in EDX, swap it stosd ;and store lea esi, [edi-16] ;get back pointer pop edx ;restore regs pop ecx loop rep_sort ;and try next DWORD popad ;stage 3 pushad ;save all regs xor eax, eax ;EAX = 0 push eax ;save it push 4 pop ecx ;ECX = 4 n_search: push edx ;save regs push ecx lea esi, [ebx+4*eax] ;get pointer to table push eax ;store reg lodsd ;load DWORD to EAX push 3 pop ecx ;ECX = 3 mov edi, ecx ;set pointerz search: mov esi, edx push eax ;save it lodsd ;load next mov ebp, eax pop eax cmp eax, ebp ;end ? je end_search dec edi ;next search add edx, 4 loop search end_search: pop eax ;and next step inc eax pop ecx pop edx add [esp], edi rol byte ptr [esp], 2 loop n_search pop [esp.Pushad_ebx] ;restore all popad ;... ;stage 4 xor ebp, ebp ;EBP = 0 xor edx, edx ;EDX = 0 mov [edi], bl ;store decryption key inc edi ;increment pointer next_byte: xor eax, eax ;EAX = 0 push ecx lodsb ;load next byte push 4 pop ecx ;ECX = 4 next_bits: push ecx ;store regs push eax and al, 3 ;separate bit group push ebx ;compare with next group and bl, 3 cmp al, bl pop ebx je cb0 push ebx ;compare with next group ror bl, 2 and bl, 3 cmp al, bl pop ebx je cb1 push ebx ;compare with next group ror bl, 4 and bl, 3 cmp al, bl pop ebx je cb2 push 0 ;store bit 0 call copy_bit push 1 ;store bit 1 call copy_bit cb0: push 1 ;store bit 1 end_cb1:call copy_bit pop eax pop ecx ror al, 2 loop next_bits ;next bit pop ecx loop next_byte ;next byte mov eax, edi ;save new size sub eax, [esp.Pushad_edi] ;... mov [esp.Pushad_eax], eax ;... popad ;restore all regs cmp eax, ecx ;test for negative compression jb c_ok ;positive compression stc ;clear flag ret ;and quit c_ok: clc ;negative compression, set flag ret ;and quit cb1: push 0 ;store bit 0 end_cb2:call copy_bit push 0 ;store bit 0 jmp end_cb1 cb2: push 0 ;store bit 0 call copy_bit push 1 ;store bit 1 jmp end_cb2 copy_bit: mov eax, ebp ;get byte from EBP shl al, 1 ;make space for next bit or al, [esp+4] ;set bit cbit: inc edx ;increment counter cmp dl, 8 ;byte full ? jne n_byte ;no, continue stosb ;yeah, store byte xor eax, eax ;and prepare next one cdq ;... n_byte: mov ebp, eax ;save back byte ret Pshd ;quit from procedure with one parameter on stack db '[BCE32]', 0 ;little signature BCE32_Compress EndP ;end of compression procedure BCE32_Decompress Proc ;decompression procedure pushad ;save all regs xor eax, eax ;EAX = 0 xor ebp, ebp ;EBP = 0 cdq ;EDX = 0 lodsb ;load decryption key push eax ;store it lodsb ;load first byte push 8 ;store 8 push edx ;store 0 d_bits: push ecx ;store ECX test al, 80h ;test for 1 jne db0 test al, 0c0h ;test for 00 je db1 test al, 0a0h ;test for 010 je db2 mov cl, 6 ;its 011 jmp tb2 testb: test bl, 1 ;is it 1 ? jne p1 push 0 ;no, store 0 _tb_: mov eax, ebp ;load byte to EAX or al, [esp] ;set bit ror al, 1 ;and make space for next one call cbit ;end of procedure ret ;... p1: push 1 ;store 1 jmp _tb_ ;and continue db0: xor cl, cl ;CL = 0 mov byte ptr [esp+4], 1 ;store 1 testbits: push eax ;store it push ebx ;... mov ebx, [esp+20] ;load parameter ror bl, cl ;shift to next bit group call testb ;test bit ror bl, 1 ;next bit call testb ;test it pop ebx ;restore regs pop eax mov ecx, [esp+4] ;load parameter bcopy: cmp byte ptr [esp+8], 8 ;8. bit ? jne dnlb ;nope, continue mov ebx, eax ;load next byte lodsb xchg eax, ebx mov byte ptr [esp+8], 0 ;and nulify parameter dec dword ptr [esp] ;decrement parameter dnlb: shl al, 1 ;next bit test bl, 80h ;is it 1 ? je nb ;no, continue or al, 1 ;yeah, set bit nb: rol bl, 1 ;next bit inc byte ptr [esp+8] ;increment parameter loop bcopy ;and align next bits pop ecx ;restore ECX inc ecx ;test flags dec ecx ;... jns d_bits ;if not sign, jump pop eax ;delete pushed parameters pop eax ;... pop eax ;... popad ;restore all regs ret ;and quit db1: mov cl, 2 ;2. bit in decryption key mov [esp+4], cl ;2 bit wide jmp testbits ;test bits db2: mov cl, 4 ;4. bit tb2: mov byte ptr [esp+4], 3 ;3 bit wide jmp testbits ;test bits BCE32_Decompress EndP ;end of decompression procedure