Dump Windows version and arch information (including ConEmu hook version)
This commit is contained in:
parent
f647952a34
commit
c677b8dd0a
@ -30,6 +30,7 @@
|
||||
#include "../shared/winpty_snprintf.h"
|
||||
#include "../shared/WinptyAssert.h"
|
||||
#include "../shared/StringUtil.h"
|
||||
#include "../shared/WindowsVersion.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -126,6 +127,7 @@ Agent::Agent(LPCWSTR controlPipeName,
|
||||
m_ptySize(initialCols, initialRows)
|
||||
{
|
||||
trace("Agent starting...");
|
||||
dumpWindowsVersion();
|
||||
|
||||
m_bufferData.resize(BUFFER_LINE_COUNT);
|
||||
|
||||
|
@ -41,6 +41,7 @@ AGENT_OBJECTS = \
|
||||
build/agent/shared/StringUtil.o \
|
||||
build/agent/shared/WindowsVersion.o \
|
||||
build/agent/shared/WinptyAssert.o \
|
||||
build/agent/shared/WinptyException.o \
|
||||
build/agent/shared/WinptyVersion.o
|
||||
|
||||
build/winpty-agent.exe : $(AGENT_OBJECTS)
|
||||
|
@ -26,6 +26,7 @@ DEBUGSERVER_OBJECTS = \
|
||||
build/debugserver/debugserver/DebugServer.o \
|
||||
build/debugserver/shared/DebugClient.o \
|
||||
build/debugserver/shared/OwnedHandle.o \
|
||||
build/debugserver/shared/StringUtil.o \
|
||||
build/debugserver/shared/WindowsSecurity.o \
|
||||
build/debugserver/shared/WindowsVersion.o \
|
||||
build/debugserver/shared/WinptyAssert.o \
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "../shared/StringBuilder.h"
|
||||
#include "../shared/StringUtil.h"
|
||||
#include "../shared/WindowsSecurity.h"
|
||||
#include "../shared/WindowsVersion.h"
|
||||
#include "../shared/WinptyException.h"
|
||||
|
||||
// TODO: Error handling, handle out-of-memory.
|
||||
@ -332,6 +333,8 @@ static bool verifyPipeClientPid(HANDLE serverPipe, DWORD agentPid)
|
||||
|
||||
WINPTY_API winpty_t *winpty_open(int cols, int rows)
|
||||
{
|
||||
dumpWindowsVersion();
|
||||
|
||||
winpty_t *pc = new winpty_t;
|
||||
|
||||
// Start pipes.
|
||||
|
@ -21,15 +21,29 @@
|
||||
#ifndef OS_MODULE_H
|
||||
#define OS_MODULE_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "DebugClient.h"
|
||||
#include "WinptyAssert.h"
|
||||
#include "WinptyException.h"
|
||||
|
||||
class OsModule {
|
||||
HMODULE m_module;
|
||||
public:
|
||||
OsModule(const wchar_t *fileName) {
|
||||
enum class LoadErrorBehavior { Abort, Throw };
|
||||
OsModule(const wchar_t *fileName,
|
||||
LoadErrorBehavior behavior=LoadErrorBehavior::Abort) {
|
||||
m_module = LoadLibraryW(fileName);
|
||||
ASSERT(m_module != NULL);
|
||||
if (behavior == LoadErrorBehavior::Abort) {
|
||||
ASSERT(m_module != NULL);
|
||||
} else {
|
||||
if (m_module == nullptr) {
|
||||
const auto err = GetLastError();
|
||||
throwWindowsError(
|
||||
(L"LoadLibraryW error: " + std::wstring(fileName)).c_str(),
|
||||
err);
|
||||
}
|
||||
}
|
||||
}
|
||||
~OsModule() {
|
||||
FreeLibrary(m_module);
|
||||
|
@ -21,10 +21,18 @@
|
||||
#include "WindowsVersion.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "DebugClient.h"
|
||||
#include "OsModule.h"
|
||||
#include "StringBuilder.h"
|
||||
#include "StringUtil.h"
|
||||
#include "WinptyAssert.h"
|
||||
#include "WinptyException.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -33,7 +41,7 @@ typedef std::tuple<DWORD, DWORD> Version;
|
||||
// This function can only return a version up to 6.2 unless the executable is
|
||||
// manifested for a newer version of Windows. See the MSDN documentation for
|
||||
// GetVersionEx.
|
||||
Version getWindowsVersion() {
|
||||
OSVERSIONINFOEX getWindowsVersionInfo() {
|
||||
// Allow use of deprecated functions (i.e. GetVersionEx). We need to use
|
||||
// GetVersionEx for the old MinGW toolchain and with MSVC when it targets XP.
|
||||
// Having two code paths makes code harder to test, and it's not obvious how
|
||||
@ -44,16 +52,109 @@ Version getWindowsVersion() {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
OSVERSIONINFO info = {};
|
||||
OSVERSIONINFOEX info = {};
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
const auto success = GetVersionEx(&info);
|
||||
const auto success = GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&info));
|
||||
ASSERT(success && "GetVersionEx failed");
|
||||
return Version(info.dwMajorVersion, info.dwMinorVersion);
|
||||
return info;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
Version getWindowsVersion() {
|
||||
const auto info = getWindowsVersionInfo();
|
||||
return Version(info.dwMajorVersion, info.dwMinorVersion);
|
||||
}
|
||||
|
||||
struct ModuleNotFound : WinptyException {
|
||||
virtual const wchar_t *what() const WINPTY_NOEXCEPT {
|
||||
return L"ModuleNotFound";
|
||||
}
|
||||
};
|
||||
|
||||
// Throws WinptyException on error.
|
||||
std::wstring getSystemDirectory() {
|
||||
wchar_t systemDirectory[MAX_PATH];
|
||||
const UINT size = GetSystemDirectory(systemDirectory, MAX_PATH);
|
||||
if (size == 0) {
|
||||
throwWindowsError(L"GetSystemDirectory failed");
|
||||
} else if (size >= MAX_PATH) {
|
||||
throwWinptyException(
|
||||
L"GetSystemDirectory: path is longer than MAX_PATH");
|
||||
}
|
||||
return systemDirectory;
|
||||
}
|
||||
|
||||
#define GET_VERSION_DLL_API(name) \
|
||||
const auto p ## name = \
|
||||
reinterpret_cast<decltype(name)*>( \
|
||||
versionDll.proc(#name)); \
|
||||
if (p ## name == nullptr) { \
|
||||
throwWinptyException(L ## #name L" is missing"); \
|
||||
}
|
||||
|
||||
// Throws WinptyException on error.
|
||||
VS_FIXEDFILEINFO getFixedFileInfo(const std::wstring &path) {
|
||||
// version.dll is not a conventional KnownDll, so if we link to it, there's
|
||||
// a danger of accidentally loading a malicious DLL. In a more typical
|
||||
// application, perhaps we'd guard against this security issue by
|
||||
// controlling which directories this code runs in (e.g. *not* the
|
||||
// "Downloads" directory), but that's harder for the winpty library.
|
||||
OsModule versionDll(
|
||||
(getSystemDirectory() + L"\\version.dll").c_str(),
|
||||
OsModule::LoadErrorBehavior::Throw);
|
||||
GET_VERSION_DLL_API(GetFileVersionInfoSizeW);
|
||||
GET_VERSION_DLL_API(GetFileVersionInfoW);
|
||||
GET_VERSION_DLL_API(VerQueryValueW);
|
||||
DWORD size = pGetFileVersionInfoSizeW(path.c_str(), nullptr);
|
||||
if (!size) {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
throw ModuleNotFound();
|
||||
} else {
|
||||
throwWindowsError(
|
||||
(L"GetFileVersionInfoSizeW failed on " + path).c_str());
|
||||
}
|
||||
}
|
||||
std::unique_ptr<char[]> versionBuffer(new char[size]);
|
||||
if (!pGetFileVersionInfoW(path.c_str(), 0, size, versionBuffer.get())) {
|
||||
throwWindowsError((L"GetFileVersionInfoW failed on " + path).c_str());
|
||||
}
|
||||
VS_FIXEDFILEINFO *versionInfo = nullptr;
|
||||
UINT versionInfoSize = 0;
|
||||
if (!pVerQueryValueW(
|
||||
versionBuffer.get(), L"\\",
|
||||
reinterpret_cast<void**>(&versionInfo), &versionInfoSize) ||
|
||||
versionInfo == nullptr ||
|
||||
versionInfoSize != sizeof(VS_FIXEDFILEINFO) ||
|
||||
versionInfo->dwSignature != 0xFEEF04BD) {
|
||||
throwWinptyException((L"VerQueryValueW failed on " + path).c_str());
|
||||
}
|
||||
return *versionInfo;
|
||||
}
|
||||
|
||||
uint64_t productVersionFromInfo(const VS_FIXEDFILEINFO &info) {
|
||||
return (static_cast<uint64_t>(info.dwProductVersionMS) << 32) |
|
||||
(static_cast<uint64_t>(info.dwProductVersionLS));
|
||||
}
|
||||
|
||||
uint64_t fileVersionFromInfo(const VS_FIXEDFILEINFO &info) {
|
||||
return (static_cast<uint64_t>(info.dwFileVersionMS) << 32) |
|
||||
(static_cast<uint64_t>(info.dwFileVersionLS));
|
||||
}
|
||||
|
||||
std::string versionToString(uint64_t version) {
|
||||
StringBuilder b(32);
|
||||
b << ((uint16_t)(version >> 48));
|
||||
b << '.';
|
||||
b << ((uint16_t)(version >> 32));
|
||||
b << '.';
|
||||
b << ((uint16_t)(version >> 16));
|
||||
b << '.';
|
||||
b << ((uint16_t)(version >> 0));
|
||||
return b.str_moved();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Returns true for Windows Vista (or Windows Server 2008) or newer.
|
||||
@ -65,3 +166,79 @@ bool isAtLeastWindowsVista() {
|
||||
bool isAtLeastWindows8() {
|
||||
return getWindowsVersion() >= Version(6, 2);
|
||||
}
|
||||
|
||||
#define WINPTY_IA32 1
|
||||
#define WINPTY_X64 2
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__)
|
||||
#define WINPTY_ARCH WINPTY_IA32
|
||||
#elif defined(_M_X64) || defined(__x86_64__)
|
||||
#define WINPTY_ARCH WINPTY_X64
|
||||
#endif
|
||||
|
||||
typedef BOOL WINAPI IsWow64Process_t(HANDLE hProcess, PBOOL Wow64Process);
|
||||
|
||||
void dumpWindowsVersion() {
|
||||
if (!isTracingEnabled()) {
|
||||
return;
|
||||
}
|
||||
const auto info = getWindowsVersionInfo();
|
||||
StringBuilder b;
|
||||
b << info.dwMajorVersion << '.' << info.dwMinorVersion
|
||||
<< '.' << info.dwBuildNumber << ' '
|
||||
<< "SP" << info.wServicePackMajor << '.' << info.wServicePackMinor
|
||||
<< ' ';
|
||||
switch (info.wProductType) {
|
||||
case VER_NT_WORKSTATION: b << "Client"; break;
|
||||
case VER_NT_DOMAIN_CONTROLLER: b << "DomainController"; break;
|
||||
case VER_NT_SERVER: b << "Server"; break;
|
||||
default:
|
||||
b << "product=" << info.wProductType; break;
|
||||
}
|
||||
b << ' ';
|
||||
#if WINPTY_ARCH == WINPTY_IA32
|
||||
b << "IA32";
|
||||
OsModule kernel32(L"kernel32.dll");
|
||||
IsWow64Process_t *pIsWow64Process =
|
||||
reinterpret_cast<IsWow64Process_t*>(
|
||||
kernel32.proc("IsWow64Process"));
|
||||
if (pIsWow64Process != nullptr) {
|
||||
BOOL result = false;
|
||||
const BOOL success = pIsWow64Process(GetCurrentProcess(), &result);
|
||||
if (!success) {
|
||||
b << " WOW64:error";
|
||||
} else if (success && result) {
|
||||
b << " WOW64";
|
||||
}
|
||||
} else {
|
||||
b << " WOW64:missingapi";
|
||||
}
|
||||
#elif WINPTY_ARCH == WINPTY_X64
|
||||
b << "X64";
|
||||
#endif
|
||||
const auto dllVersion = [](const wchar_t *dllPath) -> std::string {
|
||||
try {
|
||||
const auto info = getFixedFileInfo(dllPath);
|
||||
StringBuilder fb(64);
|
||||
fb << utf8FromWide(dllPath) << ':';
|
||||
fb << "F:" << versionToString(fileVersionFromInfo(info)) << '/'
|
||||
<< "P:" << versionToString(productVersionFromInfo(info));
|
||||
return fb.str_moved();
|
||||
} catch (const ModuleNotFound &e) {
|
||||
return utf8FromWide(dllPath) + ":none";
|
||||
} catch (const WinptyException &e) {
|
||||
trace("Error getting %s version: %s",
|
||||
utf8FromWide(dllPath).c_str(), utf8FromWide(e.what()).c_str());
|
||||
return utf8FromWide(dllPath) + ":error";
|
||||
}
|
||||
};
|
||||
b << ' ' << dllVersion(L"kernel32.dll");
|
||||
// ConEmu provides a DLL that hooks many Windows APIs, especially console
|
||||
// APIs. Its existence and version number could be useful in debugging.
|
||||
#if WINPTY_ARCH == WINPTY_IA32
|
||||
b << ' ' << dllVersion(L"ConEmuHk.dll");
|
||||
#elif WINPTY_ARCH == WINPTY_X64
|
||||
b << ' ' << dllVersion(L"ConEmuHk64.dll");
|
||||
#endif
|
||||
trace("Windows version: %s", b.c_str());
|
||||
}
|
||||
|
@ -23,5 +23,6 @@
|
||||
|
||||
bool isAtLeastWindowsVista();
|
||||
bool isAtLeastWindows8();
|
||||
void dumpWindowsVersion();
|
||||
|
||||
#endif // WINPTY_SHARED_WINDOWS_VERSION_H
|
||||
|
@ -165,6 +165,8 @@
|
||||
'shared/OwnedHandle.cc',
|
||||
'shared/OsModule.h',
|
||||
'shared/StringBuilder.h',
|
||||
'shared/StringUtil.cc',
|
||||
'shared/StringUtil.h',
|
||||
'shared/WindowsSecurity.h',
|
||||
'shared/WindowsSecurity.cc',
|
||||
'shared/WindowsVersion.h',
|
||||
|
Loading…
Reference in New Issue
Block a user