Skip to content

Commit b2dbbe5

Browse files
authored
Merge pull request #56 from mrexodia/test-framework
Actually use the new test framework
2 parents c858f31 + f96ea5d commit b2dbbe5

12 files changed

+394
-27
lines changed

.github/workflows/build.yml

+61-11
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,88 @@ jobs:
77
# Skip building pull requests from the same repository
88
if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }}
99
runs-on: windows-2019
10+
env:
11+
# Disable output buffering in an attempt to get readable errors
12+
PYTHONUNBUFFERED: '1'
1013
steps:
1114
- name: Checkout
12-
uses: actions/checkout@v2
15+
uses: actions/checkout@v3
1316

1417
- name: Python environment
15-
uses: actions/setup-python@v2
18+
uses: actions/setup-python@v4
1619
with:
1720
python-version: '3.9'
1821
architecture: 'x64'
1922

20-
- name: Build
23+
- name: Python setup
2124
run: |
2225
python setup.py develop
2326
24-
- name: StringEncryptionFun_x64
27+
- name: Add msbuild to PATH
28+
uses: microsoft/[email protected]
29+
30+
- name: Cache build
31+
uses: actions/cache@v3
32+
id: cache-build
33+
with:
34+
path: 'tests/DumpulatorTests/bin'
35+
key: ${{ runner.os }}-${{ hashFiles('tests/DumpulatorTests/**') }}
36+
37+
- name: Build DumpulatorTests
38+
if: steps.cache-build.outputs.cache-hit != 'true'
2539
run: |
26-
curl -sSOJL https://github.com/mrexodia/dumpulator/releases/download/v0.0.1/StringEncryptionFun_x64.dmp
27-
python tests/getting-started.py
40+
msbuild /p:Configuration=Release /p:Platform=Win32 tests\DumpulatorTests\DumpulatorTests.sln
41+
msbuild /p:Configuration=Release /p:Platform=x64 tests\DumpulatorTests\DumpulatorTests.sln
2842
29-
- name: StringEncryptionFun_x86
43+
- name: Cache dumps
44+
uses: actions/cache@v3
45+
id: cache-dumps
46+
with:
47+
path: 'tests/*.dmp'
48+
key: ${{ runner.os }}-${{ hashFiles('tests/download_artifacts.py') }}
49+
50+
- name: Download dumps
51+
if: steps.cache-dumps.outputs.cache-hit != 'true'
3052
run: |
53+
cd tests
54+
curl -sSOJL https://github.com/mrexodia/dumpulator/releases/download/v0.0.1/StringEncryptionFun_x64.dmp
3155
curl -sSOJL https://github.com/mrexodia/dumpulator/releases/download/v0.0.1/StringEncryptionFun_x86.dmp
32-
python tests/getting-started32.py
56+
python download_artifacts.py
57+
58+
- name: 'Test: StringEncryptionFun_x64'
59+
run: |
60+
cd tests
61+
python getting-started.py
62+
63+
- name: 'Test: StringEncryptionFun_x86'
64+
run: |
65+
cd tests
66+
python getting-started32.py
67+
68+
- name: 'Test: DumpulatorTests'
69+
run: |
70+
cd tests
71+
python harness-tests.py
72+
73+
- name: 'Test: ExceptionTest_x64'
74+
run: |
75+
cd tests
76+
python execute-dump.py ExceptionTest_x64.dmp
77+
78+
- name: 'Test: ExceptionTest_x86'
79+
run: |
80+
cd tests
81+
python execute-dump.py ExceptionTest_x86.dmp
3382
3483
publish:
3584
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
3685
runs-on: ubuntu-20.04
3786
steps:
3887
- name: Checkout
39-
uses: actions/checkout@v2
88+
uses: actions/checkout@v3
4089

4190
- name: Python environment
42-
uses: actions/setup-python@v2
91+
uses: actions/setup-python@v4
4392
with:
4493
python-version: '3.9'
4594
architecture: 'x64'
@@ -49,7 +98,8 @@ jobs:
4998
python setup.py sdist
5099
51100
- name: Publish to PyPI
52-
uses: pypa/gh-action-pypi-publish@master
101+
# https://github.com/pypa/gh-action-pypi-publish/releases/tag/v1.6.4
102+
uses: pypa/gh-action-pypi-publish@c7f29f7adef1a245bd91520e94867e5c6eedddcc
53103
with:
54104
password: ${{ secrets.PYPI_API_TOKEN }}
55105

src/dumpulator/dumpulator.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ExceptionType(Enum):
3737
Memory = 1
3838
Interrupt = 2
3939
ContextSwitch = 3
40+
Terminate = 4
4041

4142
@dataclass
4243
class ExceptionInfo:
@@ -783,7 +784,7 @@ def _setup_syscalls(self):
783784
self.info(f"Patching Wow64Transition: {export.address:x} -> {patch_addr:x}")
784785
# See: https://opcode0x90.wordpress.com/2007/05/18/kifastsystemcall-hook/
785786
# mov edx, esp; sysenter; ret
786-
KiFastSystemCall = b"\x8B\xD4\x0F\x34\xC3"
787+
KiFastSystemCall = b"\x8B\xD4\x0F\x34\x90\x90\xC3"
787788
self.write(patch_addr, KiFastSystemCall)
788789
elif export.name == "KiUserExceptionDispatcher":
789790
self.KiUserExceptionDispatcher = export.address
@@ -1003,6 +1004,12 @@ def start(self, begin, end=0xffffffffffffffff, count=0) -> None:
10031004
# Restore the context (unicorn might mess with it before stopping)
10041005
if self.exception.context is not None:
10051006
self._uc.context_restore(self.exception.context)
1007+
1008+
if self.exception.type == ExceptionType.Terminate:
1009+
if self.exit_code is not None:
1010+
self.info(f"exit code: {self.exit_code:x}")
1011+
break
1012+
10061013
try:
10071014
emu_begin = self.handle_exception()
10081015
except:
@@ -1465,7 +1472,7 @@ def syscall_arg(index):
14651472
return dp.regs.r10
14661473
return dp.args[index]
14671474

1468-
dp.info(f"[{dp.sequence_id}] syscall: {name}(")
1475+
dp.info(f"[{dp.sequence_id}] syscall (index: {hex(index)}): {name}(")
14691476
for i in range(0, argcount):
14701477
argname = argspec.args[1 + i]
14711478
argtype = argspec.annotations[argname]
@@ -1474,7 +1481,7 @@ def syscall_arg(index):
14741481
# It looks like the python designers did an oopsie, so we're going
14751482
# the fully-undocumented route.
14761483
sal = None
1477-
if argtype.__name__ == "Annotated":
1484+
if "Annotated" in type(argtype).__name__:
14781485
sal, = argtype.__metadata__
14791486
argtype = argtype.__origin__
14801487

@@ -1513,6 +1520,9 @@ def syscall_arg(index):
15131520
if dp.x64:
15141521
dp.regs.rcx = dp.regs.cip + 2
15151522
dp.regs.r11 = dp.regs.eflags
1523+
else:
1524+
# HACK: there is a bug in unicorn that doesn't increment EIP
1525+
dp.regs.eip += 2
15161526
except UcError as err:
15171527
raise err
15181528
except Exception as exc:

src/dumpulator/ntsyscalls.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -4475,7 +4475,11 @@ def ZwTerminateProcess(dp: Dumpulator,
44754475
):
44764476
assert ProcessHandle == 0 or ProcessHandle == dp.NtCurrentProcess()
44774477
dp.stop(ExitStatus)
4478-
return STATUS_SUCCESS
4478+
exception = ExceptionInfo()
4479+
exception.type = ExceptionType.Terminate
4480+
exception.final = True
4481+
exception.context = dp._uc.context_save()
4482+
return exception
44794483

44804484
@syscall
44814485
def ZwTerminateThread(dp: Dumpulator,

tests/DumpulatorTests/DumpulatorTests.sln

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HarnessMinimal", "HarnessMi
1111
EndProject
1212
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HarnessFull", "HarnessFull\HarnessFull.vcxproj", "{1FD2D0B5-53E2-4E9E-AA4B-2E822ABD2D49}"
1313
EndProject
14+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExceptionTest", "ExceptionTest\ExceptionTest.vcxproj", "{8D02ACE7-0361-45F7-B173-3188B235F2DC}"
15+
EndProject
1416
Global
1517
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1618
Release|Win32 = Release|Win32
@@ -33,6 +35,10 @@ Global
3335
{1FD2D0B5-53E2-4E9E-AA4B-2E822ABD2D49}.Release|Win32.Build.0 = Release|Win32
3436
{1FD2D0B5-53E2-4E9E-AA4B-2E822ABD2D49}.Release|x64.ActiveCfg = Release|x64
3537
{1FD2D0B5-53E2-4E9E-AA4B-2E822ABD2D49}.Release|x64.Build.0 = Release|x64
38+
{8D02ACE7-0361-45F7-B173-3188B235F2DC}.Release|Win32.ActiveCfg = Release|Win32
39+
{8D02ACE7-0361-45F7-B173-3188B235F2DC}.Release|Win32.Build.0 = Release|Win32
40+
{8D02ACE7-0361-45F7-B173-3188B235F2DC}.Release|x64.ActiveCfg = Release|x64
41+
{8D02ACE7-0361-45F7-B173-3188B235F2DC}.Release|x64.Build.0 = Release|x64
3642
EndGlobalSection
3743
GlobalSection(SolutionProperties) = preSolution
3844
HideSolutionNode = FALSE

tests/DumpulatorTests/Tests/ExceptionTest.cpp renamed to tests/DumpulatorTests/ExceptionTest/ExceptionTest.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
#include "debug.h"
1+
#include <Windows.h>
2+
#include <cstdio>
3+
4+
#include "../Tests/debug.h"
25

36
static LONG WINAPI VectoredHandler(struct _EXCEPTION_POINTERS* ExceptionInfo)
47
{
@@ -62,3 +65,10 @@ extern "C" __declspec(dllexport) bool Exception_Test()
6265
DebugPrint(L"Finished!");
6366
return true;
6467
}
68+
69+
70+
int main(int argc, char** argv)
71+
{
72+
auto exitCode = Exception_Test() ? EXIT_SUCCESS : EXIT_FAILURE;
73+
ExitProcess(exitCode);
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Release|Win32">
5+
<Configuration>Release</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Release|x64">
9+
<Configuration>Release</Configuration>
10+
<Platform>x64</Platform>
11+
</ProjectConfiguration>
12+
</ItemGroup>
13+
<PropertyGroup Label="Globals">
14+
<VCProjectVersion>16.0</VCProjectVersion>
15+
<Keyword>Win32Proj</Keyword>
16+
<ProjectGuid>{8D02ACE7-0361-45F7-B173-3188B235F2DC}</ProjectGuid>
17+
<RootNamespace>ExceptionTest</RootNamespace>
18+
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
19+
</PropertyGroup>
20+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
21+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
22+
<ConfigurationType>Application</ConfigurationType>
23+
<UseDebugLibraries>false</UseDebugLibraries>
24+
<PlatformToolset>v142</PlatformToolset>
25+
<WholeProgramOptimization>true</WholeProgramOptimization>
26+
<CharacterSet>Unicode</CharacterSet>
27+
</PropertyGroup>
28+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
29+
<ConfigurationType>Application</ConfigurationType>
30+
<UseDebugLibraries>false</UseDebugLibraries>
31+
<PlatformToolset>v142</PlatformToolset>
32+
<WholeProgramOptimization>true</WholeProgramOptimization>
33+
<CharacterSet>Unicode</CharacterSet>
34+
</PropertyGroup>
35+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
36+
<ImportGroup Label="ExtensionSettings">
37+
</ImportGroup>
38+
<ImportGroup Label="Shared">
39+
</ImportGroup>
40+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
41+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
42+
</ImportGroup>
43+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
44+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
45+
</ImportGroup>
46+
<PropertyGroup Label="UserMacros" />
47+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
48+
<LinkIncremental>false</LinkIncremental>
49+
<OutDir>$(SolutionDir)bin\</OutDir>
50+
<IntDir>$(SolutionDir)_obj\$(Platform)\$(ProjectName)\</IntDir>
51+
<TargetName>$(ProjectName)_x86</TargetName>
52+
</PropertyGroup>
53+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
54+
<LinkIncremental>false</LinkIncremental>
55+
<OutDir>$(SolutionDir)bin\</OutDir>
56+
<IntDir>$(SolutionDir)_obj\$(Platform)\$(ProjectName)\</IntDir>
57+
<TargetName>$(ProjectName)_x64</TargetName>
58+
</PropertyGroup>
59+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
60+
<ClCompile>
61+
<WarningLevel>Level3</WarningLevel>
62+
<SDLCheck>false</SDLCheck>
63+
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
64+
<ConformanceMode>true</ConformanceMode>
65+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
66+
</ClCompile>
67+
<Link>
68+
<SubSystem>Console</SubSystem>
69+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
70+
<OptimizeReferences>true</OptimizeReferences>
71+
<GenerateDebugInformation>true</GenerateDebugInformation>
72+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
73+
<DataExecutionPrevention>false</DataExecutionPrevention>
74+
<AdditionalDependencies>ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
75+
</Link>
76+
</ItemDefinitionGroup>
77+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
78+
<ClCompile>
79+
<WarningLevel>Level3</WarningLevel>
80+
<SDLCheck>false</SDLCheck>
81+
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
82+
<ConformanceMode>true</ConformanceMode>
83+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
84+
</ClCompile>
85+
<Link>
86+
<SubSystem>Console</SubSystem>
87+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
88+
<OptimizeReferences>true</OptimizeReferences>
89+
<GenerateDebugInformation>true</GenerateDebugInformation>
90+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
91+
<DataExecutionPrevention>false</DataExecutionPrevention>
92+
<AdditionalDependencies>ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
93+
</Link>
94+
</ItemDefinitionGroup>
95+
<ItemGroup>
96+
<ClCompile Include="ExceptionTest.cpp" />
97+
</ItemGroup>
98+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
99+
<ImportGroup Label="ExtensionTargets">
100+
</ImportGroup>
101+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup>
4+
<Filter Include="Source Files">
5+
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6+
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7+
</Filter>
8+
<Filter Include="Header Files">
9+
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10+
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
11+
</Filter>
12+
<Filter Include="Resource Files">
13+
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14+
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
15+
</Filter>
16+
</ItemGroup>
17+
<ItemGroup>
18+
<ClCompile Include="ExceptionTest.cpp">
19+
<Filter>Source Files</Filter>
20+
</ClCompile>
21+
</ItemGroup>
22+
</Project>

tests/DumpulatorTests/Loader/Loader.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,14 @@ int main(int argc, char** argv)
1616
return EXIT_FAILURE;
1717
}
1818
auto TestFunction = (int(*)())GetProcAddress(hLib, argv[1]);
19-
return TestFunction() ? EXIT_SUCCESS : EXIT_FAILURE;
19+
if (TestFunction == nullptr)
20+
{
21+
printf("Could not find function: %s\n", argv[1]);
22+
return EXIT_FAILURE;
23+
}
24+
// Trigger a breakpoint to allow the debugger to dump
25+
if (argc > 2)
26+
__debugbreak();
27+
auto exitCode = TestFunction() ? EXIT_SUCCESS : EXIT_FAILURE;
28+
ExitProcess(exitCode);
2029
}

tests/DumpulatorTests/Tests/Tests.vcxproj

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
</ItemGroup>
1313
<ItemGroup>
1414
<ClCompile Include="DllMain.cpp" />
15-
<ClCompile Include="ExceptionTest.cpp" />
1615
<ClCompile Include="HandleTest.cpp" />
1716
</ItemGroup>
1817
<ItemGroup>

tests/DumpulatorTests/Tests/Tests.vcxproj.filters

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
</Filter>
1616
</ItemGroup>
1717
<ItemGroup>
18-
<ClCompile Include="ExceptionTest.cpp">
19-
<Filter>Source Files</Filter>
20-
</ClCompile>
2118
<ClCompile Include="HandleTest.cpp">
2219
<Filter>Source Files</Filter>
2320
</ClCompile>

0 commit comments

Comments
 (0)