summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filters.cpp100
-rw-r--r--filters.h13
-rw-r--r--fipstest.cpp68
-rw-r--r--fltrimpl.h11
-rw-r--r--misc.h2
-rw-r--r--test.cpp47
6 files changed, 179 insertions, 62 deletions
diff --git a/filters.cpp b/filters.cpp
index f2d78d1..8d22555 100644
--- a/filters.cpp
+++ b/filters.cpp
@@ -141,46 +141,86 @@ bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocki
// *************************************************************
-size_t MeterFilter::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
+void MeterFilter::ResetMeter()
{
- if (m_transparent)
- {
- FILTER_BEGIN;
- m_currentMessageBytes += length;
- m_totalBytes += length;
-
- if (messageEnd)
- {
- m_currentMessageBytes = 0;
- m_currentSeriesMessages++;
- m_totalMessages++;
- }
+ m_currentMessageBytes = m_totalBytes = m_currentSeriesMessages = m_totalMessages = m_totalMessageSeries = 0;
+ m_rangesToSkip.clear();
+}
- FILTER_OUTPUT(1, begin, length, messageEnd);
- FILTER_END_NO_MESSAGE_END;
- }
- return 0;
+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::PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking)
+size_t MeterFilter::PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable)
{
- if (m_transparent)
+ if (!m_transparent)
+ return 0;
+
+ size_t t;
+ FILTER_BEGIN;
+
+ m_begin = begin;
+ m_length = length;
+
+ while (m_length > 0 || messageEnd)
{
- FILTER_BEGIN;
- m_currentMessageBytes += length;
- m_totalBytes += length;
+ 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 (messageEnd)
+ 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
{
- m_currentMessageBytes = 0;
- m_currentSeriesMessages++;
- m_totalMessages++;
+ 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_OUTPUT_MODIFIABLE(1, begin, length, messageEnd);
- FILTER_END_NO_MESSAGE_END;
}
- return 0;
+
+ FILTER_END_NO_MESSAGE_END;
+}
+
+size_t MeterFilter::Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
+{
+ return PutMaybeModifiable(const_cast<byte *>(begin), length, messageEnd, blocking, false);
+}
+
+size_t MeterFilter::PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking)
+{
+ return PutMaybeModifiable(begin, length, messageEnd, blocking, true);
}
bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking)
diff --git a/filters.h b/filters.h
index 0b4fa74..2737dc0 100644
--- a/filters.h
+++ b/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 &parameters) {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;
};
//! _
diff --git a/fipstest.cpp b/fipstest.cpp
index bc86fe2..78d3867 100644
--- a/fipstest.cpp
+++ b/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
diff --git a/fltrimpl.h b/fltrimpl.h
index 350bc18..d78bb6b 100644
--- a/fltrimpl.h
+++ b/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
diff --git a/misc.h b/misc.h
index a2119bf..0815c16 100644
--- a/misc.h
+++ b/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;
}
diff --git a/test.cpp b/test.cpp
index 6ac7f4b..cb4c065 100644
--- a/test.cpp
+++ b/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;
-
- byte *found = std::search(buf.begin(), buf.end(), dummyMac+0, dummyMac+sizeof(dummyMac));
+ // 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";
+
+ // 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]);