зеркало из https://github.com/microsoft/Detours.git
Tests: Add initial set of unit tests for Detours (#137)
- Import the Catch2 self-contained C++ test framework. It's used by many Microsoft OSS projects: - https://github.com/microsoft/cppwinrt/tree/master/test - https://github.com/microsoft/wil/tree/master/tests As well as many OSS projects in general. When the CMake PR is merged, we can remove this as a checked in development dependency, and can instead download it using CMake. - Start basic set of unit tests to validate failure modes of - Hook the execution into the existing NMake build system. - Hook test execution into CI pipeline
This commit is contained in:
Родитель
d8b8144c54
Коммит
2de2babb25
|
@ -16,9 +16,11 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-2019, windows-2016]
|
||||
arch: [x86, x64, x64_arm, x64_arm64]
|
||||
|
||||
steps:
|
||||
|
@ -43,24 +45,28 @@ jobs:
|
|||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL for C++
|
||||
uses: github/codeql-action/init@v1
|
||||
if: ${{ matrix.os == 'windows-2019' }}
|
||||
with:
|
||||
languages: cpp
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
# Actually run the build
|
||||
- name: Build Detours for ${{ matrix.arch }}
|
||||
- name: Build Detours for ${{ matrix.arch }} on ${{ matrix.os }}
|
||||
env:
|
||||
# Tell detours what process to target
|
||||
DETOURS_TARGET_PROCESSOR: ${{ env.VSCMD_ARG_TGT_ARCH }}
|
||||
run: nmake
|
||||
|
||||
# Upload artifacts for this subsection of the build matrix.
|
||||
- name: Upload artifacts for ${{ matrix.arch }}
|
||||
- name: Run unit tests for ${{ matrix.arch }} on ${{ matrix.os }}
|
||||
id: run-unit-tests
|
||||
run: cd tests && nmake test
|
||||
if: ${{ matrix.arch == 'x86' || matrix.arch == 'x64' }}
|
||||
|
||||
- name: Upload artifacts for ${{ matrix.arch }} on ${{ matrix.os }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
with:
|
||||
name: artifacts-${{ matrix.os }}
|
||||
path: |
|
||||
lib.*/
|
||||
bin.*/
|
||||
|
@ -68,3 +74,4 @@ jobs:
|
|||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
if: ${{ matrix.os == 'windows-2019' }}
|
||||
|
|
20
Makefile
20
Makefile
|
@ -12,32 +12,38 @@ ROOT = .
|
|||
|
||||
all:
|
||||
cd "$(MAKEDIR)"
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
cd "$(MAKEDIR)\src"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
cd "$(MAKEDIR)\samples"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
cd "$(MAKEDIR)\tests"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS)
|
||||
cd "$(MAKEDIR)"
|
||||
|
||||
clean:
|
||||
cd "$(MAKEDIR)"
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
cd "$(MAKEDIR)\src"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
cd "$(MAKEDIR)\samples"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
cd "$(MAKEDIR)\tests"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean
|
||||
cd "$(MAKEDIR)"
|
||||
|
||||
realclean: clean
|
||||
cd "$(MAKEDIR)"
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
@if exist "$(MAKEDIR)\core\makefile" cd "$(MAKEDIR)\core" && $(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
cd "$(MAKEDIR)\src"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
cd "$(MAKEDIR)\samples"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
cd "$(MAKEDIR)\tests"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
@if exist "$(MAKEDIR)\bugs\makefile" cd "$(MAKEDIR)\bugs" && $(MAKE) /NOLOGO /$(MAKEFLAGS) realclean
|
||||
cd "$(MAKEDIR)"
|
||||
-rmdir /q /s $(INCDS) 2> nul
|
||||
-rmdir /q /s $(LIBDS) 2> nul
|
||||
|
@ -50,6 +56,8 @@ realclean: clean
|
|||
test:
|
||||
cd "$(MAKEDIR)\samples"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) test
|
||||
cd "$(MAKEDIR)\tests"
|
||||
@$(MAKE) /NOLOGO /$(MAKEFLAGS) test
|
||||
cd "$(MAKEDIR)"
|
||||
|
||||
################################################################# End of File.
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
##############################################################################
|
||||
##
|
||||
## Detours Unit Tests.
|
||||
##
|
||||
## Microsoft Research Detours Package
|
||||
##
|
||||
## Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
##
|
||||
|
||||
ROOT = ..
|
||||
!include ..\samples\common.mak
|
||||
|
||||
DEPS = $(LIBD)\detours.lib
|
||||
LIBS=$(LIBS) kernel32.lib
|
||||
CFLAGS=$(CFLAGS) /EHsc /DCATCH_CONFIG_NO_WINDOWS_SEH
|
||||
|
||||
##############################################################################
|
||||
|
||||
all: dirs \
|
||||
$(BIND)\unittests.exe \
|
||||
\
|
||||
|
||||
##############################################################################
|
||||
|
||||
dirs:
|
||||
@if not exist $(BIND) mkdir $(BIND) && echo. Created $(BIND)
|
||||
@if not exist $(OBJD) mkdir $(OBJD) && echo. Created $(OBJD)
|
||||
|
||||
$(OBJD)\main.obj : main.cpp
|
||||
$(OBJD)\test_module_api.obj : test_module_api.cpp
|
||||
$(OBJD)\test_image_api.obj : test_image_api.cpp
|
||||
$(OBJD)\corruptor.obj : corruptor.cpp
|
||||
|
||||
$(BIND)\unittests.exe : $(OBJD)\main.obj \
|
||||
$(OBJD)\test_module_api.obj \
|
||||
$(OBJD)\test_image_api.obj \
|
||||
$(OBJD)\corruptor.obj $(DEPS)
|
||||
cl $(CFLAGS) /Fe$@ /Fd$(@R).pdb \
|
||||
$(OBJD)\main.obj \
|
||||
$(OBJD)\test_module_api.obj \
|
||||
$(OBJD)\test_image_api.obj \
|
||||
$(OBJD)\corruptor.obj \
|
||||
/link $(LINKFLAGS) $(LIBS) /subsystem:console
|
||||
|
||||
##############################################################################
|
||||
|
||||
clean:
|
||||
-del *~ 2>nul
|
||||
-del $(BIND)\unittests*.* 2>nul
|
||||
-rmdir /q /s $(OBJD) 2>nul
|
||||
|
||||
realclean: clean
|
||||
-rmdir /q /s $(OBJDS) 2>nul
|
||||
|
||||
option:
|
||||
##############################################################################
|
||||
|
||||
test: all
|
||||
@cls
|
||||
$(BIND)\unittests.exe --reporter console --success --durations yes
|
||||
|
||||
debug: all
|
||||
windbg -o $(BIND)\unittests.exe
|
||||
|
||||
|
||||
################################################################# End of File.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,67 @@
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unit Test Image Corruptor (corruptor.cpp of unittests.exe)
|
||||
//
|
||||
// Microsoft Research Detours Package
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
#include "windows.h"
|
||||
#include "corruptor.h"
|
||||
|
||||
ImageCorruptor::ImageCorruptor(PIMAGE_DOS_HEADER Header)
|
||||
{
|
||||
m_TargetDosHeader = Header;
|
||||
m_OriginalDosHeader = *Header;
|
||||
m_OriginalDosProtection = 0;
|
||||
m_TargetNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)Header + Header->e_lfanew);
|
||||
m_OriginalNtHeaders = *m_TargetNtHeaders;
|
||||
m_OriginalNtProtection = 0;
|
||||
|
||||
VirtualProtect(
|
||||
m_TargetDosHeader,
|
||||
sizeof(*m_TargetDosHeader),
|
||||
PAGE_READWRITE,
|
||||
&m_OriginalDosProtection);
|
||||
|
||||
VirtualProtect(
|
||||
m_TargetNtHeaders,
|
||||
sizeof(*m_TargetNtHeaders),
|
||||
PAGE_READWRITE,
|
||||
&m_OriginalNtProtection);
|
||||
}
|
||||
|
||||
ImageCorruptor::~ImageCorruptor()
|
||||
{
|
||||
// Restore original header contents.
|
||||
//
|
||||
*m_TargetDosHeader = m_OriginalDosHeader;
|
||||
*m_TargetNtHeaders = m_OriginalNtHeaders;
|
||||
|
||||
// Restore original protection of DOS header.
|
||||
//
|
||||
DWORD OldProtection {};
|
||||
VirtualProtect(
|
||||
m_TargetDosHeader,
|
||||
sizeof(*m_TargetDosHeader),
|
||||
m_OriginalDosProtection,
|
||||
&OldProtection);
|
||||
|
||||
// Restore original protection of NT headers.
|
||||
//
|
||||
VirtualProtect(
|
||||
m_TargetNtHeaders,
|
||||
sizeof(*m_TargetNtHeaders),
|
||||
m_OriginalNtProtection,
|
||||
&OldProtection);
|
||||
}
|
||||
|
||||
void ImageCorruptor::ModifyDosMagic(WORD Value)
|
||||
{
|
||||
m_TargetDosHeader->e_magic = Value;
|
||||
}
|
||||
|
||||
void ImageCorruptor::ModifyNtSignature(ULONG Value)
|
||||
{
|
||||
m_TargetNtHeaders->Signature = Value;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//////////////////////////////////////////////////////
|
||||
//
|
||||
// Unit Test Image Corruptor (corruptor.h of unittests.exe)
|
||||
//
|
||||
// Microsoft Research Detours Package
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
class ImageCorruptor final
|
||||
{
|
||||
public:
|
||||
|
||||
ImageCorruptor(PIMAGE_DOS_HEADER Header);
|
||||
|
||||
~ImageCorruptor();
|
||||
|
||||
void ModifyDosMagic(WORD Value);
|
||||
|
||||
void ModifyNtSignature(ULONG Value);
|
||||
|
||||
private:
|
||||
// Pointer to the target image header to corrupt.
|
||||
//
|
||||
PIMAGE_DOS_HEADER m_TargetDosHeader;
|
||||
|
||||
// Cached copy of the DOS header, to restore state with.
|
||||
//
|
||||
IMAGE_DOS_HEADER m_OriginalDosHeader;
|
||||
|
||||
// The original protection of the DOS header.
|
||||
//
|
||||
DWORD m_OriginalDosProtection;
|
||||
|
||||
// Pointer to the target NT image header to corrupt.
|
||||
//
|
||||
PIMAGE_NT_HEADERS m_TargetNtHeaders;
|
||||
|
||||
// Cached copy of the NT headers, to restore state with.
|
||||
//
|
||||
IMAGE_NT_HEADERS m_OriginalNtHeaders;
|
||||
|
||||
// The original protection of the NT headers.
|
||||
//
|
||||
DWORD m_OriginalNtProtection;
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unit Test Main (main.cpp of unittests.exe)
|
||||
//
|
||||
// Microsoft Research Detours Package
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
|
@ -0,0 +1,21 @@
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unit Tests for Detours Image API (test_image_api.cpp of unittests.exe)
|
||||
//
|
||||
// Microsoft Research Detours Package
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
#include "catch.hpp"
|
||||
#include "windows.h"
|
||||
#include "detours.h"
|
||||
|
||||
TEST_CASE("DetourBinaryOpen", "[image]")
|
||||
{
|
||||
SECTION("Passing INVALID_HANDLE, results in error")
|
||||
{
|
||||
auto binary = DetourBinaryOpen(INVALID_HANDLE_VALUE);
|
||||
REQUIRE( GetLastError() == ERROR_INVALID_HANDLE );
|
||||
REQUIRE( binary == nullptr );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Unit Tests for Detours Module API (test_module_api.cpp of unittests.exe)
|
||||
//
|
||||
// Microsoft Research Detours Package
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
#include "catch.hpp"
|
||||
#include "windows.h"
|
||||
#include "detours.h"
|
||||
#include "corruptor.h"
|
||||
|
||||
// Expose the image base of the current module for test assertions.
|
||||
//
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
// Expose default module entry point for test assertions.
|
||||
//
|
||||
extern "C" int mainCRTStartup();
|
||||
|
||||
// Dummy function pointer used for tests.
|
||||
//
|
||||
void NoopFunction() { }
|
||||
|
||||
TEST_CASE("DetourGetContainingModule", "[module]")
|
||||
{
|
||||
SECTION("Passing nullptr, results in nullptr")
|
||||
{
|
||||
auto mod = DetourGetContainingModule(nullptr);
|
||||
REQUIRE( GetLastError() == ERROR_BAD_EXE_FORMAT );
|
||||
REQUIRE( mod == nullptr );
|
||||
}
|
||||
|
||||
SECTION("Passing GetCommandLineW, results in kernel32 HMODULE")
|
||||
{
|
||||
auto mod = DetourGetContainingModule(GetCommandLineW);
|
||||
REQUIRE( GetLastError() == NO_ERROR );
|
||||
REQUIRE( mod == LoadLibrary("kernel32.dll") );
|
||||
}
|
||||
|
||||
SECTION("Passing own function, results in own HMODULE")
|
||||
{
|
||||
auto mod = DetourGetContainingModule(NoopFunction);
|
||||
REQUIRE( GetLastError() == NO_ERROR );
|
||||
REQUIRE( mod == reinterpret_cast<HMODULE>(&__ImageBase) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DetourGetEntyPoint", "[module]")
|
||||
{
|
||||
SECTION("Passing nullptr, results in CRT entrypoint")
|
||||
{
|
||||
auto entry = DetourGetEntryPoint(nullptr);
|
||||
REQUIRE( GetLastError() == NO_ERROR );
|
||||
REQUIRE( entry == mainCRTStartup );
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr, equals executing image")
|
||||
{
|
||||
REQUIRE( DetourGetEntryPoint(nullptr) ==
|
||||
DetourGetEntryPoint(reinterpret_cast<HMODULE>(&__ImageBase)) );
|
||||
}
|
||||
|
||||
SECTION("Passing ImageBase, results in CRT main")
|
||||
{
|
||||
auto entry = DetourGetEntryPoint(reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
REQUIRE( GetLastError() == NO_ERROR );
|
||||
REQUIRE( entry == mainCRTStartup );
|
||||
}
|
||||
|
||||
SECTION("Corrupt image DOS header magic, results in bad exe format error")
|
||||
{
|
||||
ImageCorruptor corruptor(&__ImageBase);
|
||||
corruptor.ModifyDosMagic(0xDEAD);
|
||||
|
||||
auto entry = DetourGetEntryPoint(reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
REQUIRE( GetLastError() == ERROR_BAD_EXE_FORMAT );
|
||||
REQUIRE( entry == nullptr );
|
||||
}
|
||||
|
||||
SECTION("Corrupt image NT header signature, results in invalid signature error")
|
||||
{
|
||||
ImageCorruptor corruptor(&__ImageBase);
|
||||
corruptor.ModifyNtSignature(0xDEADBEEF);
|
||||
|
||||
auto entry = DetourGetEntryPoint(reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
REQUIRE( GetLastError() == ERROR_INVALID_EXE_SIGNATURE );
|
||||
REQUIRE( entry == nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DetourGetModuleSize", "[module]")
|
||||
{
|
||||
SECTION("Passing nullptr, results in current module size")
|
||||
{
|
||||
auto size = DetourGetModuleSize(nullptr);
|
||||
REQUIRE( GetLastError() == NO_ERROR );
|
||||
REQUIRE( size >= 0 );
|
||||
}
|
||||
|
||||
SECTION("Passing stack, results in error")
|
||||
{
|
||||
int value;
|
||||
auto size = DetourGetModuleSize(reinterpret_cast<HMODULE>(&value));
|
||||
REQUIRE( GetLastError() == ERROR_BAD_EXE_FORMAT);
|
||||
REQUIRE( size == 0 );
|
||||
}
|
||||
|
||||
SECTION("Passing nullptr, equals executing image")
|
||||
{
|
||||
REQUIRE( DetourGetModuleSize(nullptr) ==
|
||||
DetourGetModuleSize(reinterpret_cast<HMODULE>(&__ImageBase)) );
|
||||
}
|
||||
|
||||
SECTION("Corrupt image DOS header magic, results in bad exe format error")
|
||||
{
|
||||
ImageCorruptor corruptor(&__ImageBase);
|
||||
corruptor.ModifyDosMagic(0xDEAD);
|
||||
|
||||
auto size = DetourGetModuleSize(reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
REQUIRE( GetLastError() == ERROR_BAD_EXE_FORMAT );
|
||||
REQUIRE( size == 0 );
|
||||
}
|
||||
|
||||
SECTION("Corrupt image NT header signature, results in invalid signature error")
|
||||
{
|
||||
ImageCorruptor corruptor(&__ImageBase);
|
||||
corruptor.ModifyNtSignature(0xDEADBEEF);
|
||||
|
||||
auto size = DetourGetModuleSize(reinterpret_cast<HMODULE>(&__ImageBase));
|
||||
REQUIRE( GetLastError() == ERROR_INVALID_EXE_SIGNATURE );
|
||||
REQUIRE( size == 0 );
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче