elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Como proteger una cartera - billetera de Bitcoin


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Apis para leer disco en forma RAW y acceder a archivos eliminados
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Apis para leer disco en forma RAW y acceder a archivos eliminados  (Leído 2,675 veces)
achernar_

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Apis para leer disco en forma RAW y acceder a archivos eliminados
« en: 24 Junio 2011, 22:28 pm »

Esta es mi duda hace un tiempo que estoy buscando y no termino de dar en el clavo. Hasta donde se los archivos no desaparecen por completo de un disco cuando son eliminados. Quiero acceder al disco en forma RAW para buscar archivos eliminados. No quiero un programa para hacerlo, quiero programarlo yo. Se que con el api CreateFile() se puede acceder a una unidad de disco, después estoy dando vueltas y no termino de leer nada del disco. Busco info sobre DeviceIOControl() pero no me termina siendo clara y hay muchas constantes para las que no encuentro los valores numericos ni muchos ejemplos de codigo (eso seria lo mejor) después creo haber visto y perdido un ejemplo donde utilizaba las mismas funciones para leer un fichero pero con el disco. En fin un ejemplo seria lo mejor pero una ayuda cualquiera sea no seria despreciada. Gracias.


En línea

Tengo una habilidad sorprendente para hacer cosas que no sorprenden.
[Zero]
Wiki

Desconectado Desconectado

Mensajes: 1.082


CALL DWORD PTR DS:[0]


Ver Perfil WWW
Re: Apis para leer disco en forma RAW y acceder a archivos eliminados
« Respuesta #1 en: 25 Junio 2011, 20:09 pm »

Muevo el tema a programación C/C++ que creo que encaja mejor. No tengo mucha idea sobre como hacer lo que pides, pero creo que en modo usuario no sería posible, y digo creo. A ver si en programación pueden ayudarte mejor.

No sé si lo viste, pero alomejor te puede ayudar esto:
Código:
http://msdn.microsoft.com/en-us/library/aa363147(v=vs.85).aspx

Saludos


« Última modificación: 25 Junio 2011, 20:14 pm por [Zero] » En línea


“El Hombre, en su orgullo, creó a Dios a su imagen y semejanza.”
Nietzsche
Karman


Desconectado Desconectado

Mensajes: 673



Ver Perfil WWW
Re: Apis para leer disco en forma RAW y acceder a archivos eliminados
« Respuesta #2 en: 29 Junio 2011, 04:39 am »

fijate esta clase, la saqué no recuerdo de donde... je  :P

Código
  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <ctype.h>
  4.  
  5. #define VWIN32_DIOC_DOS_IOCTL     1 // specified MS-DOS device I/O ctl - Interrupt 21h Function 4400h - 4411h
  6. #define VWIN32_DIOC_DOS_INT25     2 // Absolute Disk Read command - Interrupt 25h
  7. #define VWIN32_DIOC_DOS_INT26     3 // Absolute Disk Write command - Interrupt 25h
  8. #define VWIN32_DIOC_DOS_INT13     4 // Interrupt 13h commands
  9. #define VWIN32_DIOC_SIMCTRLC      5 // Simulate Ctrl-C
  10. #define VWIN32_DIOC_DOS_DRIVEINFO 6 // Interrupt 21h Function 730X commands
  11.  
  12. #define CARRY_FLAG 1
  13.  
  14. #ifndef INVALID_SET_FILE_POINTER
  15. #define INVALID_SET_FILE_POINTER (DWORD)-1
  16. #endif
  17.  
  18. typedef struct _DISKIO {
  19.  DWORD  dwStartSector;   // starting logical sector number
  20.  WORD   wSectors;        // number of sectors
  21.  DWORD  dwBuffer;        // address of read/write buffer
  22. } DISKIO, * PDISKIO;
  23.  
  24. typedef struct _DIOC_REGISTERS
  25. {
  26.  DWORD reg_EBX;
  27.  DWORD reg_EDX;
  28.  DWORD reg_ECX;
  29.  DWORD reg_EAX;
  30.  DWORD reg_EDI;
  31.  DWORD reg_ESI;
  32.  DWORD reg_Flags;
  33. } DIOC_REGISTERS, *PDIOC_REGISTERS;
  34.  
  35. struct partial_boot_sector_info{
  36.  LPSTR Fs;
  37.  DWORD FsOffs;
  38.  DWORD SerialOffs;
  39. };
  40.  
  41. class DiskSectorRW{
  42. public:
  43.  virtual bool Open(char *vol) = 0;
  44.  virtual void Close() = 0;
  45.  virtual bool ReadSector(DWORD sector, char *Buffer, int sectorSize = 512) = 0;
  46.  virtual bool WriteSector(DWORD sector, char *buffer, int sectorSize = 512) = 0;
  47. };
  48.  
  49. class DiskSectorWinNT : public DiskSectorRW
  50. {
  51. private:
  52.  HANDLE m_hDisk;
  53. public:
  54.  bool Open(char *vol);
  55.  void Close();
  56.  bool ReadSector (DWORD sector, char *Buffer, int sectorSize = 512);
  57.  bool WriteSector(DWORD sector, char *Buffer, int sectorSize = 512);
  58. };
  59.  
  60. class DiskSectorWin9x : public DiskSectorRW
  61. {
  62. private:
  63.  HANDLE m_hVmm32;
  64.  bool m_bOpened;
  65.  char m_chDrive;
  66.  BYTE m_nDriveNo;
  67.  bool m_bW9xOsr2AndAbove;
  68.  bool m_bUseLocking;
  69. public:
  70.  
  71.  DiskSectorWin9x() : m_bUseLocking(false) { }
  72.  bool Open(char *vol);
  73.  void Close();
  74.  
  75.  bool ReadSector (DWORD sector, char *Buffer, int sectorSize = 512);
  76.  bool WriteSector(DWORD sector, char *Buffer, int sectorSize = 512);
  77.  
  78.  static bool LockLogicalVolume (HANDLE hVWin32, BYTE   bDriveNum, BYTE   bLockLevel, WORD wPermissions);
  79.  static bool UnlockLogicalVolume(HANDLE hVWin32, BYTE bDriveNum);
  80.  
  81.  static bool ReadLogicalSectors (HANDLE hDev, BYTE   bDrive, DWORD  dwStartSector, WORD wSectors, LPBYTE lpSectBuff);
  82.  static bool WriteLogicalSectors (HANDLE hDev, BYTE   bDrive, DWORD  dwStartSector, WORD   wSectors, LPBYTE lpSectBuff);
  83.  
  84.  static bool NewReadSectors(HANDLE hDev, BYTE   bDrive, DWORD  dwStartSector, WORD   wSectors, LPBYTE lpSectBuff);
  85.  static bool NewWriteSectors(HANDLE hDev, BYTE   bDrive, DWORD  dwStartSector, WORD   wSectors, LPBYTE lpSectBuff);
  86.  
  87. };
  88.  
  89. class DiskSector
  90. {
  91. private:
  92.  DiskSectorRW *util;
  93. public:
  94.  DiskSector();
  95.  ~DiskSector();
  96.  bool Open(char *vol);
  97.  void Close();
  98.  bool ReadSector(DWORD sector, char *Buffer, int sectorSize = 512);
  99.  bool WriteSector(DWORD sector, char *buffer, int sectorSize = 512);
  100. };

Código
  1. #include "disk.h"
  2.  
  3. DiskSector::DiskSector()
  4. {
  5.  if (GetVersion() > 0x80000000)
  6.    util = new DiskSectorWin9x;
  7.  else
  8.    util = new DiskSectorWinNT;
  9. }
  10.  
  11. void DiskSector::Close()
  12. {
  13.  util->Close();
  14. }
  15.  
  16. bool DiskSector::Open(char *vol)
  17. {
  18.  return util->Open(vol);
  19. }
  20.  
  21. bool DiskSector::WriteSector(DWORD sector, char *Buffer, int sectorSize)
  22. {
  23.  return util->WriteSector(sector, Buffer, sectorSize);
  24. }
  25.  
  26. bool DiskSector::ReadSector(DWORD sector, char *Buffer, int sectorSize)
  27. {
  28.  return util->ReadSector(sector, Buffer, sectorSize);
  29. }
  30.  
  31. DiskSector::~DiskSector()
  32. {
  33.  delete util;
  34. }
  35.  
  36. /***********************************************************/
  37.  
  38. bool DiskSectorWinNT::Open(char *vol)
  39. {
  40.  char szDrive[10];
  41.  sprintf(szDrive, "\\\\.\\%c:", vol[0]);
  42.  m_hDisk = ::CreateFile(
  43.    szDrive,
  44.    GENERIC_READ | GENERIC_WRITE,
  45.    FILE_SHARE_READ | FILE_SHARE_WRITE,
  46.    NULL,
  47.    OPEN_EXISTING,
  48.    0,
  49.    NULL);
  50.  return m_hDisk != INVALID_HANDLE_VALUE;
  51. }
  52.  
  53. void DiskSectorWinNT::Close()
  54. {
  55.  if (m_hDisk != INVALID_HANDLE_VALUE)
  56.    ::CloseHandle(m_hDisk);
  57. }
  58.  
  59. bool DiskSectorWinNT::ReadSector (DWORD sector, char *Buffer, int sectorSize)
  60. {
  61.  DWORD read = 0;
  62.  
  63.  if (::SetFilePointer(m_hDisk, sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
  64.    return false;
  65.  
  66.  if (!::ReadFile(m_hDisk, Buffer, sectorSize, &read, NULL))
  67.    return false;
  68.  return true;
  69. }
  70.  
  71. bool DiskSectorWinNT::WriteSector(DWORD sector, char *Buffer, int sectorSize)
  72. {
  73.  DWORD wrote = 0;
  74.  
  75.  if (::SetFilePointer(m_hDisk, sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
  76.    return false;
  77.  
  78.  if (!::WriteFile(m_hDisk, Buffer, sectorSize, &wrote, NULL))
  79.    return false;
  80.  
  81.  return true;
  82. }
  83.  
  84. /***********************************************************/
  85.  
  86. bool DiskSectorWin9x::Open(char *vol){
  87.  m_bOpened = false;
  88.  
  89.  OSVERSIONINFOEX osvi = {0};
  90.  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  91.  if (!::GetVersionEx((OSVERSIONINFO *)&osvi)){
  92.    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  93.    if (!::GetVersionEx ((OSVERSIONINFO *)&osvi))
  94.      return false;
  95.  }
  96.  if (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
  97.    return false;
  98.  
  99.  m_chDrive  = toupper(vol[0]);
  100.  m_nDriveNo = m_chDrive - 'A' + 1;
  101.  
  102.  char temp[10] = {0};
  103.  sprintf(temp, "%c:\\", m_chDrive);
  104.  
  105.  if (::GetDriveType(temp) != DRIVE_FIXED)
  106.    return false;
  107.  
  108.  m_bW9xOsr2AndAbove = (osvi.dwMajorVersion >= 4 && osvi.dwMinorVersion >= 10)
  109.    ||
  110.    (
  111.      (osvi.dwBuildNumber == 4 && osvi.dwMinorVersion == 0) &&
  112.      (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B')
  113.    );
  114.  
  115.  m_hVmm32 = ::CreateFile(
  116.    "\\\\.\\VWIN32",      // name
  117.    0,                      // access mode
  118.    0,                      // share mode
  119.    NULL,           // security descriptor
  120.    0,                   // ho to create
  121.    FILE_FLAG_DELETE_ON_CLOSE, // file attributes
  122.    NULL);          // handle to file with att to copy
  123.  
  124.  m_bOpened = (m_hVmm32 != INVALID_HANDLE_VALUE);
  125.  
  126.  return m_bOpened;
  127. }
  128.  
  129. void DiskSectorWin9x::Close()
  130. {
  131.  if (m_bOpened)
  132.    ::CloseHandle(m_hVmm32);
  133.  m_bOpened = false;
  134. }
  135.  
  136.  
  137. bool DiskSectorWin9x::ReadLogicalSectors (HANDLE hDev,
  138.                         BYTE   bDrive,
  139.                         DWORD  dwStartSector,
  140.                         WORD   wSectors,
  141.                         LPBYTE lpSectBuff)
  142. {
  143.  BOOL           fResult;
  144.  DWORD          cb;
  145.  DIOC_REGISTERS reg = {0};
  146.  DISKIO         dio = {0};
  147.  
  148.  dio.dwStartSector = dwStartSector;
  149.  dio.wSectors      = wSectors;
  150.  dio.dwBuffer      = (DWORD)lpSectBuff;
  151.  
  152.  reg.reg_EAX = bDrive - 1;    // Int 25h drive numbers are 0-based.
  153.  reg.reg_EBX = (DWORD)&dio;   // Drive letter 0 = A, 1 = B  2 = C ect..
  154.  reg.reg_ECX = 0xFFFF;        // use DISKIO struct
  155.  
  156.  fResult = ::DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT25,
  157.    &reg, sizeof(reg),
  158.    &reg, sizeof(reg), &cb, 0);
  159.  
  160.  // Determine if the DeviceIoControl call and the read succeeded.
  161.  fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);
  162.  
  163.  return fResult == TRUE;
  164. }
  165.  
  166. bool DiskSectorWin9x::WriteLogicalSectors (HANDLE hDev,
  167.                          BYTE   bDrive,
  168.                          DWORD  dwStartSector,
  169.                          WORD   wSectors,
  170.                          LPBYTE lpSectBuff)
  171. {
  172.  BOOL           fResult;
  173.  DWORD          cb;
  174.  DIOC_REGISTERS reg = {0};
  175.  DISKIO         dio = {0};
  176.  
  177.  dio.dwStartSector = dwStartSector;
  178.  dio.wSectors      = wSectors;
  179.  dio.dwBuffer      = (DWORD)lpSectBuff;
  180.  
  181.  reg.reg_EAX = bDrive - 1;    // Int 26h drive numbers are 0-based.
  182.  reg.reg_EBX = (DWORD)&dio;
  183.  reg.reg_ECX = 0xFFFF;        // use DISKIO struct
  184.  
  185.  fResult = ::DeviceIoControl(hDev, VWIN32_DIOC_DOS_INT26,
  186.    &reg, sizeof(reg),
  187.    &reg, sizeof(reg), &cb, 0);
  188.  
  189.  // Determine if the DeviceIoControl call and the write succeeded.
  190.  fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);
  191.  
  192.  return fResult == TRUE;
  193. }
  194.  
  195.  
  196. bool DiskSectorWin9x::NewReadSectors(HANDLE hDev,
  197.                    BYTE   bDrive,
  198.                    DWORD  dwStartSector,
  199.                    WORD   wSectors,
  200.                    LPBYTE lpSectBuff)
  201. {
  202.  BOOL           fResult;
  203.  DWORD          cb;
  204.  DIOC_REGISTERS reg = {0};
  205.  DISKIO         dio;
  206.  
  207.  dio.dwStartSector = dwStartSector;
  208.  dio.wSectors      = wSectors;
  209.  dio.dwBuffer      = (DWORD)lpSectBuff;
  210.  
  211.  reg.reg_EAX = 0x7305;   // Ext_ABSDiskReadWrite
  212.  reg.reg_EBX = (DWORD)&dio;
  213.  reg.reg_ECX = (DWORD)-1;
  214.  reg.reg_EDX = bDrive;   // Int 21h, fn 7305h drive numbers are 1-based
  215.  
  216.  fResult = ::DeviceIoControl(hDev, VWIN32_DIOC_DOS_DRIVEINFO,
  217.    &reg, sizeof(reg),
  218.    &reg, sizeof(reg), &cb, 0);
  219.  
  220.  // Determine if the DeviceIoControl call and the read succeeded.
  221.  fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);
  222.  
  223.  return fResult == TRUE;
  224. }
  225.  
  226.  
  227. bool DiskSectorWin9x::NewWriteSectors(HANDLE hDev,
  228.                     BYTE   bDrive,
  229.                     DWORD  dwStartSector,
  230.                     WORD   wSectors,
  231.                     LPBYTE lpSectBuff)
  232. {
  233.  BOOL           fResult;
  234.  DWORD          cb;
  235.  DIOC_REGISTERS reg = {0};
  236.  DISKIO         dio;
  237.  
  238.  dio.dwStartSector = dwStartSector;
  239.  dio.wSectors      = wSectors;
  240.  dio.dwBuffer      = (DWORD)lpSectBuff;
  241.  
  242.  reg.reg_EAX = 0x7305;   // Ext_ABSDiskReadWrite
  243.  reg.reg_EBX = (DWORD)&dio;
  244.  reg.reg_ECX = (DWORD)-1;
  245.  reg.reg_EDX = bDrive;   // Int 21h, fn 7305h drive numbers are 1-based
  246.  
  247.  reg.reg_ESI = 0x6001;   // Normal file data/write (See function
  248.  // documentation for other values)
  249.  
  250.  
  251.  fResult = ::DeviceIoControl(hDev, VWIN32_DIOC_DOS_DRIVEINFO,
  252.    &reg, sizeof(reg),
  253.    &reg, sizeof(reg), &cb, 0);
  254.  
  255.  // Determine if the DeviceIoControl call and the write succeeded.
  256.  fResult = fResult && !(reg.reg_Flags & CARRY_FLAG);
  257.  
  258.  return fResult == TRUE;
  259. }
  260.  
  261. bool DiskSectorWin9x::LockLogicalVolume (HANDLE hVWin32,
  262.                               BYTE   bDriveNum,
  263.                               BYTE   bLockLevel,
  264.                               WORD   wPermissions)
  265. {
  266.  BOOL           fResult;
  267.  DIOC_REGISTERS regs = {0};
  268.  BYTE           bDeviceCat;  // can be either 0x48 or 0x08
  269.  DWORD          cb;
  270.  
  271.  bDeviceCat = 0x48;
  272.  
  273. ATTEMPT_AGAIN:
  274.  // Set up the parameters for the call.
  275.  regs.reg_EAX = 0x440D;
  276.  regs.reg_EBX = MAKEWORD(bDriveNum, bLockLevel);
  277.  regs.reg_ECX = MAKEWORD(0x4A, bDeviceCat);
  278.  regs.reg_EDX = wPermissions;
  279.  
  280.  fResult = ::DeviceIoControl (hVWin32, VWIN32_DIOC_DOS_IOCTL,
  281.    &regs, sizeof(regs), &regs, sizeof(regs),
  282.    &cb, 0);
  283.  
  284.  fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);
  285.  if (!fResult && (bDeviceCat != 0x08)){
  286.    bDeviceCat = 0x08;
  287.    goto ATTEMPT_AGAIN;
  288.  }
  289.  
  290.  return fResult == TRUE;
  291. }
  292.  
  293. bool DiskSectorWin9x::UnlockLogicalVolume (HANDLE hVWin32, BYTE bDriveNum)
  294. {
  295.  BOOL           fResult;
  296.  DIOC_REGISTERS regs = {0};
  297.  BYTE           bDeviceCat;  // can be either 0x48 or 0x08
  298.  DWORD          cb;
  299.  bDeviceCat = 0x48;
  300.  
  301. ATTEMPT_AGAIN:
  302.  regs.reg_EAX = 0x440D;
  303.  regs.reg_EBX = bDriveNum;
  304.  regs.reg_ECX = MAKEWORD(0x6A, bDeviceCat);
  305.  fResult = ::DeviceIoControl (hVWin32, VWIN32_DIOC_DOS_IOCTL,
  306.    &regs, sizeof(regs), &regs, sizeof(regs),
  307.    &cb, 0);
  308.  fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);
  309.  if (!fResult && (bDeviceCat != 0x08)){
  310.    bDeviceCat = 0x08;
  311.    goto ATTEMPT_AGAIN;
  312.  }
  313.  return fResult == TRUE;
  314. }
  315.  
  316.  
  317. bool DiskSectorWin9x::ReadSector (DWORD sector, char *Buffer, int sectorSize)
  318. {
  319.  if (!m_bOpened)
  320.    return false;
  321.  
  322.  if (m_bUseLocking)
  323.  {
  324.    if (!LockLogicalVolume(m_hVmm32, m_nDriveNo, 1, 1))
  325.      return false;
  326.  
  327.    if (!LockLogicalVolume(m_hVmm32, m_nDriveNo, 2, 0))
  328.    {
  329.      UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  330.      return false;
  331.    }
  332.  }
  333.  
  334.  bool bRet;
  335.  if (m_bW9xOsr2AndAbove)
  336.    bRet = NewReadSectors(m_hVmm32, m_nDriveNo, sector, 1, (LPBYTE)Buffer);
  337.  else
  338.    bRet = ReadLogicalSectors(m_hVmm32, m_nDriveNo, sector, 1, (LPBYTE)Buffer);
  339.  
  340.  if (m_bUseLocking)
  341.  {
  342.    UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  343.    UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  344.  }
  345.  return bRet;
  346. }
  347.  
  348. bool DiskSectorWin9x::WriteSector (DWORD sector, char *Buffer, int sectorSize)
  349. {
  350.  if (!m_bOpened)
  351.    return false;
  352.  
  353.  if (!LockLogicalVolume(m_hVmm32, m_nDriveNo, 1, 1))
  354.    return false;
  355.  
  356.  if (!LockLogicalVolume(m_hVmm32, m_nDriveNo, 2, 0))
  357.  {
  358.    UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  359.    return false;
  360.  }
  361.  
  362.  if (!LockLogicalVolume(m_hVmm32, m_nDriveNo, 3, 0))
  363.  {
  364.    UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  365.    UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  366.    return false;
  367.  }
  368.  
  369.  bool bRet;
  370.  
  371.  if (m_bW9xOsr2AndAbove)
  372.    bRet = NewWriteSectors(m_hVmm32, m_nDriveNo, sector, 1, (LPBYTE) Buffer);
  373.  else
  374.    bRet = WriteLogicalSectors(m_hVmm32, m_nDriveNo, sector, 1, (LPBYTE) Buffer);
  375.  
  376.  UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  377.  UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  378.  UnlockLogicalVolume(m_hVmm32, m_nDriveNo);
  379.  
  380.  return bRet;
  381. }

S2

PD: cabe aclarar que tenes que tener permisos administrativos al usar el código.
PD2: con esto solo accedes al los datos raw del disco, luego tenes que analizar la cabecera de las particiones, detectar el tipo (FAT, NTFS) y según eso ver la lista de nodos de archivos... en google había visto algunos ejemplos hace un tiempo.
« Última modificación: 29 Junio 2011, 04:40 am por Karman » En línea

achernar_

Desconectado Desconectado

Mensajes: 117



Ver Perfil
Re: Apis para leer disco en forma RAW y acceder a archivos eliminados
« Respuesta #3 en: 2 Julio 2011, 01:35 am »

Gracias. Voy a ver si puedo crear una dll y subirla en agradecimiento.  ;-)
En línea

Tengo una habilidad sorprendente para hacer cosas que no sorprenden.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines