cresourceripper.cpp

来自「pe exe packer (must use vc2005 to compil」· C++ 代码 · 共 895 行 · 第 1/2 页

CPP
895
字号
    // allocate a dummy node
    m_pResourceTree = (PRESOURCELEAF)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, sizeof(RESOURCELEAF));
    ProcessDirectory((PIMAGE_RESOURCE_DIRECTORY)m_pbRsrc, m_pResourceTree);
}

// Performs the retention and deletion processes and cleans up deleted leaves.
VOID CResourceRipper::FilterResources()
{
	ProcessLeaf(m_pResourceTree, m_pRetentionFilters, &CResourceRipper::RetentionCallback);
	ProcessLeaf(m_pResourceTree, m_pDeletionFilters, &CResourceRipper::DeletionCallback);
    DeleteResources(m_pResourceTree, m_bStrip);
}

// Returns the first or the last sibling of the supplied leaf alphabetically
// sorted. Note that strings are considered greater than ids.
PRESOURCELEAF CResourceRipper::FindAlphaLeaf(PRESOURCELEAF pLeaf, BOOL bNot)
{
    PRESOURCELEAF pAlphaLeaf,
                  pCurrentLeaf;
    BOOL          bNewAlpha;

    pAlphaLeaf = FindFirstLeaf(pLeaf, FALSE);
    pCurrentLeaf = pAlphaLeaf->pSibling;
    while(pCurrentLeaf)
    {
        bNewAlpha = FALSE;
        if(pAlphaLeaf->bNameIsString = pCurrentLeaf->bNameIsString)
        {
            if(pAlphaLeaf->bNameIsString) // both leaves are strings
            {
                if(lstrcmp(pAlphaLeaf->pNameString, pCurrentLeaf->pNameString) > 0)
                    bNewAlpha = TRUE;
            }
            else // both leaves are ids
            {
                if(pAlphaLeaf->wId > pCurrentLeaf->wId)
                    bNewAlpha = TRUE;
            }
        }
        else if(pAlphaLeaf->bNameIsString)
            bNewAlpha = TRUE;

        if(bNot)
            bNewAlpha ^= TRUE;

        if(bNewAlpha)
            pAlphaLeaf = pCurrentLeaf;

        pCurrentLeaf = pCurrentLeaf->pSibling;
    }
    return pAlphaLeaf;
}

// Returns the first or the last sibling of the supplied leaf.
PRESOURCELEAF CResourceRipper::FindFirstLeaf(PRESOURCELEAF pLeaf, BOOL bNot)
{
    PRESOURCELEAF pFirstLeaf;

    pFirstLeaf = pLeaf->pParent->pChild;
    if(bNot)
    {
        while(pFirstLeaf->pSibling)
            pFirstLeaf = pFirstLeaf->pSibling;
    }
    return pFirstLeaf;
}

// Returns the parent of the specified data leaf that is at the specified level.
PRESOURCELEAF CResourceRipper::FindLeafByLevel(PRESOURCELEAF pDataLeaf, DWORD dwLevel)
{
    PRESOURCELEAF pLeaf;

    pLeaf = NULL;
    if(dwLevel <= pDataLeaf->dwLevel)
    {
        pLeaf = pDataLeaf;
        while(pLeaf->dwLevel != dwLevel)
            pLeaf = pLeaf->pParent;
    }
    return pLeaf;
}

// Calculates the size of the resource section upon export.
DWORD CResourceRipper::GetSize()
{
    return m_dwHeaderSize + m_dwStringSize + m_dwDataSize;
}

// Checks if a supplied data leaf is a GROUP_ICON or GROUP_CURSOR data item.
BOOL CResourceRipper::IsGroupIconOrCursor(PRESOURCELEAF pDataLeaf)
{
    BOOL          bRet;
    PRESOURCELEAF pTypeLeaf;

    bRet = FALSE;
    if(pDataLeaf->bDirectory == FALSE)
    {
        if(pDataLeaf->dwLevel == 3 && pDataLeaf->bNameIsString == FALSE)
        {
            pTypeLeaf = FindLeafByLevel(pDataLeaf, 1);
            if(pTypeLeaf)
            {
                if(pTypeLeaf->bNameIsString == FALSE)
                {
                    if(pTypeLeaf->wId == (WORD)RT_GROUP_ICON || pTypeLeaf->wId == (WORD)RT_GROUP_CURSOR)
                    {
                        bRet = TRUE;
                    }
                }
            }
        }
    }
    return bRet;
}

// Sets up input file pointers. Returns TRUE if the input has a resource section.
BOOL CResourceRipper::LoadFile(PBYTE pbFile)
{
    BOOL              bRet;
    DWORD             dwRsrcRva;
    PIMAGE_NT_HEADERS pNt;

    bRet = FALSE;
    m_pbFile = pbFile;
    pNt = PIMAGE_NT_HEADERS(pbFile + PIMAGE_DOS_HEADER(pbFile)->e_lfanew);
    dwRsrcRva = pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
    m_pbRsrc = RvaToPointer(pbFile, dwRsrcRva);
    if(m_pbRsrc) bRet = TRUE;
    return bRet;
}

// Locates a filter in the linked list with the specified uid.
PRESOURCEFILTER CResourceRipper::LocateFilter(PRESOURCEFILTER pFilterList, DWORD dwId)
{
    PRESOURCEFILTER pCurrentFilter;

    pCurrentFilter = pFilterList;
    while(pCurrentFilter)
    {
        if(pCurrentFilter->dwId == dwId)
            return pCurrentFilter;
        pCurrentFilter = pCurrentFilter->pNext;
    }
    return NULL;
}

// Tells the ripper whether or not it should null out the original resources.
VOID CResourceRipper::MoveData(BOOL bMoveData)
{
    m_bMoveData = bMoveData;
}

// Parses the RT_GROUP_ICON or RT_GROUP_CURSOR data to determine which icons or
// cursors it refers to. Next, it searches the resource tree for the icons or
// cursors and calls the specified callback.
VOID CResourceRipper::ParseGroupIconOrCursor(PRESOURCELEAF pGroupLeaf, FILTERCALLBACK pfCallback)
{
    PGRPDIR       pHeader;
    PGRPDIRENTRY  pEntries;
    DWORD         x;
    WORD          wTypeId;
    PRESOURCELEAF pTypeLeaf,
                  pIdLeaf,
                  pLangLeaf;

    if(pGroupLeaf->bRetain)
        pHeader = (PGRPDIR)pGroupLeaf->pbData;
    else
        pHeader = (PGRPDIR)RvaToPointer(m_pbFile, pGroupLeaf->dwDataRva);

    if(pHeader)
    {
        pEntries = PGRPDIRENTRY(pHeader + 1);

        // Convert directory type id to resource type id
        wTypeId = 0;
        if(pHeader->idType == 1) wTypeId = (WORD)RT_ICON;
        else if(pHeader->idType == 2) wTypeId = (WORD)RT_CURSOR;

        if(wTypeId)
        {
            // we start searching the level 1 leaves looking for RT_ICON or RT_CURSOR
            pTypeLeaf = m_pResourceTree->pChild;
            while(pTypeLeaf)
            {
                if(pTypeLeaf->bNameIsString == FALSE && pTypeLeaf->wId == wTypeId)
                {
                    // now loop through each group entry
                    for(x = 0; x < pHeader->idCount; x++)
                    {
                        // search level 2 leaves for id in the group entry
                        pIdLeaf = pTypeLeaf->pChild;
                        while(pIdLeaf)
                        {
                            if(pIdLeaf->bNameIsString == FALSE && pIdLeaf->wId == pEntries[x].nID)
                            {
                                pLangLeaf = pIdLeaf->pChild;
                                while(pLangLeaf)
                                {
                                    // ensure the level 3 leaf is a data leaf
                                    if(pLangLeaf->bDirectory == FALSE)
                                    {
                                        // only process icons with same language id as group entry
                                        if(pLangLeaf->wId == pGroupLeaf->wId)
                                        {
                                            (this->*pfCallback)(pLangLeaf);
                                        }
                                    }
                                    pLangLeaf = pLangLeaf->pSibling;
                                }
                            }
                            pIdLeaf = pIdLeaf->pSibling;
                        }
                    }
                }

                pTypeLeaf = pTypeLeaf->pSibling;
            }
        }
    }
}

// Does the actual ripping of the resources from the input file.
VOID CResourceRipper::ProcessDirectory(PIMAGE_RESOURCE_DIRECTORY pDir, PRESOURCELEAF pParentLeaf)
{
    DWORD                            dwEntryCount,
                                     x,
                                     y;
    PIMAGE_RESOURCE_DIRECTORY        pChildDirectory;
    PRESOURCELEAF                    pCurrentLeaf,
                                   * ppLink;
    PIMAGE_RESOURCE_DIRECTORY_ENTRY  pEntries;
    PIMAGE_RESOURCE_DATA_ENTRY       pResourceDataEntry;
    PIMAGE_RESOURCE_DIRECTORY_STRING pResourceString;
    PTSTR                            pNameMemory;

    ppLink = &pParentLeaf->pChild;
    dwEntryCount = pDir->NumberOfIdEntries + pDir->NumberOfNamedEntries;
    pEntries = PIMAGE_RESOURCE_DIRECTORY_ENTRY(pDir + 1);
    for(x = 0; x < dwEntryCount; x++)
    {
        // create an empty leaf
        pCurrentLeaf = (PRESOURCELEAF)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, sizeof(RESOURCELEAF));
        *ppLink = pCurrentLeaf;
        pCurrentLeaf->pParent = pParentLeaf;
        pCurrentLeaf->dwLevel = pParentLeaf->dwLevel + 1;

        // copy the name/id from the resource section to the leaf
        if(pEntries[x].NameIsString)
        {
            pResourceString = PIMAGE_RESOURCE_DIRECTORY_STRING(m_pbRsrc + pEntries[x].NameOffset);
            pNameMemory = (PTSTR)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, (pResourceString->Length + 1) * sizeof(TCHAR));

            // it's important that we copy the string character by character so
            // that ansi compilations will work
            for(y = 0; y < pResourceString->Length; y++)
                pNameMemory[y] = (TCHAR)PWSTR(pResourceString->NameString)[y];

            pCurrentLeaf->bNameIsString = TRUE;
            pCurrentLeaf->wNameLength = pResourceString->Length;
            pCurrentLeaf->pNameString = pNameMemory;
            m_dwStringSize += (pResourceString->Length * sizeof(WCHAR) + sizeof(pResourceString->Length));
            if(m_bNullSource)
                ZeroMemory(pResourceString, pResourceString->Length * sizeof(WCHAR) + sizeof(pResourceString->Length));
        }
        else
            pCurrentLeaf->wId = pEntries[x].Id;

        // continue based on whether the entry points to another directory
        if(pEntries[x].DataIsDirectory)
        {
            pCurrentLeaf->bDirectory = TRUE;
            pChildDirectory = PIMAGE_RESOURCE_DIRECTORY(m_pbRsrc + pEntries[x].OffsetToDirectory);
            ProcessDirectory(pChildDirectory, pCurrentLeaf);
        }
        else
        {
            pResourceDataEntry = PIMAGE_RESOURCE_DATA_ENTRY(m_pbRsrc + pEntries[x].OffsetToData);
            pCurrentLeaf->dwDataSize = pResourceDataEntry->Size;
            pCurrentLeaf->dwDataRva = pResourceDataEntry->OffsetToData;
            if(m_bNullSource)
                ZeroMemory(pResourceDataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY));
            m_dwHeaderSize += sizeof(IMAGE_RESOURCE_DATA_ENTRY);
        }
        if(m_bNullSource)
            ZeroMemory(&pEntries[x], sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
        m_dwHeaderSize += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
        ppLink = &pCurrentLeaf->pSibling;
    }
    if(m_bNullSource)
        ZeroMemory(pDir, sizeof(IMAGE_RESOURCE_DIRECTORY));
    m_dwHeaderSize += sizeof(IMAGE_RESOURCE_DIRECTORY);
}

// Searches a resource tree structure for data leaves. When it finds a data leaf
// that is filtered by the specified filters, it calls the callback function.
VOID CResourceRipper::ProcessLeaf(PRESOURCELEAF pLeaf, PRESOURCEFILTER pFilters, FILTERCALLBACK pfCallback)
{
    PRESOURCELEAF pCurrentLeaf;

    pCurrentLeaf = pLeaf;
    while(pCurrentLeaf)
    {
        ProcessLeaf(pCurrentLeaf->pChild, pFilters, pfCallback);
        if(pCurrentLeaf->bDirectory == FALSE)
        {
            if(TestDataLeaf(pCurrentLeaf, pFilters))
            {
                (this->*pfCallback)(pCurrentLeaf);
                if(IsGroupIconOrCursor(pCurrentLeaf))
                {
                    ParseGroupIconOrCursor(pCurrentLeaf, pfCallback);
                }
            }
        }
        pCurrentLeaf = pCurrentLeaf->pSibling;
    }
}

// Callback used to retain filtered resources.
VOID CResourceRipper::RetentionCallback(PRESOURCELEAF pDataLeaf)
{
    PBYTE pbDataMemory,
          pbDataPointer;

    if(pDataLeaf->bRetain == FALSE)
    {
        pbDataMemory = (PBYTE)VirtualAlloc(0, pDataLeaf->dwDataSize, MEM_COMMIT, PAGE_READWRITE);
        pbDataPointer = RvaToPointer(m_pbFile, pDataLeaf->dwDataRva);
        if(pbDataPointer)
        {
            CopyMemory(pbDataMemory, pbDataPointer, pDataLeaf->dwDataSize);
            pDataLeaf->pbData = pbDataMemory;
            pDataLeaf->bRetain = TRUE;
            if(m_bNullSource)
                ZeroMemory(pbDataPointer, pDataLeaf->dwDataSize);
            m_dwDataSize += pDataLeaf->dwDataSize;
        }
        else
            VirtualFree(pbDataMemory, 0, MEM_RELEASE);
    }
}

// Driver for ripping resources.
VOID CResourceRipper::Rip(PVOID pvFile)
{
    DeleteResources(m_pResourceTree, TRUE);
    m_bNullSource = m_bMoveData;
    if(LoadFile((PBYTE)pvFile))
    {
        ExtractResources();
        FilterResources();
    }

    // resource data can only be nulled out during ripping
    m_bNullSource = FALSE;
}

// Sets the strip flag.
VOID CResourceRipper::Strip(BOOL bStrip)
{
    m_bStrip = bStrip;
}

// Loops through each filter and determines if any of them filter out the
// specified data leaf.
BOOL CResourceRipper::TestDataLeaf(PRESOURCELEAF pDataLeaf, PRESOURCEFILTER pFilters)
{
    PRESOURCEFILTER pCurrentFilter;

    pCurrentFilter = pFilters;
    while(pCurrentFilter)
    {
        if(TestFilter(pCurrentFilter, pDataLeaf))
            return TRUE;
        pCurrentFilter = pCurrentFilter->pNext;
    }
    return FALSE;
}

// Determines whether or not the specified filter matches the supplied data leaf.
BOOL CResourceRipper::TestFilter(PRESOURCEFILTER pFilter, PRESOURCELEAF pDataLeaf)
{
    PFILTERLEVEL pCurrentLevel;
    PRESOURCELEAF pCurrentLeaf;
    BOOL bPass;

    pCurrentLevel = pFilter->pLevels;
    while(pCurrentLevel)
    {
        bPass = FALSE;

        // get the leaf that corresponds to the level specified by the filter
        pCurrentLeaf = FindLeafByLevel(pDataLeaf, pCurrentLevel->dwLevel);
        if(pCurrentLeaf)
        {
            // if level flag is FF_ID
            if(pCurrentLevel->dwFlags & FF_ID)
            {
                if(pCurrentLeaf->bNameIsString == FALSE)
                {
                    if(pCurrentLevel->wId == pCurrentLeaf->wId)
                        bPass = TRUE;
                }
                if(pCurrentLevel->dwFlags & FF_NOT)
                    bPass ^= TRUE;
            }

            // if level flag is FF_STRING
            else if(pCurrentLevel->dwFlags & FF_STRING)
            {
                if(pCurrentLeaf->bNameIsString)
                {
                    if(lstrcmpi(pCurrentLeaf->pNameString, pCurrentLevel->pString) == 0)
                        bPass = TRUE;
                }
                if(pCurrentLevel->dwFlags & FF_NOT)
                    bPass ^= TRUE;
            }

            // if level flag is FF_ALL
            else if(pCurrentLevel->dwFlags & FF_ALL)
                bPass = TRUE;

            // if level flag is FF_ALPHA
            else if(pCurrentLevel->dwFlags & FF_ALPHA)
            {
                if(FindAlphaLeaf(pCurrentLeaf, pCurrentLevel->dwFlags & FF_NOT) == pCurrentLeaf)
                    bPass = TRUE;
            }

            else if(pCurrentLevel->dwFlags & FF_FIRST)
            {
                if(FindFirstLeaf(pCurrentLeaf, pCurrentLevel->dwFlags & FF_NOT) == pCurrentLeaf)
                    bPass = TRUE;
            }
        }

        // if any level doesn't match then the filter doesn't match so return failure
        if(bPass == FALSE)
            return FALSE;

        pCurrentLevel = pCurrentLevel->pNext;
    }
    return TRUE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?