📄 cimportripper.cpp
字号:
// Author: Brandon LaCombe
// Date: February 3, 2006
// License: Public Domain
#include "CImportRipper.h"
#include "..\Loader\loaderstructs.h"
#include "..\..\FileTools.h"
#include "..\..\remem.h"
// user defined types
// Defines a structure that details information about an imported dll.
struct _IMPORTED_DLL
{
PIMPORTED_DLL pLink;
PSTR pDllName;
BOOL bImportIsString;
union
{
WORD wOrdinal;
PSTR pFunctionName;
};
};
// code start
// Class constructor.
CImportRipper::CImportRipper()
{
m_hHeap = GetProcessHeap();
m_pImportedDlls = NULL;
m_dwHeaderSize = sizeof(KERNEL_IAT) + (sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2);
m_dwStringSize = sizeof("KERNEL32.DLL") +
sizeof("GetModuleHandleA") +
sizeof("GetProcAddress") +
sizeof("VirtualAlloc") +
sizeof("VirtualFree") +
sizeof("VirtualProtect");
}
// Class destructor
CImportRipper::~CImportRipper()
{
DeleteImportedDlls();
}
// Calculates the rva where the import descriptor array starts
DWORD CImportRipper::CalculateDescriptorRva(DWORD dwBaseRva)
{
return dwBaseRva + sizeof(KERNEL_IAT);
}
// Creates a new dll structure and adds it to the end of the dll list.
PIMPORTED_DLL CImportRipper::CreateImportedDll()
{
PIMPORTED_DLL pNewDll,
* ppLink;
pNewDll = (PIMPORTED_DLL)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, sizeof(IMPORTED_DLL));
ppLink = &m_pImportedDlls;
while(*ppLink)
ppLink = &(*ppLink)->pLink;
*ppLink = pNewDll;
return pNewDll;
}
// Frees all the imported dll structures.
VOID CImportRipper::DeleteImportedDlls()
{
PIMPORTED_DLL pCurrentDll,
pNextDll;
pCurrentDll = m_pImportedDlls;
while(pCurrentDll)
{
pNextDll = pCurrentDll->pLink;
HeapFree(m_hHeap, 0, pCurrentDll->pDllName);
if(pCurrentDll->bImportIsString)
HeapFree(m_hHeap, 0, pCurrentDll->pFunctionName);
HeapFree(m_hHeap, 0, pCurrentDll);
pCurrentDll = pNextDll;
}
m_pImportedDlls = NULL;
m_dwHeaderSize = sizeof(KERNEL_IAT) + (sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2);
m_dwStringSize = sizeof("KERNEL32.DLL") +
sizeof("GetModuleHandleA") +
sizeof("GetProcAddress") +
sizeof("VirtualAlloc") +
sizeof("VirtualFree") +
sizeof("VirtualProtect");
}
// Exports an import section.
VOID CImportRipper::Export(PVOID pvOutput, DWORD dwBaseRva)
{
PBYTE pbHeaders,
pbStrings;
PIMPORTED_DLL pCurrentDll;
PIMAGE_IMPORT_DESCRIPTOR pDescriptor;
if(pvOutput)
{
pbHeaders = (PBYTE)pvOutput;
pbStrings = pbHeaders + m_dwHeaderSize;
// write the kernel descriptor and iat
WriteKernelData(&pbHeaders, &pbStrings, dwBaseRva);
// write the other dll descriptors
pCurrentDll = m_pImportedDlls;
while(pCurrentDll)
{
pDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)pbHeaders;
pbHeaders += sizeof(IMAGE_IMPORT_DESCRIPTOR);
// all iats have only one entry, so we use the two unused members of
// the descriptor to house the 8 byte iat (TimeDateStamp and
// ForwarderChain)
pDescriptor->OriginalFirstThunk = DWORD((PBYTE)&pDescriptor->TimeDateStamp - (PBYTE)pvOutput) + dwBaseRva;
pDescriptor->FirstThunk = pDescriptor->OriginalFirstThunk;
// copy dll name
pDescriptor->Name = DWORD(pbStrings - (PBYTE)pvOutput) + dwBaseRva;
lstrcpyA((PSTR)pbStrings, pCurrentDll->pDllName);
pbStrings += (lstrlenA(pCurrentDll->pDllName) + 1);
// handle the single iat entry
// TimeDateStamp is used as the iat entry; calculate string rva
if(pCurrentDll->bImportIsString)
{
pDescriptor->TimeDateStamp = DWORD(pbStrings - (PBYTE)pvOutput) + dwBaseRva - 2;
lstrcpyA((PSTR)pbStrings, pCurrentDll->pFunctionName);
pbStrings += (lstrlenA(pCurrentDll->pFunctionName) + 1);
}
else
pDescriptor->TimeDateStamp = IMAGE_ORDINAL_FLAG | pCurrentDll->wOrdinal;
// ForwarderChain is used as the null terminating iat entry
pDescriptor->ForwarderChain = NULL;
pCurrentDll = pCurrentDll->pLink;
}
ZeroMemory(pbHeaders, sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
}
// Gathers import information from a pe file and saves the collected data to a
// linked list. The dll name and the import with the shortest name is recorded.
VOID CImportRipper::ExtractImports()
{
DWORD dwDllNameLength,
dwFunctionNameLength,
dwINTSize,
dwShortestIndex;
PIMAGE_IMPORT_DESCRIPTOR pCurrentDesc;
PSTR pDllName;
PDWORD pdwIAT,
pdwINT;
PIMAGE_IMPORT_BY_NAME pFunctionName;
PIMPORTED_DLL pNewDll;
PVOID pvINTBackup;
pCurrentDesc = (PIMAGE_IMPORT_DESCRIPTOR)m_pbImports;
while(pCurrentDesc->FirstThunk)
{
pdwINT = (PDWORD)RvaToPointer(m_pbFile, pCurrentDesc->OriginalFirstThunk);
pvINTBackup = NULL;
// if an OriginalFirstThunk chain exists we copy it to the
// FirstThunk chain and null out the OriginalFirstThunk chain
if(pdwINT)
{
// calculate size of the chain
for(dwINTSize = 0; pdwINT[dwINTSize]; dwINTSize++);
dwINTSize *= sizeof(DWORD);
pvINTBackup = HeapAlloc(m_hHeap, 0, dwINTSize);
CopyMemory(pvINTBackup, pdwINT, dwINTSize);
ZeroMemory(pdwINT, dwINTSize);
pCurrentDesc->OriginalFirstThunk = NULL;
}
pdwIAT = (PDWORD)RvaToPointer(m_pbFile, pCurrentDesc->FirstThunk);
// generally we want to null these two unused fields in the input
// file, but not if they are being used as the iat
if(pdwIAT != &pCurrentDesc->TimeDateStamp)
{
pCurrentDesc->TimeDateStamp = NULL;
pCurrentDesc->ForwarderChain = NULL;
}
// copy the OriginalFirstThunk chain to the FirstThunkChain
if(pvINTBackup)
{
CopyMemory(pdwIAT, pvINTBackup, dwINTSize);
HeapFree(m_hHeap, 0, pvINTBackup);
}
// now we copy the dll info to the class
pDllName = (PSTR)RvaToPointer(m_pbFile, pCurrentDesc->Name);
if(IsDllUnique(pDllName))
{
dwShortestIndex = FindShortestFunctionName(pdwIAT);
if(dwShortestIndex != -1)
{
pNewDll = CreateImportedDll();
dwDllNameLength = lstrlenA(pDllName) + 1;
pNewDll->pDllName = (PSTR)HeapAlloc(m_hHeap, 0, dwDllNameLength);
lstrcpyA(pNewDll->pDllName, pDllName);
dwFunctionNameLength = 0;
if(pdwIAT[dwShortestIndex] & IMAGE_ORDINAL_FLAG)
pNewDll->wOrdinal = (WORD)IMAGE_ORDINAL(pdwIAT[dwShortestIndex]);
else
{
pNewDll->bImportIsString = TRUE;
pFunctionName = (PIMAGE_IMPORT_BY_NAME)RvaToPointer(m_pbFile, pdwIAT[dwShortestIndex]);
dwFunctionNameLength = lstrlenA((PSTR)pFunctionName->Name) + 1;
pNewDll->pFunctionName = (PSTR)HeapAlloc(m_hHeap, 0, dwFunctionNameLength);
lstrcpyA(pNewDll->pFunctionName, (PSTR)pFunctionName->Name);
}
m_dwStringSize += (dwDllNameLength + dwFunctionNameLength);
m_dwHeaderSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
}
}
pCurrentDesc++;
}
}
// Finds the index in an import table that has the shortest function name.
// Ordinals are considered to have a name length of zero.
DWORD CImportRipper::FindShortestFunctionName(PDWORD pdwINT)
{
DWORD x,
dwShortestIndex,
dwShortestLength,
dwNameLength;
PIMAGE_IMPORT_BY_NAME pFunctionName;
dwShortestLength = INFINITE;
dwShortestIndex = -1;
for(x = 0; pdwINT[x]; x++)
{
if(pdwINT[x] & IMAGE_ORDINAL_FLAG)
{
dwShortestIndex = x;
break;
}
else
{
pFunctionName = (PIMAGE_IMPORT_BY_NAME)RvaToPointer(m_pbFile, pdwINT[x]);
if(pFunctionName)
{
dwNameLength = lstrlenA((PSTR)pFunctionName->Name);
if(dwNameLength < dwShortestLength)
{
dwShortestLength = dwNameLength;
dwShortestIndex = x;
}
}
}
}
return dwShortestIndex;
}
// Returns size of the import section.
DWORD CImportRipper::GetSize()
{
return m_dwHeaderSize + m_dwStringSize;
}
// Ensures that the given dll name is not currently recorded in the dll info
// list.
BOOL CImportRipper::IsDllUnique(PSTR pDllName)
{
BOOL bRet;
PIMPORTED_DLL pCurrentDll;
bRet = TRUE;
if(pDllName)
{
// kernel32.dll is always used, so no need to reimport it
if(lstrcmpiA(pDllName, "KERNEL32.DLL") == 0)
bRet = FALSE;
pCurrentDll = m_pImportedDlls;
while(bRet && pCurrentDll)
{
if(lstrcmpiA(pDllName, pCurrentDll->pDllName) == 0)
bRet = FALSE;
pCurrentDll = pCurrentDll->pLink;
}
}
else bRet = FALSE; // if the given name pointer is invalid then return false
return bRet;
}
// Loads the input file. Returns FALSE if no import section exists.
BOOL CImportRipper::LoadFile(PBYTE pbFile)
{
BOOL bRet;
DWORD dwImportsRva;
PIMAGE_NT_HEADERS pNt;
bRet = FALSE;
m_pbFile = pbFile;
pNt = PIMAGE_NT_HEADERS(pbFile + PIMAGE_DOS_HEADER(pbFile)->e_lfanew);
dwImportsRva = pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
m_pbImports = RvaToPointer(pbFile, dwImportsRva);
if(m_pbImports) bRet = TRUE;
return bRet;
}
// Rips the import section from the input file.
VOID CImportRipper::Rip(PVOID pvFile)
{
DeleteImportedDlls();
if(LoadFile((PBYTE)pvFile))
{
ExtractImports();
}
// strip any bound import table
StripBoundImportsFromFile();
}
// Strips any bound import table.
VOID CImportRipper::StripBoundImportsFromFile()
{
DWORD dwRefCount,
x;
PBYTE pbBoundImports,
pbString;
PIMAGE_BOUND_IMPORT_DESCRIPTOR pDesc;
PIMAGE_BOUND_FORWARDER_REF pRef;
PIMAGE_NT_HEADERS pNt;
pNt = PIMAGE_NT_HEADERS(m_pbFile + PIMAGE_DOS_HEADER(m_pbFile)->e_lfanew);
pbBoundImports = RvaToPointer(m_pbFile, pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress);
if(pbBoundImports)
{
pDesc = PIMAGE_BOUND_IMPORT_DESCRIPTOR(pbBoundImports);
while(pDesc->TimeDateStamp)
{
dwRefCount = pDesc->NumberOfModuleForwarderRefs;
// null out module name
if(pDesc->OffsetModuleName)
{
pbString = pbBoundImports + pDesc->OffsetModuleName;
for(; *pbString; pbString++)
*pbString = NULL;
}
// null out forwarder refs
pRef = PIMAGE_BOUND_FORWARDER_REF(pDesc + 1);
for(x = 0; x < dwRefCount; x++)
{
// null out module name
if(pRef[x].OffsetModuleName)
{
pbString = pbBoundImports + pRef[x].OffsetModuleName;
for(; *pbString; pbString++)
*pbString = NULL;
}
ZeroMemory(&pRef[x], sizeof(IMAGE_BOUND_FORWARDER_REF));
}
ZeroMemory(pDesc, sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR));
// skip past import descriptor and any forwarder refs
pDesc++;
pDesc = PIMAGE_BOUND_IMPORT_DESCRIPTOR(PIMAGE_BOUND_FORWARDER_REF(pDesc) + dwRefCount);
}
}
}
// Writes the kernel import information that is used by the loader.
VOID CImportRipper::WriteKernelData(PBYTE * ppbHeaders, PBYTE * ppbStrings, DWORD dwBaseRva)
{
PIMAGE_IMPORT_DESCRIPTOR pKernelDesc;
union
{
PKERNEL_IAT pKernelIAT;
PBYTE pbBase;
};
pKernelIAT = (PKERNEL_IAT)*ppbHeaders;
pKernelDesc = PIMAGE_IMPORT_DESCRIPTOR(*ppbHeaders + sizeof(KERNEL_IAT));
*ppbHeaders += (sizeof(KERNEL_IAT) + sizeof(IMAGE_IMPORT_DESCRIPTOR));
ZeroMemory(pKernelDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
pKernelDesc->OriginalFirstThunk = dwBaseRva;
pKernelDesc->FirstThunk = pKernelDesc->OriginalFirstThunk;
// copy the dll name and store it's rva
pKernelDesc->Name = DWORD(*ppbStrings - pbBase) + dwBaseRva;
lstrcpyA((PSTR)*ppbStrings, "KERNEL32.DLL");
*ppbStrings += sizeof("KERNEL32.DLL");
// copy GetModuleHandleA and store it's rva in the iat
pKernelIAT->pGetModuleHandleA = DWORD(*ppbStrings - pbBase) + dwBaseRva - 2;
lstrcpyA((PSTR)*ppbStrings, "GetModuleHandleA");
*ppbStrings += sizeof("GetModuleHandleA");
// copy GetProcAddress and store it's rva in the iat
pKernelIAT->pGetProcAddress = DWORD(*ppbStrings - pbBase) + dwBaseRva - 2;
lstrcpyA((PSTR)*ppbStrings, "GetProcAddress");
*ppbStrings += sizeof("GetProcAddress");
// copy VirtualAlloc and store it's rva in the iat
pKernelIAT->pVirtualAlloc = DWORD(*ppbStrings - pbBase) + dwBaseRva - 2;
lstrcpyA((PSTR)*ppbStrings, "VirtualAlloc");
*ppbStrings += sizeof("VirtualAlloc");
// copy VirtualFree and store it's rva in the iat
pKernelIAT->pVirtualFree = DWORD(*ppbStrings - pbBase) + dwBaseRva - 2;
lstrcpyA((PSTR)*ppbStrings, "VirtualFree");
*ppbStrings += sizeof("VirtualFree");
// copy VirtualProtect and store it's rva in the iat
pKernelIAT->pVirtualProtect = DWORD(*ppbStrings - pbBase) + dwBaseRva - 2;
lstrcpyA((PSTR)*ppbStrings, "VirtualProtect");
*ppbStrings += sizeof("VirtualProtect");
// ensure terminating iat entry is null
pKernelIAT->dwNullEntry = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -