mirror of
https://github.com/Kong/insomnia.git
synced 2026-08-04 03:42:20 -04:00
sec(inso): Added secure wrapper for inso.exe
This commit is contained in:
9
.github/workflows/release-build.yml
vendored
9
.github/workflows/release-build.yml
vendored
@@ -243,13 +243,18 @@ jobs:
|
||||
env:
|
||||
VERSION: ${{ env.INSO_VERSION }}
|
||||
|
||||
- name: Compile inso secure wrapper (Windows only)
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: ./build-inso-wrapper.sh
|
||||
|
||||
- name: Code-sign inso exe (Windows only)
|
||||
if: runner.os == 'Windows'
|
||||
uses: digicert/code-signing-software-trust-action@fae23a455ba4bde62b64fd7cb2f81ade788f5a95 # v1.2.1
|
||||
with:
|
||||
simple-signing-mode: true
|
||||
# If the below 2 parameters are supplied, then smctl executable is invoked to attempt the signing.
|
||||
input: packages/insomnia-inso/binaries/inso.exe
|
||||
# Sign the directory so both inso.exe (wrapper) and inso-node.exe (inner) are signed.
|
||||
input: packages/insomnia-inso/binaries
|
||||
keypair-alias: ${{ secrets.DIGICERT_KEYPAIR_ALIAS }}
|
||||
env:
|
||||
SM_HOST: ${{ vars.DIGICERT_SM_HOST }}
|
||||
|
||||
43
build-inso-wrapper.sh
Executable file
43
build-inso-wrapper.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
|
||||
# Wraps the pkg-bundled inso.exe with a C++ launcher that applies Windows process
|
||||
# mitigation policies (ProcessImageLoadPolicy PreferSystem32Images=1) to prevent
|
||||
# DLL sideloading. See packages/insomnia-inso/src/cpp/ for the wrapper source.
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=$(jq .version ./packages/insomnia-inso/package.json -rj)
|
||||
echo "Starting inso secure wrapper build for version $VERSION..."
|
||||
MAJOR=$(echo $VERSION | cut -d '.' -f 1)
|
||||
MINOR=$(echo $VERSION | cut -d '.' -f 2)
|
||||
PATCH=$(echo $VERSION | cut -d '.' -f 3 | cut -d '-' -f 1)
|
||||
TAG=$(echo $VERSION | cut -d '-' -f 2)
|
||||
CPP_DIR=packages/insomnia-inso/src/cpp
|
||||
BINARIES_DIR=packages/insomnia-inso/binaries
|
||||
|
||||
if [ -n "$TAG" ]; then
|
||||
TAG="-$TAG"
|
||||
fi
|
||||
|
||||
# Rename the pkg-built binary so the wrapper can take the inso.exe name.
|
||||
echo "Renaming inso.exe to inso-node.exe..."
|
||||
mv $BINARIES_DIR/inso.exe $BINARIES_DIR/inso-node.dll
|
||||
|
||||
echo "Injecting version strings..."
|
||||
sed "s/__MAJOR__/$MAJOR/g" $CPP_DIR/resources.rc > $CPP_DIR/final.rc
|
||||
sed -i "s/__MINOR__/$MINOR/g" $CPP_DIR/final.rc
|
||||
sed -i "s/__PATCH__/$PATCH/g" $CPP_DIR/final.rc
|
||||
sed -i "s/__TAG__/$TAG/g" $CPP_DIR/final.rc
|
||||
sed -i "s/__YEAR__/$(date +%Y)/g" $CPP_DIR/final.rc
|
||||
|
||||
echo "Compiling resources..."
|
||||
windres $CPP_DIR/final.rc $CPP_DIR/res.o
|
||||
|
||||
echo "Compiling inso wrapper..."
|
||||
# Note: no -mwindows flag — inso is a console application.
|
||||
g++ -lkernel32 -c $CPP_DIR/inso.cpp -o $CPP_DIR/inso.o
|
||||
|
||||
echo "Linking inso wrapper..."
|
||||
g++ -O2 -static -static-libgcc -static-libstdc++ -lwinpthread \
|
||||
$CPP_DIR/inso.o $CPP_DIR/res.o -o $BINARIES_DIR/inso.exe
|
||||
|
||||
echo "Inso secure wrapper built successfully."
|
||||
95
packages/insomnia-inso/src/cpp/inso.cpp
Normal file
95
packages/insomnia-inso/src/cpp/inso.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// NOTE: The calls in this wrapper are only supported on Windows >= 8.
|
||||
#define _WIN32_WINNT 0x602
|
||||
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
|
||||
int main() {
|
||||
// Apply process mitigation policies before any further DLL loading occurs.
|
||||
// PreferSystem32Images is inherited by child processes, so inso-node.exe is
|
||||
// also protected without needing its own policy setup.
|
||||
|
||||
::PROCESS_MITIGATION_POLICY psp = ::ProcessSignaturePolicy;
|
||||
::PROCESS_MITIGATION_POLICY pilp = ::ProcessImageLoadPolicy;
|
||||
::PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY pmbsp;
|
||||
::PROCESS_MITIGATION_IMAGE_LOAD_POLICY pmilp;
|
||||
|
||||
if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), psp, &pmbsp, sizeof(pmbsp))) {
|
||||
::WriteFile(::GetStdHandle(STD_ERROR_HANDLE),
|
||||
"inso: could not get ProcessSignaturePolicy\n", 44, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
if (pmbsp.MitigationOptIn == 0) {
|
||||
pmbsp.MitigationOptIn = 1;
|
||||
if (!::SetProcessMitigationPolicy(psp, &pmbsp, sizeof(pmbsp))) {
|
||||
::WriteFile(::GetStdHandle(STD_ERROR_HANDLE),
|
||||
"inso: could not set ProcessSignaturePolicy\n", 44, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), pilp, &pmilp, sizeof(pmilp))) {
|
||||
::WriteFile(::GetStdHandle(STD_ERROR_HANDLE),
|
||||
"inso: could not get ProcessImageLoadPolicy\n", 44, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
if (pmilp.PreferSystem32Images == 0) {
|
||||
pmilp.PreferSystem32Images = 1;
|
||||
if (!::SetProcessMitigationPolicy(pilp, &pmilp, sizeof(pmilp))) {
|
||||
::WriteFile(::GetStdHandle(STD_ERROR_HANDLE),
|
||||
"inso: could not set ProcessImageLoadPolicy\n", 44, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the path to inso-node.exe (same directory as this wrapper).
|
||||
wchar_t wrapperPath[MAX_PATH];
|
||||
::GetModuleFileNameW(NULL, wrapperPath, MAX_PATH);
|
||||
std::wstring dir(wrapperPath);
|
||||
dir = dir.substr(0, dir.find_last_of(L"\\"));
|
||||
std::wstring innerExe = dir + L"\\inso-node.dll";
|
||||
|
||||
// Rebuild the command line, replacing argv[0] (this wrapper) with inso-node.exe.
|
||||
// GetCommandLineW() returns the full command line including the wrapper's path,
|
||||
// which may be quoted. We skip past that first token to get the remaining args.
|
||||
LPWSTR origCmd = ::GetCommandLineW();
|
||||
LPWSTR argsStart = origCmd;
|
||||
|
||||
if (*argsStart == L'"') {
|
||||
argsStart++; // skip opening quote
|
||||
while (*argsStart && *argsStart != L'"') argsStart++;
|
||||
if (*argsStart == L'"') argsStart++; // skip closing quote
|
||||
} else {
|
||||
while (*argsStart && *argsStart != L' ') argsStart++;
|
||||
}
|
||||
|
||||
// argsStart now points to " arg1 arg2 ..." or an empty string.
|
||||
std::wstring cmdLine = L"\"" + innerExe + L"\"" + std::wstring(argsStart);
|
||||
|
||||
::STARTUPINFOW si;
|
||||
::PROCESS_INFORMATION pi;
|
||||
::ZeroMemory(&si, sizeof(si));
|
||||
::ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
|
||||
si.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
si.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (!::CreateProcessW(NULL, &cmdLine[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
|
||||
const char *msg = "inso: could not launch inso-node.dll\n";
|
||||
::WriteFile(::GetStdHandle(STD_ERROR_HANDLE), msg, 37, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
::WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
|
||||
DWORD exitCode = 1;
|
||||
::GetExitCodeProcess(pi.hProcess, &exitCode);
|
||||
|
||||
::CloseHandle(pi.hProcess);
|
||||
::CloseHandle(pi.hThread);
|
||||
|
||||
return static_cast<int>(exitCode);
|
||||
}
|
||||
21
packages/insomnia-inso/src/cpp/manifest.txt
Normal file
21
packages/insomnia-inso/src/cpp/manifest.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- windows server 2012 R2 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<maxversiontested Id="10.0.18362.0"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
0
packages/insomnia-inso/src/cpp/resource.h
Normal file
0
packages/insomnia-inso/src/cpp/resource.h
Normal file
29
packages/insomnia-inso/src/cpp/resources.rc
Normal file
29
packages/insomnia-inso/src/cpp/resources.rc
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "resource.h"
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
1 VERSIONINFO
|
||||
|
||||
FILEVERSION __MAJOR__,__MINOR__,__PATCH__,0
|
||||
PRODUCTVERSION __MAJOR__,__MINOR__,__PATCH__,0
|
||||
FILEOS 0x40004
|
||||
FILETYPE 0x1
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904B0"
|
||||
{
|
||||
VALUE "CompanyName", "Kong"
|
||||
VALUE "FileDescription", "inso"
|
||||
VALUE "FileVersion", "__MAJOR__.__MINOR__.__PATCH____TAG__"
|
||||
VALUE "InternalName", "inso"
|
||||
VALUE "LegalCopyright", "Copyright \xA9 __YEAR__ Kong"
|
||||
VALUE "OriginalFilename", ""
|
||||
VALUE "ProductName", "inso"
|
||||
VALUE "ProductVersion", "__MAJOR__.__MINOR__.__PATCH__.0"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x0409, 0x04B0
|
||||
}
|
||||
}
|
||||
1 MANIFEST "manifest.txt"
|
||||
@@ -24,7 +24,7 @@ const spawnCompressProcess = (cwd: ProcessEnvOptions['cwd']) => {
|
||||
'../binaries',
|
||||
platform === 'win32' ? '-a -cf' : '-cJf',
|
||||
platform === 'win32' ? `inso-windows-${version}.zip` : `inso-linux-${process.arch}-${version}.tar.xz`,
|
||||
platform === 'win32' ? 'inso.exe' : 'inso',
|
||||
...(platform === 'win32' ? ['inso.exe', 'inso-node.dll'] : ['inso']),
|
||||
],
|
||||
{ cwd, shell: platform === 'win32' },
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user