exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

winamprev.txt

winamprev.txt
Posted Jan 10, 2000
Authored by s0ftpj, Ma

Reverse Engineering Winamp - How to modify windows binaries to do anything you want. Uses reverse engineering winamp to read encrypted mp3's as an example.

systems | windows
SHA-256 | b205c7aa737490b5282634163d7d5c96864e4fc24cac7d39c30de010ec9c410e

winamprev.txt

Change Mirror Download
-[ WINAMP REVERSING ]---------------------------------------------------------
---[ original italian text by .+Ma. - translation by ins4ne/s0ftpj
---[ published on BFi#7, file 18 of 22, 12/25/99 - http://www.s0ftpj.org/bfi


Winamp Reversing
or
make your programs do
whatever you want

by .+Ma.

*********************************** INTRO ***********************************

The aim of this tut is to show what you can do by little manipulations of the
PE... and with a sick brain (my nick, Italian word for sickness, was not
random choosed :) If you go wild, maybe you'll be able to do something as
crazy as this... I challenge you doing so! But now sit down, make a deep
breath and try to follow the idea: I'm sure that at the end of the tutorial
you'll look at your executables from a different viewpoint. But now, ready...
go!

USAGE: 2 Cokes 33cl
Tropical fruits juice
Pizza (YUM!)
MUSIC: Afterhours - Non รจ per sempre (the album, encrypted of course ;)

*********************************** TOOLS ***********************************

File XORer 0.3 build 009 [by JFL]
Sadd v1.0b by NeuRaL_NoiSE (thx!)
Pebrowse v4.0 by PRUDENS inc. (http://www.spywindows.com)

************************************DOCS*************************************

Everything you can get about PE, especially:

-"PE-Crypters : a close look to the PE format by Kill3xx
-"How to add a new section and a new function to a PE" by Pusillus (Ita)
-The NeuRaL_NoiSE tutorials. Many talk about PE manipulation... and anyway
if you get another one from a totally different topic it will anyway be a
good thing to read it ;)

*************************** THE TUTE, AT LAST :) ****************************

Some time ago I got a really strange idea: modify winamp to make it read
encrypted mp3s. This didn't seem an impossible thing to me, but it required
two essential elements: a motivated cracker and some free time. At that time
I missed both of them, while now I miss just the second... But the solution
was rather easy: I just had to cut some sleeping hours to make the "winamp
project" possible and write this tutorial (kids, don't do it at home)!

The first question that everyone that heard about this project was: "what's
the point in encrypting mp3s?" Well, how should I make them understand that
it was just a funny exercise, something without a real motivation, just a
matter of doing it? They probably (all the enlightened minds) should have
understood... but I had to give a real motivation about the usefulness
of my work :) Here are the conclusions I've been able to get:

- Nowadays most of the free web space providers check for mp3 and if they find
any they just close your free account. Since the trick of changing the
extension is actually a little out of date, a good idea should be to encrypt
the files so they aren't easily detected;

- If you have to do a massive trade of mp3s on CD via snail-mail it could be
quite risky... actually the encryption of the files on the CD isn't the
most smart idea, but it is an idea... In fact while at the previous point
you should decrypt the mp3 after you downloaded it from the Internet in
this case you should need to decrypt the entire CD and re-master it: an
on-the-fly decryptor should be the real solution;

Now that the "why doing this" problem was solved, I just had to decide how
to do it... in fact the second question I got was "But why don't you write an
encrypted mp3 player?". My first answer was "because I'm a reverse engineer
and if I don't reverse something I'm not happy with it"... but this wasn't
too persuasive. So I decided that the official version will be:

- After I'd understand how to modify Winamp to make it work with encrypted
mp3s instead of the normal ones I should be able to do the same thing with
almost every other program. As a result, even if your encryption algorithm
is very easy it will be in a non-standard format and it should be harder to
decrypt than a standard one, since is just recognized by your version of the
program.

... funny, isn't it? :)
Now I had to start at some point. Schematically my work (and, from now, yours)
can be summarized this way:

a) Program analisys
or: "damn, it had to be a dll?"
b) Adding a new section
or: "there is quite some place but I like to play with the PE"
c) Experiments
or: "let's try not to encrypt the HDD, the ram, the monitor and the keyboard"
d) API hook
or: "not sure the name is right, but it sounded good"
e) Decryption
or: "all this work for two lines of code? fuck...."
f) Encryption
or: "yeah, I did a good job, but what should I listen to now?"
g) Listening
or: "It works? Naaah, can't be real"
Let's analyze the entire work, step by step.

***************************************************
a) Program analisys
or: "damn, it had to be a dll?"
***************************************************

Well, the winamp code that manages to load the mp3s is in fact contained in a
dll. Actually all the winamp code that manages to load some kind of audio
file can be found in a dll file. The one that is used to load a mp3 file is
called in_mp3.dll.

How can you get this? Very easy, just execute winamp, open the softice window
with a CTRL-D (heh, you'll have to select the winamp double size feature from
the menu ;) and then set a breakpoint at the ReadFile API. When you'll get the
control back to the original program the dear old Sice will be reactivated
when inside the API call: press F12 and you'll be transferred inside the
code part that we were looking for and you'll get the name of the DLL where
the code is.

The fact that we will be working on a dll has some advantages and some
disvantages: a considerable advantage is that we can suppose that all the
calls to readfile to read the mp3 are inside it; even we can suppose that
ALL the calls to a readfile are interesting for us (and a deeper analisys of
the code will confirm this); the disvantage tho is that we'll have to learn
a little more about dlls and it's PE... and is just at this point that we
jump to the next section.

************************************************************************
b) Adding a new section
or: "there is quite some space but I like to play with the PE"
************************************************************************

The first thing that you must do when adding some code to an executable is to
choose if you could append it to an existing section (if there is some place)
or add it in a new one. To do this you have first of all to check the actual
state of the sections:

Disassembly of File: in_mp3.dll
Code Offset = 00001000, Code Size = 0001E000
Data Offset = 00025000, Data Size = 00005000

Number of Objects = 0005 (dec), Imagebase = 11000000h

Object01: .text RVA: 00001000 Offset: 00001000 Size: 0001E000 Flags: 60...
Object02: .rdata RVA: 0001F000 Offset: 0001F000 Size: 00006000 Flags: 40...
Object03: .data RVA: 00025000 Offset: 00025000 Size: 00005000 Flags: C0...
Object04: .rsrc RVA: 0005A000 Offset: 0002A000 Size: 00003000 Flags: 40...
Object05: .reloc RVA: 0005D000 Offset: 0002D000 Size: 00003000 Flags: 42...

Good. The first section, called .text, is the one that contains the code
and, as you can see with any hexeditor, has a lot of unused space at its
end. In fact, by knowing that it is 1E000 bytes long and it has an offset of
1000 from the beginning of the file, we could just try to check near the
offset 1F000 with the hexeditor to find quite a lot of zeros. We should then
use this space for our code, so... we will add a new section :)

(I know you hate me for this, but remember that I'm doing this for you:
this lesson has to be the most generic possible, so I can't assume that
you'll always find some free space!)

To add a new section some basic knowledge of the PE format is
required. I missed this at my first experiments... that had also been
disastrous of course :) Anyway get some good documentation (on Ringzer0
there should be more or less everything you should need) and you'll see
that you won't have too many troubles in understanding this tut. A hint:
backup your in_mp3.ddl or, even better, copy it to another name and work
on that copy (it will be anyway added as a new plugin by winamp!). I called
mine in_mal.dll :)

First of all it is needed to find the characteristics of our new section, that
is the data that describes it inside the PE header. To do this let's use a
"spying" tool (PEBrowse) and then a definition of the PE sections table, like
for example the "kill3xx" one, the great reference text ;) I'll mention it
with big respect:

- SName: 8 bytes string with the section name. Select the name you like most,
i used ".mala" :)

- SVirtualSize: it contains the physical space (see SizeOfRawData) of the
data rounded to a multiple of the section alignment. Since section
alignment is equal to 1000 (like you can read with PEBrowse at the
Optional Header section), let's select 1000 for the SVirtualSize.

- SVirtualAddress (RVA): this enables you to calculate the position that
the section will have when loaded in memory by the loader. It has
to be a multiple of the section alignment. In our example, since the
last section has a RVA of 5D000 and Size 3000, the .mala RVA will be
5D000+3000=60000, that is already rounded to the section alignment.

- SizeOfRawData: the physical space of the data on the disk rounded to file
alignment. Since file alignment is 1000, let's put as for
SVirtualSize a length of 1000 bytes.

- PointerToRawData: the physical offset where you'll find data in the section.
You just have to add the offset of the last section to the
SizeOfRawData of the last section, rounding it to the file alignment.
So: 2D000 + 3000 = 30000. Also this value is already rounded.

- SFlags: the flags that identify the characteristics (code,data,etc.) and
so the flags that will be used in protected mode paging (writeable,
readable,etc.). We will have to put the same ones as the first one,
that is 0x60000020.

Notice that while some values are easily found by Wdasm, other ones have to be
readed with PEBrowse... since you can find everything you should need in
PEBrowse you'd better to leave Wdasm :)

Now that you had to read all the technical boring stuff and you're ready to
play with your hexeditor with the dll... stop it! The Sadd program written by
the good old Neuro will do all the dirty work for you! It will automatically
update also the Image Size, a very important field (especially in NT) that
wasn't already described: it contains the length of the image once loaded in
memory and, of course, it has to be changed when a section is added.

Of course, if you should have to add in the section some functions to export
this tool wouldn't be enough. But, luckily, it is not our business: the code
that we will add won't be called by winamp but directly by the dll code
(how lucky, so we don't care anymore for the "disadvantage" to work with a
dll!).

Very good: now that we added our new section we have to try it out... that's
why we jump to the next section.

**************************************************************************
c) Experiments
or: "let's try not to encrypt the HDD, the ram, the monitor and
the keyboard"
**************************************************************************

Well, in fact the situation isn't so bad as it could seem... but usually I
prefer to move on by small steps and I don't want to insert immediately
the encryption routine without knowing exactly what I'd like to do. So let's
do a small checkpoint.

We want to read the encrypted mp3s. But how? Well, first of all by reading the
file from the disk, like we already understood when we have set the breakpoint
on the readfile api. Later, once readed the file (or, more generically, once
readed a given amount of bytes from this file), we would like to have a
chance to decrypt it in memory in a way that the program won't even know
about this operation. How to do it exactly? Let's see the API:

BOOL ReadFile(

byte HANDLE hFile, // handle of file to read
dword LPVOID lpBuffer, // address of buffer that receives data
dword DWORD nNumberOfBytesToRead, // number of bytes to read
dword LPDWORD lpNumberOfBytesRead, // address of number of bytes read
dword LPOVERLAPPED lpOverlapped // address of structure for data
);

Good. Look at the parameters that are given to the function: you can see a
pointer to the buffer where the readed data is set and the number of bytes
that have been readed. Perfect, is exactly what we needed: after we should
read some bytes from the file, we could modify them in memory since we know
the address and the number of them. How? Easy: we will intercept all the calls
to ReadFile and redirect them to our routine that will first call the readfile
and then will decrypt the block of bytes that has been readed. At the return
the program will just think that it executed the ReadFile.

And now it's time to start to write our new function: for now it will be just
a copy of the call to the ReadFile, so we can easily control the given
parameters and understand how the stack works. Actually we will just need
to take the parameters to the call back from the stack, repush them, call
ReadFile and then put off the stack the "original" parameters.

At this moment we have to add a small theorical explanation: when a function
that requires some parameters is called, they are PUSHed on the stack before
the real call. For example since the ReadFile requires five parameters, they
are the five last ones PUSHed (and they are the ones we are interested in).
This concept has to be always clear, since it is VEEERY useful in many
situations, for example when you want to understand a disassembly or when
you have to check for serial numbers in memory.

When a call is executed, on the top of the stack the return address for the
function is also pushed: this address, that points to the address just after
the call, is used by the program to get back to the calling position when it
will find a RET instruction.
This means that, once in our function, the first parameter (the one that is
pointed by ESP) will be the return address, while the real parameters to
the ReadFile function are set starting from the address ESP+4. To be more
exact at the ESP+4 will be set the LAST parameter pushed (do you remember
that the pushes have an inverse order from the one from the API definition?)
and the others continues each 4 bytes. At this point the code to reply the
original ReadFile could be:

55 push ebp // save ebp value
NOTE: at this point all the
elements on the stack are
"moved" by 4 bytes!
8BEC mov ebp, esp // let's use ebp as a fixed value
to read stack cells
8B4518 mov eax, dword ptr [ebp+18] // save to eax the 5th parameter
50 push eax // PUSH 5th parameter
8B4514 mov eax, dword ptr [ebp+14] // save to eax the 4th parameter
50 push eax // PUSH 4th parameter
8B4510 mov eax, dword ptr [ebp+10] // save to eax the 3rd parameter
50 push eax // PUSH 3rd parameter
8B450C mov eax, dword ptr [ebp+0C] // save to eax the 2nd parameter
50 push eax // PUSH 2nd parameter
8B4508 mov eax, dword ptr [ebp+08] // save to eax the 1st parameter
50 push eax // PUSH 1st parameter
FF1520F00111 Call dword ptr [1101F020] // Call ReadFile
5D pop ebp // get the original ebp value back
from stack

****************************************************
INSERT DECRYPTION ALGORITHM HERE!!!
****************************************************
C21400 ret 0014 // return deleting the last 5
cells from the stack

Notice the last command, the RET 0014: this is needed because on the stack,
after the return address there are still present the 5 parameters pushed by
the original program! So it is needed to delete it so the stack will be
back to the state as if only the original ReadFile should have been executed.

At this point we just have to do a test: before we change all the addresses
for all the calls, of course, let's try just one, the one at address 110014DD,
that reads the tag id3 to display the song name. It is called just once at the
beginning of the playing, so it's quite ok for some tests since it can't do
much havoc :)

* Reference To: KERNEL32.ReadFile, Ord:0218h
|
:110014DD FF1520F00111 Call dword ptr [1101F020]

since our function begins at the address 11060000 (remember that the address
is calculated by an easy sum by imagebase and RVA) we can modify the call at
the address 100014DD with a

:110014DD E81EEB0500 call 11060000
:110014E2 90 nop

To calculate the relative value of the call you have just to substract at the
value 11060000 the address of the instruction next to the call. In this
example you just have to do 11060000-110014E2=0005EB1E. Remember also that the
value in opcode format is exactly the one that is written up here. At this
point you can execute the program (remember to add your dll to the mp3 player
and disable the original one) and... it can't be real, but it works! :)

***********************************************************
d) API hook
or: "not sure the name is right, but it sounded good"
***********************************************************

I'm not sure if this name is right... but it is just what I'd been thinking
to do: "hook" the API calls and direct them where I wanted to. Well, let's
hope it will work :)

This operation has just been done in the previous section to do our test:
now we have to do the same for all the calls to a ReadFile. By looking inside
the disassembly for the "ReadFile" string I founded 11 calls, 9 of which were
exactly identical

FF1520F00111 Call dword ptr [1101F020]

while the other 2 were different, respectively a CALL EDI and a CALL ESI,
which values have been identified by the commands

8b3D20f00111 mov edi, dword ptr [1001F020]

and

8b3520f00111 mov esi, dword ptr [1001F020]

Good, so we have now to redo all that boring calculations we did before for
all the relative values for all the nine calls? Yeah, sadly yes... but there
is a small trick to make things easier :)
Since the command takes 5 bytes (1 opcode + 4 operand) we can solve the
simple equation:

Operand = Address of the called function - (Command address + 5)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
this value is always fixed this one changes

that is like:

Operand = (Address of the called function - 5) - Command address
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
this value is always fixed this one changes

Nothing special... but calculations are easier! This can be useful especially
in such cases when you have to redirect from various addresses to the same
function. So now we have just to do for each calculations the easy
substraction 1105FFFB-(call address). The values at the end are:

01) 11001087: FF1520F00111 --> E874EF050090
02) 110014DD: FF1520F00111 --> E81EEB050090
03) 110015A8: FF1520F00111 --> E853EA050090
04) 11001649: FF1520F00111 --> E8B2E9050090
05) 110017be: FF1520F00111 --> E83DE8050090
07) 11007e05: FF1520F00111 --> E8F681050090
08) 11008333: FF1520F00111 --> E8C87C050090
09) 110083f1: FF1520F00111 --> E80A7C050090
11) 110088b2: FF1520F00111 --> E84977050090

Now we have just to deal with the two "special" calls... one way to patch that
calls is to modify the command that saves the address to ESI (or EDI) with a
command that saves the value 11060000 in that registers.

06) 110077f8: CALL EDI: modify to 110077f0 mov edi, dword ptr etc.
8b3D20f00111 --> BF0000061190
10) 11008665: CALL ESI: modify to 11008650 mov esi, dword ptr etc.
8b3520f00111 --> BE0000061190

Et voila'... it's done! That are the substitutions to be made, a bit boring
but at the end it still works... does it sound obvious? :) At this moment,
let's change our do-almost-nothing function to one that will do really
something useful... dunno, decrypt a mp3 file!

*************************************************************
e) Decryption
or: "all this work for two lines of code? fuck...."
*************************************************************

Previously, at the C section, when we described the code of our function I
left an empty space where you should put the encryption algorithm. Now it's
time to write one, by choosing first of all the encryption type.

First of all it is necessary to specify the fact that such algorithm can't
work directly on the entire file, but just on parts of the file that are
readed time by time by the program. So it is not a good idea (nor easy to do
at the encryption stage) to work moving bytes, but a better choice is
definitely to manipulate them with some easy operations. In this example I
decided to use a very simple xor, but you can choose another one by moving by
my own one.

I'd like to say a few things before showing the code: first of all we will
need two elements that are on the stack, precisely the second and the fourth,
that are respectively the address where the file bytes are readed and the
number of bytes readed. Since when the end of the file is reached this will
be zero we will have to check the number of readed bytes so we won't be going
to encrypt some random memory places (ehehe...Neu knows I did this ;).
Finally, since the xor key can be selected in different ways I'll leave in the
code a label "val" that can be modified at the right moment... you could even
call a dialogbox to ask for the password, from which the decryption key could
be generated!

Here comes the commented code:

56 push esi // Save the values of the
51 push ecx // 3 registers that we will
50 push eax // use
8b742414 mov esi, dword ptr [esp+14] // esi=starting address
8b4c241c mov ecx, dword ptr [esp+1c] //
8b09 mov ecx, dword ptr [ecx] // ecx=bytes to decrypt

85c9 test ecx, ecx // ecx=0? then finished.
740c jz endloop

loop:
8a06 mov al, byte ptr [esi] // read 1 byte
34[val] xor al, [VAL] // xor the byte with value
in VAL
8806 mov byte ptr [esi], al // put the byte again there
46 inc esi
49 dec ecx
85c9 test ecx, ecx // finished decryption?
75f4 jnz loop

endloop:
58 pop eax
59 pop ecx
5e pop esi // restore values in regs

Done! There is nothing strange as you can see... but what is nice is that you
can put whatever you want in that loop :) For example I selected the hex
value ED and the disasm of the final version of my function is:

***************************LAST VERSION DISASSEMBLY*************************

:11060000 55 push ebp
:11060001 8BEC mov ebp, esp
:11060003 8B4518 mov eax, dword ptr [ebp+18]
:11060006 50 push eax
:11060007 8B4514 mov eax, dword ptr [ebp+14]
:1106000A 50 push eax
:1106000B 8B4510 mov eax, dword ptr [ebp+10]
:1106000E 50 push eax
:1106000F 8B450C mov eax, dword ptr [ebp+0C]
:11060012 50 push eax
:11060013 8B4508 mov eax, dword ptr [ebp+08]
:11060016 50 push eax

* Reference To: KERNEL32.ReadFile, Ord:0218h
|
:11060017 FF1520F00111 Call dword ptr [1101F020]
:1106001D 5D pop ebp
:1106001E 56 push esi
:1106001F 51 push ecx
:11060020 50 push eax
:11060021 8B742414 mov esi, dword ptr [esp+14]
:11060025 8B4C241C mov ecx, dword ptr [esp+1C]
:11060029 8B09 mov ecx, dword ptr [ecx]
:1106002B 85C9 test ecx, ecx
:1106002D 740C je 1106003B

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:11060039(C)
|
:1106002F 8A06 mov al, byte ptr [esi]
:11060031 34ED xor al, ED
:11060033 8806 mov byte ptr [esi], al
:11060035 46 inc esi
:11060036 49 dec ecx
:11060037 85C9 test ecx, ecx
:11060039 75F4 jne 1106002F

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1106002D(C)
|
:1106003B 58 pop eax
:1106003C 59 pop ecx
:1106003D 5E pop esi
:1106003E C21400 ret 0014


************************************************************************
f) Encryption
or: "yeah, I did a good work but what should I listen to now?"
************************************************************************

Good, now you have a dll that enables you to listen to encrypted mp3s... and
I'm gonna kick the ass of the guy that will say "but I don't have encrypted
mp3s!" :)

If you used my xor algorithm there isn't any problem, just write an easy
program that XOR-es the file... or get the JFL File XORer from my web site
(http://malattia.cjb.net, at the tools/downloads section)... I personally
used this second way (Ehehe... why did you think I choosed such a stupid
algorithm? :))
If you choosed a personal algorithm... then it's your problem, I think you'll
have to write a tool from your own! >:)))

Now I'm sure you are all intelligent students... but please don't write me
saying that you can't listen to your favourite songs since you encrypted
your playlist... ok? ;)

***************************************************
g) Listening
or: "It works? Naaah, can't be real"
***************************************************

Et voila'... it works! Really! The confirmation is done by the fact that I'm
just listening to an entirely encrypted album (yeah, I know you can't hear it,
but trust me, ok?)... to be honest I didn't believe it myself too! :)


************************************OUTRO************************************

Woa, it's finished! Guys, I worked more to write this tut than completing
the entire project! Now be nice, use your uncle +Ma's teachings and modify
your program as you like... this was just an example, now free your mind
and lemme see what you can do! For any info, greetings, insult, contribute,
offer you can email me at malattia@gmx.net. If this address should be dead you
can check the one that is at my web page at: http://malattia.cjb.net.

**********************************THANKS*********************************

Thanks to Ringzer0, the best cracker group in the universe and to the entire
#crack-it, but especially to:

Neuro, for the tons of hints on PE;
Pusi, that was listening to me when I was blabbering about the mp3 encryption;
Suby, that said I was sick when I was blabbering about the mp3 encryption;
everyone that was listening to me when I was blabbering about mp3 encryption;
everyone that didn't insult me when I was blabbering about mp3 encryption;
everyone that was able to read this file to this point :)

byez,

.+Ma.

LAST_NOTE: my friend Genius saved me from being highly shitted (if I can
be shitted more than this) by noticing a small thing that wasn't described
in this tut. Since it won't totally fuck-up the new dll, but could make some
small undocumented problems, I decided to leave it as a homework to understand
what was wrong. The solution to this homework will be published with the
list of all the reversers that coworked by mailing me in the next BFI :)

-[ EOF ]----------------------------------------------------------------------
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close