在 PE 可选头的数据目录里,DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] 保存着数字签名的位置和大小。要清除数字签名,只要根据这些信息删除掉数字签名,再把字段清零就可以了。
关键代码如下:
先把文件映射到内存:
__forceinline LPVOID MapPeFile(LPCWSTR pwzFile, PLARGE_INTEGER lpFileSize)
{
if (StrSafeLen(pwzFile) <= 0) // 如果传入的文件路径为空
return NULL;
HANDLE hFile = CreateFileW(pwzFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return NULL;
GetFileSizeEx(hFile, lpFileSize);
HANDLE hMapFile = CreateFileMappingW(hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL);
CloseHandle(hFile);
if (NULL == hMapFile)
return NULL;
LPVOID pRet = MapViewOfFile(hMapFile,
FILE_MAP_READ,
0,
0,
0);
CloseHandle(hMapFile);
return pRet;
}
判断 PE 文件是否有效
// 判断 PE 文件格式是否是无效的
__forceinline BOOL IsInvalidPe(LPVOID pBase)
{
if (NULL == pBase)
return TRUE;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase;
if (IMAGE_DOS_SIGNATURE != pDosHeader->e_magic)
return TRUE;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pBase + pDosHeader->e_lfanew);
if (IMAGE_NT_SIGNATURE != pNtHeaders->Signature)
return TRUE;
return FALSE;
}
再获取数字签名的位置和大小:
__forceinline BOOL GetPeSignOffsetAndSize(LPVOID pBase, LPDWORD lpOffset, LPDWORD lpSize)
{
if (NULL == pBase || NULL == lpOffset || NULL == lpSize)
return FALSE;
*lpOffset = *lpSize = 0;
if (IsInvalidPe(pBase))
return FALSE;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBase;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pBase + pDosHeader->e_lfanew);
*lpOffset = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
*lpSize = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
if (0 == *lpOffset || 0 == *lpSize)
return FALSE;
return TRUE;
}
清除数字签名:
__forceinline BOOL RemovePeSign(LPVOID pBase, PLARGE_INTEGER lpFileSize, LPCWSTR pwzNewFile)
{
BOOL bRet = FALSE;
if (NULL == pBase || NULL == lpFileSize)
return FALSE;
if (IsInvalidPe(pBase))
return FALSE;
DWORD dwOffset;
DWORD dwSize;
GetPeSignOffsetAndSize(pBase, &dwOffset, &dwSize);
if (0 == dwOffset || 0 == dwSize)
return FALSE;
LPVOID pNewBase = VirtualAlloc(NULL, lpFileSize->LowPart, MEM_COMMIT, PAGE_READWRITE);
if (NULL == pNewBase)
return FALSE;
DWORD dwRealFileSize = lpFileSize->LowPart - dwSize;
memcpy(pNewBase, pBase, dwRealFileSize);
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pNewBase;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pNewBase + pDosHeader->e_lfanew);
pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = 0;
pNtHeaders->OptionalHeader.CheckSum = 0;
// 重新计算校检和
DWORD dwHeaderSum, dwCheckSum;
CheckSumMappedFile(pNewBase, dwRealFileSize, &dwHeaderSum, &dwCheckSum);
pNtHeaders->OptionalHeader.CheckSum = dwCheckSum;
HANDLE hFile = CreateFile(pwzNewFile,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
goto _exit;
DWORD dwBytes;
bRet = WriteFile(hFile, pNewBase, dwRealFileSize, &dwBytes, NULL);
CloseHandle(hFile);
_exit:
VirtualFree(pNewBase, 0, MEM_RELEASE);
return bRet;
}
最后的清理工作:
__forceinline void UnmapPeFile(LPVOID pBase)
{
if (NULL != pBase)
UnmapViewOfFile(pBase);
}
一个简单的图形界面:
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法