mirror of
https://github.com/shadps4-emu/ext-cryptopp.git
synced 2025-02-12 08:11:05 +00:00
change DLL integrity self-test to allow DLL to be Authenticode signed
This commit is contained in:
parent
a0c89ccaae
commit
1b6b327200
108
filters.cpp
108
filters.cpp
@ -141,46 +141,86 @@ bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocki
|
||||
|
||||
// *************************************************************
|
||||
|
||||
void MeterFilter::ResetMeter()
|
||||
{
|
||||
m_currentMessageBytes = m_totalBytes = m_currentSeriesMessages = m_totalMessages = m_totalMessageSeries = 0;
|
||||
m_rangesToSkip.clear();
|
||||
}
|
||||
|
||||
void MeterFilter::AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow)
|
||||
{
|
||||
MessageRange r = {message, position, size};
|
||||
m_rangesToSkip.push_back(r);
|
||||
if (sortNow)
|
||||
std::sort(m_rangesToSkip.begin(), m_rangesToSkip.end());
|
||||
}
|
||||
|
||||
size_t MeterFilter::PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable)
|
||||
{
|
||||
if (!m_transparent)
|
||||
return 0;
|
||||
|
||||
size_t t;
|
||||
FILTER_BEGIN;
|
||||
|
||||
m_begin = begin;
|
||||
m_length = length;
|
||||
|
||||
while (m_length > 0 || messageEnd)
|
||||
{
|
||||
if (!m_rangesToSkip.empty() && m_rangesToSkip.front().message == m_totalMessages && m_currentMessageBytes + m_length > m_rangesToSkip.front().position)
|
||||
{
|
||||
FILTER_OUTPUT_MAYBE_MODIFIABLE(1, m_begin, t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position, m_currentMessageBytes), false, modifiable);
|
||||
|
||||
assert(t < m_length);
|
||||
m_begin += t;
|
||||
m_length -= t;
|
||||
m_currentMessageBytes += t;
|
||||
m_totalBytes += t;
|
||||
|
||||
if (m_currentMessageBytes + m_length < m_rangesToSkip.front().position + m_rangesToSkip.front().size)
|
||||
t = m_length;
|
||||
else
|
||||
{
|
||||
t = (size_t)SaturatingSubtract(m_rangesToSkip.front().position + m_rangesToSkip.front().size, m_currentMessageBytes);
|
||||
assert(t <= m_length);
|
||||
m_rangesToSkip.pop_front();
|
||||
}
|
||||
|
||||
m_begin += t;
|
||||
m_length -= t;
|
||||
m_currentMessageBytes += t;
|
||||
m_totalBytes += t;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILTER_OUTPUT_MAYBE_MODIFIABLE(2, m_begin, m_length, messageEnd, modifiable);
|
||||
|
||||
m_currentMessageBytes += m_length;
|
||||
m_totalBytes += m_length;
|
||||
m_length = 0;
|
||||
|
||||
if (messageEnd)
|
||||
{
|
||||
m_currentMessageBytes = 0;
|
||||
m_currentSeriesMessages++;
|
||||
m_totalMessages++;
|
||||
messageEnd = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FILTER_END_NO_MESSAGE_END;
|
||||
}
|
||||
|
||||
size_t MeterFilter::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
|
||||
{
|
||||
if (m_transparent)
|
||||
{
|
||||
FILTER_BEGIN;
|
||||
m_currentMessageBytes += length;
|
||||
m_totalBytes += length;
|
||||
|
||||
if (messageEnd)
|
||||
{
|
||||
m_currentMessageBytes = 0;
|
||||
m_currentSeriesMessages++;
|
||||
m_totalMessages++;
|
||||
}
|
||||
|
||||
FILTER_OUTPUT(1, begin, length, messageEnd);
|
||||
FILTER_END_NO_MESSAGE_END;
|
||||
}
|
||||
return 0;
|
||||
return PutMaybeModifiable(const_cast<byte *>(begin), length, messageEnd, blocking, false);
|
||||
}
|
||||
|
||||
size_t MeterFilter::PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking)
|
||||
{
|
||||
if (m_transparent)
|
||||
{
|
||||
FILTER_BEGIN;
|
||||
m_currentMessageBytes += length;
|
||||
m_totalBytes += length;
|
||||
|
||||
if (messageEnd)
|
||||
{
|
||||
m_currentMessageBytes = 0;
|
||||
m_currentSeriesMessages++;
|
||||
m_totalMessages++;
|
||||
}
|
||||
|
||||
FILTER_OUTPUT_MODIFIABLE(1, begin, length, messageEnd);
|
||||
FILTER_END_NO_MESSAGE_END;
|
||||
}
|
||||
return 0;
|
||||
return PutMaybeModifiable(begin, length, messageEnd, blocking, true);
|
||||
}
|
||||
|
||||
bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking)
|
||||
|
13
filters.h
13
filters.h
@ -7,6 +7,7 @@
|
||||
#include "smartptr.h"
|
||||
#include "queue.h"
|
||||
#include "algparam.h"
|
||||
#include <deque>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
@ -86,7 +87,9 @@ public:
|
||||
: m_transparent(transparent) {Detach(attachment); ResetMeter();}
|
||||
|
||||
void SetTransparent(bool transparent) {m_transparent = transparent;}
|
||||
void ResetMeter() {m_currentMessageBytes = m_totalBytes = m_currentSeriesMessages = m_totalMessages = m_totalMessageSeries = 0;}
|
||||
void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true);
|
||||
void ResetMeter();
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters) {ResetMeter();}
|
||||
|
||||
lword GetCurrentMessageBytes() const {return m_currentMessageBytes;}
|
||||
lword GetTotalBytes() {return m_totalBytes;}
|
||||
@ -101,12 +104,20 @@ public:
|
||||
bool IsolatedMessageSeriesEnd(bool blocking);
|
||||
|
||||
private:
|
||||
size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable);
|
||||
bool ShouldPropagateMessageEnd() const {return m_transparent;}
|
||||
bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;}
|
||||
|
||||
struct MessageRange {unsigned int message; lword position; lword size;};
|
||||
friend inline bool operator<(const MessageRange &a, const MessageRange &b)
|
||||
{return a.message < b.message || (a.message == b.message && a.position < b.position);}
|
||||
|
||||
bool m_transparent;
|
||||
lword m_currentMessageBytes, m_totalBytes;
|
||||
unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries;
|
||||
std::deque<MessageRange> m_rangesToSkip;
|
||||
byte *m_begin;
|
||||
size_t m_length;
|
||||
};
|
||||
|
||||
//! _
|
||||
|
68
fipstest.cpp
68
fipstest.cpp
@ -8,7 +8,17 @@
|
||||
#include "dll.h"
|
||||
|
||||
#ifdef CRYPTOPP_WIN32_AVAILABLE
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 14
|
||||
#ifdef _M_IX86
|
||||
#define _CRT_DEBUGGER_HOOK _crt_debugger_hook
|
||||
#else
|
||||
#define _CRT_DEBUGGER_HOOK __crt_debugger_hook
|
||||
#endif
|
||||
extern "C" {_CRTIMP void __cdecl _CRT_DEBUGGER_HOOK(int);}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
@ -249,20 +259,31 @@ bool IntegrityCheckModule(const char *moduleFilename, const byte *expectedModule
|
||||
unsigned long &macFileLocation = pMacFileLocation ? *pMacFileLocation : tempLocation;
|
||||
macFileLocation = 0;
|
||||
|
||||
HashFilter verifier(*mac, new ArraySink(actualMac, actualMac.size()));
|
||||
// FileSink verifier("c:\\dt.tmp");
|
||||
MeterFilter verifier(new HashFilter(*mac, new ArraySink(actualMac, actualMac.size())));
|
||||
// MeterFilter verifier(new FileSink("c:\\dt.tmp"));
|
||||
FileStore file(moduleFilename);
|
||||
|
||||
#ifdef CRYPTOPP_WIN32_AVAILABLE
|
||||
// try to hash from memory first
|
||||
HMODULE h = GetModuleHandle(moduleFilename);
|
||||
const byte *memBase = (const byte *)h;
|
||||
IMAGE_DOS_HEADER *ph = (IMAGE_DOS_HEADER *)h;
|
||||
IMAGE_NT_HEADERS *phnt = (IMAGE_NT_HEADERS *)((byte *)h + ph->e_lfanew);
|
||||
IMAGE_SECTION_HEADER *phs = IMAGE_FIRST_SECTION(phnt);
|
||||
const IMAGE_DOS_HEADER *ph = (IMAGE_DOS_HEADER *)memBase;
|
||||
const IMAGE_NT_HEADERS *phnt = (IMAGE_NT_HEADERS *)(memBase + ph->e_lfanew);
|
||||
const IMAGE_SECTION_HEADER *phs = IMAGE_FIRST_SECTION(phnt);
|
||||
DWORD nSections = phnt->FileHeader.NumberOfSections;
|
||||
size_t currentFilePos = 0;
|
||||
|
||||
size_t checksumPos = (byte *)&phnt->OptionalHeader.CheckSum - memBase;
|
||||
size_t checksumSize = sizeof(phnt->OptionalHeader.CheckSum);
|
||||
size_t certificateTableDirectoryPos = (byte *)&phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] - memBase;
|
||||
size_t certificateTableDirectorySize = sizeof(phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
|
||||
size_t certificateTablePos = phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
|
||||
size_t certificateTableSize = phnt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
|
||||
|
||||
verifier.AddRangeToSkip(0, checksumPos, checksumSize);
|
||||
verifier.AddRangeToSkip(0, certificateTableDirectoryPos, certificateTableDirectorySize);
|
||||
verifier.AddRangeToSkip(0, certificateTablePos, certificateTableSize);
|
||||
|
||||
while (nSections--)
|
||||
{
|
||||
switch (phs->Characteristics)
|
||||
@ -295,16 +316,27 @@ bool IntegrityCheckModule(const char *moduleFilename, const byte *expectedModule
|
||||
}
|
||||
}
|
||||
|
||||
file.TransferTo(verifier, subSectionFileStart - currentFilePos);
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 14
|
||||
// first byte of _CRT_DEBUGGER_HOOK gets modified in memory by the debugger invisibly, so read it from file
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
if (subSectionMemStart <= (byte *)&_CRT_DEBUGGER_HOOK && (byte *)&_CRT_DEBUGGER_HOOK < subSectionMemStart + subSectionSize)
|
||||
{
|
||||
subSectionSize = (byte *)&_CRT_DEBUGGER_HOOK - subSectionMemStart;
|
||||
nextSubSectionStart = (byte *)&_CRT_DEBUGGER_HOOK - sectionMemStart + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (subSectionMemStart <= expectedModuleMac && expectedModuleMac < subSectionMemStart + subSectionSize)
|
||||
{
|
||||
// skip over the MAC
|
||||
verifier.Put(subSectionMemStart, expectedModuleMac - subSectionMemStart);
|
||||
verifier.Put(expectedModuleMac + macSize, subSectionSize - macSize - (expectedModuleMac - subSectionMemStart));
|
||||
// found stored MAC
|
||||
macFileLocation = (unsigned long)(subSectionFileStart + (expectedModuleMac - subSectionMemStart));
|
||||
verifier.AddRangeToSkip(0, macFileLocation, macSize);
|
||||
}
|
||||
else
|
||||
verifier.Put(subSectionMemStart, subSectionSize);
|
||||
|
||||
file.TransferTo(verifier, subSectionFileStart - currentFilePos);
|
||||
verifier.Put(subSectionMemStart, subSectionSize);
|
||||
file.Skip(subSectionSize);
|
||||
currentFilePos = subSectionFileStart + subSectionSize;
|
||||
subSectionStart = nextSubSectionStart;
|
||||
@ -321,13 +353,13 @@ bool IntegrityCheckModule(const char *moduleFilename, const byte *expectedModule
|
||||
if (memcmp(expectedModuleMac, actualMac, macSize) != 0)
|
||||
{
|
||||
OutputDebugString("In memory integrity check failed. This may be caused by debug breakpoints or DLL relocation.\n");
|
||||
file.Initialize(MakeParameters("InputFileName", moduleFilename));
|
||||
verifier.Detach(new ArraySink(actualMac, actualMac.size()));
|
||||
if (macFileLocation)
|
||||
{
|
||||
file.TransferTo(verifier, macFileLocation);
|
||||
file.Skip(macSize);
|
||||
}
|
||||
file.Initialize(MakeParameters(Name::InputFileName(), moduleFilename));
|
||||
verifier.Initialize(MakeParameters(Name::OutputBuffer(), ByteArrayParameter(actualMac, (unsigned int)actualMac.size())));
|
||||
// verifier.Initialize(MakeParameters(Name::OutputFileName(), (const char *)"c:\\dt2.tmp"));
|
||||
verifier.AddRangeToSkip(0, checksumPos, checksumSize);
|
||||
verifier.AddRangeToSkip(0, certificateTableDirectoryPos, certificateTableDirectorySize);
|
||||
verifier.AddRangeToSkip(0, certificateTablePos, certificateTableSize);
|
||||
verifier.AddRangeToSkip(0, macFileLocation, macSize);
|
||||
file.TransferAllTo(verifier);
|
||||
}
|
||||
#endif
|
||||
|
11
fltrimpl.h
11
fltrimpl.h
@ -50,4 +50,15 @@
|
||||
#define FILTER_OUTPUT_MODIFIABLE(site, output, length, messageEnd) \
|
||||
FILTER_OUTPUT2_MODIFIABLE(site, 0, output, length, messageEnd)
|
||||
|
||||
#define FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, statement, output, length, messageEnd, modifiable) \
|
||||
{\
|
||||
case site: \
|
||||
statement; \
|
||||
if (modifiable ? OutputModifiable(site, output, length, messageEnd, blocking) : Output(site, output, length, messageEnd, blocking)) \
|
||||
return STDMAX(size_t(1), length-m_inputPosition);\
|
||||
}
|
||||
|
||||
#define FILTER_OUTPUT_MAYBE_MODIFIABLE(site, output, length, messageEnd, modifiable) \
|
||||
FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, 0, output, length, messageEnd, modifiable)
|
||||
|
||||
#endif
|
||||
|
2
misc.h
2
misc.h
@ -224,7 +224,7 @@ template <class T1, class T2>
|
||||
inline bool SafeConvert(T1 from, T2 &to)
|
||||
{
|
||||
to = (T2)from;
|
||||
if (from != to || (from > 0 && to < 0))
|
||||
if (from != to || (from > 0) != (to > 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
43
test.cpp
43
test.cpp
@ -170,38 +170,61 @@ int __cdecl main(int argc, char *argv[])
|
||||
}
|
||||
else if (command == "mac_dll")
|
||||
{
|
||||
// sanity check on file size
|
||||
std::fstream dllFile(argv[2], ios::in | ios::out | ios::binary);
|
||||
std::ifstream::pos_type fileEnd = dllFile.seekg(0, std::ios_base::end).tellg();
|
||||
if (fileEnd > 20*1000*1000) // sanity check on file size
|
||||
if (fileEnd > 20*1000*1000)
|
||||
{
|
||||
cerr << "Input file too large (more than 20 MB).\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read file into memory
|
||||
unsigned int fileSize = (unsigned int)fileEnd;
|
||||
SecByteBlock buf(fileSize);
|
||||
dllFile.seekg(0, std::ios_base::beg);
|
||||
dllFile.read((char *)buf.begin(), fileSize);
|
||||
|
||||
byte dummyMac[] = CRYPTOPP_DUMMY_DLL_MAC;
|
||||
// find positions of relevant sections in the file, based on version 8 of documentation from http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
|
||||
word32 coffPos = *(word16 *)(buf+0x3c);
|
||||
word32 optionalHeaderPos = coffPos + 24;
|
||||
word16 optionalHeaderMagic = *(word16 *)(buf+optionalHeaderPos);
|
||||
if (optionalHeaderMagic != 0x10b && optionalHeaderMagic != 0x20b)
|
||||
{
|
||||
cerr << "Target file is not a PE32 or PE32+ image.\n";
|
||||
return 3;
|
||||
}
|
||||
word32 checksumPos = optionalHeaderPos + 64;
|
||||
word32 certificateTableDirectoryPos = optionalHeaderPos + (optionalHeaderMagic == 0x10b ? 128 : 144);
|
||||
word32 certificateTablePos = *(word32 *)(buf+certificateTableDirectoryPos);
|
||||
word32 certificateTableSize = *(word32 *)(buf+certificateTableDirectoryPos+4);
|
||||
if (certificateTableSize != 0)
|
||||
cerr << "Warning: certificate table (IMAGE_DIRECTORY_ENTRY_SECURITY) of target image is not empty.\n";
|
||||
|
||||
byte *found = std::search(buf.begin(), buf.end(), dummyMac+0, dummyMac+sizeof(dummyMac));
|
||||
// find where to place computed MAC
|
||||
byte mac[] = CRYPTOPP_DUMMY_DLL_MAC;
|
||||
byte *found = std::search(buf.begin(), buf.end(), mac+0, mac+sizeof(mac));
|
||||
if (found == buf.end())
|
||||
{
|
||||
cerr << "MAC placeholder not found. Possibly the actual MAC was already placed.\n";
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
word32 macPos = (unsigned int)(found-buf.begin());
|
||||
|
||||
unsigned int macPos = (unsigned int)(found-buf.begin());
|
||||
// compute MAC
|
||||
member_ptr<MessageAuthenticationCode> pMac(NewIntegrityCheckingMAC());
|
||||
pMac->Update(buf.begin(), macPos);
|
||||
pMac->Update(buf.begin() + macPos + sizeof(dummyMac), fileSize - sizeof(dummyMac) - macPos);
|
||||
assert(pMac->DigestSize() == sizeof(dummyMac));
|
||||
pMac->Final(dummyMac);
|
||||
assert(pMac->DigestSize() == sizeof(mac));
|
||||
MeterFilter f(new HashFilter(*pMac, new ArraySink(mac, sizeof(mac))));
|
||||
f.AddRangeToSkip(0, checksumPos, 4);
|
||||
f.AddRangeToSkip(0, certificateTableDirectoryPos, 8);
|
||||
f.AddRangeToSkip(0, macPos, sizeof(mac));
|
||||
f.AddRangeToSkip(0, certificateTablePos, certificateTableSize);
|
||||
f.PutMessageEnd(buf.begin(), buf.size());
|
||||
|
||||
// place MAC
|
||||
cout << "Placing MAC in file " << argv[2] << ", location " << macPos << ".\n";
|
||||
dllFile.seekg(macPos, std::ios_base::beg);
|
||||
dllFile.write((char *)dummyMac, sizeof(dummyMac));
|
||||
dllFile.write((char *)mac, sizeof(mac));
|
||||
}
|
||||
else if (command == "m")
|
||||
DigestFile(argv[2]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user