読者です 読者をやめる 読者になる 読者になる

めいくりぷとのブログ

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

D3D9 Hook Project Template

特にネタないので、D3D9 Hook (x86/x64)のプロジェクトテンプレート作ったついでに...
IDirect3D9/IDirect3DDevice9/IDirect3DStateBlock9.hpp はtypedefで定義してるだけのラップファイルです
基本的にはIDirect3D9/IDirect3DDevice9しか使わないので、必要になり次第追加していこうかなと。


追記:
静的の関数ポインタに動的で関数ポインタ渡すのを関数外からやってるせいで、普通に取得できてないっていう。
まあ使う時に書き直したらいいや。

#ifndef _DIRECT3D9_HPP
#define _DIRECT3D9_HPP

#include "IDirect3D9.hpp"
#include "IDirect3DDevice9.hpp"
#include "IDirect3DStateBlock9.hpp"

#ifdef _M_X86
typedef DWORD DWORD_XX;
#else 
typedef DWORD64 DWORD_XX;
#endif

class Direct3D9
{
public:
	static Direct3D9 * GetInstance();

	BOOL Initialize();

	_IDirect3D9 *m_pD3Dint;				// IDirect3D9
	_IDirect3DDevice9 *m_pD3Ddev;			// IDirect3DDevice 
	_IDirect3DStateBlock9 *m_pD3Dstate;		// IDirect3DStateBlock9

private:
	DWORD_XX *m_pVtbl;
};

#endif

#include "stdafx.h"
#include "Direct3D9.hpp"

#include <d3d9.h>
#include <d3dx9.h>

Direct3D9 * Direct3D9::GetInstance()
{
	static Direct3D9 *pInstance = new Direct3D9;
	return pInstance;
}

BOOL Direct3D9::Initialize()
{
	IDirect3D9 *pD3Dint = NULL;
	IDirect3DDevice9 *pD3Ddev = NULL;
	D3DPRESENT_PARAMETERS d3dpp;

	HWND hWnd = CreateWindow(_T("BUTTON"), _T("Temp Window"), WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, NULL, NULL);
	if (hWnd == NULL)
		return FALSE;

	pD3Dint = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3Dint == NULL)
	{
		DestroyWindow(hWnd);
		return FALSE;
	}

	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hWnd;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

	HRESULT hResult = pD3Dint->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pD3Ddev);
	if (hResult != D3D_OK)
	{
		pD3Dint->Release();
		DestroyWindow(hWnd);
		return FALSE;
	}

	// IDirect3DDevice9
	m_pVtbl = reinterpret_cast<DWORD_XX*>(pD3Ddev);
	m_pVtbl = reinterpret_cast<DWORD_XX*>(m_pVtbl[0]);
	m_pD3Ddev = reinterpret_cast<_IDirect3DDevice9*>(&m_pVtbl);

	// IDirect3D
	m_pVtbl = reinterpret_cast<DWORD_XX*>(pD3Dint);
	m_pVtbl = reinterpret_cast<DWORD_XX*>(m_pVtbl[0]);
	m_pD3Dint = reinterpret_cast<_IDirect3D9*>(&m_pVtbl);

	DestroyWindow(hWnd);

	return TRUE;
}
#include "stdafx.h"

#include "Hook.hpp"
#include "detour.hpp"
#include "Direct3D9.hpp"

#define D3D_DEVICE Direct3D9::GetInstance()->m_pD3Ddev->vfptr
#define D3D_INTERFACE Direct3D9::GetInstance()->m_pD3Dint->vfptr

static pfnDrawIndexedPrimitive _DrawIndexedPrimitive = reinterpret_cast<pfnDrawIndexedPrimitive>(D3D_DEVICE->DrawIndexedPrimitive);
pfnDrawIndexedPrimitive DrawIndexedPrimitive_Hook = [](
	D3DPRIMITIVETYPE Type, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount) -> HRESULT
{
	IDirect3DVertexBuffer9* pvBuffer;
	UINT uOffset, uStride;

	if (D3D_DEVICE->GetStreamSource(0, &pvBuffer, &uOffset, &uStride) == S_OK)
		pvBuffer->Release();

	if (uStride == 32)
	{
		D3D_DEVICE->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
		_DrawIndexedPrimitive(Type, BaseVertexIndex, MinVertexIndex, NumVertices, StartIndex, PrimitiveCount);
		D3D_DEVICE->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
	}

	return _DrawIndexedPrimitive(Type, BaseVertexIndex, MinVertexIndex, NumVertices, StartIndex, PrimitiveCount);
};

static pfnCreateQuery _CreateQuery = reinterpret_cast<pfnCreateQuery>(D3D_DEVICE->CreateQuery);
pfnCreateQuery CreateQuery_Hook = [](
	D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery) -> HRESULT
{
	if (Type == D3DQUERYTYPE_OCCLUSION)
		Type = D3DQUERYTYPE_TIMESTAMP;

	return _CreateQuery(Type, ppQuery);
};

static pfnGetDirect3D _GetDirect3D = reinterpret_cast<pfnGetDirect3D>(D3D_DEVICE->GetDirect3D);
pfnGetDirect3D GetDirect3D_Hook = [](
	IDirect3D9 **ppD3D9) -> HRESULT
{
	HRESULT hr = _GetDirect3D(ppD3D9);
	if (SUCCEEDED(hr))
		*ppD3D9 = reinterpret_cast<IDirect3D9*>(D3D_INTERFACE);
	return hr;
};

BOOL Init()
{
	if (!Direct3D9::GetInstance()->Initialize())
		return FALSE;

	DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_DrawIndexedPrimitive), DrawIndexedPrimitive_Hook);
	DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_CreateQuery), CreateQuery_Hook);
	DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_GetDirect3D), GetDirect3D_Hook);

	return TRUE;
}

Wrapper opengl32.dll

// opengl32.dll export function
namespace opengl32
{
	pfnglAlphaFunc	_glAlphaFunc;
	pfnglBegin	_glBegin;
	pfnglBitmap	_glBitmap;
	pfnglBlendFunc	_glBlendFunc;
	pfnglClear	_glClear;
        ....
        ....
}

namespace opengl32
{
	typedef void (WINAPI * pfnglAlphaFunc)(GLenum func, GLclampf ref);
	typedef void (WINAPI * pfnglBegin)(GLenum mode);
	typedef void (WINAPI * pfnglBitmap)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
	typedef void (WINAPI * pfnglBlendFunc)(GLenum sfactor, GLenum dfactor);
	typedef void (WINAPI * pfnglClear)(GLbitfield mask);
        ....
        ....
}

かなり面倒ですが、opengl32.dll のエクスポート関数(360個)を自動生成なりで書いていきます。
自分は自動生成という概念すら思い浮かばなかったので、1つ1つ書いていきましたが...


そして、必要な関数だけ、opengl32.dllのそれに対応したエクスポート関数のポインタを渡します。
で、フックしたい関数を __declspec(dllexport) を使ってやればオーケー


以上

D3D9 Texture をフックする

// IDirect3DDevice9.cpp

HRESULT APIENTRY _IDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture)
{
	IDirect3DDevice9 *pDevice = NULL;

	if (pTexture != NULL)
	{
		if (reinterpret_cast<_IDirect3DTexture9*>(pTexture)->GetDevice(&pDevice) == D3D_OK)
		{
			if (pDevice == this)
			{
				return m_pD3Ddev->SetTexture(Stage, reinterpret_cast<_IDirect3DTexture9*>(pTexture)->m_pD3Dtex);
			}
		}
	}

	return m_pD3Ddev->SetTexture(Stage, pTexture);
}

// IDirect3DTexture9.hpp

#ifndef _D3D9TEX_HPP
#define _D3D9TEX_HPP

#include "d3d9.hpp"

interface _IDirect3DTexture9 : public IDirect3DTexture9
{
	_IDirect3DTexture9(IDirect3DTexture9 **ppTex, IDirect3DDevice9 *pIDirect3DDevice9, UINT Width, UINT Height, D3DFORMAT Format)
	{
		m_pD3Dtex = *ppTex;
		m_pD3Ddev = pIDirect3DDevice9;
		m_Width = Width;
		m_Height = Height;
		m_Format = Format;
	}

	UINT m_Width, m_Height;
	D3DFORMAT m_Format;

	// callback interface
	IDirect3DTexture9 *m_pD3Dtex;
	IDirect3DDevice9 *m_pD3Ddev;

	// original interface
	STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj);
	STDMETHOD_(ULONG, AddRef)();
	STDMETHOD_(ULONG, Release)();
	STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice);
	STDMETHOD(SetPrivateData)(REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags);
	STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData);
	STDMETHOD(FreePrivateData)(REFGUID refguid);
	STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew);
	STDMETHOD_(DWORD, GetPriority)();
	STDMETHOD_(void, PreLoad)();
	STDMETHOD_(D3DRESOURCETYPE, GetType)();
	STDMETHOD_(DWORD, SetLOD)(DWORD LODNew);
	STDMETHOD_(DWORD, GetLOD)();
	STDMETHOD_(DWORD, GetLevelCount)();
	STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType);
	STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)();
	STDMETHOD_(void, GenerateMipSubLevels)();
	STDMETHOD(GetLevelDesc)(UINT Level, D3DSURFACE_DESC *pDesc);
	STDMETHOD(GetSurfaceLevel)(UINT Level, IDirect3DSurface9** ppSurfaceLevel);
	STDMETHOD(LockRect)(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
	STDMETHOD(UnlockRect)(UINT Level);
	STDMETHOD(AddDirtyRect)(CONST RECT* pDirtyRect);
};

#endif

// IDirect3DTexture9.cpp
#include "stdafx.h"

#include "IDirect3DTexture9.hpp"

HRESULT APIENTRY _IDirect3DTexture9::QueryInterface(REFIID riid, void** ppvObj)
{
	return m_pD3Dtex->QueryInterface(riid, ppvObj);
}

ULONG APIENTRY _IDirect3DTexture9::AddRef()
{
	return m_pD3Dtex->AddRef();
}

ULONG APIENTRY _IDirect3DTexture9::Release()
{
	return m_pD3Dtex->Release();
}

HRESULT APIENTRY _IDirect3DTexture9::GetDevice(IDirect3DDevice9** ppDevice)
{
	*ppDevice = m_pD3Ddev;
	return D3D_OK;
}

HRESULT APIENTRY _IDirect3DTexture9::SetPrivateData(REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags)
{
	return m_pD3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}

HRESULT APIENTRY _IDirect3DTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData)
{
	return m_pD3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}

HRESULT APIENTRY _IDirect3DTexture9::FreePrivateData(REFGUID refguid)
{
	return m_pD3Dtex->FreePrivateData(refguid);
}

DWORD APIENTRY _IDirect3DTexture9::SetPriority(DWORD PriorityNew)
{
	return m_pD3Dtex->SetPriority(PriorityNew);
}

DWORD APIENTRY _IDirect3DTexture9::GetPriority()
{
	return m_pD3Dtex->GetPriority();
}

void APIENTRY _IDirect3DTexture9::PreLoad()
{
	return m_pD3Dtex->PreLoad();
}

D3DRESOURCETYPE APIENTRY _IDirect3DTexture9::GetType()
{
	return m_pD3Dtex->GetType();
}

DWORD APIENTRY _IDirect3DTexture9::SetLOD(DWORD LODNew)
{
	return m_pD3Dtex->SetLOD(LODNew);
}

DWORD APIENTRY _IDirect3DTexture9::GetLOD()
{
	return m_pD3Dtex->GetLOD();
}

DWORD APIENTRY _IDirect3DTexture9::GetLevelCount()
{
	return m_pD3Dtex->GetLevelCount();
}

HRESULT APIENTRY _IDirect3DTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType)
{
	return m_pD3Dtex->SetAutoGenFilterType(FilterType);
}

D3DTEXTUREFILTERTYPE APIENTRY _IDirect3DTexture9::GetAutoGenFilterType()
{
	return m_pD3Dtex->GetAutoGenFilterType();
}

void APIENTRY _IDirect3DTexture9::GenerateMipSubLevels()
{
	return m_pD3Dtex->GenerateMipSubLevels();
}

HRESULT APIENTRY _IDirect3DTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc)
{
	return m_pD3Dtex->GetLevelDesc(Level, pDesc);
}

HRESULT APIENTRY _IDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel)
{
	return m_pD3Dtex->GetSurfaceLevel(Level, ppSurfaceLevel);
}

HRESULT APIENTRY _IDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
{
	return m_pD3Dtex->LockRect(Level, pLockedRect, pRect, Flags);
}

HRESULT APIENTRY _IDirect3DTexture9::UnlockRect(UINT Level)
{
	return m_pD3Dtex->UnlockRect(Level);
}

HRESULT APIENTRY _IDirect3DTexture9::AddDirtyRect(CONST RECT* pDirtyRect)
{
	return m_pD3Dtex->AddDirtyRect(pDirtyRect);
}

ハードウェアID(PC固有)情報を調べる

Anti-Cheatプロテクターにも HWID BAN というものがありますよね。
今回は、それらを紹介していきたいと思います。


マイナーな手法として、以下のように、NIC(ネットワークインターフェースカード)のGUIDを列挙し、それに対応したMac-Addressを取得するといったものです。

#include "stdafx.h"

#include <NtDDNdis.h>
#include <string>
#include <strsafe.h>
#include <IPHlpApi.h>
#pragma comment(lib, "IPHlpApi.lib")

BOOL WINAPI GetPhysicalMacAddress()
{
	IP_INTERFACE_INFO *pInterface = { 0 };
	HANDLE hDevice;
	DWORD dwLength;

	std::wstring wsBuffer;
	WCHAR szPath[MAX_PATH];
	UCHAR uch[6];
	DWORD dwIoObj = OID_802_3_CURRENT_ADDRESS;

	if (GetInterfaceInfo(pInterface, &dwLength) == ERROR_INSUFFICIENT_BUFFER)
		pInterface = (IP_INTERFACE_INFO *)malloc(dwLength);

	if (GetInterfaceInfo(pInterface, &dwLength) == NO_ERROR)
	{
		for (int i = 0; i < pInterface->NumAdapters; i++)
		{
			wsBuffer = pInterface->Adapter[i].Name;

			StringCchPrintf(szPath, MAX_PATH, TEXT("\\\\.\\%s"), wsBuffer.substr(wsBuffer.size() - 38, 38).c_str());

			hDevice = CreateFile(szPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

			if (hDevice == INVALID_HANDLE_VALUE)
				continue;

			if (!DeviceIoControl(hDevice, IOCTL_NDIS_QUERY_GLOBAL_STATS, &dwIoObj, sizeof(dwIoObj), &uch, sizeof(uch), &dwLength, NULL))
				continue;

			_tprintf(TEXT("%s - %02X:%02X:%02X:%02X:%02X:%02X\n"), 
				szPath, uch[0], uch[1], uch[2], uch[3], uch[4], uch[5]);
		}

		return TRUE;
	}

	return FALSE;
}

int main()
{
	GetPhysicalMacAddress();

	getchar();

    return 0;
}

↑の実行結果
\\.\{XXXXXXXX-AAAA-BBBB-CCCC-YYYYYYYYYYYY} - AA:BB:CC:DD:EE:FF
というようになります。興味がある方は実行してみてください。


他にも、HDDのシリアルナンバーを取得するものがありますが、かなりメジャーな手法ですので、簡単にbypass出来てしまいます。

API Check

こちらを参考にしてAPI Checkを作ってみました。
mhllchan.hatenablog.com


www.youtube.com

比較元のDLL(copy_ntdll等)をどのように持ってくるかで強度さが変わってくるでしょう。

ラッパーAPI _GetProcAddress

GetProcAddressのラッパーAPI書いてみました。
第二引数に序数を指定した場合は対応出来ていません。

#define EXPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]

FARPROC WINAPI _GetProcAddress(
    _In_ HMODULE hModule,
    _In_ LPCSTR  lpProcName)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
    if (hModule == NULL) {
        pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
    }

    __try {
        if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
            SetLastError(ERROR_BAD_EXE_FORMAT);
            return NULL;
        }

        PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<PBYTE>(pDosHeader) + pDosHeader->e_lfanew);
        if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
            SetLastError(ERROR_INVALID_EXE_SIGNATURE);
            return NULL;
        }
        if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
            SetLastError(ERROR_EXE_MARKED_INVALID);
            return NULL;
        }

        PIMAGE_EXPORT_DIRECTORY pExportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<PBYTE>(pDosHeader) + pNtHeader->EXPORT_DIRECTORY.VirtualAddress);
        LPDWORD lpdwName = reinterpret_cast<LPDWORD>(reinterpret_cast<PBYTE>(pDosHeader) + pExportDir->AddressOfNames);
        LPDWORD lpdwFunction = reinterpret_cast<LPDWORD>(reinterpret_cast<PBYTE>(pDosHeader) + pExportDir->AddressOfFunctions);
        LPWORD lpwOrdinals = reinterpret_cast<LPWORD>(reinterpret_cast<PBYTE>(pDosHeader) + pExportDir->AddressOfNameOrdinals);

        for (int i = 0; i < pExportDir->NumberOfNames; i++) {
            WORD wOrdinal = lpwOrdinals[i];
            LPSTR pszName = reinterpret_cast<LPSTR>(reinterpret_cast<PBYTE>(pDosHeader) + lpdwName[i]);
            LPVOID lpvFunction = reinterpret_cast<LPVOID>(reinterpret_cast<PBYTE>(pDosHeader) + lpdwFunction[wOrdinal]);

            if (strcmp(pszName, lpProcName) == 0) {
                SetLastError(NO_ERROR);
                return (FARPROC)lpvFunction;
            }
        }

        SetLastError(ERROR_INVALID_DATA);
        return NULL;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        SetLastError(ERROR_EXE_MARKED_INVALID);
        return NULL;
    }
}

PEBを用いたモジュール隠蔽 + α

PEBを理解するために適当に書いたコードです。

///////////////////////////////////////////////////////////
// peb.hpp
///////////////////////////////////////////////////////////
#pragma once
 
#ifndef Padding
#define Padding(x) struct { unsigned char __padding##x[(x)]; };
#endif
 
typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
 
typedef struct _PEB_LDR_DATA
{
    Padding(0x0C);
    LIST_ENTRY InLoadOrderModuleList; // 0x0c
    LIST_ENTRY InMemoryOrderModuleList; // 0x14
    LIST_ENTRY InInitializationOrderModuleList; // 0x1c
}PEB_LDR_DATA, PPEB_LDR_DATA;
 
typedef struct _PEB
{
#ifdef _WIN64
    Padding(0x18);
#else
    Padding(0x0C);
#endif
    PEB_LDR_DATA* Ldr;
}PEB, *PPEB;
 
typedef struct _LDR_DATA_TABLE_ENTRY
{
    LIST_ENTRY            InLoadOrderModuleList;
    LIST_ENTRY            InMemoryOrderModuleList;
    LIST_ENTRY            InInitializationOrderModuleList;
    PVOID                 BaseAddress;
    PVOID                 EntryPoint;
    ULONG                 SizeOfImage;
    UNICODE_STRING        FullDllName;
    UNICODE_STRING        BaseDllName;
    ULONG                 Flags;
    USHORT                LoadCount;
    USHORT                TlsIndex;
    LIST_ENTRY            HashTableEntry;
    union
    {
        LIST_ENTRY HashLinks;
        struct
        {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
    };
    union
    {
        ULONG TimeDateStamp;
        PVOID LoadedImports;
    };
    _ACTIVATION_CONTEXT *   EntryPointActivationContext;
    PVOID                   PatchInformation;
    LIST_ENTRY              ForwarderLinks;
    LIST_ENTRY              ServiceTagLinks;
    LIST_ENTRY              StaticLinks;
    PVOID                   ContextInformation;
    DWORD                   OriginalBase;
    LARGE_INTEGER           LoadTime;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
///////////////////////////////////////////////////////////
// dllmain.cpp
///////////////////////////////////////////////////////////
 
#include "stdafx.h"
 
#include "peb.hpp"
#include <algorithm>
 
#define UNLINK(x)                   \
    (x).Flink->Blink = (x).Blink;   \
    (x).Blink->Flink = (x).Flink;
 
// hide module
VOID WINAPI HideModule(__in HMODULE hModule)
{
#ifdef _WIN64
    PEB *pPEB = reinterpret_cast<PEB*>(__readfsqword(0x60));
#else
    PEB *pPEB = reinterpret_cast<PEB*>(__readfsdword(0x30));
#endif
 
    PLDR_DATA_TABLE_ENTRY pData;
    PLIST_ENTRY           pEntry;
 
    pEntry = pPEB->Ldr->InLoadOrderModuleList.Flink;
 
    while (pEntry != &pPEB->Ldr->InLoadOrderModuleList &&
        pEntry != NULL)
    {
        pData = CONTAINING_RECORD(pEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
        if (pData->BaseAddress == hModule)
        {
#ifdef _DEBUG
            _tprintf(TEXT("\nDll name: %s \nBase: %08X \nEntryPoint: %08X \n"),
                pData->BaseDllName.Buffer, pData->BaseAddress, pData->EntryPoint);
#endif
 
            UNLINK(pData->InLoadOrderModuleList);
            UNLINK(pData->InInitializationOrderModuleList);
            UNLINK(pData->InMemoryOrderModuleList);
        }
 
        pEntry = pEntry->Flink;
    }
}
 
// remove pe header
VOID WINAPI EraseHeaders(__in HMODULE hModule)
{
    DWORD i, size, protect;
 
    IMAGE_DOS_HEADER *pDosHeader = PIMAGE_DOS_HEADER(hModule);
    IMAGE_NT_HEADERS *pNtHeaders = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<PBYTE>(hModule) + pDosHeader->e_lfanew);
 
    size = sizeof(IMAGE_DOS_HEADER);
 
    if (VirtualProtect(pDosHeader, size, PAGE_READWRITE, &protect))
    {
        for (i = 0; i < size; i++)
            *(BYTE*)((BYTE*)pDosHeader + i) = 0x00;
    }
 
    size = sizeof(IMAGE_NT_HEADERS);
 
    if (pNtHeaders && VirtualProtect(pNtHeaders, size, PAGE_READWRITE, &protect))
    {
        for (i = 0; i < size; i++)
            *(BYTE*)((BYTE*)pNtHeaders + i) = 0x00;
    }
}

終わり。