めいくりぷとのブログ

技術的なことやゲームのことやら・・・

kousin

ネタないので、某プロテクタのお話。

プロセス検出の際にOpenProcessフックすれば潰れて、知らないうちにNtOpenProcessが呼ばれるようになって、また知らないうちに、コピーされたntdllのNtOpenProcessが呼ばれるようになったけど、それ自体はどうにかする必要がなく、その前後で呼ばれる Get/SetKernelObjectSecurity をtrue返すだけで潰れるっていう・・・。エラー処理やら割りとガバガバなプロテクタのお話でした。

まあ潰し方によってはプロセス検出に限らず、ほぼ全てが潰れてしまうっていう・・・。

kousin

xigncode あっぷでーと

なんでもコピーすりゃ良いって訳でも無いと思う。
アプデ前からコピーされたntdll.dllがマッピングされてて、NtQueryVirtualMemoryでモジュール列挙するやら、NtOpenProcessからプロセス検出やらあったけど、
アプデ後に、user32.dllとkernelbase.dllのコピーされたdllもマッピングされるようになって、ウィンドウ検出のGetWindowThreadProcessIdとかもコピーされたuser32.dllから呼ばれるようになった。

まあ結局API hookだけで完結したから、どうでも良いけど...

ネタが無いので、ただそれだけの記事。

ドライバ

_Success_(NT_SUCCESS(return))
NTSTATUS
NTAPI
ZwOpenDriver(
	_In_  PUNICODE_STRING DeviceName,
	_Out_ PHANDLE		  DeviceHandle
	)
{
	HANDLE Device;

	if (!DeviceName || !DeviceHandle)
		return STATUS_INVALID_PARAMETER;

	Device = CreateFile(DeviceName->Buffer,
		GENERIC_READ | GENERIC_WRITE | FILE_GENERIC_EXECUTE,
		0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, 0);

	if (Device != NULL &&
		Device != INVALID_HANDLE_VALUE)
	{
		*DeviceHandle = Device;
		return STATUS_SUCCESS;
	}

	return STATUS_UNSUCCESSFUL;
}

_Success_(NT_SUCCESS(return))
NTSTATUS
NTAPI
ZwCloseDriver(
	_In_ HANDLE DeviceHandle
	)
{
	return NtClose(DeviceHandle);
}

_Success_(NT_SUCCESS(return))
NTSTATUS
NTAPI
ZwStartDriver(
	_In_  PUNICODE_STRING DeviceName,
	_In_  PUNICODE_STRING DeviceDosName,
	_Out_ PHANDLE		  DeviceHandle
	)
{
	SC_HANDLE SCManager;
	SC_HANDLE ServiceHandle;
	HANDLE Device;

	if (!DeviceName || !DeviceDosName || !DeviceHandle)
		return STATUS_INVALID_PARAMETER;

	SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	ServiceHandle = OpenService(SCManager, DeviceName->Buffer, SERVICE_ALL_ACCESS);

	if (ServiceHandle == NULL)
	{
		ServiceHandle = CreateService(SCManager, DeviceName->Buffer, DeviceName->Buffer, 
			SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
			SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
			DeviceName->Buffer, NULL, NULL, NULL, NULL, NULL);

		if (ServiceHandle == NULL)
		{
			CloseServiceHandle(SCManager);
			return STATUS_INVALID_HANDLE;
		}
	}

	if (StartService(ServiceHandle, 0, NULL) == FALSE)
	{
		ULONG ErrorCode = GetLastError();
		if (ErrorCode != ERROR_SERVICE_ALREADY_RUNNING)
		{
			DeleteService(ServiceHandle);
			CloseServiceHandle(ServiceHandle);
			CloseServiceHandle(SCManager);
			return NULL;
		}
	}

	Device = CreateFile(DeviceDosName->Buffer, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
		OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

	if (Device == INVALID_HANDLE_VALUE)
	{
		SERVICE_STATUS ServiceStatus = { 0 };
		ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
		return STATUS_INVALID_HANDLE;
	}	

	*DeviceHandle = Device;
	CloseServiceHandle(ServiceHandle);
	CloseServiceHandle(SCManager);	

	return STATUS_SUCCESS;
}

_Success_(NT_SUCCESS(return))
NTSTATUS
NTAPI
ZwStopDriver(
	_In_ PUNICODE_STRING DeviceName
	)
{
	SC_HANDLE SCManager;
	SC_HANDLE ServiceHandle;
	NTSTATUS Status;

	if (!DeviceName)
		return STATUS_INVALID_PARAMETER;

	SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	ServiceHandle = OpenService(SCManager, DeviceName->Buffer, SERVICE_ALL_ACCESS);

	SERVICE_STATUS ServiceStatus = { 0 };
	ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);

	Status = STATUS_UNSUCCESSFUL;
	if (DeleteService(ServiceHandle))
		Status = STATUS_SUCCESS;

	CloseServiceHandle(ServiceHandle);
	CloseServiceHandle(SCManager);

	return Status;
}

マニュアルマッピングされたモジュールをマニュアルリンクする。

_Success_(return != NULL)
PTEB 
WINAPI 
GetThreadEnvironmentBlock(
	)
{
#ifdef _WIN64
	return reinterpret_cast<PTEB>(__readgsqword(0x00000030));
#else
	return reinterpret_cast<PTEB>(__readfsdword(0x00000018));
#endif
}

_Success_(return != NULL)
PPEB 
WINAPI 
GetProcessEnvironmentBlock(
	)
{
	PTEB pThreadEnvironmentBlock;

	pThreadEnvironmentBlock = GetThreadEnvironmentBlock();
	if (pThreadEnvironmentBlock)
		return pThreadEnvironmentBlock->ProcessEnvironmentBlock;

	return NULL;
}

_Success_(return != NULL)
PPEB_LDR_DATA 
WINAPI 
GetLoaderData(
	)
{
	PPEB pProcessEnvironmentBlock;
	PPEB_LDR_DATA pLdrData;

	pProcessEnvironmentBlock = GetProcessEnvironmentBlock();
	if (pProcessEnvironmentBlock != NULL)
	{
		pLdrData = pProcessEnvironmentBlock->Ldr;
		if (pLdrData != NULL)
		{
			return pLdrData;
		}
	}

	return NULL;
}

_Success_(return != FALSE)
BOOL 
WINAPI 
AddLoaderEntry(
	_In_ LPCWSTR lpcwszImageName, 
	_In_ LPVOID lpBaseAddress,
	_In_ SIZE_T uSizeOfImage
	)
{
	PLDR_DATA_TABLE_ENTRY pNewEntry;
	PLDR_DATA_TABLE_ENTRY pLastEntry;
	PPEB_LDR_DATA pLdrData;
	PLIST_ENTRY pBaseEntry;
	PIMAGE_NT_HEADERS pNtHeaders;

	pLdrData = GetLoaderData();
	if (!pLdrData)
		return FALSE;

	pLastEntry = reinterpret_cast<PLDR_DATA_TABLE_ENTRY>(pLdrData->InLoadOrderModuleList.Blink);
	if (!pLastEntry)
		return FALSE;

	pNtHeaders = ImageNtHeader(lpBaseAddress);
	if (!pNtHeaders)
		return FALSE;

	pNewEntry = new LDR_DATA_TABLE_ENTRY;
	pNewEntry->InLoadOrderModuleList.Flink = pLastEntry->InLoadOrderModuleList.Flink;
	pNewEntry->InLoadOrderModuleList.Blink = pLastEntry->InLoadOrderModuleList.Blink;
	pNewEntry->InMemoryOrderModuleList = pLastEntry->InMemoryOrderModuleList;
	pNewEntry->InInitializationOrderModuleList = pLastEntry->InInitializationOrderModuleList;
	pNewEntry->BaseAddress = lpBaseAddress;
	pNewEntry->SizeOfImage = uSizeOfImage;
	pNewEntry->EntryPoint = (PVOID)pNtHeaders->OptionalHeader.AddressOfEntryPoint;
	pNewEntry->Flags = pLastEntry->Flags;
	pNewEntry->LoadCount = pLastEntry->LoadCount;
	pNewEntry->TlsIndex = pLastEntry->TlsIndex;
	pNewEntry->HashTableEntry = pLastEntry->HashTableEntry;
	pNewEntry->CheckSum = pNtHeaders->OptionalHeader.CheckSum;
	pNewEntry->TimeDateStamp = pNtHeaders->FileHeader.TimeDateStamp;
	pNewEntry->EntryPointActivationContext = pLastEntry->EntryPointActivationContext;
	pNewEntry->PatchInformation = pLastEntry->PatchInformation;
	pNewEntry->ForwarderLinks = pLastEntry->ForwarderLinks;
	pNewEntry->ServiceTagLinks = pLastEntry->ServiceTagLinks;
	pNewEntry->StaticLinks = pLastEntry->StaticLinks;
	RtlInitUnicodeString(&pNewEntry->FullDllName, (L"C:\\" + std::wstring(lpcwszImageName)).c_str());
	RtlInitUnicodeString(&pNewEntry->BaseDllName, lpcwszImageName);

	pLastEntry->InLoadOrderModuleList.Flink = reinterpret_cast<PLIST_ENTRY>(pNewEntry);

	//Log(L"xmodule: %s, %08X, %08X\n", lpcwszImageName, lpBaseAddress, uSizeOfImage);

	return TRUE;
}

マニュアルマッピングされたシステムモジュールをアンロードして、正規のモジュールにすり替える。

    EXTERN_C
    NTSTATUS
    NTAPI LdrLoadDll(
        _In_  PWCHAR          PathToFile OPTIONAL,
        _In_  ULONG           Flags OPTIONAL,
        _In_  PUNICODE_STRING ModuleFileName,
        _Out_ PHANDLE         ModuleHandle
        );
 
    VOID Detour_LdrLoadDll()
    {
        static decltype(&LdrLoadDll) _LdrLoadDll = LdrLoadDll;
 
        decltype(&LdrLoadDll) LdrLoadDll_Hook = [](
            _In_  PWCHAR          PathToFile OPTIONAL,
            _In_  ULONG           Flags OPTIONAL,
            _In_  PUNICODE_STRING ModuleFileName,
            _Out_ PHANDLE         ModuleHandle) -> NTSTATUS
        {
            IMAGE_EXPORT_DIRECTORY *pExportDirectory;
            NTSTATUS ntStatus;
            HMODULE  hModule;
            HMODULE  hModuleOriginal;
 
            ntStatus = _LdrLoadDll(PathToFile, Flags, ModuleFileName, ModuleHandle);
            if (NT_SUCCESS(ntStatus))
            {
                hModule = reinterpret_cast<HMODULE>(*ModuleHandle);
                if (hModule != NULL)
                {
                    pExportDirectory = ImageExportDirectory(reinterpret_cast<PVOID>(hModule));
                    if (pExportDirectory != NULL)
                    {
                        hModuleOriginal = GetModuleHandleA(reinterpret_cast<LPCSTR>(PBYTE(hModule) + pExportDirectory->Name));
                        if (hModuleOriginal != NULL &&
                            hModuleOriginal != hModule)
                        {
                            // _tprintf(L"%p, %s\n", hModule, ModuleFileName->Buffer);
                            FreeLibrary(hModule);
                            *ModuleHandle = hModuleOriginal;
                        }
                    }                  
                }
            }
 
            return ntStatus;
        };
 
        DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_LdrLoadDll), LdrLoadDll_Hook);
    }