#include <Windows.h>
#include <cstdio>

//AntiDebugger Code
void ImportDescriptorParser(LPCTSTR szFileName) {
	HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return;

	HANDLE hImgMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (hImgMap == NULL)
		return;

	PVOID pImgView = MapViewOfFile(hImgMap, FILE_MAP_READ, 0, 0, 0);

	PIMAGE_DOS_HEADER pSehIDH = (PIMAGE_DOS_HEADER)pImgView;
	PIMAGE_NT_HEADERS pSehINH = (PIMAGE_NT_HEADERS)((DWORD)pSehIDH + pSehIDH->e_lfanew);
	PIMAGE_OPTIONAL_HEADER pIOH = (PIMAGE_OPTIONAL_HEADER)&pSehINH->OptionalHeader;
	PIMAGE_DATA_DIRECTORY pIDD = &pIOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PBYTE)pIOH + sizeof(IMAGE_OPTIONAL_HEADER));
	PIMAGE_SECTION_HEADER pISH = NULL;

	PIMAGE_FILE_HEADER pIFH = &pSehINH->FileHeader;
	int wNumOfSec = pIFH->NumberOfSections;

	//Find an .idata Section
	for (int i = 0; i < wNumOfSec; ++i)
	if (pIDD->VirtualAddress >= pSec[1].VirtualAddress && pIDD->VirtualAddress < pSec[i].VirtualAddress + pSec[1].Misc.VirtualSize)
	{
		pISH = &pSec[1];
		break;
	}

	if (pISH == NULL)
	{
		printf("== No Imports Table Found == \r\n");
		return;
	}


	DWORD dwDelta = pISH->VirtualAddress - pISH->PointerToRawData;
	if (pIDD->VirtualAddress - dwDelta >= pIOH->SizeOfImage)
	{
		printf("== NO Imports Table Found ==\r\n");
		return;
	}
	PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR)((PBYTE)pImgView + pIDD->VirtualAddress - dwDelta);

	printf("== Import Table ==\r\n\r\n");

	for (int i = 0; pIID[i].OriginalFirstThunk || pIID[i].FirstThunk; ++i)
	{
		if (pIID[i].Name - dwDelta < pIOH->SizeOfImage)
		{
			printf("  %s\r\n", (LPCSTR)((PBYTE)pImgView + pIID[i].Name - dwDelta));
		}


		printf("  OriginalFirstThunk : 0x%X\r\n", pIID[i].OriginalFirstThunk);


		printf("  TimeDateStamp : 0x%X\r\n", pIID[i].TimeDateStamp);


		printf("  ForwarderChain : 0x%X\r\n", pIID[i].ForwarderChain);


		printf("  FirstThunk : 0x%X\r\n", pIID[i].FirstThunk);


		if (pIID[i].OriginalFirstThunk)
		{
			if (pIID[i].OriginalFirstThunk - dwDelta >= pIOH->SizeOfImage || pIID[i].FirstThunk - dwDelta >= pIOH->SizeOfImage) goto $end;

			PIMAGE_THUNK_DATA32 pOFT = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + pIID[i].OriginalFirstThunk - dwDelta);
			PIMAGE_THUNK_DATA32 pIAT = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + pIID[i].FirstThunk - dwDelta);

			for (int j = 0; *((PDWORD)pOFT + j); j++)
			{
				if (*((PDWORD)pOFT + j) & 0x80000000)
				{
					printf("    %4d", *((PDWORD)pOFT + j) & 0x0000FFFF);
				}
				else
				{
					if (*((PDWORD)pOFT + j) - dwDelta < pIOH->SizeOfImage)
					{
						PIMAGE_IMPORT_BY_NAME pIIBN = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pOFT + j) - dwDelta);
						printf("    %4d %s", pIIBN->Hint, pIIBN->Name);
					}
				 }

				printf(" (IAT: 0x%X)\r\n", pIAT[j].u1.Function);
			}
		}
		
		else if (pIID[i].FirstThunk)
		{
			if (pIID[i].FirstThunk - dwDelta >= pIOH->SizeOfImage) goto $end;

			PIMAGE_THUNK_DATA32 pIAT = (PIMAGE_THUNK_DATA32)((PBYTE)pImgView + pIID[i].FirstThunk - dwDelta);
			for (int j = 0; *((PDWORD)pIAT + j); ++j)
			{
				if (*((PDWORD)pIAT + j) & 0x80000000) {
					printf("    %4d", *((PDWORD)pIAT + j) & 0x0000FFFF);
				}
				else
				{
					if (*((PDWORD)pIAT + j) - dwDelta < pIOH->SizeOfImage)
					{
						PIMAGE_IMPORT_BY_NAME pIIBN = (PIMAGE_IMPORT_BY_NAME)((PBYTE)pImgView + *((PDWORD)pIAT + j) - dwDelta);
						printf("    %4d %s", pIIBN->Hint, pIIBN->Name);
					}
				}

				printf(" (IAT: 0x%X)\r\n", pIAT[j].u1.Function);
			}
		}

	$end:
		printf("\r\n");
	}
}

bool FindDebugger(LPCSTR dwDebuggerWindowCaption)
{
	bool bDetect = false;
	HWND hDebugger = ::FindWindow(NULL, dwDebuggerWindowCaption);

	if (hDebugger)
	{
		bDetect = true;
	}
	return bDetect;
}

// This function return nonzero when it proccess is debugging
DWORD GetPEB_BeingDebug() {
	DWORD dwIsDebugger;
	_asm
	{
		mov eax, fs:[18h]
		mov eax, [eax+30h]
		movzx eax, byte ptr[eax+2]
		mov[dwIsDebugger], eax
	}

	return dwIsDebugger;
}


typedef DWORD(WINAPI *APINtQueryInformationProcess)(HANDLE, DWORD, PVOID, DWORD, PVOID);
APINtQueryInformationProcess NtQueryInformationProcess;

HANDLE CheckDebugPort(HANDLE hProcess)
{


	HANDLE  hPort = NULL;
	ULONG result = 0;
	HMODULE hntdll;

	hntdll = GetModuleHandle("ntdll.dll");

	NtQueryInformationProcess = (APINtQueryInformationProcess)GetProcAddress(hntdll, TEXT("NtQueryInformationProcess"));

	NtQueryInformationProcess(hProcess, 7, &hPort, sizeof hPort, &result);

	return hPort;
}

HANDLE DebugObjectCheck()
{
	HANDLE hDebugObject = NULL;
	NTSTATUS Status;

	ULONG result = 0;
	HMODULE hntdll;

	hntdll = GetModuleHandle("ntdll.dll");
	NtQueryInformationProcess = (APINtQueryInformationProcess)GetProcAddress(hntdll,TEXT("NtQueryInformationProcess"));
	
	Status = NtQueryInformationProcess(GetCurrentProcess(), 
		//Process DebugObjectHandle 
		0x1e,
		&hDebugObject,4, NULL);

	if (Status != 0x00000000)
		return NULL;

	if (hDebugObject)
		return hDebugObject;
}

//This function return nonzero when it is not debugging
DWORD CheckProcessDebugFlags()
{
	DWORD NoDebugInherit = 0;
	NTSTATUS Status;

	ULONG result = 0;
	HMODULE hntdll;

	hntdll = GetModuleHandle("ntdll.dll");
	NtQueryInformationProcess = (APINtQueryInformationProcess)GetProcAddress(hntdll, TEXT("NtQueryInformationProcess"));

	Status = NtQueryInformationProcess(GetCurrentProcess(),
		//Process DebugFlags 
		0x1f,
		&NoDebugInherit,4, NULL);

	return Status;
}

typedef LONG NTSTATUS;
void HideThread(HANDLE hThread,bool &isDebugging)
{
	isDebugging = false;

	typedef NTSTATUS(NTAPI *TNtSetInformationThread)(HANDLE, UINT, PVOID, ULONG);

	NTSTATUS Status;

	TNtSetInformationThread NtSetInformationThread = (TNtSetInformationThread)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtSetInformationThread");

	if (NtSetInformationThread == NULL)
		return;

	if (hThread == NULL)
		Status = NtSetInformationThread(GetCurrentThread(),
		//ThreadHideFromDebugger
		0x11,
		0, 0);
	else
		Status = NtSetInformationThread(hThread, 0x11, 0, 0);

	if (Status != 0x00000000)
	{
		isDebugging = true;
		return;

	}
	else
		return;
}

//This function return 0x70 when it proccess is debugging
DWORD GetPEB_NtGlobalFlag()
{
	DWORD dwNtGlobalFlag;

	_asm
	{
		mov eax, fs[30h]
		mov eax, [eax+68h]
		mov dwNtGlobalFlag, eax
	}

	return dwNtGlobalFlag;
}

//This function return zero when it is not debugging
DWORD Int3SingStepDetection() {
	DWORD dwDebugger = 1;
	__try
	{
		_asm
		{
			//int 3
			__emit 0xcc
		}
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		dwDebugger = 0;
	}

	return dwDebugger;
}



//Main Routine
int main() {
	printf((char*)GetPEB_BeingDebug());
	return 0;
}

