📄 cresourceripper.cpp
字号:
// Author: Brandon LaCombe
// Date: February 3, 2006
// License: Public Domain
#include "CResourceRipper.h"
#include "..\..\FileTools.h"
#include "..\..\remem.h"
// user defined types
// Defines the nodes that make up the filter level linked list attachted to each
// RESOURCEFILTER structure.
typedef struct _FILTERLEVEL FILTERLEVEL, *PFILTERLEVEL;
struct _FILTERLEVEL
{
PFILTERLEVEL pNext;
DWORD dwLevel; // level the filter applies to
DWORD dwFlags;
union
{
WORD wId;
PTSTR pString;
};
};
// Defines the nodes that make up the filter linked list.
struct _RESOURCEFILTER
{
PRESOURCEFILTER pNext;
DWORD dwId;
PFILTERLEVEL pLevels;
};
// Defines the nodes that makeup the resource tree structure. The tree mirrors
// the information stored in the resource section of the pe file processed.
struct _RESOURCELEAF
{
// LINKAGE VARIABLES (used to form the tree structure)
PRESOURCELEAF pParent;
PRESOURCELEAF pSibling;
PRESOURCELEAF pChild;
// COMMON VARIABLES (used in directory and data leaves)
DWORD dwLevel; // level of the leaf (total number of parents)
BOOL bDirectory;
BOOL bNameIsString;
union
{
WORD wId;
WORD wNameLength;
};
PTSTR pNameString;
// DATA LEAF VARIABLES (only used if leaf is a data leaf)
BOOL bDeleteFlag;
BOOL bRetain;
DWORD dwDataSize;
union
{
DWORD dwDataRva; // if leaf is not retained then contains the rva
PBYTE pbData; // otherwise it is a memory pointer to the data
};
};
// Combines the three different output pointers into one variable.
struct _RESOURCEPOINTERS
{
PBYTE pbOutput;
PBYTE pbHeaders;
PBYTE pbStrings;
PBYTE pbData;
};
// code start
// Class constructor.
CResourceRipper::CResourceRipper()
{
m_hHeap = GetProcessHeap();
m_pDeletionFilters = NULL;
m_pRetentionFilters = NULL;
m_pResourceTree = NULL;
m_dwHeaderSize = 0;
m_dwStringSize = 0;
m_dwDataSize = 0;
m_bMoveData = TRUE;
m_bNullSource = FALSE;
m_bStrip = FALSE;
}
// Class destructor.
CResourceRipper::~CResourceRipper()
{
DeleteResources(m_pResourceTree, TRUE);
DeleteFilters(&m_pRetentionFilters);
DeleteFilters(&m_pDeletionFilters);
}
// Wrapper around the AddFilter function.
VOID CResourceRipper::AddDeletionFilter(DWORD dwId, DWORD dwLevel, DWORD dwFlags, PVOID pvName)
{
AddFilter(&m_pDeletionFilters, dwId, dwLevel, dwFlags, pvName);
}
// Adds a resource filter to the specified filter linked list.
VOID CResourceRipper::AddFilter(PRESOURCEFILTER * pFilterList, DWORD dwId, DWORD dwLevel, DWORD dwFlags, PVOID pvName)
{
BOOL bRet;
PRESOURCEFILTER pFilter;
PFILTERLEVEL pCurrentLevel,
* ppLink;
DWORD dwLength;
bRet = FALSE;
// get a pointer to a filter with the specified id or create a new filter
// if no filter has that id
pFilter = LocateFilter(*pFilterList, dwId);
if(pFilter == NULL)
pFilter = CreateFilter(pFilterList, dwId);
// go to the end of the level list
ppLink = &pFilter->pLevels;
pCurrentLevel = pFilter->pLevels;
while(pCurrentLevel)
{
// level already exists so edit it
if(pCurrentLevel->dwLevel == dwLevel)
break;
ppLink = &pCurrentLevel->pNext;
pCurrentLevel = pCurrentLevel->pNext;
}
// if the filter level doesn't already exist then create it
if(pCurrentLevel == NULL)
pCurrentLevel = (PFILTERLEVEL)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, sizeof(FILTERLEVEL));
*ppLink = pCurrentLevel;
// if FF_STRING is present in the flags then we must be modifying
// an existing level, so we free the memory associated with pString
if(pCurrentLevel->dwFlags & FF_STRING)
HeapFree(m_hHeap, 0, pCurrentLevel->pString);
pCurrentLevel->dwLevel = dwLevel;
pCurrentLevel->dwFlags = dwFlags;
if(dwFlags & FF_STRING)
{
dwLength = lstrlen((PTSTR)pvName);
pCurrentLevel->pString = (PTSTR)HeapAlloc(m_hHeap, 0, (dwLength + 1) * sizeof(TCHAR));
lstrcpy(pCurrentLevel->pString, (PTSTR)pvName);
}
else
{
pCurrentLevel->wId = (WORD)pvName;
}
}
// Wrapper around the AddFilter function.
VOID CResourceRipper::AddRetentionFilter(DWORD dwId, DWORD dwLevel, DWORD dwFlags, PVOID pvName)
{
AddFilter(&m_pRetentionFilters, dwId, dwLevel, dwFlags, pvName);
}
// Counts the number of siblings the specified leaf has.
DWORD CResourceRipper::CountSiblings(PRESOURCELEAF pLeaf)
{
DWORD dwCount;
PRESOURCELEAF pCurrentLeaf;
dwCount = 0;
pCurrentLeaf = FindFirstLeaf(pLeaf, FALSE);
while(pCurrentLeaf)
{
dwCount++;
pCurrentLeaf = pCurrentLeaf->pSibling;
}
return dwCount;
}
// Creates a filter and adds it to the specified list.
PRESOURCEFILTER CResourceRipper::CreateFilter(PRESOURCEFILTER * pFilterList, DWORD dwId)
{
PRESOURCEFILTER * ppLink,
pNewFilter;
pNewFilter = (PRESOURCEFILTER)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, sizeof(RESOURCEFILTER));
pNewFilter->dwId = dwId;
ppLink = pFilterList;
while(*ppLink)
ppLink = &(*ppLink)->pNext;
*ppLink = pNewFilter;
return pNewFilter;
}
// Deletes a filter tree.
VOID CResourceRipper::DeleteFilters(PRESOURCEFILTER * pFilter)
{
PRESOURCEFILTER pCurrentFilter,
pNextFilter;
PFILTERLEVEL pCurrentLevel,
pNextLevel;
pCurrentFilter = *pFilter;
while(pCurrentFilter)
{
pNextFilter = pCurrentFilter->pNext;
pCurrentLevel = pCurrentFilter->pLevels;
while(pCurrentLevel)
{
pNextLevel = pCurrentLevel->pNext;
if(pCurrentLevel->dwFlags & FF_STRING)
HeapFree(m_hHeap, 0, pCurrentLevel->pString);
HeapFree(m_hHeap, 0, pCurrentLevel);
pCurrentLevel = pNextLevel;
}
HeapFree(m_hHeap, 0, pCurrentFilter);
pCurrentFilter = pNextFilter;
}
*pFilter = NULL;
}
// Deletes a resource leaf.
// Returns TRUE if the leaf deleted was the last leaf at that level.
BOOL CResourceRipper::DeleteLeaf(PRESOURCELEAF pLeaf)
{
BOOL bRet;
PBYTE pbData;
PRESOURCELEAF * ppLink;
// assume there are no sibling leaves
bRet = TRUE;
// here we determine where the specified leaf is linked from
if(pLeaf->pParent)
{
// start with the child of the parent
ppLink = &pLeaf->pParent->pChild;
// keep looping till we find the specified leaf
while(*ppLink != pLeaf)
{
bRet = FALSE;
ppLink = &(*ppLink)->pSibling;
}
}
else
// dummy node, so it's linked from the class member variable
ppLink = &m_pResourceTree;
// unlink the to be deleted leaf
*ppLink = pLeaf->pSibling;
// handle string
if(pLeaf->bNameIsString)
{
HeapFree(m_hHeap, 0, pLeaf->pNameString);
m_dwStringSize -= (pLeaf->wNameLength * sizeof(WCHAR) + sizeof(((PIMAGE_RESOURCE_DIRECTORY_STRING)0)->Length));
}
// handle data
if(pLeaf->bDirectory == FALSE)
{
if(pLeaf->bRetain)
{
VirtualFree(pLeaf->pbData, 0, MEM_RELEASE);
m_dwDataSize -= pLeaf->dwDataSize;
}
else
{
if(m_bNullSource)
{
pbData = RvaToPointer(m_pbFile, pLeaf->dwDataRva);
ZeroMemory(pbData, pLeaf->dwDataSize);
}
}
}
if(pLeaf->pSibling)
bRet = FALSE;
// update header size
if(pLeaf->pParent)
{
m_dwHeaderSize -= sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
if(pLeaf->bDirectory == FALSE)
m_dwHeaderSize -= sizeof(IMAGE_RESOURCE_DATA_ENTRY);
if(bRet)
m_dwHeaderSize -= sizeof(IMAGE_RESOURCE_DIRECTORY);
}
HeapFree(m_hHeap, 0, pLeaf);
return bRet;
}
// Deletes all leaves that are flagged for deletion. Also cleans up empty
// directories. Returns TRUE if the entire tree was deleted.
BOOL CResourceRipper::DeleteResources(PRESOURCELEAF pLeaf, BOOL bDeleteAll)
{
PRESOURCELEAF pCurrentLeaf,
pNextLeaf;
// loop through all siblings
pCurrentLeaf = pLeaf;
while(pCurrentLeaf)
{
pNextLeaf = pCurrentLeaf->pSibling;
// recusively search the tree
if(DeleteResources(pCurrentLeaf->pChild, bDeleteAll))
{
// if all children were delted then delete this one also
if(DeleteLeaf(pCurrentLeaf))
return TRUE; // i have no siblings now
}
else if(pCurrentLeaf->bDirectory == FALSE) // found a data leaf
{
if(pCurrentLeaf->bDeleteFlag || bDeleteAll)
{
if(DeleteLeaf(pCurrentLeaf))
return TRUE; // i have no siblings now
}
}
pCurrentLeaf = pNextLeaf;
}
return FALSE;
}
// Callback used to set deletion flag on filtered resources.
VOID CResourceRipper::DeletionCallback(PRESOURCELEAF pDataLeaf)
{
if(pDataLeaf->bRetain == FALSE)
pDataLeaf->bDeleteFlag = TRUE;
}
// Driver for exporting a resource section.
VOID CResourceRipper::Export(PVOID pvOutput, DWORD dwBaseRva)
{
RESOURCEPOINTERS OutputPointers;
if(pvOutput && m_pResourceTree)
{
OutputPointers.pbOutput = (PBYTE)pvOutput;
OutputPointers.pbHeaders = OutputPointers.pbOutput;
OutputPointers.pbStrings = OutputPointers.pbHeaders + m_dwHeaderSize;
OutputPointers.pbData = OutputPointers.pbStrings + m_dwStringSize;
ExportLeaf(m_pResourceTree, &OutputPointers, dwBaseRva);
}
}
// Exports a leaf and all it's siblings.
VOID CResourceRipper::ExportLeaf(PRESOURCELEAF pParentLeaf, PRESOURCEPOINTERS pOutputPointers, DWORD dwBaseRva)
{
DWORD dwDirSize,
dwEntryCount,
x,
y;
PRESOURCELEAF pCurrentLeaf;
PIMAGE_RESOURCE_DATA_ENTRY pDataEntry;
PIMAGE_RESOURCE_DIRECTORY pDir;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntries;
PIMAGE_RESOURCE_DIRECTORY_STRING pString;
pCurrentLeaf = pParentLeaf->pChild;
if(pCurrentLeaf)
{
// reserve memory for directories and entries
pDir = (PIMAGE_RESOURCE_DIRECTORY)pOutputPointers->pbHeaders;
pEntries = PIMAGE_RESOURCE_DIRECTORY_ENTRY(pDir + 1);
dwEntryCount = CountSiblings(pCurrentLeaf);
dwDirSize = sizeof(IMAGE_RESOURCE_DIRECTORY) + sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) * dwEntryCount;
ZeroMemory(pOutputPointers->pbHeaders, dwDirSize);
pOutputPointers->pbHeaders += dwDirSize;
// loop through each leaf
for(x = 0; x < dwEntryCount; x++)
{
// handle naming
if(pCurrentLeaf->bNameIsString)
{
pDir->NumberOfNamedEntries++;
pEntries[x].NameIsString = TRUE;
pEntries[x].NameOffset = pOutputPointers->pbStrings - pOutputPointers->pbOutput;
pString = (PIMAGE_RESOURCE_DIRECTORY_STRING)pOutputPointers->pbStrings;
pString->Length = pCurrentLeaf->wNameLength;
// need to copy char by char for ansi compilations
for(y = 0; y < pString->Length; y++)
PWSTR(pString->NameString)[y] = (WCHAR)pCurrentLeaf->pNameString[y];
pOutputPointers->pbStrings += (pCurrentLeaf->wNameLength * sizeof(WCHAR) + sizeof(pString->Length));
}
else
{
pDir->NumberOfIdEntries++;
pEntries[x].Id = pCurrentLeaf->wId;
}
// handle directory/data pointer
if(pCurrentLeaf->bDirectory)
{
pEntries[x].DataIsDirectory = TRUE;
pEntries[x].OffsetToDirectory = pOutputPointers->pbHeaders - pOutputPointers->pbOutput;
// recursively handle the directory
ExportLeaf(pCurrentLeaf, pOutputPointers, dwBaseRva);
}
else
{
pEntries[x].OffsetToData = DWORD(pOutputPointers->pbHeaders - pOutputPointers->pbOutput);
pDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)pOutputPointers->pbHeaders;
ZeroMemory(pDataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY));
pOutputPointers->pbHeaders += sizeof(IMAGE_RESOURCE_DATA_ENTRY);
pDataEntry->Size = pCurrentLeaf->dwDataSize;
// do we need to use the old data rva or write new data?
if(pCurrentLeaf->bRetain)
{
CopyMemory(pOutputPointers->pbData, pCurrentLeaf->pbData, pCurrentLeaf->dwDataSize);
pDataEntry->OffsetToData = dwBaseRva + (pOutputPointers->pbData - pOutputPointers->pbOutput);
pOutputPointers->pbData += pCurrentLeaf->dwDataSize;
}
else
pDataEntry->OffsetToData = pCurrentLeaf->dwDataRva;
}
pCurrentLeaf = pCurrentLeaf->pSibling;
}
}
}
// Wraps the recursive function ProcessDirectory to encapsulate its operation.
VOID CResourceRipper::ExtractResources()
{
m_dwHeaderSize = 0;
m_dwStringSize = 0;
m_dwDataSize = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -