/////////////////////////////////////////////////////////////////////////////////
// Module32HLP.cpp
//

#include "stdafx.h"
#include "Module32HLP.h"

#pragma warning( disable : 4996 4090 4127 )


//////////////////////////////////////////////////////////////////////
// CModule32HLP Class
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CModule32HLP::CModule32HLP(
    HANDLE hProcessHandle
    )
: m_hProcessHandle(hProcessHandle)
, m_pModuleListTable(NULL)
, m_pModuleInfoEntry(NULL)
, m_pHeaderEntry(NULL)
, m_pRemotePEHeaders(NULL)
, m_pCopyOf_idata(NULL)
, m_dw_idataSize(0)
, m_pPebBaseAddress(NULL)
, m_pProcessParameters(NULL)
, m_pwsProcessModuleFileName(NULL)
, m_hImageBaseAddress(NULL)
, m_dw_idataRVA(0)
, m_pRemote_idata(NULL)
, m_pCopyImpDirectoty(NULL)
, m_pAddressOfFunctions(0)
, m_pAddressOfNames(0)
, m_nFunctions(0)
, m_nNames(0)
, m_dwNameIndx(0)
, m_pCopyOf_edata(NULL)
, m_dwUpdateAddr(0)
, m_pImageBase(NULL)
, m_dwExportTableRVA(0)
, m_dw_edataSize(0)
, m_dwImportUpdateValue(0)
, m_pImportDescriptor(NULL)
, m_pImportThunkArray(NULL)
, m_pIporterModule(NULL)
{
    NTSTATUS                        dwNTStatus;
    PROCESS_BASIC_INFORMATION       stProcessInfo;
    PRTL_USER_PROCESS_PARAMETERS    pProcessParameters;
    PPEB                            pstPEB;
    PEB                             stPEB;
    RTL_USER_PROCESS_PARAMETERS     stProcessParameters;
    PWSTR                           pwsCurrentDirectory;
    PWSTR                           wsBuffer;
    DWORD                           dwNubOfChars;
    PBYTE                           pMemory1;
    RtlZeroMemory(
        &m_stModuleListTable,
        sizeof(m_stModuleListTable)
        );
    RtlZeroMemory(
        &m_stModuleInfoEntry,
        sizeof(m_stModuleInfoEntry)
        );
    RtlZeroMemory(
        &m_wsStringBuffer,
        sizeof(m_wsStringBuffer)
        );
    RtlZeroMemory(
        &m_stPEImageHeaders,
        sizeof(m_stPEImageHeaders)
        );
    RtlZeroMemory(
        &m_wsProcessModuleFileName,
        sizeof(m_wsProcessModuleFileName)
        );
    dwNTStatus = NtQueryInformationProcess(
        hProcessHandle,
        ProcessBasicInformation,
        PVOID(&stProcessInfo),
        sizeof(stProcessInfo),
        NULL
        );
    assert(NT_SUCCESS(dwNTStatus));
    m_pPebBaseAddress = (PBYTE) stProcessInfo.PebBaseAddress;
    if (m_hProcessHandle == NtCurrentProcess())
    {
        pstPEB = (PPEB) m_pPebBaseAddress;
        m_pModuleListTable = pstPEB->Ldr;
        m_pHeaderEntry = (PLDR_DATA_TABLE_ENTRY) (&m_pModuleListTable->InLoadOrderModuleList);
        m_hImageBaseAddress = HINSTANCE(pstPEB->ImageBaseAddress);
        pProcessParameters = pstPEB->ProcessParameters;
        m_pProcessParameters = (PRTL_USER_PROCESS_PARAMETERS) new BYTE[pProcessParameters->AllocationSize];
        assert((pProcessParameters->Flags & PPFLAG_NORMALIZED) != 0);
        RtlDeNormalizeProcessParams(
            pProcessParameters
            );
        RtlCopyMemory(
            m_pProcessParameters,
            pProcessParameters,
            pProcessParameters->AllocationSize
            );
        RtlNormalizeProcessParams(
            pProcessParameters
            );
        RtlNormalizeProcessParams(
            m_pProcessParameters
            );
        m_pwsProcessModuleFileName = m_pProcessParameters->ImagePathName.Buffer;
        if (pProcessParameters->CurrentDirectory.Length > 0)
        {
            pwsCurrentDirectory = wcscpy(
                m_wsCurrentDirectory,
                pProcessParameters->CurrentDirectory.Buffer
                );
            assert(NULL != pwsCurrentDirectory);
        }
        else
        {
            dwNubOfChars = GetCurrentDirectoryW(
                260,
                m_wsCurrentDirectory
                );
            assert(dwNubOfChars > 0);
        }
        RtlInitUnicodeString(
            &m_pProcessParameters->CurrentDirectory,
            m_wsCurrentDirectory
            );
        return;
    }
    // get remote Process Parameters
    dwNTStatus = NtReadVirtualMemory(
        hProcessHandle,
        m_pPebBaseAddress,
        PVOID(&stPEB),
        sizeof(stPEB),
        NULL
        );
    assert(NT_SUCCESS(dwNTStatus));
    m_hImageBaseAddress = HINSTANCE(stPEB.ImageBaseAddress);
    pProcessParameters = stPEB.ProcessParameters;
    dwNTStatus = NtReadVirtualMemory(
        hProcessHandle,
        pProcessParameters,
        PVOID(&stProcessParameters),
        sizeof(stProcessParameters),
        NULL
        );
    assert(NT_SUCCESS(dwNTStatus));
    m_pProcessParameters = (PRTL_USER_PROCESS_PARAMETERS) new BYTE[stProcessParameters.AllocationSize];
    dwNTStatus = NtReadVirtualMemory(
        hProcessHandle,
        pProcessParameters,
        PVOID(m_pProcessParameters),
        stProcessParameters.AllocationSize,
        NULL
        );
    assert(NT_SUCCESS(dwNTStatus));
    if ((m_pProcessParameters->Flags & PPFLAG_NORMALIZED) != 0)
    {
        dwNTStatus = NtReadVirtualMemory(
            hProcessHandle,
            m_pProcessParameters->ImagePathName.Buffer,
            PVOID(m_wsProcessModuleFileName),
            stProcessParameters.ImagePathName.MaximumLength,
            NULL
            );
        assert(NT_SUCCESS(dwNTStatus));
        m_pwsProcessModuleFileName = m_wsProcessModuleFileName;
        if (m_pProcessParameters->CurrentDirectory.Length > 0)
        {
            dwNTStatus = NtReadVirtualMemory(
                hProcessHandle,
                m_pProcessParameters->CurrentDirectory.Buffer,
                PVOID(m_wsCurrentDirectory),
                stProcessParameters.CurrentDirectory.MaximumLength,
                NULL
                );
            assert(NT_SUCCESS(dwNTStatus));
            RtlInitUnicodeString(
                &m_pProcessParameters->CurrentDirectory,
                m_wsCurrentDirectory
                );
        }
        else
        {
            m_wsCurrentDirectory[0] = 0;
        }
        RtlInitUnicodeString(
            &m_pProcessParameters->ImagePathName,
            m_wsProcessModuleFileName
            );
        // Normalize local copy of RTL_USER_PROCESS_PARAMETERS
        if (m_pProcessParameters->SearchPaths.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->SearchPaths.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->SearchPaths.Buffer = wsBuffer;
        }
        if (m_pProcessParameters->CommandLine.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->CommandLine.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->CommandLine.Buffer = wsBuffer;
        }
        if (m_pProcessParameters->usConsoleTitle.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->usConsoleTitle.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->usConsoleTitle.Buffer = wsBuffer;
        }
        if (m_pProcessParameters->usDesktop.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->usDesktop.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->usDesktop.Buffer = wsBuffer;
        }
        if (m_pProcessParameters->usShellInfo.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->usShellInfo.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->usShellInfo.Buffer = wsBuffer;
        }
        if (m_pProcessParameters->usRuntimeData.Length > 0)
        {
            wsBuffer = PWSTR(PBYTE(m_pProcessParameters)
                + DWORD_PTR(PBYTE(m_pProcessParameters->usRuntimeData.Buffer) - PBYTE(pProcessParameters)));
            m_pProcessParameters->usRuntimeData.Buffer = wsBuffer;
        }
    }
    else
    {
        if (stProcessParameters.CurrentDirectory.Length > 0)
        {
            pMemory1 = PBYTE(pProcessParameters) + DWORD(stProcessParameters.CurrentDirectory.Buffer);
            dwNTStatus = NtReadVirtualMemory(
                hProcessHandle,
                pMemory1,
                PVOID(m_wsCurrentDirectory),
                stProcessParameters.CurrentDirectory.MaximumLength,
                NULL
                );
            assert(NT_SUCCESS(dwNTStatus));
            RtlNormalizeProcessParams(
                m_pProcessParameters
                );
            RtlInitUnicodeString(
                &m_pProcessParameters->CurrentDirectory,
                m_wsCurrentDirectory
                );
        }
        else
        {
            m_wsCurrentDirectory[0] = 0;
            RtlNormalizeProcessParams(
                m_pProcessParameters
                );
        }
        m_pwsProcessModuleFileName = m_pProcessParameters->ImagePathName.Buffer;
    }
    if (NULL == stPEB.Ldr)
    {
        return;
    }
    // read remote Modules Table
    dwNTStatus = NtReadVirtualMemory(
        hProcessHandle,
        PVOID(stPEB.Ldr),
        PVOID(&m_stModuleListTable),
        sizeof(m_stModuleListTable),
        NULL
        );
    assert(NT_SUCCESS(dwNTStatus));
    m_pHeaderEntry = PLDR_DATA_TABLE_ENTRY(PBYTE(stPEB.Ldr) + FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList));
    m_pModuleListTable = &m_stModuleListTable;
}

CModule32HLP::~CModule32HLP()
{
    if(m_pProcessParameters != NULL)
    {
        delete m_pProcessParameters;
        m_pProcessParameters = NULL;
    }
    if (NULL != m_pCopyOf_edata)
    {
        delete m_pCopyOf_edata;
        m_pCopyOf_edata = NULL;
    }
    if (NULL != m_pCopyOf_idata)
    {
        delete m_pCopyOf_idata;
        m_pCopyOf_idata = NULL;
    }
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::GetFirstModuleInfoEntry( )
{
    NTSTATUS    dwNTStatus;
    if(m_hProcessHandle == NULL) {
        return NULL;
    }
    m_pModuleInfoEntry = NULL;
    if(m_hProcessHandle == NtCurrentProcess( ))
    {
        if (m_pModuleListTable->InLoadOrderModuleList.Flink == &m_pModuleListTable->InLoadOrderModuleList)
        {
            return NULL;
        }
        m_pModuleInfoEntry = PLDR_DATA_TABLE_ENTRY(m_pModuleListTable->InLoadOrderModuleList.Flink);
        return m_pModuleInfoEntry;
    }
    // read remote Module Information Entry
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_stModuleListTable.InLoadOrderModuleList.Flink,
        PVOID(&m_stModuleInfoEntry),
        sizeof(m_stModuleInfoEntry),
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    if (m_stModuleInfoEntry.InMemoryEntryLinks.Flink == PLIST_ENTRY(m_pHeaderEntry))
    {
        return NULL;
    }
    m_pModuleInfoEntry = &m_stModuleInfoEntry;
    return m_pModuleInfoEntry;
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::GetNextModuleInfoEntry( )
{
    NTSTATUS    dwNTStatus;
    if ((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return NULL;
    }
    if (m_pModuleInfoEntry->InMemoryEntryLinks.Flink == PLIST_ENTRY(m_pHeaderEntry))
    {
        return NULL;
    }
    if (m_hProcessHandle == NtCurrentProcess( ))
    {
        m_pModuleInfoEntry = (PLDR_DATA_TABLE_ENTRY) m_pModuleInfoEntry->InMemoryEntryLinks.Flink;
        return m_pModuleInfoEntry;
    }
    // read remote Module Information Entry
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_stModuleInfoEntry.InMemoryEntryLinks.Flink,
        PVOID(&m_stModuleInfoEntry),
        sizeof m_stModuleInfoEntry,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    return m_pModuleInfoEntry;
}

PWSTR CModule32HLP::GetModuleNameW( )
{
    NTSTATUS    dwNTStatus;
    if ((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return NULL;
    }
    if (m_hProcessHandle == NtCurrentProcess( ))
    {
        return m_pModuleInfoEntry->ShortDllName.Buffer;
    }
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_stModuleInfoEntry.ShortDllName.Buffer,
        m_wsStringBuffer,
        m_stModuleInfoEntry.ShortDllName.MaximumLength,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    return m_wsStringBuffer;
}

PWSTR CModule32HLP::GetModuleFileNameW( )
{
    NTSTATUS    dwNTStatus;
    if((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return NULL;
    }
    if (m_hProcessHandle == NtCurrentProcess( )) {
        return m_pModuleInfoEntry->FullDllName.Buffer;
    }
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_stModuleInfoEntry.FullDllName.Buffer,
        m_wsStringBuffer,
        m_stModuleInfoEntry.FullDllName.MaximumLength,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    return m_wsStringBuffer;
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::FindModule( PCWSTR pwsModuleName )
{
    WCHAR   wsBuffer[260];
    PWSTR   pwsFindPos;
    PWSTR   pwsCurrentModuleName;
    PLDR_DATA_TABLE_ENTRY   pResult;
    int     ncResult;
    if (m_hProcessHandle == NULL)
    {
        return NULL;
    }
    pwsFindPos = PWSTR(wcsrchr( pwsModuleName, L'.' ));
    if ((pwsFindPos == NULL) || (pwsFindPos == pwsModuleName))
    {
        wcscpy( wsBuffer, pwsModuleName );
        pwsFindPos = wcscat( wsBuffer, L".dll" );
    }
    else
    {
        pwsFindPos = PWSTR(pwsModuleName);
    }
    for(
        pResult = GetFirstModuleInfoEntry( );
        pResult != NULL;
        pResult = GetNextModuleInfoEntry( ))
    {
        pwsCurrentModuleName = GetModuleNameW();
        ncResult = _wcsicmp(
            pwsCurrentModuleName,
            pwsFindPos
            );
        if (ncResult == 0)
        {
            return pResult;
        }
    }
    return NULL;
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::FindModule(HMODULE hModuleHandle)
{
    PLDR_DATA_TABLE_ENTRY   pResult;
    if (m_hProcessHandle == NULL)
    {
        return NULL;
    }
    for(
        pResult = GetFirstModuleInfoEntry( );
        pResult != NULL;
        pResult = GetNextModuleInfoEntry( ))
    {
        if (pResult->DllBase == hModuleHandle) {
            return pResult;
        }
    }
    return NULL;
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::FindModuleByAddress(DWORD_PTR dwAddress)
{
    PLDR_DATA_TABLE_ENTRY   pResult;
    if (m_hProcessHandle == NULL)
    {
        return NULL;
    }
    for(
        pResult = GetFirstModuleInfoEntry( );
        pResult != NULL;
        pResult = GetNextModuleInfoEntry( ))
    {
        DWORD_PTR   dwStartAddress = (DWORD_PTR) pResult->DllBase;
        DWORD_PTR   dwEndAddress = dwStartAddress + pResult->dwImageSize;
        if ((dwAddress >= dwStartAddress)&&(dwAddress <= dwEndAddress))
        {
            return pResult;
        }
    }
    return NULL;
}

PLDR_DATA_TABLE_ENTRY CModule32HLP::FindModule( PCSTR psModuleName )
{
    NTSTATUS        dwNTStatus;
    WCHAR           wsBuffer[260];
    ANSI_STRING     asModuleName;
    UNICODE_STRING  usModuleName = { 0, sizeof wsBuffer, wsBuffer };
    RtlInitAnsiString(
        &asModuleName,
        psModuleName
        );
    dwNTStatus = RtlAnsiStringToUnicodeString(
        &usModuleName,
        &asModuleName,
        FALSE
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    return  FindModule(wsBuffer);
}

PIMAGE_NT_HEADERS CModule32HLP::GetImageHeaders( )
{
    NTSTATUS    dwNTStatus;
    PBYTE       pPointToPEHeaders;
    DWORD       dwPEHeadersRVA;
    DWORD       dwPEHeadersSize;
    DWORD       dwSignature;
    if((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return NULL;
    }
    if(m_hProcessHandle == NtCurrentProcess( )) {
        return RtlImageNtHeader(
            m_pModuleInfoEntry->DllBase
            );
    }
    RtlZeroMemory(
        &m_stPEImageHeaders,
        sizeof(m_stPEImageHeaders)
        );
    pPointToPEHeaders = PBYTE(m_stModuleInfoEntry.DllBase) + 0x3C;
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        pPointToPEHeaders,
        &dwPEHeadersRVA,
        sizeof(dwPEHeadersRVA),
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    if ((dwPEHeadersRVA == 0) || (dwPEHeadersRVA >= m_stModuleInfoEntry.dwImageSize))
    {
        return NULL;
    }
    m_pRemotePEHeaders = PBYTE(m_stModuleInfoEntry.DllBase) + dwPEHeadersRVA;
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_pRemotePEHeaders,
        &dwSignature,
        sizeof(dwSignature),
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    if (dwSignature != IMAGE_NT_SIGNATURE)
    {
        return NULL;
    }
    dwPEHeadersSize = (dwPEHeadersRVA + sizeof(m_stPEImageHeaders) > m_stModuleInfoEntry.dwImageSize)
        ? DWORD(m_stModuleInfoEntry.dwImageSize - dwPEHeadersRVA) : sizeof(m_stPEImageHeaders);
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_pRemotePEHeaders,
        &m_stPEImageHeaders,
        dwPEHeadersSize,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        return NULL;
    }
    return &m_stPEImageHeaders;
}

#pragma warning(push)
#pragma warning(disable: 4701 4703)
bool CModule32HLP::EvaluteForwardExport(
    PCSTR psForwardRef,
    RREAL_EXPORT_DESCRIPTOR rExportDescriptor
    )
{
    CHAR                    sDLLName[260];
    PCSTR                   psFunctionName;
    DWORD                   dwFindPos;
    PBYTE                   pImageBase;
    NTSTATUS                dwNTStatus;
    DWORD_PTR               dwImageSize;
    PBYTE                   pCopyOf_edata;
    DWORD                   dw_edataSize;
    PBYTE                   pRemoteAddr1;
    DWORD                   dwExportTableRVA;
    PIMAGE_EXPORT_DIRECTORY pExportDirectory;
    PDWORD                  pAddressOfFunctions;
    PDWORD                  pArrayOfNameRVAs;
    PWORD                   pAddressOfNameOrdinals;
    DWORD_PTR               dwUpdateAddr;
    DWORD                   dwOrdBase;
    DWORD                   nFunctions;
    DWORD                   dwThunk;
    PCSTR                   psForwardNest;
    DWORD                   dwOrdIndx;
    DWORD                   dwFunctionAddr;
    PBYTE                   pFunctionAddr;
    DWORD                   nNames;
    DWORD                   dwNameIndx;
    DWORD                   dwNameOrgIndx;
    bool                    bReturn;
    PLDR_DATA_TABLE_ENTRY   pModuleEntry;
    PIMAGE_NT_HEADERS       pPEImageHeaders;
    PCSTR                   pNameString;
    DWORD                   dwMin;
    DWORD                   dwMax;
    WCHAR                   wsBuffer[260];
    PWSTR                   pwsBuffer;
    ANSI_STRING             asModuleName;
    UNICODE_STRING          usModuleName = { 0, sizeof wsBuffer, wsBuffer };
    WORD                    wWSTRLength;
    psFunctionName = strrchr(psForwardRef, '.') + 1;
    dwFindPos = DWORD(psFunctionName - psForwardRef) - 1;
    strncpy( sDLLName, psForwardRef, dwFindPos );
    sDLLName[dwFindPos] = 0;
    pModuleEntry = FindModule(sDLLName);
    if (pModuleEntry == NULL)
    {
        RtlInitAnsiString(
            &asModuleName,
            sDLLName
            );
        dwNTStatus = RtlAnsiStringToUnicodeString(
            &usModuleName,
            &asModuleName,
            FALSE
            );
        assert(NT_SUCCESS(dwNTStatus));
        wWSTRLength = (usModuleName.Length >> 1);
        pwsBuffer = wcsncpy(
            m_wsLastModuleName,
            usModuleName.Buffer,
            wWSTRLength + 1
            );
        assert(NULL != pwsBuffer);
        m_wsLastModuleName[wWSTRLength] = 0;
        pNameString = strcpy(
            m_sLastExportName,
            psFunctionName
            );
        assert(NULL != pNameString);
        rExportDescriptor.cwsDllName = m_wsLastModuleName;
        rExportDescriptor.pEntryPoint = NULL;
        rExportDescriptor.wOrderIndex = WORD(-1);
        rExportDescriptor.csExportName = m_sLastExportName;
        return true;
    }
    pPEImageHeaders = GetImageHeaders();
    if (NULL == pPEImageHeaders)
    {
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        if (psFunctionName[0] == '#')
        {
            psFunctionName += 1;
            pImageBase = PBYTE(pModuleEntry->DllBase);
            dwImageSize = pModuleEntry->dwImageSize;
            if (m_stPEImageHeaders.OptionalHeader.NumberOfRvaAndSizes == 0)
            {
                // Image not have Export Section
                return false;
            }
            dw_edataSize = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
            if (dw_edataSize == 0) {
                // Image not have Export Endtries
                return false;
            }
            dwExportTableRVA = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
            pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pImageBase + dwExportTableRVA);
            pAddressOfFunctions = PDWORD(pImageBase + pExportDirectory->AddressOfFunctions);
            pArrayOfNameRVAs = PDWORD(pImageBase + pExportDirectory->AddressOfNames);
            pAddressOfNameOrdinals = PWORD(pImageBase + pExportDirectory->AddressOfNameOrdinals);
            dwOrdBase = pExportDirectory->Base;
            nFunctions = pExportDirectory->NumberOfFunctions;
            nNames = pExportDirectory->NumberOfNames;
            dwThunk = strtoul(psFunctionName, NULL, 10);
            dwOrdIndx = dwThunk - dwOrdBase;
            if (dwOrdIndx >= nFunctions)
            {
                return false;
            }
            dwFunctionAddr = pAddressOfFunctions[dwOrdIndx];
            if ((dwFunctionAddr < dwExportTableRVA)
                || (dwFunctionAddr >= dwExportTableRVA + dw_edataSize))
            {
                pFunctionAddr = pImageBase + dwFunctionAddr;
            }
            else
            {
                psForwardNest = PCSTR(pImageBase + dwFunctionAddr);
                bReturn = EvaluteForwardExport(
                    psForwardNest,
                    rExportDescriptor
                    );
                return bReturn;
            }
            if (nNames < 16)
            {
                // linear search
                for (dwNameIndx = 0; dwNameIndx<nNames; dwNameIndx++)
                {
                    if (dwOrdIndx == pAddressOfNameOrdinals[dwNameIndx])
                    {
                        pNameString = PCSTR(pImageBase + pArrayOfNameRVAs[dwNameIndx]);
                        break;
                    }
                    if (dwOrdIndx < pAddressOfNameOrdinals[dwNameIndx])
                    {
                        pNameString = "";
                        break;
                    }
                }
            }
            else
            {
                // binary search
                dwMin = 0;
                dwMax = nNames - 1;
                do
                {
                    dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx = dwMin];
                    if (dwOrdIndx == dwNameOrgIndx)
                    {
                        pNameString = PCSTR(pImageBase + pArrayOfNameRVAs[dwNameIndx]);
                        break;
                    }
                    if (dwOrdIndx < dwNameOrgIndx)
                    {
                        pNameString = "";
                        break;
                    }
                    dwMin++;
                    dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx = dwMax];
                    if (dwOrdIndx == dwNameOrgIndx)
                    {
                        pNameString = PCSTR(pImageBase + pArrayOfNameRVAs[dwNameIndx]);
                        break;
                    }
                    if (dwOrdIndx > dwNameOrgIndx)
                    {
                        pNameString = "";
                        break;
                    }
                    dwMax--;
                    if (dwMax < dwMin)
                    {
                        pNameString = "";
                        break;
                    }
                    dwNameIndx = ((dwMax - dwMin + 1) >> 1) + dwMin;
                    dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx];
                    if (dwOrdIndx == dwNameOrgIndx)
                    {
                        pNameString = PCSTR(pImageBase + pArrayOfNameRVAs[dwNameIndx]);
                        break;
                    }
                    if (dwMax == dwMin)
                    {
                        pNameString = "";
                        break;
                    }
                    if (dwOrdIndx > dwNameOrgIndx)
                    {
                        dwMin = dwNameIndx + 1;
                    }
                    else
                    {
                        dwMax = dwNameIndx - 1;
                    }
                } while (true);
            }
            rExportDescriptor.cwsDllName = GetModuleNameW();
            rExportDescriptor.pEntryPoint = pFunctionAddr;
            rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
            rExportDescriptor.csExportName = pNameString;
            return true;
        }
        return GetExportByName(
            psFunctionName,
            rExportDescriptor
            );
    }
    if (psFunctionName[0] == '#')
    {
        psFunctionName += 1;
        pImageBase  = PBYTE(m_stModuleInfoEntry.DllBase);
        dwImageSize = m_stModuleInfoEntry.dwImageSize;
        if (m_stPEImageHeaders.OptionalHeader.NumberOfRvaAndSizes == 0)
        {
            // Image not have Export Section
            return false;
        }
        dw_edataSize = m_stPEImageHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
        if (dw_edataSize == 0) {
            // Image not have Export Endtries
            return false;
        }
        pCopyOf_edata = new BYTE[dw_edataSize];
        if (pCopyOf_edata == NULL)
        {
            return false;
        }
        dwExportTableRVA = m_stPEImageHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        pRemoteAddr1 = pImageBase + dwExportTableRVA;
        dwNTStatus = NtReadVirtualMemory(
            m_hProcessHandle,
            pRemoteAddr1,
            pCopyOf_edata,
            dw_edataSize,
            NULL
            );
        if (!NT_SUCCESS(dwNTStatus))
        {
            delete pCopyOf_edata;
            return false;
        }
        pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pCopyOf_edata);
        dwUpdateAddr = DWORD_PTR(pCopyOf_edata - dwExportTableRVA);
        pAddressOfFunctions = PDWORD(dwUpdateAddr + pExportDirectory->AddressOfFunctions);
        pArrayOfNameRVAs = PDWORD(dwUpdateAddr + pExportDirectory->AddressOfNames);
        pAddressOfNameOrdinals = PWORD(dwUpdateAddr + pExportDirectory->AddressOfNameOrdinals);
        dwOrdBase = pExportDirectory->Base;
        nFunctions = pExportDirectory->NumberOfFunctions;
        nNames     = pExportDirectory->NumberOfNames;
        dwThunk = strtoul( psFunctionName, NULL, 10 );
        dwOrdIndx = dwThunk - dwOrdBase;
        if(dwOrdIndx >= nFunctions) {
            delete pCopyOf_edata;
            return false;
        }
        dwFunctionAddr = pAddressOfFunctions[dwOrdIndx];
        if ((dwFunctionAddr < dwExportTableRVA)
            || (dwFunctionAddr >= dwExportTableRVA + dw_edataSize))
        {
            pFunctionAddr = pImageBase + dwFunctionAddr;
        }
        else
        {
            psForwardNest = PCSTR(dwUpdateAddr + dwFunctionAddr);
            bReturn = EvaluteForwardExport(
                psForwardNest,
                rExportDescriptor
                );
            delete pCopyOf_edata;
            return bReturn;
        }
        if (nNames < 16)
        {
            // linear search
            for (dwNameIndx = 0; dwNameIndx<nNames; dwNameIndx++)
            {
                if (dwOrdIndx == pAddressOfNameOrdinals[dwNameIndx])
                {
                    pNameString = PCSTR(dwUpdateAddr + pArrayOfNameRVAs[dwNameIndx]);
                    break;
                }
                if (dwOrdIndx < pAddressOfNameOrdinals[dwNameIndx])
                {
                    pNameString = "";
                    break;
                }
            }
        }
        else
        {
            // binary search
            dwMin = 0;
            dwMax = nNames - 1;
            do
            {
                dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx = dwMin];
                if (dwOrdIndx == dwNameOrgIndx)
                {
                    pNameString = PCSTR(dwUpdateAddr + pArrayOfNameRVAs[dwNameIndx]);
                    break;
                }
                if (dwOrdIndx < dwNameOrgIndx)
                {
                    pNameString = "";
                    break;
                }
                dwMin++;
                dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx = dwMax];
                if (dwOrdIndx == dwNameOrgIndx)
                {
                    pNameString = PCSTR(dwUpdateAddr + pArrayOfNameRVAs[dwNameIndx]);
                    break;
                }
                if (dwOrdIndx > dwNameOrgIndx)
                {
                    pNameString = "";
                    break;
                }
                dwMax--;
                if (dwMax < dwMin)
                {
                    pNameString = "";
                    break;
                }
                dwNameIndx = ((dwMax - dwMin + 1) >> 1) + dwMin;
                dwNameOrgIndx = pAddressOfNameOrdinals[dwNameIndx];
                if (dwOrdIndx == dwNameOrgIndx)
                {
                    pNameString = PCSTR(dwUpdateAddr + pArrayOfNameRVAs[dwNameIndx]);
                    break;
                }
                if (dwMax == dwMin)
                {
                    pNameString = "";
                    break;
                }
                if (dwOrdIndx > dwNameOrgIndx)
                {
                    dwMin = dwNameIndx + 1;
                }
                else
                {
                    dwMax = dwNameIndx - 1;
                }
            } while (true);
        }
        rExportDescriptor.cwsDllName = GetModuleNameW();
        rExportDescriptor.pEntryPoint = pFunctionAddr;
        rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
        strcpy(
            m_sExportName,
            pNameString
            );
        rExportDescriptor.csExportName = m_sExportName;
        delete pCopyOf_edata;
        return true;
    }
    return GetExportByName(
        psFunctionName,
        rExportDescriptor
        );
}
#pragma warning(pop)


bool CModule32HLP::EnumExportStart(PCWSTR pwsModuleName)
{
    PLDR_DATA_TABLE_ENTRY   pModuleEntry;
    PIMAGE_NT_HEADERS       pPEImageHeaders;
    PBYTE                   pRemoteAddr1;
    NTSTATUS                dwNTStatus;
    if (NULL != m_pCopyOf_edata)
    {
        delete m_pCopyOf_edata;
        m_pCopyOf_edata = NULL;
    }
    pModuleEntry = FindModule(pwsModuleName);
    if ((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return false;
    }
    pPEImageHeaders = GetImageHeaders();
    if (NULL == pPEImageHeaders)
    {
        return false;
    }
    m_pImageBase = PBYTE(m_pModuleInfoEntry->DllBase);
    if (pPEImageHeaders->OptionalHeader.NumberOfRvaAndSizes == 0)
    {
        // Image not have Export Section
        return false;
    }
    m_dw_edataSize = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    if (m_dw_edataSize == 0)
    {
        // Image not have Export Endtries
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        m_dwExportTableRVA = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        m_pExportDirectory = PIMAGE_EXPORT_DIRECTORY(m_pImageBase + m_dwExportTableRVA);
        m_pAddressOfFunctions = PDWORD(m_pImageBase + m_pExportDirectory->AddressOfFunctions);
        m_pAddressOfNames = PDWORD(m_pImageBase + m_pExportDirectory->AddressOfNames);
        m_pAddressOfNameOrdinals = PWORD(m_pImageBase + m_pExportDirectory->AddressOfNameOrdinals);
        m_nFunctions = m_pExportDirectory->NumberOfFunctions;
        m_nNames = m_pExportDirectory->NumberOfNames;
        m_dwNameIndx = 0;
    }
    m_pCopyOf_edata = new BYTE[m_dw_edataSize];
    if (m_pCopyOf_edata == NULL)
    {
        return false;
    }
    m_dwExportTableRVA = m_stPEImageHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    pRemoteAddr1 = m_pImageBase + m_dwExportTableRVA;
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        pRemoteAddr1,
        m_pCopyOf_edata,
        m_dw_edataSize,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        delete m_pCopyOf_edata;
        m_pCopyOf_edata = NULL;
        return false;
    }
    m_pExportDirectory = PIMAGE_EXPORT_DIRECTORY(m_pCopyOf_edata);
    m_dwUpdateAddr = DWORD_PTR(m_pCopyOf_edata - m_dwExportTableRVA);
    m_pAddressOfFunctions = PDWORD(m_dwUpdateAddr + m_pExportDirectory->AddressOfFunctions);
    m_pAddressOfNames = PDWORD(m_dwUpdateAddr + m_pExportDirectory->AddressOfNames);
    m_pAddressOfNameOrdinals = PWORD(m_dwUpdateAddr + m_pExportDirectory->AddressOfNameOrdinals);
    m_nFunctions = m_pExportDirectory->NumberOfFunctions;
    m_nNames = m_pExportDirectory->NumberOfNames;
    m_dwNameIndx = 0;
    return true;
}


bool CModule32HLP::GetExportByName(
    PCSTR sExportName,
    RREAL_EXPORT_DESCRIPTOR rExportDescriptor
    )
{
    NTSTATUS                dwNTStatus;
    PBYTE                   pResult;
    PBYTE                   pImageBase;
    PBYTE                   pCopyOf_edata;
    DWORD                   dw_edataSize;
    PBYTE                   pRemoteAddr1;
    DWORD                   dwExportTableRVA;
    PIMAGE_EXPORT_DIRECTORY pExportDirectory;
    DWORD_PTR               dwUpdateAddr;
    PDWORD                  pAddressOfFunctions;
    PDWORD                  pAddressOfNames;
    PWORD                   pAddressOfNameOrdinals;
    DWORD                   nFunctions;
    DWORD                   nNames;
    DWORD                   dwNameIndx;
    DWORD                   dwMin;
    DWORD                   dwMax;
    int                     nCompRet;
    DWORD                   dwOrdIndx;
    DWORD                   dwFunctionAddr;
    PCSTR                   psForwardRef;
    PCSTR                   pNameString;
    bool                    bResult;
    PIMAGE_NT_HEADERS       pPEImageHeaders;
    if ((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return false;
    }
    pPEImageHeaders = GetImageHeaders();
    if (NULL == pPEImageHeaders)
    {
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        pImageBase = PBYTE(m_pModuleInfoEntry->DllBase);
        if (pPEImageHeaders->OptionalHeader.NumberOfRvaAndSizes == 0)
        {
            // Image not have Export Section
            return false;
        }
        dw_edataSize = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
        if (dw_edataSize == 0)
        {
            // Image not have Export Endtries
            return false;
        }
        dwExportTableRVA = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pImageBase + dwExportTableRVA);
        pAddressOfFunctions = PDWORD(pImageBase + pExportDirectory->AddressOfFunctions);
        pAddressOfNames = PDWORD(pImageBase + pExportDirectory->AddressOfNames);
        pAddressOfNameOrdinals = PWORD(pImageBase + pExportDirectory->AddressOfNameOrdinals);
        nFunctions = pExportDirectory->NumberOfFunctions;
        nNames = pExportDirectory->NumberOfNames;
        if (nNames < 16)
        {
            // linear search
            for (dwNameIndx = 0; dwNameIndx<nNames; dwNameIndx++)
            {
                pNameString = PCSTR(pImageBase + pAddressOfNames[dwNameIndx]);
                nCompRet = strcmp(sExportName, pNameString);
                if (nCompRet == 0) {
                    goto mFindSuccessCurrProc;
                }
                if (nCompRet < 0)
                {
                    return false;
                }
            }
        }
        // binary search
        dwMin = 0;
        dwMax = nNames - 1;
        do
        {
            pNameString = PCSTR(pImageBase + pAddressOfNames[dwNameIndx = dwMin]);
            nCompRet = strcmp(sExportName, pNameString);
            if (nCompRet == 0)
            {
                goto mFindSuccessCurrProc;
            }
            if (nCompRet < 0)
            {
                return false;
            }
            dwMin++;
            pNameString = PCSTR(pImageBase + pAddressOfNames[dwNameIndx = dwMax]);
            nCompRet = strcmp(sExportName, pNameString);
            if (nCompRet == 0)
            {
                goto mFindSuccessCurrProc;
            }
            if (nCompRet > 0)
            {
                return false;
            }
            dwMax--;
            if (dwMax < dwMin)
            {
                return false;
            }
            dwNameIndx = ((dwMax - dwMin + 1) >> 1) + dwMin;
            pNameString = PCSTR(pImageBase + pAddressOfNames[dwNameIndx]);
            nCompRet = strcmp(sExportName, pNameString);
            if (nCompRet == 0)
            {
                goto mFindSuccessCurrProc;
            }
            if (dwMax == dwMin)
            {
                return false;
            }
            if (nCompRet > 0)
            {
                dwMin = dwNameIndx + 1;
            }
            else
            {
                dwMax = dwNameIndx - 1;
            }
        } while (true);
    mFindSuccessCurrProc:
        dwOrdIndx = pAddressOfNameOrdinals[dwNameIndx];
        dwFunctionAddr = pAddressOfFunctions[dwOrdIndx];
        if ((dwFunctionAddr < dwExportTableRVA)
            || (dwFunctionAddr >= dwExportTableRVA + dw_edataSize))
        {
            pResult = pImageBase + dwFunctionAddr;
        }
        else
        {
            psForwardRef = PCSTR(pImageBase + dwFunctionAddr);
            bResult = EvaluteForwardExport(
                psForwardRef,
                rExportDescriptor
                );
            return bResult;
        }
        rExportDescriptor.cwsDllName = GetModuleNameW();
        rExportDescriptor.pEntryPoint = pResult;
        rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
        rExportDescriptor.csExportName = pNameString;
        return true;
    }
    pImageBase = PBYTE(m_stModuleInfoEntry.DllBase);
    if (pPEImageHeaders->OptionalHeader.NumberOfRvaAndSizes == 0)
    {
        // Image not have Export Section
        return false;
    }
    dw_edataSize = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    if (dw_edataSize == 0)
    {
        // Image not have Export Endtries
        return false;
    }
    pCopyOf_edata = new BYTE[dw_edataSize];
    if (pCopyOf_edata == NULL)
    {
        return false;
    }
    dwExportTableRVA = pPEImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    pRemoteAddr1 = pImageBase + dwExportTableRVA;
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        pRemoteAddr1,
        pCopyOf_edata,
        dw_edataSize,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        delete pCopyOf_edata;
        return false;
    }
    pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pCopyOf_edata);
    dwUpdateAddr = DWORD_PTR(pCopyOf_edata - dwExportTableRVA);
    pAddressOfFunctions = PDWORD(dwUpdateAddr + pExportDirectory->AddressOfFunctions);
    pAddressOfNames = PDWORD(dwUpdateAddr + pExportDirectory->AddressOfNames);
    pAddressOfNameOrdinals = PWORD(dwUpdateAddr + pExportDirectory->AddressOfNameOrdinals);
    nFunctions = pExportDirectory->NumberOfFunctions;
    nNames = pExportDirectory->NumberOfNames;
    if (nNames < 16)
    {
        // linear search
        for (dwNameIndx = 0; dwNameIndx<nNames; dwNameIndx++)
        {
            pNameString = PCSTR(dwUpdateAddr + pAddressOfNames[dwNameIndx]);
            nCompRet = strcmp(sExportName, pNameString);
            if (nCompRet == 0) {
                goto mFindSuccess;
            }
            if (nCompRet < 0)
            {
                delete pCopyOf_edata;
                return false;
            }
        }
    }
    // binary search
    dwMin = 0;
    dwMax = nNames - 1;
    do
    {
        pNameString = PCSTR(dwUpdateAddr + pAddressOfNames[dwNameIndx = dwMin]);
        nCompRet = strcmp(sExportName, pNameString);
        if (nCompRet == 0)
        {
            goto mFindSuccess;
        }
        if (nCompRet < 0)
        {
            delete pCopyOf_edata;
            return false;
        }
        dwMin++;
        pNameString = PCSTR(dwUpdateAddr + pAddressOfNames[dwNameIndx = dwMax]);
        nCompRet = strcmp(sExportName, pNameString);
        if (nCompRet == 0)
        {
            goto mFindSuccess;
        }
        if (nCompRet > 0)
        {
            delete pCopyOf_edata;
            return false;
        }
        dwMax--;
        if (dwMax < dwMin)
        {
            delete pCopyOf_edata;
            return false;
        }
        dwNameIndx = ((dwMax - dwMin + 1) >> 1) + dwMin;
        pNameString = PCSTR(dwUpdateAddr + pAddressOfNames[dwNameIndx]);
        nCompRet = strcmp(sExportName, pNameString);
        if (nCompRet == 0)
        {
            goto mFindSuccess;
        }
        if (dwMax == dwMin)
        {
            delete pCopyOf_edata;
            return false;
        }
        if (nCompRet > 0)
        {
            dwMin = dwNameIndx + 1;
        }
        else
        {
            dwMax = dwNameIndx - 1;
        }
    } while (true);
mFindSuccess:
    dwOrdIndx = pAddressOfNameOrdinals[dwNameIndx];
    dwFunctionAddr = pAddressOfFunctions[dwOrdIndx];
    if ((dwFunctionAddr < dwExportTableRVA)
        || (dwFunctionAddr >= dwExportTableRVA + dw_edataSize))
    {
        pResult = pImageBase + dwFunctionAddr;
    }
    else
    {
        psForwardRef = PCSTR(dwUpdateAddr + dwFunctionAddr);
        bResult = EvaluteForwardExport(
            psForwardRef,
            rExportDescriptor
            );
        delete pCopyOf_edata;
        return bResult;
    }
    rExportDescriptor.cwsDllName = GetModuleNameW();
    rExportDescriptor.pEntryPoint = pResult;
    rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
    strcpy(
        m_sExportName,
        pNameString
        );
    rExportDescriptor.csExportName = m_sExportName;
    delete pCopyOf_edata;
    return true;
}


bool CModule32HLP::EnumExportNext(RREAL_EXPORT_DESCRIPTOR rExportDescriptor)
{
    DWORD                   dwOrdIndx;
    DWORD                   dwFunctionAddr;
    PCSTR                   psForwardRef;
    PCSTR                   pNameString;
    PBYTE                   pResult;
    bool                    bResult;
    WCHAR                   wsModuleNameSave[260];
    PLDR_DATA_TABLE_ENTRY   pModuleEntry;
    if (NULL == m_pModuleInfoEntry)
    {
        return false;
    }
    if (m_dwNameIndx >= m_nNames)
    {
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        pNameString = PCSTR(m_pImageBase + m_pAddressOfNames[m_dwNameIndx]);
        dwOrdIndx = m_pAddressOfNameOrdinals[m_dwNameIndx];
        m_dwNameIndx++;
        dwFunctionAddr = m_pAddressOfFunctions[dwOrdIndx];
        if ((dwFunctionAddr < m_dwExportTableRVA)
            || (dwFunctionAddr >= m_dwExportTableRVA + m_dw_edataSize))
        {
            pResult = m_pImageBase + dwFunctionAddr;
        }
        else
        {
            psForwardRef = PCSTR(m_pImageBase + dwFunctionAddr);
            wcscpy(
                wsModuleNameSave,
                GetModuleNameW()
                );
            bResult = EvaluteForwardExport(
                psForwardRef,
                rExportDescriptor
                );
            if (!bResult)
            {
                return false;
            }
            if (WORD(-1) != rExportDescriptor.wOrderIndex)
            {
                wcscpy(
                    m_wsLastModuleName,
                    GetModuleNameW()
                    );
            }
            pModuleEntry = FindModule(wsModuleNameSave);
            assert(NULL != pModuleEntry);
            rExportDescriptor.cwsDllName = m_wsLastModuleName;
            rExportDescriptor.csOriginalExportName = pNameString;
            rExportDescriptor.wOriginalOrderIndex = WORD(dwOrdIndx);
            return true;
        }
        rExportDescriptor.cwsDllName = GetModuleNameW();
        rExportDescriptor.pEntryPoint = pResult;
        rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
        rExportDescriptor.csExportName = pNameString;
        return true;
    }
    pNameString = PCSTR(m_dwUpdateAddr + m_pAddressOfNames[m_dwNameIndx]);
    dwOrdIndx = m_pAddressOfNameOrdinals[m_dwNameIndx];
    m_dwNameIndx++;
    dwFunctionAddr = m_pAddressOfFunctions[dwOrdIndx];
    if ((dwFunctionAddr < m_dwExportTableRVA)
        || (dwFunctionAddr >= m_dwExportTableRVA + m_dw_edataSize))
    {
        pResult = PBYTE(m_dwUpdateAddr + dwFunctionAddr);
    }
    else
    {
        psForwardRef = PCSTR(m_dwUpdateAddr + dwFunctionAddr);
        wcscpy(
            wsModuleNameSave,
            GetModuleNameW()
            );
        bResult = EvaluteForwardExport(
            psForwardRef,
            rExportDescriptor
            );
        if (!bResult)
        {
            return false;
        }
        if (WORD(-1) != rExportDescriptor.wOrderIndex)
        {
            wcscpy(
                m_wsLastModuleName,
                GetModuleNameW()
                );
        }
        pModuleEntry = FindModule(wsModuleNameSave);
        assert(NULL != pModuleEntry);
        rExportDescriptor.cwsDllName = m_wsLastModuleName;
        rExportDescriptor.csOriginalExportName = pNameString;
        rExportDescriptor.wOriginalOrderIndex = WORD(dwOrdIndx);
        return true;
    }
    rExportDescriptor.cwsDllName = GetModuleNameW();
    rExportDescriptor.pEntryPoint = pResult;
    rExportDescriptor.wOrderIndex = WORD(dwOrdIndx);
    rExportDescriptor.csExportName = pNameString;
    return true;
}


void CModule32HLP::EnumExportStop()
{
    if (NULL != m_pCopyOf_edata)
    {
        delete m_pCopyOf_edata;
        m_pCopyOf_edata = NULL;
    }
}


bool CModule32HLP::EnumImportStart(PCWSTR pwsModuleName)
{
    PLDR_DATA_TABLE_ENTRY       pModuleEntry;
    PIMAGE_NT_HEADERS           pImageHeaders;
    PBYTE                       pModuleBase;
    PIMAGE_SECTION_HEADER       pRemoteSectionsTable;
    PIMAGE_SECTION_HEADER       pCopyOfSectionsTable;
    DWORD                       dwSectionsTableSize;
    DWORD                       dwNumberOfSections, j;
    BYTE                        _idataName[IMAGE_SIZEOF_SHORT_NAME] = ".idata\000";
    NTSTATUS                    dwNTStatus;
    if (NULL != m_pCopyOf_idata)
    {
        delete m_pCopyOf_idata;
        m_pCopyOf_idata = NULL;
    }
    m_pImportDescriptor = NULL;
    pModuleEntry = FindModule(pwsModuleName);
    if ((m_hProcessHandle == NULL) || (m_pModuleInfoEntry == NULL))
    {
        return false;
    }
    pModuleBase = PBYTE(m_pModuleInfoEntry->DllBase);
    m_pIporterModule = pModuleBase;
    pImageHeaders = GetImageHeaders();
    if (pImageHeaders->OptionalHeader.NumberOfRvaAndSizes < 2)
    {
        // Image not have Import Section
        return false;
    }
    m_dw_idataSize = pImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
    if (m_dw_idataSize == 0)
    {
        // Image not have Import Section
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        m_pImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR(
            pModuleBase + pImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
            );
        if (0 == m_pImportDescriptor->Characteristics)
        {
            // module not have import table
            m_pImportDescriptor = NULL;
            return false;
        }
        return true;
    }
    pRemoteSectionsTable = (PIMAGE_SECTION_HEADER) (m_pRemotePEHeaders + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)
        + pImageHeaders->FileHeader.SizeOfOptionalHeader);
    dwNumberOfSections = pImageHeaders->FileHeader.NumberOfSections;
    dwSectionsTableSize = dwNumberOfSections*sizeof(IMAGE_SECTION_HEADER);
    pCopyOfSectionsTable = new IMAGE_SECTION_HEADER[dwNumberOfSections];
    if (pCopyOfSectionsTable == NULL)
    {
        return false;
    }
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        pRemoteSectionsTable,
        pCopyOfSectionsTable,
        dwSectionsTableSize,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        delete pCopyOfSectionsTable;
        return false;
    }
    m_dw_idataSize = 0;
    for (j = 0; j<dwNumberOfSections; j++)
    {
        if (memcmp(_idataName, pCopyOfSectionsTable[j].Name, 8) == 0)
        {
            if (pCopyOfSectionsTable[j].Misc.VirtualSize > pCopyOfSectionsTable[j].SizeOfRawData)
            {
                m_dw_idataSize = pCopyOfSectionsTable[j].SizeOfRawData;
            }
            else
            {
                m_dw_idataSize = pCopyOfSectionsTable[j].Misc.VirtualSize;
            }
            m_dw_idataRVA = pCopyOfSectionsTable[j].VirtualAddress;
            m_pRemote_idata = pModuleBase + m_dw_idataRVA;
            break;
        }
    }
    if (m_dw_idataSize == 0)
    {
        for (j = 0; j<dwNumberOfSections; j++)
        {
            DWORD   dwSectSize;
            if (pCopyOfSectionsTable[j].Misc.VirtualSize > pCopyOfSectionsTable[j].SizeOfRawData)
            {
                dwSectSize = pCopyOfSectionsTable[j].SizeOfRawData;
            }
            else
            {
                dwSectSize = pCopyOfSectionsTable[j].Misc.VirtualSize;
            }
            if (
                (pImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress >=
                pCopyOfSectionsTable[j].VirtualAddress) &&
                (pImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress <
                pCopyOfSectionsTable[j].VirtualAddress + dwSectSize)
                )
            {
                m_dw_idataSize = dwSectSize;
                m_dw_idataRVA = pCopyOfSectionsTable[j].VirtualAddress;
                m_pRemote_idata = pModuleBase + m_dw_idataRVA;
                break;
            }
        }
    }
    delete pCopyOfSectionsTable;
    if (m_dw_idataSize == 0)
    {
        return false;
    }
    m_pCopyOf_idata = new BYTE[m_dw_idataSize];
    if (m_pCopyOf_idata == NULL)
    {
        return false;
    }
    dwNTStatus = NtReadVirtualMemory(
        m_hProcessHandle,
        m_pRemote_idata,
        m_pCopyOf_idata,
        m_dw_idataSize,
        NULL
        );
    if (!NT_SUCCESS(dwNTStatus))
    {
        delete m_pCopyOf_idata;
        m_pCopyOf_idata = NULL;
        return false;
    }
    m_dwImportUpdateValue = DWORD_PTR(m_pCopyOf_idata - m_dw_idataRVA);
    m_pCopyImpDirectoty = PIMAGE_IMPORT_DESCRIPTOR(
        m_pCopyOf_idata + (pImageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - m_dw_idataRVA)
        );
    m_pImportDescriptor = m_pCopyImpDirectoty;
    if (0 == m_pImportDescriptor->Characteristics)
    {
        // module not have import table
        delete m_pCopyOf_idata;
        m_pCopyOf_idata = NULL;
        m_pImportDescriptor = NULL;
        return false;
    }
    return true;
}


void CModule32HLP::EnumImportStop()
{
    if (NULL != m_pCopyOf_idata)
    {
        delete m_pCopyOf_idata;
        m_pCopyOf_idata = NULL;
    }
    m_pImportDescriptor = NULL;
    m_pIporterModule = NULL;
}


bool CModule32HLP::EnumImportNext(RREAL_IMPORT_DESCRIPTOR rImportDescriptor)
{
    PIMAGE_IMPORT_BY_NAME   pImportByName;
    if ((NULL == m_pImportDescriptor) || (NULL == m_pIporterModule))
    {
        return false;
    }
    if (m_hProcessHandle == NtCurrentProcess())
    {
        if (NULL == rImportDescriptor.szCalledModuleName)
        {
            rImportDescriptor.dwThunkIndex = 0;
            rImportDescriptor.dwTimeDateStamp = m_pImportDescriptor->TimeDateStamp;
            rImportDescriptor.dwForwarderChain = m_pImportDescriptor->ForwarderChain;
            rImportDescriptor.szCalledModuleName = PCSTR(m_pIporterModule + m_pImportDescriptor->Name);
            m_pThunkDataArray = PIMAGE_THUNK_DATA(m_pIporterModule + m_pImportDescriptor->OriginalFirstThunk);
            m_pImportThunkArray = (PBYTE*) (m_pIporterModule + m_pImportDescriptor->FirstThunk);
            if (NULL == m_pThunkDataArray[0].u1.AddressOfData)
            {
                return false;
            }
            if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[0].u1.Ordinal))
            {
                rImportDescriptor.wHint = WORD(-1);
                rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[0].u1.Ordinal));
                rImportDescriptor.szFunctionName = NULL;
            }
            else
            {
                pImportByName = PIMAGE_IMPORT_BY_NAME(m_pIporterModule + m_pThunkDataArray[0].u1.AddressOfData);
                rImportDescriptor.wOrder = WORD(-1);
                rImportDescriptor.wHint = pImportByName->Hint;
                rImportDescriptor.szFunctionName = pImportByName->Name;
            }
            rImportDescriptor.pFunctionAddress = m_pImportThunkArray[0];
            return true;
        }
        rImportDescriptor.dwThunkIndex++;
        if (0 == m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal)
        {
            m_pImportDescriptor++;
            if (0 == m_pImportDescriptor->Characteristics)
            {
                return false;
            }
            rImportDescriptor.dwThunkIndex = 0;
            rImportDescriptor.dwTimeDateStamp = m_pImportDescriptor->TimeDateStamp;
            rImportDescriptor.dwForwarderChain = m_pImportDescriptor->ForwarderChain;
            rImportDescriptor.szCalledModuleName = PCSTR(m_pIporterModule + m_pImportDescriptor->Name);
            m_pThunkDataArray = PIMAGE_THUNK_DATA(m_pIporterModule + m_pImportDescriptor->OriginalFirstThunk);
            m_pImportThunkArray = (PBYTE*) (m_pIporterModule + m_pImportDescriptor->FirstThunk);
            if (NULL == m_pThunkDataArray[0].u1.AddressOfData)
            {
                return false;
            }
            if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[0].u1.Ordinal))
            {
                rImportDescriptor.wHint = WORD(-1);
                rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[0].u1.Ordinal));
                rImportDescriptor.szFunctionName = NULL;
            }
            else
            {
                pImportByName = PIMAGE_IMPORT_BY_NAME(m_pIporterModule + m_pThunkDataArray[0].u1.AddressOfData);
                rImportDescriptor.wOrder = WORD(-1);
                rImportDescriptor.wHint = pImportByName->Hint;
                rImportDescriptor.szFunctionName = pImportByName->Name;
            }
            rImportDescriptor.pFunctionAddress = m_pImportThunkArray[0];
            return true;
        }
        if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal))
        {
            rImportDescriptor.wHint = WORD(-1);
            rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal));
            rImportDescriptor.szFunctionName = NULL;
        }
        else
        {
            pImportByName = PIMAGE_IMPORT_BY_NAME(m_pIporterModule + m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.AddressOfData);
            rImportDescriptor.wOrder = WORD(-1);
            rImportDescriptor.wHint = pImportByName->Hint;
            rImportDescriptor.szFunctionName = pImportByName->Name;
        }
        rImportDescriptor.pFunctionAddress = m_pImportThunkArray[rImportDescriptor.dwThunkIndex];
        return true;
    }
    if (NULL == m_pCopyOf_idata)
    {
        return false;
    }
    if (NULL == rImportDescriptor.szCalledModuleName)
    {
        rImportDescriptor.dwThunkIndex = 0;
        rImportDescriptor.dwTimeDateStamp = m_pImportDescriptor->TimeDateStamp;
        rImportDescriptor.dwForwarderChain = m_pImportDescriptor->ForwarderChain;
        rImportDescriptor.szCalledModuleName = PCSTR(m_dwImportUpdateValue + m_pImportDescriptor->Name);
        m_pThunkDataArray = PIMAGE_THUNK_DATA(m_dwImportUpdateValue + m_pImportDescriptor->OriginalFirstThunk);
        m_pImportThunkArray = (PBYTE*) (m_dwImportUpdateValue + m_pImportDescriptor->FirstThunk);
        if (NULL == m_pThunkDataArray[0].u1.AddressOfData)
        {
            return false;
        }
        if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[0].u1.Ordinal))
        {
            rImportDescriptor.wHint = WORD(-1);
            rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[0].u1.Ordinal));
            rImportDescriptor.szFunctionName = NULL;
        }
        else
        {
            pImportByName = PIMAGE_IMPORT_BY_NAME(m_dwImportUpdateValue + m_pThunkDataArray[0].u1.AddressOfData);
            rImportDescriptor.wOrder = WORD(-1);
            rImportDescriptor.wHint = pImportByName->Hint;
            rImportDescriptor.szFunctionName = pImportByName->Name;
        }
        rImportDescriptor.pFunctionAddress = m_pImportThunkArray[0];
        return true;
    }
    rImportDescriptor.dwThunkIndex++;
    if (0 == m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal)
    {
        m_pImportDescriptor++;
        if (0 == m_pImportDescriptor->Characteristics)
        {
            return false;
        }
        rImportDescriptor.dwThunkIndex = 0;
        rImportDescriptor.dwTimeDateStamp = m_pImportDescriptor->TimeDateStamp;
        rImportDescriptor.dwForwarderChain = m_pImportDescriptor->ForwarderChain;
        rImportDescriptor.szCalledModuleName = PCSTR(m_dwImportUpdateValue + m_pImportDescriptor->Name);
        m_pThunkDataArray = PIMAGE_THUNK_DATA(m_dwImportUpdateValue + m_pImportDescriptor->OriginalFirstThunk);
        m_pImportThunkArray = (PBYTE*) (m_dwImportUpdateValue + m_pImportDescriptor->FirstThunk);
        if (NULL == m_pThunkDataArray[0].u1.AddressOfData)
        {
            return false;
        }
        if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[0].u1.Ordinal))
        {
            rImportDescriptor.wHint = WORD(-1);
            rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[0].u1.Ordinal));
            rImportDescriptor.szFunctionName = NULL;
        }
        else
        {
            pImportByName = PIMAGE_IMPORT_BY_NAME(m_dwImportUpdateValue + m_pThunkDataArray[0].u1.AddressOfData);
            rImportDescriptor.wOrder = WORD(-1);
            rImportDescriptor.wHint = pImportByName->Hint;
            rImportDescriptor.szFunctionName = pImportByName->Name;
        }
        rImportDescriptor.pFunctionAddress = m_pImportThunkArray[0];
        return true;
    }
    if (IMAGE_SNAP_BY_ORDINAL(m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal))
    {
        rImportDescriptor.wHint = WORD(-1);
        rImportDescriptor.wOrder = WORD(IMAGE_ORDINAL(m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.Ordinal));
        rImportDescriptor.szFunctionName = NULL;
    }
    else
    {
        pImportByName = PIMAGE_IMPORT_BY_NAME(m_dwImportUpdateValue + m_pThunkDataArray[rImportDescriptor.dwThunkIndex].u1.AddressOfData);
        rImportDescriptor.wOrder = WORD(-1);
        rImportDescriptor.wHint = pImportByName->Hint;
        rImportDescriptor.szFunctionName = pImportByName->Name;
    }
    rImportDescriptor.pFunctionAddress = m_pImportThunkArray[rImportDescriptor.dwThunkIndex];
    return true;
}
