//+--------------------------------------------------------------- // // Member: FatStream::SetSize // // Synopsis: method of IStream interface // //---------------------------------------------------------------- STDMETHODIMP FatStream::SetSize(ULARGE_INTEGER libNewSize) { DWORD newpos; if(_hfile == INVALID_HANDLE_VALUE) { RRETURN(E_FAIL); } if(libNewSize.HighPart != 0) { RRETURN(E_FAIL); } newpos = SetFilePointer(_hfile, (LONG)libNewSize.LowPart, NULL, FILE_BEGIN); if(newpos == -1) { RRETURN(GetLastWin32Error()); } if(!SetEndOfFile(_hfile)) { RRETURN(GetLastWin32Error()); } return S_OK; }
DllImpl::DllImpl(const std::wstring& installationDir) { auto dllPath(installationDir + L"temple.dll"); // Does it even exist? if (!PathFileExists(dllPath.c_str())) { auto msg(fmt::format("Temple.dll does not exist: {}", ucs2_to_utf8(dllPath))); throw TempleException(msg); } SetCurrentDirectory(installationDir.c_str()); // Try to load it mDllHandle = LoadLibrary(dllPath.c_str()); if (!mDllHandle) { throw TempleException("Unable to load temple.dll from {}: {}", ucs2_to_utf8(dllPath), GetLastWin32Error()); } // calculate the offset from the default 0x10000000 base address auto baseAddr = reinterpret_cast<uint32_t>(mDllHandle); mDeltaFromVanilla = baseAddr - defaultBaseAddr; logger->info("The temple.dll base address delta is: {}", mDeltaFromVanilla); auto status = MH_Initialize(); if (status != MH_OK) { FreeLibrary(mDllHandle); auto msg(fmt::format("Unable to initialize MinHook: {}", MH_StatusToString(status))); throw TempleException(msg); } }
HRESULT CExecFT::Launch(BOOL fWait) { DWORD dwResult; DWORD dwStackSize = 0; if(fWait) { _hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); if(_hEvent == NULL) { RRETURN(GetLastWin32Error()); } } SubAddRef(); _hThread = CreateThread(NULL, dwStackSize, &CExecFT::StaticThreadProc, this, 0, &_dwThreadId); if(_hThread == NULL) { SubRelease(); RRETURN(GetLastWin32Error()); } if(fWait) { dwResult = WaitForSingleObject(_hEvent, INFINITE); Assert(dwResult == WAIT_OBJECT_0); CloseHandle(_hEvent); _hEvent = NULL; RRETURN(_hrInit); } return S_OK; }
DllImpl::~DllImpl() { auto status = MH_Uninitialize(); if (status != MH_OK) { logger->error("Unable to shutdown MinHook: {}", MH_StatusToString(status)); } if (mDllHandle) { if (!FreeLibrary(mDllHandle)) { logger->error("Unable to free the temple.dll library handle: {}", GetLastWin32Error()); } } }
//+--------------------------------------------------------------- // // Member: FatStream::Read // // Synopsis: method of IStream interface // //---------------------------------------------------------------- STDMETHODIMP FatStream::Read(void* pv, ULONG cb, ULONG* pcbRead) { ULONG cbTemp; if(_hfile == INVALID_HANDLE_VALUE) { RRETURN(E_FAIL); } RRETURN(ReadFile( _hfile, pv, cb, pcbRead?pcbRead:&cbTemp, NULL)?S_OK:GetLastWin32Error()); }
//+--------------------------------------------------------------- // // Member: FatStream::Write // // Synopsis: method of IStream interface // //---------------------------------------------------------------- STDMETHODIMP FatStream::Write(void const* pv, ULONG cb, ULONG* pcbWritten) { BOOL fSuccess; DWORD cbWritten; if(_hfile == INVALID_HANDLE_VALUE) { RRETURN(E_FAIL); } fSuccess = WriteFile(_hfile, pv, (DWORD)cb, &cbWritten, NULL); if(pcbWritten != NULL) { *pcbWritten = cbWritten; } RRETURN(fSuccess?S_OK:GetLastWin32Error()); }
HRESULT CloseStreamOnFile(LPSTREAM pStm) { HRESULT hr = S_OK; FatStream* pStmFat = DYNCAST(FatStream, pStm); if(pStmFat->_hfile == INVALID_HANDLE_VALUE) { hr = E_FAIL; goto Cleanup; } if(!CloseHandle(pStmFat->_hfile)) { hr = GetLastWin32Error(); } pStmFat->_hfile = INVALID_HANDLE_VALUE; Cleanup: RRETURN(hr); }
//+--------------------------------------------------------------- // // Function: CreateStreamOnFile, public // // Synopsis: Provides an IStream interface to a DOS file // // Arguments: [pchFile] -- the DOS file // [dwDesiredAccess] -- see CreateFile // [dwShareMode] -- see CreateFile // [dwCreationDistribution] -- see CreateFile // [ppstrm] -- where the opened stream is returned // // Returns: Success if the stream interface could be provided // //---------------------------------------------------------------- HRESULT CreateStreamOnFile(LPCTSTR pchFile, DWORD dwSTGM, LPSTREAM* ppstrm) { DWORD dwDesiredAccess = 0; DWORD dwShareMode = 0; DWORD dwCreationDistribution = 0; HANDLE hfile; FatStream* pStmFat = NULL; HRESULT hr = S_OK; Assert(pchFile!=NULL && _tcsclen(pchFile)!=0); if(dwSTGM & STGM_READWRITE) { dwDesiredAccess |= (GENERIC_READ|GENERIC_WRITE); } else if(dwSTGM & STGM_WRITE) { dwDesiredAccess |= GENERIC_WRITE; } else { dwDesiredAccess |= GENERIC_READ; } if(dwSTGM & STGM_SHARE_DENY_NONE) { dwShareMode |= (FILE_SHARE_READ|FILE_SHARE_WRITE); } else if(dwSTGM & STGM_SHARE_DENY_WRITE) { dwShareMode |= FILE_SHARE_READ; } else if(dwSTGM & STGM_SHARE_DENY_READ) { dwShareMode |= FILE_SHARE_WRITE; } if(dwSTGM & STGM_CREATE) { dwCreationDistribution |= CREATE_ALWAYS; } else { dwCreationDistribution |= OPEN_EXISTING; } hfile = CreateFile( pchFile, dwDesiredAccess, dwShareMode, NULL, dwCreationDistribution, FILE_ATTRIBUTE_NORMAL, NULL); if(hfile == INVALID_HANDLE_VALUE) { hr = GetLastWin32Error(); goto Cleanup; } pStmFat = new FatStream(); if(!pStmFat) { hr = E_OUTOFMEMORY; goto Cleanup; } hr = pStmFat->Init(hfile, dwSTGM&STGM_DELETEONRELEASE?pchFile:NULL); if(hr) { goto Error; } *ppstrm = pStmFat; Cleanup: RRETURN(hr); Error: delete pStmFat; goto Cleanup; }