#include <windows.h>
#include <string.h>
#include "plugin.h"
#include <dbghelp.h>
#include <psapi.h>
int _cdecl CheckDlls();
HINSTANCE				hinst; 
HWND					hwmain;
BOOL 
CALLBACK
EnumerateSymbols(
				 PSYMBOL_INFO  pSymInfo,
				 ULONG SymbolSize,
				 PVOID UserContext
				 )
{
	UNREFERENCED_PARAMETER( UserContext );
	UNREFERENCED_PARAMETER( SymbolSize );
	Insertname(
		(DWORD)pSymInfo->Address,
		NM_LIBRARY,
		pSymInfo->Name
		);
	return TRUE;
}
BOOL WINAPI DllMain(
					HINSTANCE hi,
					DWORD reason,
					LPVOID reserved
					)
{
	UNREFERENCED_PARAMETER( reserved );
	if (reason==DLL_PROCESS_ATTACH)
		hinst=hi;
	return 1;
};
extc int _export _cdecl ODBG_Plugindata(
										char shortname[32]
)
{
	strcpy_s(
		shortname,
		30,
		"SymbolLoader"
		);
	return PLUGIN_VERSION;
};
extc int _export _cdecl ODBG_Plugininit( 
										int ollydbgversion,
										HWND hw,
										ulong *features
										)
{
	UNREFERENCED_PARAMETER( features );
	if (ollydbgversion<PLUGIN_VERSION)
		return -1;
	hwmain=hw;
	Addtolist(
		0,
		1,
		"SymbolLoader Plugin"
		);
	Addtolist(
		0,
		1,
		"  As Usual Dedicated To Oleh Yuschuk"
		);
	return 0;
};
extc int _export _cdecl ODBG_Pluginmenu(
										int origin,
										char data[4096],
										void *item
										)
{
	UNREFERENCED_PARAMETER( item );
	switch (origin) {
			case PM_MAIN:
				strcpy_s(
					data,
					4000,
					"0 &SymbolLoader|1 &About"
					);
				return 1;
			default: break;
	};
	return 0;
};
extc void _export _cdecl ODBG_Pluginaction(
	int origin,
	int action,
	void *item
	)
{
	HANDLE								hProcess;
	t_table	*							ModuleTable;
	t_module *							Module;
	DWORD64								dwModuleBase;
	int									i;
	t_sorted							sorted;
	LPTSTR								Envvar;
	IMAGEHLP_MODULE64					im;
	UNREFERENCED_PARAMETER( item );
	memset(&im,0,sizeof(im));
	im.SizeOfStruct = sizeof(im);
	if (origin==PM_MAIN) {
		switch (action){
			case 0:
				Addtolist(
					0,
					1,
					"SymbolLoader Plugin Was Called"
					);
				Envvar= (LPTSTR) malloc(4096);
				if( ! GetEnvironmentVariable(
					"_NT_SYMBOL_PATH",
					Envvar,
					4094 
					)) {
						Addtolist (
							0,
							1,
							"Set EnivronmemtVariable "
							"_NT_SYMBOL_PATH for symsrv "
							"to fetch or lookup symbol cache "
							);
						return;
				}
				if (( CheckDlls()) == FALSE) {
					Addtolist(
						0,
						1,
						"dbghelp.dll or symsrv.dll or both are missing "
						"please put them from windbg installation to ollydbg dir"
						);
					return;
				}
				if (( hProcess	= OpenProcess(
					PROCESS_ALL_ACCESS,
					FALSE,
					Plugingetvalue(VAL_PROCESSID)
					) ) == NULL) {
						Addtolist(
							0,
							1,
							"no debuggee found OpenProcess Failed"
							);
						return;
				}
				SymSetOptions(
					SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE
					);
				if ( ! SymInitialize( hProcess, Envvar, FALSE ) ) {
					Addtolist ( 
						0,
						1,
						"SymInitialize failed"
						);
					CloseHandle(hProcess);
					return;
				}
				ModuleTable = (t_table *)Plugingetvalue(
					VAL_MODULES
					);
				if(ModuleTable !=0) {
					sorted = ModuleTable->data;
					for(i=0;i<sorted.n;i++)
					{
						Module = (t_module *) ( (int)sorted.data+(i*sorted.itemsize));
						Addtolist(
							0,
							1,
							"Loading Symbols For %s",
							Module->path
							);
						if ( ( dwModuleBase = SymLoadModuleEx(
							hProcess,
							NULL,
							Module->path,
							"",
							0,
							0,
							0,
							NULL
							) ) == 0 ) {
								Addtolist(
									0,
									1,
									"SymLoadModuleEx %s Failed last error returned was %x",
									Module->path,
									GetLastError()
									);								
						}
						SymGetModuleInfo64(
							hProcess,
							dwModuleBase,
							&im
							);
						if ( im.SymType == SymExport || im.SymType == SymNone )
						{
							Addtolist(
								0,
								1,
								"Only Export symbols - skipping module %s",
								Module->name
								);
						}
						if( ( SymEnumSymbols(
							hProcess,
							dwModuleBase,
							"*",
							EnumerateSymbols,
							NULL
							))==FALSE) {
								Addtolist(
									0,
									1,
									"SymEnumSymbols Failed for %x Getlast Error returned %x",
									dwModuleBase,
									GetLastError()
									);
								break;
						}
						Module++;
					}
				}
				SymCleanup(hProcess);
				CloseHandle(hProcess);
				free(Envvar);
				break;
			case 1:
				MessageBox(
					hwmain,
					"SymbolLoader\n"
					"Copyright (C) From Genesis to Eternity Blabberer",
					"SymbolLoader",MB_OK|MB_ICONINFORMATION
					);
				break;
			default:
				break;
		};
	};
};
int _cdecl CheckDlls()
{
	char			Filename[MAX_PATH];
	char			Ollydrive[0x20];
	char			Ollydir[MAX_PATH - sizeof("ollydbg.exe"

];
	WIN32_FIND_DATA	Foundfile;
	HANDLE			hProcess;
	HANDLE			hFile;
	DWORD			status = TRUE;
	if (( hProcess	= OpenProcess(
		PROCESS_ALL_ACCESS,
		FALSE,
		GetCurrentProcessId()
		) ) == NULL) {
			Addtolist(
				0,
				1,
				"OpenProcess Ollydbg Failed"
				);
			return FALSE;
	}
	if( ( GetModuleFileNameEx (
		hProcess,
		NULL,
		Filename,
		MAX_PATH
		) ) == 0 ) {
			Addtolist(
				0,
				1,
				"Path to Ollydbg.exe is not available"
				);
			CloseHandle(hProcess);
			return FALSE;
	}
	Addtolist(
		0,
		1,
		"path to ollydbg.exe is %s",
		Filename
		);
	_splitpath_s(
		Filename,
		Ollydrive,
		sizeof(Ollydrive),
		(char *)&Ollydir,
		(MAX_PATH - sizeof("ollydbg.exe"

),
		NULL,
		0,
		NULL,
		0
		);
	_makepath_s(
		Filename,
		MAX_PATH,
		Ollydrive,
		Ollydir,
		"dbghelp",
		"dll"
		);
	Addtolist(
		0,
		1,
		"checking for presence %s ",
		Filename
		);
	if ( ( hFile = FindFirstFile(
		Filename,
		&Foundfile
		) ) == INVALID_HANDLE_VALUE) {
			Addtolist(
				0,
				1,
				"you need the latest dbghelp.dll in the directory where ollydbg resides"
				);
			status = FALSE;
	}
	FindClose(hFile);
	_makepath_s(
		Filename,
		MAX_PATH,
		Ollydrive,
		Ollydir,
		"symsrv",
		"dll"					
		);
	Addtolist(
		0,
		1,
		"checking for presence %s ",
		Filename
		);
	if ( ( hFile = FindFirstFile(
		Filename,
		&Foundfile
		) ) == INVALID_HANDLE_VALUE) {
			Addtolist(
				0,
				1,
				"you need the latest symsrv.dll in the directory where ollydbg resides"
				);
			status = FALSE;
	}
	FindClose(hFile);
	CloseHandle(hProcess);
	return status;
}