-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathVirTool.Win32.Compression.Nibble.asm
198 lines (184 loc) · 6.88 KB
/
VirTool.Win32.Compression.Nibble.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
; BNCE - BlueOwls Nibble Compression Engine
; *****************************************
;
; Introduction
; ************
;
; I made this engine for virusses which want to use some algorithm to make
; themselves or something else smaller (obviously), but i wanted the
; algorithm to be small too, because if it isn't it would have little use
; for virusses. In this case, I tried to make the decompressor as small as
; possible, and let the compressor do most of the work.
;
; How it works
; ************
;
; Every byte has 4 nibbles and these can be compressed. The compression is
; done by counting the number of nibbles in the entire data and change
; the nibble sizes accordingly. The most common of the four possible
; nibbles will be compressed, #2 will stay the same size and #3 & #4 will
; be expanded. This means that as long as the number #1s > the numbers
; #3+#4 compression occurs, otherwise the data will be expanded. The
; maximum reducement is 50%, and the maximum enlargement is 112,5%.
;
; Notes
; *****
;
; - The bnce_compress and bnce_decompress are not in any way dependent on
; each other, and both do not use any (external) data, you can run them
; without the write flag set.
; - A small optimization is possible for the decryptor if you like to
; decrypt only one thing with a static size with it; remove the (*)
; lines in the compressor and change the (@) lines in mov ecx, size;
; or push size, pop ecx. It will save one or three bytes in the
; decompressor, wow! :P
; - I have not encounterd any bugs, and the only errors could arrise from
; a faulty parameters; too small output buffers or corrupted compressed
; data fed to the decompressor. All which are not very likely.
; - In some extreme cases, already compressed data can be compressed again
; but this is only possible when the are a lot of same nibble repeaten-
; cies; for example: 1111b becomes 00b; and 00b becomes 0b. But it does
; not occur very often.
; - As the maximum enlargement is 112,5% I would at least allocate an
; output buffer of size *12 /10 if the data is not static.
;
; Last words
; **********
;
; I made this engine for fun and I had fun with it, I hope you like it and
; can use it in someway. Feel free to modify it to your needs. See Notes
; for more details. Anyway, I hope you like it and if you like to let
; me know something please do and send mail to [email protected].
; I compiled this stuff with FASM, but you should be able to assemble this
; with any popular assembler (MASM/TASM/FASM/NASM?) :).
; compress
; in: esi = ptr to data to compress
; ecx = size of data to compress
; edi = ptr to output buffer
; out: edi = end of data put in output buffer
; size: 165 bytes
bnce_compress: push 03020100h ; push table
push esi
push ecx
sub eax, eax ; eax = 0
cdq ; edx = 0
push eax ; 4 counters for the 4 existing nibbles
push eax
push eax
push eax
count_bytes: push ecx ; save no. of bytes
push 4
pop ecx ; ecx = 4
lodsb
count_bits: sub ah, ah
shl eax, 2 ; ah = first 2 bits
mov dl, ah ; dl = 2 bits
inc dword [esp+4+edx*4] ; count it
loop count_bits
pop ecx
loop count_bytes ; now the 4 counters are filled with the correct values
sort_again: sub ecx, ecx ; ecx = 0
mov esi, esp ; esi = ptr to first counter
lodsd ; esi = ptr to next counter
no_bubble: inc ecx
cmp ecx, 4
jz sort_done ; if no changes were made 4 times bubbling is done
lodsd ; eax = this counter; esi = next counter
cmp [esi-8], eax ; compare to previous counter
jae no_bubble ; if previous counter is bigger or equal make no change
xchg [esi-8], eax ; swap counters
mov [esi-4], eax
mov al, [esp+23+ecx]; swap nibbles
xchg al, [esp+24+ecx]
mov [esp+23+ecx], al
jmp sort_again ; start over
sort_done: add esp, 16 ; delete counters (only nibbles remaining)
pop ecx ; ecx = size of data
pop esi ; esi = start of data
pop eax ; eax = nibble table
push eax
shl eax, 6 ; move up table
stosd ; save table
mov eax, ecx ; eax = ecx = size of data (*)
stosd ; save it (*)
sub edx, edx ; edx = 0 (bits stored counter)
compress_loop: push ecx
push 4
pop ecx ; ecx = 4
lodsb
compress_bits: sub ebx, ebx ; ebx = 0
sub ah, ah ; ah = 0
shl eax, 2 ; ah = xxb
inc ebx ; 1 bit large; output is: 0b
cmp ah, [esp+0+4] ; is it main compress byte?
jz move_bits
mov bh, 10000000b ; output is: 10b
inc ebx ; 2 bit large
cmp ah, [esp+1+4]
jz move_bits
mov bh, 11000000b
inc ebx ; 3 bit large; output is: 110b
cmp ah, [esp+2+4]
jz move_bits
mov bh, 11100000b ; output is: 111b
move_bits: shl dh, 1 ; get a free bit in dh
shl bh, 1 ; carry on/of
adc dh, 0 ; add it to dh
inc edx
mov [edi], dh
cmp dl, 8
jnz no_store_bits
inc edi
sub edx, edx
no_store_bits: dec bl
jnz move_bits
loop compress_bits
pop ecx
loop compress_loop
mov cl, 8
sub cl, dl
rol dh, cl ; make sure last byte's bits are placed correctly
mov [edi], dh
inc edi
pop eax ; table not needed anymore
ret
; decompress
;
; in: esi = pointer to data to be decompressed
; edi = pointer to output buffer
; out: edi = pointer to end of output buffer
; size: 54 bytes
bnce_decompress:lodsd
push eax ; push decoder table
lodsd ; (@)
xchg eax, ecx ; ecx = size when uncompressed (@)
mov dl, 8 ; indicate new byte needed
decompress_next:push ecx
push 4 ; start byte reconstruction (4 nibbles remaining)
pop ecx
decompress_loop:sub ebx, ebx ; type = 0
push ecx
push 3 ; repeat 3 times if necessary
pop ecx
find_type: cmp dl, 8 ; next byte needed?
jnz dont_fill
sub edx, edx ; clear bit-counter
lodsb ; load new byte
dont_fill: inc edx ; 1 bit is used from byte
shl al, 1 ; get the bit
jnc dmove_bits ; if it is off, type is found
inc ebx ; type ++
loop find_type ; repeat
dmove_bits: pop ecx ; restore ecx (stored bit counter)
mov dh, al ; save al
mov al, [esp+4+ebx] ; get appropiate bits
shl eax, 2 ; add bits to ah
mov al, dh ; restore al
loop decompress_loop ; if byte is not ready to be put, go on
mov [edi], ah ; save byte
inc edi ; move up ptr
pop ecx
loop decompress_next ; go on decompressing
pop eax
ret
; BlueOwl 23 august, 2004