mirror of
https://github.com/klezVirus/SilentMoonwalk/
synced 2026-06-06 16:04:32 +00:00
Public Release
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Debug files
|
||||
*.pdb
|
||||
|
||||
# Visual Studio Files
|
||||
.vs/
|
||||
x64/
|
||||
*.html
|
||||
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2022, Alessandro Magnosi, Arash Parsa, Åthanasios Tserpelis
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,152 @@
|
||||
# SilentMoonwalk
|
||||
|
||||
PoC Implementation of a true call stack spoofer
|
||||
|
||||
## TL;DR
|
||||
|
||||
SilentMoonwalk is a PoC implementation of a true call stack spoofer, implementing a technique to remove the original caller from the call stack,
|
||||
using ROP to desynchronize unwinding from control flow.
|
||||
|
||||
## Authors
|
||||
|
||||
This PoC is the result of a joint research done on the topic of stack spoofing. The authors of the research are:
|
||||
|
||||
* [KlezVirus][9]
|
||||
* [Waldo-IRC][5]
|
||||
* [Trickster0][6]
|
||||
|
||||
I want to stress that this work would have been impossible without the work of [Waldo-IRC][5] and [Trickster0][6], which both
|
||||
contributed to the early stages of the PoC, and to the research behind the PoC.
|
||||
|
||||
## Overview
|
||||
|
||||
This repository demonstrates a PoC implementation to spoof the call stack when calling arbitrary Windows APIs.
|
||||
|
||||
This attempt was inspired by [this Twitter thread][8], and [this Twitter thread], where sensei [namazso][1] showed and suggested
|
||||
to extend the stack unwinding approach with a ROP chain to both desynchronize the unwinding from real control flow and restore
|
||||
the original stack afterwards.
|
||||
|
||||
This PoC attempts to do something similar to the above, and uses a desync stack to completely hide the original
|
||||
call stack, also removing the EXE image base from it. Upon return, a ROP gadget is invoked to restore the original stack.
|
||||
In the code, this process is repeated 10 times in a loop, using different frames at each iteration, to prove stability.
|
||||
|
||||
### Supported Modes
|
||||
|
||||
The tool currently supports 2 modes, where one is actually a wrong patch to a non-working pop RBP frame identified, which operates by shifting the current
|
||||
RSP and adding two fake frames to the call stack. As it operates using synthetic frames, I refer to this mode as "SYNTHETIC".
|
||||
|
||||
When selecting the frame that unwinds by popping the RBP register from the stack, the tool might select an unsuitable frame, ending up in an abruptly
|
||||
cut call stack, as observable below.
|
||||
|
||||

|
||||
|
||||
### Synthetic Call Stack Mode
|
||||
|
||||
A silly solution to the problem would be to create two fake frames and link them back to the cut call stack. This would create a sort of apparently legit call stack,
|
||||
even without a suitable frame which unwinds calling POP RBP, but:
|
||||
* You would lose the advantage of the desync technique
|
||||
* The stack would be still unwindable
|
||||
* The resulting call stack could seem legit just on the first glance, but it would probably not pass a strict check
|
||||
|
||||
The result of the _synthetic spoof can be observed in the image below:
|
||||
|
||||

|
||||
|
||||
*Figure 1: Windows 10 - Valid call stack whereby the EXE module was completely removed (calling no parameters function getchar)*
|
||||
|
||||
*Note: This operation mode is disabled by default. To enable this mode, change the CALLSTACK_TYPE to 1*
|
||||
|
||||
### Desync Stack Mode
|
||||
|
||||
This mode is the right solution to the above problem, whereby the non-suitable frame is simply replaced by another, suitable one.
|
||||
|
||||

|
||||
|
||||
*Figure 2: Windows 10 - Valid call stack whereby the EXE module was completely removed (calling 4 parameters function MessageBoxA)*
|
||||
|
||||
## Utility
|
||||
|
||||
In the repository, you can find also a little util to inspect runtime functions, which might be useful to analyse runtime function entries.
|
||||
|
||||
```
|
||||
UnwindInspector.exe -h
|
||||
|
||||
Unwind Inspector v0.100000
|
||||
|
||||
Mandatory args:
|
||||
-m <module>: Target DLL
|
||||
-f <function>: Target Function
|
||||
-a <function-address>: Target Function Address
|
||||
```
|
||||
|
||||
Sample Output:
|
||||
|
||||
```
|
||||
UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
|
||||
[*] Using function address 0x7ffaae12182c
|
||||
|
||||
Runtime Function (0x000000000000182C, 0x00000000000019ED)
|
||||
Unwind Info Address: 0x000000000026AA88
|
||||
Version: 0
|
||||
Ver + Flags: 00000000
|
||||
SizeOfProlog: 0x1f
|
||||
CountOfCodes: 0xc
|
||||
FrameRegister: 0x0
|
||||
FrameOffset: 0x0
|
||||
UnwindCodes:
|
||||
[00h] Frame: 0x741f - 0x04 - UWOP_SAVE_NONVOL (RDI, 0x001f)
|
||||
[01h] Frame: 0x0015 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0015)
|
||||
[02h] Frame: 0x641f - 0x04 - UWOP_SAVE_NONVOL (RSI, 0x001f)
|
||||
[03h] Frame: 0x0014 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0014)
|
||||
[04h] Frame: 0x341f - 0x04 - UWOP_SAVE_NONVOL (RBX, 0x001f)
|
||||
[05h] Frame: 0x0012 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0012)
|
||||
[06h] Frame: 0xb21f - 0x02 - UWOP_ALLOC_SMALL (R11, 0x001f)
|
||||
[07h] Frame: 0xf018 - 0x00 - UWOP_PUSH_NONVOL (R15, 0x0018)
|
||||
[08h] Frame: 0xe016 - 0x00 - UWOP_PUSH_NONVOL (R14, 0x0016)
|
||||
[09h] Frame: 0xd014 - 0x00 - UWOP_PUSH_NONVOL (R13, 0x0014)
|
||||
[0ah] Frame: 0xc012 - 0x00 - UWOP_PUSH_NONVOL (R12, 0x0012)
|
||||
[0bh] Frame: 0x5010 - 0x00 - UWOP_PUSH_NONVOL (RBP, 0x0010)
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
In order to build the POC and observe a similar behaviour to the one in the picture, ensure to:
|
||||
|
||||
* Disable GS (`/GS-`)
|
||||
* Disable Code Optimisation (`/Od`)
|
||||
* Disable Whole Program Optimisation (Remove `/GL`)
|
||||
* Disable size and speed preference (Remove `/Os`, `/Ot`)
|
||||
* **Enable** intrinsic if not enabled (`/Oi`)
|
||||
|
||||
## Previous Work
|
||||
|
||||
It's worth mentioning previous work done on this topic, which built the foundation of this work.
|
||||
|
||||
* [Return Address Spoofing][7]: Original technique and idea, by Namaszo. Every other PoC I'm aware of was built on top of that.
|
||||
* [YouMayPasser][10]: This amazing work by Arash is the first properly done extension of the Return Address Spoofing PoC by Namaszo.
|
||||
* [VulcanRaven][2]: A call stack spoofer that operates the spoofing by synthetically creating a Thread Stack mirroring another real call stack.
|
||||
* [Unwinder][3]: A very nice Rust PoC implementation of a call stack spoofer which operates by parsing unwind code information to replace frames in the call stack.
|
||||
|
||||
## Credits
|
||||
|
||||
* Huge shoutout to [waldo-irc][5] and [trickster0][6], which collaborated with me on this research. I owe everything to them.
|
||||
* All the credit for the idea behind this goes to [namaszo][1], which I personally consider a genius. He also cross checked this PoC before release, so huge thanks to him.
|
||||
|
||||
## Notes
|
||||
|
||||
* [SYNTHETIC STACK ONLY]: For a limitation in the way I'm locating the gadgets, the maximum number of arguments is 8 for now (it is TRIVIAL to modify and add more params, but I couldn't bother).
|
||||
* Testing on this one was pretty limited. There might be exceptions I'm not aware of at the moment.
|
||||
* Unwinding involving 128-bit registers was no tested.
|
||||
* Calling functions that use 128-bit registers is not officially supported.
|
||||
|
||||
[1]: https://twitter.com/namazso
|
||||
[2]: https://github.com/WithSecureLabs/CallStackSpoofer/
|
||||
[3]: https://github.com/Kudaes/Unwinder/
|
||||
[4]: https://twitter.com/_Kudaes_
|
||||
[5]: https://twitter.com/waldoirc
|
||||
[6]: https://twitter.com/trickster012
|
||||
[7]: https://www.unknowncheats.me/forum/anti-cheat-bypass/268039-x64-return-address-spoofing-source-explanation.html
|
||||
[8]: https://twitter.com/_Kudaes_/status/1594753842310434816
|
||||
[9]: https://twitter.com/KlezVirus
|
||||
[10]: https://github.com/waldo-irc/YouMayPasser
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32407.343
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SilentMoonwalk", "SilentMoonwalk\SilentMoonwalk.vcxproj", "{E11DC25D-E96D-495D-8968-1BA09C95B673}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{25E04E93-D4AF-4A27-8568-7B0CBE3AF0A2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnwindInspector", "UnwindInspector\UnwindInspector.vcxproj", "{E86ABDAA-444C-409A-B466-9E034E859C80}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Debug|x64.Build.0 = Debug|x64
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Release|x64.ActiveCfg = Release|x64
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Release|x64.Build.0 = Release|x64
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E11DC25D-E96D-495D-8968-1BA09C95B673}.Release|x86.Build.0 = Release|Win32
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Debug|x64.Build.0 = Debug|x64
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Release|x64.ActiveCfg = Release|x64
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Release|x64.Build.0 = Release|x64
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E86ABDAA-444C-409A-B466-9E034E859C80}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {54F8980C-A52E-4F1D-B737-D212E6F548AF}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,35 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Visual Studio Dir
|
||||
x64
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{e11dc25d-e96d-495d-8968-1ba09c95b673}</ProjectGuid>
|
||||
<RootNamespace>TheRealStackSpoof</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>SilentMoonwalk</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);vcruntime.lib;</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SilentMoonwalk.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\AddressHunter.h" />
|
||||
<ClInclude Include="include\Common.h" />
|
||||
<ClInclude Include="include\Functions.h" />
|
||||
<ClInclude Include="include\Spoof.h" />
|
||||
<ClInclude Include="include\Test.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="include\asm\SyntheticSpoofer.asm" />
|
||||
<MASM Include="include\asm\DesyncSpoofer.asm" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SilentMoonwalk.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\AddressHunter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Functions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Spoof.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Test.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="include\asm\SyntheticSpoofer.asm">
|
||||
<Filter>Source Files</Filter>
|
||||
</MASM>
|
||||
<MASM Include="include\asm\DesyncSpoofer.asm">
|
||||
<Filter>Source Files</Filter>
|
||||
</MASM>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,356 @@
|
||||
// https://raw.githubusercontent.com/paranoidninja/PIC-Get-Privileges/main/addresshunter.h
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define DEREF( name )*(UINT_PTR *)(name)
|
||||
#define DEREF_64( name )*(DWORD64 *)(name)
|
||||
#define DEREF_32( name )*(DWORD *)(name)
|
||||
#define DEREF_16( name )*(WORD *)(name)
|
||||
#define DEREF_8( name )*(BYTE *)(name)
|
||||
|
||||
#define KERNELBASE_HASH 0xc42f2982
|
||||
#define KERNEL32DLL_HASH 0xbc5d4571
|
||||
#define MSVCRTDLL_HASH 0xc3222c90
|
||||
#define ADVAPI32DLL_HASH 0x8353484b
|
||||
#define NTDLL_HASH 0x4f576ca1
|
||||
|
||||
#define FH_RND_SEED 0xDC072B8A
|
||||
#define ROL8(v) (v << 8 | v >> 24)
|
||||
#define ROR8(v) (v >> 8 | v << 24)
|
||||
#define ROX8(v) ((FH_RND_SEED % 2) ? ROL8(v) : ROR8(v))
|
||||
|
||||
//redefine UNICODE_STR struct
|
||||
typedef struct _UNICODE_STR
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR pBuffer;
|
||||
} UNICODE_STR, * PUNICODE_STR;
|
||||
|
||||
//redefine PEB_LDR_DATA struct
|
||||
typedef struct _PEB_LDR_DATA
|
||||
{
|
||||
DWORD dwLength;
|
||||
DWORD dwInitialized;
|
||||
LPVOID lpSsHandle;
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
LPVOID lpEntryInProgress;
|
||||
} PEB_LDR_DATA, * PPEB_LDR_DATA;
|
||||
|
||||
//redefine LDR_DATA_TABLE_ENTRY struct
|
||||
typedef struct _LDR_DATA_TABLE_ENTRY
|
||||
{
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
PVOID DllBase;
|
||||
PVOID EntryPoint;
|
||||
ULONG SizeOfImage;
|
||||
UNICODE_STR FullDllName;
|
||||
UNICODE_STR BaseDllName;
|
||||
ULONG Flags;
|
||||
SHORT LoadCount;
|
||||
SHORT TlsIndex;
|
||||
LIST_ENTRY HashTableEntry;
|
||||
ULONG TimeDateStamp;
|
||||
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
|
||||
|
||||
//redefine PEB_FREE_BLOCK struct
|
||||
typedef struct _PEB_FREE_BLOCK
|
||||
{
|
||||
struct _PEB_FREE_BLOCK* pNext;
|
||||
DWORD dwSize;
|
||||
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
|
||||
|
||||
//redefine PEB struct
|
||||
typedef struct __PEB
|
||||
{
|
||||
BYTE bInheritedAddressSpace;
|
||||
BYTE bReadImageFileExecOptions;
|
||||
BYTE bBeingDebugged;
|
||||
BYTE bSpareBool;
|
||||
LPVOID lpMutant;
|
||||
LPVOID lpImageBaseAddress;
|
||||
PPEB_LDR_DATA pLdr;
|
||||
LPVOID lpProcessParameters;
|
||||
LPVOID lpSubSystemData;
|
||||
LPVOID lpProcessHeap;
|
||||
PRTL_CRITICAL_SECTION pFastPebLock;
|
||||
LPVOID lpFastPebLockRoutine;
|
||||
LPVOID lpFastPebUnlockRoutine;
|
||||
DWORD dwEnvironmentUpdateCount;
|
||||
LPVOID lpKernelCallbackTable;
|
||||
DWORD dwSystemReserved;
|
||||
DWORD dwAtlThunkSListPtr32;
|
||||
PPEB_FREE_BLOCK pFreeList;
|
||||
DWORD dwTlsExpansionCounter;
|
||||
LPVOID lpTlsBitmap;
|
||||
DWORD dwTlsBitmapBits[2];
|
||||
LPVOID lpReadOnlySharedMemoryBase;
|
||||
LPVOID lpReadOnlySharedMemoryHeap;
|
||||
LPVOID lpReadOnlyStaticServerData;
|
||||
LPVOID lpAnsiCodePageData;
|
||||
LPVOID lpOemCodePageData;
|
||||
LPVOID lpUnicodeCaseTableData;
|
||||
DWORD dwNumberOfProcessors;
|
||||
DWORD dwNtGlobalFlag;
|
||||
LARGE_INTEGER liCriticalSectionTimeout;
|
||||
DWORD dwHeapSegmentReserve;
|
||||
DWORD dwHeapSegmentCommit;
|
||||
DWORD dwHeapDeCommitTotalFreeThreshold;
|
||||
DWORD dwHeapDeCommitFreeBlockThreshold;
|
||||
DWORD dwNumberOfHeaps;
|
||||
DWORD dwMaximumNumberOfHeaps;
|
||||
LPVOID lpProcessHeaps;
|
||||
LPVOID lpGdiSharedHandleTable;
|
||||
LPVOID lpProcessStarterHelper;
|
||||
DWORD dwGdiDCAttributeList;
|
||||
LPVOID lpLoaderLock;
|
||||
DWORD dwOSMajorVersion;
|
||||
DWORD dwOSMinorVersion;
|
||||
WORD wOSBuildNumber;
|
||||
WORD wOSCSDVersion;
|
||||
DWORD dwOSPlatformId;
|
||||
DWORD dwImageSubsystem;
|
||||
DWORD dwImageSubsystemMajorVersion;
|
||||
DWORD dwImageSubsystemMinorVersion;
|
||||
DWORD dwImageProcessAffinityMask;
|
||||
DWORD dwGdiHandleBuffer[34];
|
||||
LPVOID lpPostProcessInitRoutine;
|
||||
LPVOID lpTlsExpansionBitmap;
|
||||
DWORD dwTlsExpansionBitmapBits[32];
|
||||
DWORD dwSessionId;
|
||||
ULARGE_INTEGER liAppCompatFlags;
|
||||
ULARGE_INTEGER liAppCompatFlagsUser;
|
||||
LPVOID lppShimData;
|
||||
LPVOID lpAppCompatInfo;
|
||||
UNICODE_STR usCSDVersion;
|
||||
LPVOID lpActivationContextData;
|
||||
LPVOID lpProcessAssemblyStorageMap;
|
||||
LPVOID lpSystemDefaultActivationContextData;
|
||||
LPVOID lpSystemAssemblyStorageMap;
|
||||
DWORD dwMinimumStackCommit;
|
||||
} _PEB, * _PPEB;
|
||||
|
||||
|
||||
DWORD HashModule(PCSTR ModuleName, size_t length)
|
||||
{
|
||||
DWORD i = 0;
|
||||
DWORD Hash = FH_RND_SEED;
|
||||
|
||||
while (i < length / 2)
|
||||
{
|
||||
WORD PartialName = *(WORD*)((ULONG64)ModuleName + i++) | 0x20202020;
|
||||
Hash ^= PartialName + ROR8(Hash);
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
|
||||
|
||||
// function to fetch the base address of a Mmodule from the Process Environment Block
|
||||
UINT64 GetModule(DWORD TargetHash) {
|
||||
ULONG_PTR dll, val1;
|
||||
PWSTR val2;
|
||||
USHORT usCounter;
|
||||
// We want to stop when we find this
|
||||
DWORD firstHash = 0;
|
||||
|
||||
// PEB is at 0x60 offset and __readgsqword is compiler intrinsic,
|
||||
// so we don't need to extract it's symbol
|
||||
dll = __readgsqword(0x60);
|
||||
|
||||
dll = (ULONG_PTR)((_PPEB)dll)->pLdr;
|
||||
val1 = (ULONG_PTR)((PPEB_LDR_DATA)dll)->InMemoryOrderModuleList.Flink;
|
||||
|
||||
while (NULL != val1) {
|
||||
val2 = (PWSTR)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.pBuffer;
|
||||
usCounter = (USHORT)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.Length;
|
||||
|
||||
//calculate the hash of kernel32.dll
|
||||
DWORD Hash = HashModule((PCSTR)val2, usCounter);
|
||||
if (firstHash == 0) {
|
||||
firstHash = Hash;
|
||||
}
|
||||
else if (firstHash == Hash) {
|
||||
break;
|
||||
}
|
||||
|
||||
//wprintf(L"%s: %u\n --> Hash: %x - Target: %x\n", (WCHAR*)val2, usCounter, Hash, TargetHash);
|
||||
|
||||
// compare the hash kernel32.dll
|
||||
if (Hash == TargetHash) {
|
||||
//return kernel32.dll if found
|
||||
dll = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)val1)->DllBase;
|
||||
return dll;
|
||||
}
|
||||
val1 = DEREF(val1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// custom strcmp function since this function will be called by GetSymbolAddress
|
||||
// which means we have to call strcmp before loading msvcrt.dll
|
||||
// so we are writing our own my_strcmp so that we don't have to play with egg or chicken dilemma
|
||||
int my_strcmp(const char* p1, const char* p2) {
|
||||
const unsigned char* s1 = (const unsigned char*)p1;
|
||||
const unsigned char* s2 = (const unsigned char*)p2;
|
||||
unsigned char c1, c2;
|
||||
do {
|
||||
c1 = (unsigned char)*s1++;
|
||||
c2 = (unsigned char)*s2++;
|
||||
if (c1 == '\0') {
|
||||
return c1 - c2;
|
||||
}
|
||||
} while (c1 == c2);
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
UINT64 GetSymbolAddress(HMODULE hModule, LPCSTR lpProcName) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0,
|
||||
exportedAddressTable = 0,
|
||||
namePointerTable = 0,
|
||||
ordinalTable = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions);
|
||||
namePointerTable = (dllAddress + exportDirectory->AddressOfNames);
|
||||
ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) {
|
||||
exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable));
|
||||
}
|
||||
else {
|
||||
DWORD dwCounter = exportDirectory->NumberOfNames;
|
||||
while (dwCounter--) {
|
||||
char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable));
|
||||
if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) {
|
||||
exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable));
|
||||
break;
|
||||
}
|
||||
namePointerTable += sizeof(DWORD);
|
||||
ordinalTable += sizeof(WORD);
|
||||
}
|
||||
}
|
||||
|
||||
return symbolAddress;
|
||||
}
|
||||
|
||||
|
||||
UINT64 GetSymbolOffset(HMODULE hModule, LPCSTR lpProcName) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0,
|
||||
exportedAddressTable = 0,
|
||||
namePointerTable = 0,
|
||||
ordinalTable = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions);
|
||||
namePointerTable = (dllAddress + exportDirectory->AddressOfNames);
|
||||
ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) {
|
||||
exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)DEREF_32(exportedAddressTable);
|
||||
}
|
||||
else {
|
||||
DWORD dwCounter = exportDirectory->NumberOfNames;
|
||||
while (dwCounter--) {
|
||||
char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable));
|
||||
if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) {
|
||||
exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)DEREF_32(exportedAddressTable);
|
||||
break;
|
||||
}
|
||||
namePointerTable += sizeof(DWORD);
|
||||
ordinalTable += sizeof(WORD);
|
||||
}
|
||||
}
|
||||
|
||||
return symbolAddress;
|
||||
}
|
||||
|
||||
char* GetSymbolNameByOffset(HMODULE hModule, UINT64 offset) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
LPDWORD exportedAddressTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfFunctions);
|
||||
LPDWORD namePointerTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfNames);
|
||||
LPWORD ordinalTable = (LPWORD)(dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
char* currProcName;
|
||||
|
||||
for (SIZE_T i = 0; i < exportDirectory->NumberOfNames; i++) {
|
||||
// Get current function name
|
||||
currProcName = (LPSTR)((LPBYTE)hModule + namePointerTable[i]);
|
||||
|
||||
// Get current function address
|
||||
if (exportedAddressTable[ordinalTable[i]] == offset) {
|
||||
return currProcName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PVOID GetExceptionDirectoryAddress(HMODULE hModule, DWORD* tSize)
|
||||
{
|
||||
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew);
|
||||
DWORD64 exceptionDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[3].VirtualAddress;
|
||||
*tSize = ntHeader->OptionalHeader.DataDirectory[3].Size;
|
||||
DWORD64 imageExceptionDirectory = (DWORD64)((DWORD_PTR)hModule + exceptionDirectoryRVA);
|
||||
return (PVOID)imageExceptionDirectory;
|
||||
|
||||
}
|
||||
|
||||
PVOID GetExportDirectoryAddress(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew);
|
||||
DWORD_PTR exportDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
DWORD64 imageExportDirectory = (DWORD64)((DWORD_PTR)hModule + exportDirectoryRVA);
|
||||
|
||||
return (PVOID)imageExportDirectory;
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef COMMON_H_INCLUDED
|
||||
#define COMMON_H_INCLUDED
|
||||
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#include <dbghelp.h>
|
||||
#include "AddressHunter.h"
|
||||
|
||||
#define SEED 123456
|
||||
#define MAX_FRAMES 154
|
||||
// Remove if you have a self-made definition of memcmp
|
||||
#define MemCompare memcmp
|
||||
// Using custom printf
|
||||
#define printf custom_printf
|
||||
void custom_printf(const char* pszFormat, ...);
|
||||
|
||||
// Removing malloc deps
|
||||
#undef malloc
|
||||
#define malloc(x) HeapAlloc(GetProcessHeap(), 0, x)
|
||||
|
||||
#undef realloc
|
||||
#define realloc(x,s) HeapReAlloc(GetProcessHeap(), 0, x, s)
|
||||
|
||||
#undef free
|
||||
#define free(x) HeapFree(GetProcessHeap(), 0, x)
|
||||
|
||||
// Removing memset deps
|
||||
void* custom_memset(void* dest, int c, size_t count);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DPRINT(...) { printf(__VA_ARGS__); }
|
||||
#else
|
||||
#define DPRINT(...) {}
|
||||
#endif
|
||||
#define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF))
|
||||
|
||||
#define BitVal(data,y) ( (data>>y) & 1)
|
||||
|
||||
#define BitChainInfo(data) BitVal(data, 2)
|
||||
#define BitUHandler(data) BitVal(data, 1)
|
||||
#define BitEHandler(data) BitVal(data, 0)
|
||||
#define Version(data) BitVal(data, 4)*2 + BitVal(data, 3)
|
||||
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define B2BP BYTE_TO_BINARY_PATTERN
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
(byte & 0x80 ? '1' : '0'), \
|
||||
(byte & 0x40 ? '1' : '0'), \
|
||||
(byte & 0x20 ? '1' : '0'), \
|
||||
(byte & 0x10 ? '1' : '0'), \
|
||||
(byte & 0x08 ? '1' : '0'), \
|
||||
(byte & 0x04 ? '1' : '0'), \
|
||||
(byte & 0x02 ? '1' : '0'), \
|
||||
(byte & 0x01 ? '1' : '0')
|
||||
|
||||
|
||||
typedef UCHAR UBYTE;
|
||||
|
||||
typedef enum _REGISTERS {
|
||||
RAX = 0,
|
||||
RCX,
|
||||
RDX,
|
||||
RBX,
|
||||
RSP,
|
||||
RBP,
|
||||
RSI,
|
||||
RDI,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15
|
||||
} REGISTERS;
|
||||
|
||||
|
||||
typedef union _UNWIND_CODE {
|
||||
struct {
|
||||
UBYTE CodeOffset; // 0xFF00
|
||||
UBYTE UnwindOp : 4; // 0x000f OPCODE
|
||||
UBYTE OpInfo : 4; // 0x00f0
|
||||
};
|
||||
USHORT FrameOffset;
|
||||
} UNWIND_CODE, * PUNWIND_CODE;
|
||||
|
||||
typedef struct _UNWIND_INFO {
|
||||
UBYTE Version : 3;
|
||||
UBYTE Flags : 5; // 4 bytes
|
||||
UBYTE SizeOfProlog; // 4 bytes
|
||||
UBYTE CountOfCodes; // 4 bytes
|
||||
UBYTE FrameRegister : 4;
|
||||
UBYTE FrameOffset : 4; // 4bytes
|
||||
UNWIND_CODE UnwindCode[1];
|
||||
union {
|
||||
OPTIONAL ULONG ExceptionHandler;
|
||||
OPTIONAL ULONG FunctionEntry;
|
||||
};
|
||||
OPTIONAL ULONG ExceptionData[];
|
||||
} UNWIND_INFO, * PUNWIND_INFO;
|
||||
|
||||
#define GetUnwindCodeEntry(info, index) \
|
||||
((info)->UnwindCode[index])
|
||||
|
||||
#define GetLanguageSpecificDataPtr(info) \
|
||||
((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
|
||||
|
||||
#define GetExceptionHandler(base, info) \
|
||||
((PEXCEPTION_ROUTINE)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
|
||||
|
||||
#define GetChainedFunctionEntry(base, info) \
|
||||
((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
|
||||
|
||||
#define GetExceptionDataPtr(info) \
|
||||
((PVOID)((PULONG)GetLanguageSpecificDataPtr(info) + 1))
|
||||
|
||||
#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
|
||||
#define ADDRESS ADDRESS64
|
||||
#define LPADDRESS LPADDRESS64
|
||||
#else
|
||||
typedef struct _tagADDRESS {
|
||||
DWORD Offset;
|
||||
WORD Segment;
|
||||
ADDRESS_MODE Mode;
|
||||
} ADDRESS, * LPADDRESS;
|
||||
#endif
|
||||
|
||||
typedef struct _MIN_CTX {
|
||||
|
||||
DWORD64 Rax;
|
||||
DWORD64 Rcx;
|
||||
DWORD64 Rdx;
|
||||
DWORD64 Rbx;
|
||||
DWORD64 Rsp;
|
||||
DWORD64 Rbp;
|
||||
DWORD64 Rsi;
|
||||
DWORD64 Rdi;
|
||||
DWORD64 R8;
|
||||
DWORD64 R9;
|
||||
DWORD64 R10;
|
||||
DWORD64 R11;
|
||||
DWORD64 R12;
|
||||
DWORD64 R13;
|
||||
DWORD64 R14;
|
||||
DWORD64 R15;
|
||||
|
||||
DWORD64 Rip;
|
||||
DWORD64 Reserved;
|
||||
DWORD64 StackSize;
|
||||
|
||||
} MIN_CTX, *PMIN_CTX;
|
||||
|
||||
typedef enum _UNWIND_OP_CODES {
|
||||
// x86_64. https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
|
||||
UWOP_PUSH_NONVOL = 0,
|
||||
UWOP_ALLOC_LARGE, // 1
|
||||
UWOP_ALLOC_SMALL, // 2
|
||||
UWOP_SET_FPREG, // 3
|
||||
UWOP_SAVE_NONVOL, // 4
|
||||
UWOP_SAVE_NONVOL_BIG, // 5
|
||||
UWOP_EPILOG, // 6
|
||||
UWOP_SPARE_CODE, // 7
|
||||
UWOP_SAVE_XMM128, // 8
|
||||
UWOP_SAVE_XMM128BIG, // 9
|
||||
UWOP_PUSH_MACH_FRAME, // 10
|
||||
|
||||
// ARM64. https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
UWOP_ALLOC_MEDIUM,
|
||||
UWOP_SAVE_R19R20X,
|
||||
UWOP_SAVE_FPLRX,
|
||||
UWOP_SAVE_FPLR,
|
||||
UWOP_SAVE_REG,
|
||||
UWOP_SAVE_REGX,
|
||||
UWOP_SAVE_REGP,
|
||||
UWOP_SAVE_REGPX,
|
||||
UWOP_SAVE_LRPAIR,
|
||||
UWOP_SAVE_FREG,
|
||||
UWOP_SAVE_FREGX,
|
||||
UWOP_SAVE_FREGP,
|
||||
UWOP_SAVE_FREGPX,
|
||||
UWOP_SET_FP,
|
||||
UWOP_ADD_FP,
|
||||
UWOP_NOP,
|
||||
UWOP_END,
|
||||
UWOP_SAVE_NEXT,
|
||||
UWOP_TRAP_FRAME,
|
||||
UWOP_CONTEXT,
|
||||
UWOP_CLEAR_UNWOUND_TO_CALL,
|
||||
// ARM: https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
|
||||
|
||||
UWOP_ALLOC_HUGE,
|
||||
UWOP_WIDE_ALLOC_MEDIUM,
|
||||
UWOP_WIDE_ALLOC_LARGE,
|
||||
UWOP_WIDE_ALLOC_HUGE,
|
||||
|
||||
UWOP_WIDE_SAVE_REG_MASK,
|
||||
UWOP_WIDE_SAVE_SP,
|
||||
UWOP_SAVE_REGS_R4R7LR,
|
||||
UWOP_WIDE_SAVE_REGS_R4R11LR,
|
||||
UWOP_SAVE_FREG_D8D15,
|
||||
UWOP_SAVE_REG_MASK,
|
||||
UWOP_SAVE_LR,
|
||||
UWOP_SAVE_FREG_D0D15,
|
||||
UWOP_SAVE_FREG_D16D31,
|
||||
UWOP_WIDE_NOP, // UWOP_NOP
|
||||
UWOP_END_NOP, // UWOP_END
|
||||
UWOP_WIDE_END_NOP,
|
||||
// Custom implementation opcodes (implementation specific).
|
||||
UWOP_CUSTOM,
|
||||
} UNWIND_OP_CODES;
|
||||
|
||||
// Stack allocations use UOP_AllocSmall, UOP_AllocLarge from above, plus
|
||||
// the following. AllocSmall, AllocLarge and AllocHuge represent a 16 bit
|
||||
// instruction, while the WideAlloc* opcodes represent a 32 bit instruction.
|
||||
// Small can represent a stack offset of 0x7f*4 (252) bytes, Medium can
|
||||
// represent up to 0x3ff*4 (4092) bytes, Large up to 0xffff*4 (262140) bytes,
|
||||
// and Huge up to 0xffffff*4 (67108860) bytes.
|
||||
|
||||
|
||||
#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
|
||||
#define STACKFRAME STACKFRAME64
|
||||
#define LPSTACKFRAME LPSTACKFRAME64
|
||||
#else
|
||||
typedef struct _tagSTACKFRAME {
|
||||
ADDRESS AddrPC;
|
||||
ADDRESS AddrReturn;
|
||||
ADDRESS AddrFrame;
|
||||
ADDRESS AddrStack;
|
||||
PVOID FuncTableEntry;
|
||||
DWORD Params[4];
|
||||
BOOL Far;
|
||||
BOOL Virtual;
|
||||
DWORD Reserved[3];
|
||||
KDHELP KdHelp;
|
||||
ADDRESS AddrBStore;
|
||||
} STACKFRAME, * LPSTACKFRAME;
|
||||
#endif
|
||||
|
||||
|
||||
BYTE ExtractOpInfo(BYTE OpIC) {
|
||||
return OpIC >> 4;
|
||||
}
|
||||
|
||||
BYTE ExtractOpCode(BYTE OpIC) {
|
||||
return OpIC & 0x0F;
|
||||
}
|
||||
|
||||
char* GetOpInfo(int op) {
|
||||
char* reg = (char*)malloc(4);
|
||||
if (reg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
custom_memset(reg, 0, 4);
|
||||
|
||||
if(op == 0) {
|
||||
memcpy(reg, "RAX", 4);
|
||||
}
|
||||
else if(op == 1) {
|
||||
memcpy(reg, "RCX", 4);
|
||||
}
|
||||
else if(op == 2) {
|
||||
memcpy(reg, "RDX", 4);
|
||||
}
|
||||
else if(op == 3) {
|
||||
memcpy(reg, "RBX", 4);
|
||||
}
|
||||
else if(op == 4) {
|
||||
memcpy(reg, "RSP", 4);
|
||||
}
|
||||
else if(op == 5) {
|
||||
memcpy(reg, "RBP", 4);
|
||||
}
|
||||
else if(op == 6) {
|
||||
memcpy(reg, "RSI", 4);
|
||||
}
|
||||
else if(op == 7) {
|
||||
memcpy(reg, "RDI", 4);
|
||||
}
|
||||
else if(op == 8) {
|
||||
memcpy(reg, "R8\0", 4);
|
||||
}
|
||||
else if(op == 9) {
|
||||
memcpy(reg, "R9\0", 4);
|
||||
}
|
||||
else if(op == 10) {
|
||||
memcpy(reg, "R10", 4);
|
||||
}
|
||||
else if(op == 11) {
|
||||
memcpy(reg, "R11", 4);
|
||||
}
|
||||
else if(op == 12) {
|
||||
memcpy(reg, "R12", 4);
|
||||
}
|
||||
else if(op == 13) {
|
||||
memcpy(reg, "R13", 4);
|
||||
}
|
||||
else if(op == 14) {
|
||||
memcpy(reg, "R14", 4);
|
||||
}
|
||||
else if(op == 15) {
|
||||
memcpy(reg, "R15", 4);
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void custom_printf(const char* pszFormat, ...) {
|
||||
char buf[1024];
|
||||
va_list argList;
|
||||
va_start(argList, pszFormat);
|
||||
wvsprintfA(buf, pszFormat, argList);
|
||||
va_end(argList);
|
||||
DWORD done;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &done, NULL);
|
||||
}
|
||||
|
||||
void* custom_memset(void* dest, int val, size_t len) {
|
||||
for (char* dst = (char*)dest; len != 0; len--) {
|
||||
*dst++ = val;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
static unsigned long int next = 1;
|
||||
|
||||
int rand(void) // RAND_MAX assumed as 256 + 20
|
||||
{
|
||||
next = next * 1103515245 + 12345;
|
||||
return ((unsigned int)(next / 65536) % 0x7f) + 0x20;
|
||||
}
|
||||
|
||||
void srand(unsigned int seed)
|
||||
{
|
||||
next = seed;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include "Windows.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DPRINTUNWINDCODE(x) { \
|
||||
printf("0x%x\t", x->CodeOffset); \
|
||||
printf("0x%x\t", x->OpInfo); \
|
||||
printf("0x%x\n", x->UnwindOp); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define DPRINTUNWINDCODE(x) {}
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
#ifdef _VERBOSE_DEBUG
|
||||
#define DPRINTCTX(x) { \
|
||||
printf("RAX: 0x%llx -", x.Rax); \
|
||||
printf("RBX :0x%llx -", x.Rbx); \
|
||||
printf("RCX: 0x%llx -", x.Rcx); \
|
||||
printf("RDX: 0x%llx -", x.Rdx); \
|
||||
printf("RDI: 0x%llx -", x.Rdi); \
|
||||
printf("RSI: 0x%llx -", x.Rsi); \
|
||||
printf("RBP: 0x%llx -", x.Rbp); \
|
||||
printf("RSP: 0x%llx -\n", x.Rsp); \
|
||||
printf("R8 : 0x%llx -", x.R8 ); \
|
||||
printf("R9 : 0x%llx -", x.R9 ); \
|
||||
printf("R10: 0x%llx -", x.R10); \
|
||||
printf("R11: 0x%llx -", x.R11); \
|
||||
printf("R12: 0x%llx -", x.R12); \
|
||||
printf("R13: 0x%llx -", x.R13); \
|
||||
printf("R14: 0x%llx -", x.R14); \
|
||||
printf("R15: 0x%llx \n", x.R15); \
|
||||
printf("RIP: 0x%llx \n", x.Rip); \
|
||||
}
|
||||
#else
|
||||
#define DPRINTCTX(x) {}
|
||||
#endif
|
||||
#else
|
||||
#define DPRINTCTX(x) {}
|
||||
#endif
|
||||
|
||||
typedef PIMAGE_RUNTIME_FUNCTION_ENTRY PERF;
|
||||
typedef SIZE_T(WINAPI* VirtualQueryType)(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
|
||||
typedef HANDLE(WINAPI* OpenProcessType)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
typedef DWORD(WINAPI* GetCurrentProcessIdType)();
|
||||
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddress(UINT64, DWORD64);
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByIndex(UINT64, DWORD);
|
||||
DWORD GetStackFrameSize(HMODULE, PVOID, DWORD*);
|
||||
DWORD GetStackFrameSizeWhereRbpIsPushedOnStack(HMODULE, PVOID, DWORD*);
|
||||
DWORD GetStackFrameSizeIgnoringUwopSetFpreg(HMODULE, PVOID, DWORD*);
|
||||
void PrintUnwindInfo(HMODULE, PVOID);
|
||||
void LookupSymbolFromRTIndex(HMODULE, int, bool);
|
||||
void EnumAllRTFunctions(HMODULE);
|
||||
DWORD FindRTFunctionsUnwind(HMODULE, PVOID);
|
||||
|
||||
|
||||
VOID FindGadget(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, DWORD gadgetType);
|
||||
DWORD FindProlog(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset);
|
||||
DWORD FindPushRbp(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset);
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "Common.h"
|
||||
|
||||
#define JMP_RBX 9215 // 0xff 0x23 --> reversed 0x23 0xff --> to Integer 9215
|
||||
#define ADD_RSP_0x38 952402760 // 4883C438 --> reversed 38C48348 --> to Integer 952402760
|
||||
#define RET 0xc3 // One byte, no conversion needed
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* POINTERS */
|
||||
PVOID KernelBaseAddress;
|
||||
PVOID KernelBaseAddressEnd;
|
||||
|
||||
PVOID RtlUserThreadStartAddress;
|
||||
PVOID BaseThreadInitThunkAddress;
|
||||
|
||||
PVOID FirstFrameFunctionPointer;
|
||||
PVOID SecondFrameFunctionPointer;
|
||||
PVOID JmpRbxGadget;
|
||||
PVOID AddRspXGadget;
|
||||
|
||||
/* SIZES / OFFSETS */
|
||||
UINT64 FirstFrameSize;
|
||||
UINT64 FirstFrameRandomOffset;
|
||||
UINT64 SecondFrameSize;
|
||||
UINT64 SecondFrameRandomOffset;
|
||||
|
||||
UINT64 JmpRbxGadgetFrameSize;
|
||||
UINT64 AddRspXGadgetFrameSize;
|
||||
|
||||
UINT64 RtlUserThreadStartFrameSize;
|
||||
UINT64 BaseThreadInitThunkFrameSize;
|
||||
|
||||
/* FRAME OFFSET */
|
||||
UINT64 StackOffsetWhereRbpIsPushed;
|
||||
|
||||
/* OTHERS */
|
||||
PVOID JmpRbxGadgetRef;
|
||||
PVOID SpoofFunctionPointer;
|
||||
PVOID ReturnAddress;
|
||||
|
||||
/* SPOOFED FOUNCTION NUMBER OF PARAMETERS */
|
||||
UINT64 Nargs;
|
||||
/* SPOOFED FOUNCTION PARAMETERS */
|
||||
PVOID Arg01;
|
||||
PVOID Arg02;
|
||||
PVOID Arg03;
|
||||
PVOID Arg04;
|
||||
PVOID Arg05;
|
||||
PVOID Arg06;
|
||||
PVOID Arg07;
|
||||
PVOID Arg08;
|
||||
|
||||
} SPOOFER, * PSPOOFER;
|
||||
|
||||
VOID SpoofCallStack(PSPOOFER);
|
||||
EXTERN_C PVOID spoof_call(PSPOOFER sConfig);
|
||||
EXTERN_C PVOID spoof_call_synthetic(PSPOOFER sConfig);
|
||||
EXTERN_C PVOID get_current_rsp();
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "Windows.h"
|
||||
|
||||
void TestLocateFunctionByAddress();
|
||||
void TestLookupByFrameOffset();
|
||||
void TestEnumAllRT(DWORD);
|
||||
void Test();
|
||||
@@ -0,0 +1,236 @@
|
||||
; ------------------------------------------------------------------------------------
|
||||
;
|
||||
; Author : klezVirus 2022
|
||||
; Twitter : https://twitter.com/klezVirus
|
||||
; Original Idea: Namazso
|
||||
; Twitter : https://twitter.com/namazso
|
||||
; ------------------------------------------------------------------------------------
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
spoof_call proto
|
||||
restore proto
|
||||
|
||||
.data
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Spoofing Configuration Structure
|
||||
; Utility structure to pass all the relevant details from C to ASM regarding the
|
||||
; stack frames to spoof
|
||||
; ------------------------------------------------------------------------------------
|
||||
SPOOFER STRUCT
|
||||
|
||||
KernelBaseAddress DQ 1
|
||||
KernelBaseAddressEnd DQ 1
|
||||
|
||||
RtlUserThreadStartAddress DQ 1
|
||||
BaseThreadInitThunkAddress DQ 1
|
||||
|
||||
FirstFrameFunctionPointer DQ 1
|
||||
SecondFrameFunctionPointer DQ 1
|
||||
JmpRbxGadget DQ 1
|
||||
AddRspXGadget DQ 1
|
||||
|
||||
FirstFrameSize DQ 1
|
||||
FirstFrameRandomOffset DQ 1
|
||||
SecondFrameSize DQ 1
|
||||
SecondFrameRandomOffset DQ 1
|
||||
JmpRbxGadgetFrameSize DQ 1
|
||||
AddRspXGadgetFrameSize DQ 1
|
||||
|
||||
RtlUserThreadStartFrameSize DQ 1
|
||||
BaseThreadInitThunkFrameSize DQ 1
|
||||
|
||||
StackOffsetWhereRbpIsPushed DQ 1
|
||||
|
||||
JmpRbxGadgetRef DQ 1
|
||||
SpoofFunctionPointer DQ 1
|
||||
ReturnAddress DQ 1
|
||||
|
||||
Nargs DQ 1
|
||||
Arg01 DQ 1
|
||||
Arg02 DQ 1
|
||||
Arg03 DQ 1
|
||||
Arg04 DQ 1
|
||||
Arg05 DQ 1
|
||||
Arg06 DQ 1
|
||||
Arg07 DQ 1
|
||||
Arg08 DQ 1
|
||||
|
||||
SPOOFER ENDS
|
||||
|
||||
.code
|
||||
|
||||
get_current_rsp proc
|
||||
mov rax, rsp
|
||||
add rax, 8
|
||||
ret
|
||||
get_current_rsp endp
|
||||
|
||||
spoof_call proc
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Saving non-vol registers
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov [rsp+08h], rbp
|
||||
mov [rsp+10h], rbx
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Creating a stack reference to the JMP RBX gadget
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov rbx, [rcx].SPOOFER.JmpRbxGadget
|
||||
mov [rsp+18h], rbx
|
||||
mov rbx, rsp
|
||||
add rbx, 18h
|
||||
mov [rcx].SPOOFER.JmpRbxGadgetRef, rbx
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Prolog
|
||||
; RBP -> Keeps track of original Stack
|
||||
; RSP -> Desync Stack for Unwinding Info
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Note: Everything between RSP and RBP is our new stack frame for unwinding
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov rbp, rsp
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Creating stack pointer to Restore PROC
|
||||
; ------------------------------------------------------------------------------------
|
||||
lea rax, restore
|
||||
push rax
|
||||
|
||||
; Now RBX contains the stack pointer to Restore PROC
|
||||
; -> Will be called by the JMP [RBX] gadget
|
||||
lea rbx, [rsp]
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Starting Frames Tampering
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
; First Frame (Fake origin)
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.FirstFrameFunctionPointer
|
||||
mov rax, [rcx].SPOOFER.FirstFrameRandomOffset
|
||||
add qword ptr [rsp], rax
|
||||
|
||||
mov rax, [rcx].SPOOFER.ReturnAddress
|
||||
sub rax, [rcx].SPOOFER.FirstFrameSize
|
||||
|
||||
sub rsp, [rcx].SPOOFER.SecondFrameSize
|
||||
mov r10, [rcx].SPOOFER.StackOffsetWhereRbpIsPushed
|
||||
mov [rsp+r10], rax
|
||||
; ------------------------------------------------------------------------------------
|
||||
; ROP Frames
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.SecondFrameFunctionPointer
|
||||
mov rax, [rcx].SPOOFER.SecondFrameRandomOffset
|
||||
add qword ptr [rsp], rax
|
||||
; ------------------------------------------------------------------------------------
|
||||
; 1. JMP [RBX] Gadget
|
||||
; ------------------------------------------------------------------------------------
|
||||
sub rsp, [rcx].SPOOFER.JmpRbxGadgetFrameSize
|
||||
push [rcx].SPOOFER.JmpRbxGadgetRef
|
||||
sub rsp, [rcx].SPOOFER.AddRspXGadgetFrameSize
|
||||
mov r10, [rcx].SPOOFER.JmpRbxGadget
|
||||
mov [rsp+38h], r10
|
||||
; ------------------------------------------------------------------------------------
|
||||
; 2. Stack PIVOT (To restore original Control Flow Stack)
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.AddRspXGadget
|
||||
mov rax, [rcx].SPOOFER.AddRspXGadgetFrameSize
|
||||
mov [rbp+28h], rax
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Set the pointer to the function to call in RAX
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov rax, [rcx].SPOOFER.SpoofFunctionPointer
|
||||
jmp parameter_handler
|
||||
jmp execute
|
||||
spoof_call endp
|
||||
|
||||
restore proc
|
||||
mov rsp, rbp
|
||||
mov rbp, [rsp+08h]
|
||||
mov rbx, [rsp+10h]
|
||||
ret
|
||||
restore endp
|
||||
|
||||
parameter_handler proc
|
||||
mov r9, rax
|
||||
mov rax, 8
|
||||
mov r8, [rcx].SPOOFER.Nargs
|
||||
mul r8
|
||||
; pop rdx
|
||||
; sub rsp, rax -- Not necessary
|
||||
; push rdx
|
||||
xchg r9, rax
|
||||
cmp [rcx].SPOOFER.Nargs, 8
|
||||
je handle_eight
|
||||
cmp [rcx].SPOOFER.Nargs, 7
|
||||
je handle_seven
|
||||
cmp [rcx].SPOOFER.Nargs, 6
|
||||
je handle_six
|
||||
cmp [rcx].SPOOFER.Nargs, 5
|
||||
je handle_five
|
||||
cmp [rcx].SPOOFER.Nargs, 4
|
||||
je handle_four
|
||||
cmp [rcx].SPOOFER.Nargs, 3
|
||||
je handle_three
|
||||
cmp [rcx].SPOOFER.Nargs, 2
|
||||
je handle_two
|
||||
cmp [rcx].SPOOFER.Nargs, 1
|
||||
je handle_one
|
||||
cmp [rcx].SPOOFER.Nargs, 0
|
||||
je handle_none
|
||||
parameter_handler endp
|
||||
|
||||
handle_eight proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg08
|
||||
mov [rsp+48h], r15
|
||||
pop r15
|
||||
jmp handle_seven
|
||||
handle_eight endp
|
||||
handle_seven proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg07
|
||||
mov [rsp+40h], r15
|
||||
pop r15
|
||||
jmp handle_six
|
||||
handle_seven endp
|
||||
handle_six proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg06
|
||||
mov [rsp+38h], r15
|
||||
pop r15
|
||||
jmp handle_five
|
||||
handle_six endp
|
||||
handle_five proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg05
|
||||
mov [rsp+30h], r15
|
||||
pop r15
|
||||
jmp handle_four
|
||||
handle_five endp
|
||||
handle_four proc
|
||||
mov r9, [rcx].SPOOFER.Arg04
|
||||
jmp handle_three
|
||||
handle_four endp
|
||||
handle_three proc
|
||||
mov r8, [rcx].SPOOFER.Arg03
|
||||
jmp handle_two
|
||||
handle_three endp
|
||||
handle_two proc
|
||||
mov rdx, [rcx].SPOOFER.Arg02
|
||||
jmp handle_one
|
||||
handle_two endp
|
||||
handle_one proc
|
||||
mov rcx, [rcx].SPOOFER.Arg01
|
||||
jmp handle_none
|
||||
handle_one endp
|
||||
|
||||
handle_none proc
|
||||
jmp execute
|
||||
handle_none endp
|
||||
|
||||
execute proc
|
||||
jmp qword ptr rax
|
||||
execute endp
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,297 @@
|
||||
; ------------------------------------------------------------------------------------
|
||||
;
|
||||
; Author : klezVirus 2022
|
||||
; Twitter : https://twitter.com/klezVirus
|
||||
; Original Idea: Namazso
|
||||
; Twitter : https://twitter.com/namazso
|
||||
; ------------------------------------------------------------------------------------
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
spoof_call_synthetic proto
|
||||
restore_synthetic proto
|
||||
|
||||
.data
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Spoofing Configuration Structure
|
||||
; Utility structure to pass all the relevant details from C to ASM regarding the
|
||||
; stack frames to spoof
|
||||
; ------------------------------------------------------------------------------------
|
||||
SPOOFER STRUCT
|
||||
|
||||
KernelBaseAddress DQ 1
|
||||
KernelBaseAddressEnd DQ 1
|
||||
|
||||
RtlUserThreadStartAddress DQ 1
|
||||
BaseThreadInitThunkAddress DQ 1
|
||||
|
||||
FirstFrameFunctionPointer DQ 1
|
||||
SecondFrameFunctionPointer DQ 1
|
||||
JmpRbxGadget DQ 1
|
||||
AddRspXGadget DQ 1
|
||||
|
||||
FirstFrameSize DQ 1
|
||||
FirstFrameRandomOffset DQ 1
|
||||
SecondFrameSize DQ 1
|
||||
SecondFrameRandomOffset DQ 1
|
||||
JmpRbxGadgetFrameSize DQ 1
|
||||
AddRspXGadgetFrameSize DQ 1
|
||||
|
||||
RtlUserThreadStartFrameSize DQ 1
|
||||
BaseThreadInitThunkFrameSize DQ 1
|
||||
|
||||
StackOffsetWhereRbpIsPushed DQ 1
|
||||
|
||||
JmpRbxGadgetRef DQ 1
|
||||
SpoofFunctionPointer DQ 1
|
||||
ReturnAddress DQ 1
|
||||
|
||||
Nargs DQ 1
|
||||
Arg01 DQ 1
|
||||
Arg02 DQ 1
|
||||
Arg03 DQ 1
|
||||
Arg04 DQ 1
|
||||
Arg05 DQ 1
|
||||
Arg06 DQ 1
|
||||
Arg07 DQ 1
|
||||
Arg08 DQ 1
|
||||
|
||||
SPOOFER ENDS
|
||||
|
||||
.code
|
||||
|
||||
spoof_call_synthetic proc
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Saving non-vol registers
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov [rsp+08h], rbp
|
||||
mov [rsp+10h], rbx
|
||||
mov [rsp+18h], r15
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Creating a stack reference to the JMP RBX gadget
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov rbx, [rcx].SPOOFER.JmpRbxGadget
|
||||
mov [rsp+20h], rbx
|
||||
mov rbx, rsp
|
||||
add rbx, 20h
|
||||
mov [rcx].SPOOFER.JmpRbxGadgetRef, rbx
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Prolog
|
||||
; RBP -> Keeps track of original Stack
|
||||
; RSP -> Desync Stack for Unwinding Info
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Note: Everything between RSP and RBP is our new stack frame for unwinding
|
||||
; ------------------------------------------------------------------------------------
|
||||
sub rsp, 200h
|
||||
mov rbp, rsp
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Creating stack pointer to Restore PROC
|
||||
; ------------------------------------------------------------------------------------
|
||||
lea rax, restore_synthetic
|
||||
push rax
|
||||
|
||||
|
||||
; Now RBX contains the stack pointer to Restore PROC
|
||||
; -> Will be called by the JMP [RBX] gadget
|
||||
lea rbx, [rsp]
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Starting Frames Tampering
|
||||
; ------------------------------------------------------------------------------------
|
||||
; First Frame (Frame preparation)
|
||||
; The first frame contains the details
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.FirstFrameFunctionPointer
|
||||
add qword ptr [rsp], 20h
|
||||
|
||||
mov rax, [rcx].SPOOFER.ReturnAddress
|
||||
sub rax, [rcx].SPOOFER.FirstFrameSize
|
||||
sub rsp, [rcx].SPOOFER.SecondFrameSize
|
||||
mov r10, [rcx].SPOOFER.StackOffsetWhereRbpIsPushed
|
||||
mov [rsp+r10], rax
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Cutting the call stack. The 0 pushed in this position will be the return address
|
||||
; of the next frame "RtlUserThreadStart", making it effectively the originating function
|
||||
; ------------------------------------------------------------------------------------
|
||||
xor rax, rax
|
||||
push rax
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Here we proceed by adding the two top fake frames:
|
||||
; - RtlUserThreadStart
|
||||
; - BaseThreadInitThunk
|
||||
; ------------------------------------------------------------------------------------
|
||||
mov rax, [rcx].SPOOFER.FirstFrameFunctionPointer
|
||||
sub rax, [rcx].SPOOFER.FirstFrameSize
|
||||
sub rsp, [rcx].SPOOFER.RtlUserThreadStartFrameSize
|
||||
mov [rsp+30h], rax
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; RtlUserThreadStart
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
push [rcx].SPOOFER.RtlUserThreadStartAddress
|
||||
add qword ptr [rsp], 21h
|
||||
|
||||
sub rsp, [rcx].SPOOFER.BaseThreadInitThunkFrameSize
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; BaseThreadInitThunk
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
push [rcx].SPOOFER.BaseThreadInitThunkAddress
|
||||
add qword ptr [rsp], 14h
|
||||
|
||||
mov rax, [rcx].SPOOFER.RtlUserThreadStartAddress
|
||||
sub rax, [rcx].SPOOFER.RtlUserThreadStartFrameSize
|
||||
sub rsp, [rcx].SPOOFER.JmpRbxGadgetFrameSize
|
||||
mov [rsp+30h], rax
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; ROP Frames
|
||||
; These two frames contain the ROP gadgets that will be used to restore the original
|
||||
; Control Flow stack
|
||||
; ------------------------------------------------------------------------------------
|
||||
; ------------------------------------------------------------------------------------
|
||||
; 1. JMP [RBX] Gadget
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.JmpRbxGadget
|
||||
|
||||
mov rax, [rcx].SPOOFER.BaseThreadInitThunkAddress
|
||||
sub rax, [rcx].SPOOFER.SecondFrameSize
|
||||
sub rsp, [rcx].SPOOFER.AddRspXGadgetFrameSize
|
||||
mov [rsp+30h], rax
|
||||
|
||||
mov r10, [rcx].SPOOFER.JmpRbxGadget
|
||||
mov [rsp+38h], r10
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; 2. Stack PIVOT (To restore original Control Flow Stack)
|
||||
; ------------------------------------------------------------------------------------
|
||||
push [rcx].SPOOFER.AddRspXGadget
|
||||
|
||||
|
||||
mov rax, [rcx].SPOOFER.AddRspXGadgetFrameSize
|
||||
mov [rbp+28h], rax
|
||||
|
||||
; ------------------------------------------------------------------------------------
|
||||
; Finalise
|
||||
; Placing the pointer to the function to call
|
||||
; ------------------------------------------------------------------------------------
|
||||
|
||||
mov rax, [rbp+28h]
|
||||
mov [rsp+28h], rax
|
||||
mov rax, [rbp+30h]
|
||||
mov [rsp+30h], rax
|
||||
mov rax, [rcx].SPOOFER.SpoofFunctionPointer
|
||||
|
||||
jmp parameter_handler_synthetic
|
||||
jmp execute_synthetic
|
||||
spoof_call_synthetic endp
|
||||
|
||||
restore_synthetic proc
|
||||
mov rsp, rbp
|
||||
add rsp, 200h
|
||||
mov rbp, [rsp+08h]
|
||||
mov rbx, [rsp+10h]
|
||||
mov r15, [rsp+18h]
|
||||
ret
|
||||
restore_synthetic endp
|
||||
|
||||
parameter_handler_synthetic proc
|
||||
mov r9, rax
|
||||
mov rax, 8
|
||||
mov r8, [rcx].SPOOFER.Nargs
|
||||
mul r8
|
||||
; cmp rax, 020h
|
||||
; ja allocate
|
||||
; jmp post_allocate
|
||||
|
||||
;allocate:
|
||||
; ------------------------------------------------------------------------------------
|
||||
; If Not necessary to allocate space for parameters
|
||||
; ------------------------------------------------------------------------------------
|
||||
; pop rdx
|
||||
; sub rax, 020h
|
||||
; sub rsp, rax
|
||||
; push rdx
|
||||
; ------------------------------------------------------------------------------------
|
||||
;post_allocate:
|
||||
xchg r9, rax
|
||||
cmp [rcx].SPOOFER.Nargs, 8
|
||||
je handle_eight_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 7
|
||||
je handle_seven_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 6
|
||||
je handle_six_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 5
|
||||
je handle_five_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 4
|
||||
je handle_four_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 3
|
||||
je handle_three_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 2
|
||||
je handle_two_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 1
|
||||
je handle_one_synthetic
|
||||
cmp [rcx].SPOOFER.Nargs, 0
|
||||
je handle_none_synthetic
|
||||
parameter_handler_synthetic endp
|
||||
|
||||
handle_eight_synthetic proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg08
|
||||
mov [rsp+48h], r15
|
||||
pop r15
|
||||
jmp handle_seven_synthetic
|
||||
handle_eight_synthetic endp
|
||||
handle_seven_synthetic proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg07
|
||||
mov [rsp+40h], r15
|
||||
pop r15
|
||||
jmp handle_six_synthetic
|
||||
handle_seven_synthetic endp
|
||||
handle_six_synthetic proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg06
|
||||
mov [rsp+38h], r15
|
||||
pop r15
|
||||
jmp handle_five_synthetic
|
||||
handle_six_synthetic endp
|
||||
handle_five_synthetic proc
|
||||
push r15
|
||||
mov r15, [rcx].SPOOFER.Arg05
|
||||
mov [rsp+30h], r15
|
||||
pop r15
|
||||
jmp handle_four_synthetic
|
||||
handle_five_synthetic endp
|
||||
handle_four_synthetic proc
|
||||
mov r9, [rcx].SPOOFER.Arg04
|
||||
jmp handle_three_synthetic
|
||||
handle_four_synthetic endp
|
||||
handle_three_synthetic proc
|
||||
mov r8, [rcx].SPOOFER.Arg03
|
||||
jmp handle_two_synthetic
|
||||
handle_three_synthetic endp
|
||||
handle_two_synthetic proc
|
||||
mov rdx, [rcx].SPOOFER.Arg02
|
||||
jmp handle_one_synthetic
|
||||
handle_two_synthetic endp
|
||||
handle_one_synthetic proc
|
||||
mov rcx, [rcx].SPOOFER.Arg01
|
||||
jmp handle_none_synthetic
|
||||
handle_one_synthetic endp
|
||||
|
||||
handle_none_synthetic proc
|
||||
jmp execute_synthetic
|
||||
handle_none_synthetic endp
|
||||
|
||||
execute_synthetic proc
|
||||
jmp qword ptr rax
|
||||
execute_synthetic endp
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,333 @@
|
||||
#include "include/Common.h"
|
||||
#include "include/Functions.h"
|
||||
|
||||
void LookupSymbolFromRTIndex(HMODULE dllBase, int rtFuntionIndex, bool verbose) {
|
||||
|
||||
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY rtFunction = RTFindFunctionByIndex((UINT64)dllBase, rtFuntionIndex);
|
||||
|
||||
if (rtFunction == NULL) {
|
||||
printf("Function not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("Function found: \n");
|
||||
printf(" Begin Address 0x%p \n", (PVOID)rtFunction->BeginAddress);
|
||||
printf(" End Address 0x%p \n", (PVOID)rtFunction->EndAddress);
|
||||
printf(" Unwind Info Address 0x%p \n", (PVOID)rtFunction->UnwindInfoAddress);
|
||||
printf("Looking up in exports... \n");
|
||||
}
|
||||
char* procName = GetSymbolNameByOffset(dllBase, rtFunction->BeginAddress);
|
||||
|
||||
if (procName == NULL) {
|
||||
if (verbose) {
|
||||
printf("Function not found\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Function %u found: %s\n", rtFuntionIndex, procName);
|
||||
|
||||
if (verbose) {
|
||||
PrintUnwindInfo(dllBase, (PVOID)rtFunction->UnwindData);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void PrintUnwindInfo(HMODULE dllBase, PVOID unwindDataAddress) {
|
||||
|
||||
PUNWIND_INFO tInfo = (PUNWIND_INFO)((UINT64)dllBase + (DWORD)unwindDataAddress);
|
||||
|
||||
printf(" Version: %d \n", Version(tInfo->Flags));
|
||||
printf(" Ver + Flags: " B2BP " \n", BYTE_TO_BINARY(tInfo->Flags));
|
||||
printf(" SizeOfProlog: 0x%x \n", tInfo->SizeOfProlog);
|
||||
printf(" CountOfCodes: 0x%x \n", tInfo->CountOfCodes);
|
||||
printf(" FrameRegister: 0x%x \n", tInfo->FrameRegister);
|
||||
printf(" FrameOffset: 0x%x \n", tInfo->FrameOffset);
|
||||
printf(" UnwindCodes: \n");
|
||||
|
||||
char* reg = NULL;
|
||||
|
||||
for (int j = 0; j < tInfo->CountOfCodes; j++) {
|
||||
printf(" [%.2xh] Frame: 0x%.4x - ", j, tInfo->UnwindCode[j].FrameOffset);
|
||||
reg = GetOpInfo(tInfo->UnwindCode[j].OpInfo);
|
||||
|
||||
switch (tInfo->UnwindCode[j].UnwindOp) {
|
||||
|
||||
case UWOP_PUSH_NONVOL: // 0
|
||||
printf("0x%.2x - UWOP_PUSH_NONVOL (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_ALLOC_LARGE: // 1
|
||||
printf("0x%.2x - UWOP_ALLOC_LARGE (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_ALLOC_SMALL: // 2
|
||||
printf("0x%.2x - UWOP_ALLOC_SMALL (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_SET_FPREG: // 3
|
||||
printf("0x%.2x - UWOP_SET_FPREG (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_SAVE_NONVOL: // 4
|
||||
printf("0x%.2x - UWOP_SAVE_NONVOL (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_SAVE_NONVOL_BIG: // 5
|
||||
printf("0x%.2x - UWOP_SAVE_NONVOL_BIG (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_EPILOG: // 6
|
||||
printf("0x%.2x - UWOP_EPILOG (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
case UWOP_SAVE_XMM128: // 8
|
||||
printf("0x%.2x - UWOP_SAVE_XMM128 (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_SPARE_CODE: // 7
|
||||
printf("0x%.2x - UWOP_SPARE_CODE (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
case UWOP_SAVE_XMM128BIG: // 9
|
||||
printf("0x%.2x - UWOP_SAVE_XMM128BIG (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
case UWOP_PUSH_MACH_FRAME:
|
||||
printf("0x%.2x - UWOP_PUSH_MACH_FRAME (%3s, 0x%.4x)\n", tInfo->UnwindCode[j].UnwindOp, reg, tInfo->UnwindCode[j].CodeOffset);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (NULL != reg) {
|
||||
free(reg);
|
||||
}
|
||||
}
|
||||
|
||||
if (BitChainInfo(tInfo->Flags)) {
|
||||
printf(" Function Entry Offset: 0x%p\n", GetChainedFunctionEntry(dllBase, tInfo));
|
||||
}
|
||||
if (BitUHandler(tInfo->Flags)) {
|
||||
|
||||
}
|
||||
if (BitEHandler(tInfo->Flags)) {
|
||||
PVOID dataPtr = GetExceptionDataPtr(tInfo);
|
||||
PVOID handlerPtr = GetExceptionHandler(dllBase, tInfo);
|
||||
ULONG data = *((PULONG)dataPtr);
|
||||
INT32 handler = *((PDWORD)handlerPtr);
|
||||
|
||||
printf(" Exception Handler Offset: 0x%p\n", GetExceptionHandler(dllBase, tInfo));
|
||||
printf(" Exception Data Offset: 0x%x\n", data);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void EnumAllRTFunctions(HMODULE moduleBase)
|
||||
{
|
||||
DWORD tSize;
|
||||
PRUNTIME_FUNCTION pRuntimeFunctionTable;
|
||||
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;
|
||||
|
||||
pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress(moduleBase, &tSize));
|
||||
|
||||
for (DWORD i = 0; i <= 5038; i++)
|
||||
{
|
||||
/*
|
||||
PRUNTIME_FUNCTION rtft = (PRUNTIME_FUNCTION)(imageExportDirectory + 0xc*i);
|
||||
|
||||
*/
|
||||
|
||||
printf("Runtime Function %u \n", i);
|
||||
printf(" Begin Address 0x%p\n End Address 0x%p\n Unwind Info Address 0x%p\n",
|
||||
(PVOID)pRuntimeFunctionTable[i].BeginAddress,
|
||||
(PVOID)pRuntimeFunctionTable[i].EndAddress,
|
||||
(PVOID)pRuntimeFunctionTable[i].UnwindInfoAddress);
|
||||
|
||||
PrintUnwindInfo(moduleBase, (PVOID)pRuntimeFunctionTable[i].UnwindData);
|
||||
|
||||
}
|
||||
// printf(BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(UBYTE(UNW_FLAG_CHAININFO | UNW_FLAG_UHANDLER| UNW_FLAG_EHANDLER )));
|
||||
|
||||
}
|
||||
|
||||
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddress(UINT64 moduleBase, DWORD64 functionOffset) {
|
||||
|
||||
DWORD tSize;
|
||||
PRUNTIME_FUNCTION pRuntimeFunctionTable;
|
||||
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;
|
||||
|
||||
pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress((HMODULE)moduleBase, &tSize));
|
||||
pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress((HMODULE)moduleBase));
|
||||
|
||||
for (DWORD i = 0; i < pImageExportDirectory->NumberOfFunctions; i++)
|
||||
{
|
||||
// printf("0x%X - 0x%X\n", pRuntimeFunctionTable[i].BeginAddress, functionOffset);
|
||||
if (pRuntimeFunctionTable[i].BeginAddress == functionOffset) {
|
||||
|
||||
printf("\n Runtime Function (0x%p, 0x%p)\n Unwind Info Address: 0x%p\n",
|
||||
(PVOID)pRuntimeFunctionTable[i].BeginAddress,
|
||||
(PVOID)pRuntimeFunctionTable[i].EndAddress,
|
||||
(PVOID)pRuntimeFunctionTable[i].UnwindInfoAddress);
|
||||
return pRuntimeFunctionTable + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByIndex(UINT64 kernelBase, DWORD index) {
|
||||
|
||||
DWORD tSize;
|
||||
PRUNTIME_FUNCTION pRuntimeFunctionTable;
|
||||
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory;
|
||||
|
||||
pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress((HMODULE)kernelBase, &tSize));
|
||||
pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(GetExportDirectoryAddress((HMODULE)kernelBase));
|
||||
|
||||
return pRuntimeFunctionTable + index;
|
||||
}
|
||||
|
||||
DWORD FindRTFunctionsUnwind(HMODULE moduleBase, PVOID tUnwindCodeAddress) {
|
||||
|
||||
DWORD tSize;
|
||||
PUNWIND_CODE tUnwindCode;
|
||||
PUNWIND_INFO unwindInfo;
|
||||
PRUNTIME_FUNCTION pRuntimeFunctionTable;
|
||||
|
||||
tUnwindCode = (PUNWIND_CODE)tUnwindCodeAddress;
|
||||
pRuntimeFunctionTable = (PRUNTIME_FUNCTION)(GetExceptionDirectoryAddress(moduleBase, &tSize));
|
||||
|
||||
for (DWORD i = 0; i <= 5038; i++)
|
||||
{
|
||||
|
||||
unwindInfo = (PUNWIND_INFO)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].UnwindData);
|
||||
for (int j = 0; j < unwindInfo->CountOfCodes; j++) {
|
||||
|
||||
if (unwindInfo->UnwindCode[j].FrameOffset == tUnwindCode->FrameOffset) {
|
||||
|
||||
printf("Found frame offset with Runtime Function: %u, unwindCode: %u \n", i + 1, j);
|
||||
printf("Found: 0x%x - Expected: 0x%x \n", unwindInfo->UnwindCode[j].FrameOffset, tUnwindCode->FrameOffset);
|
||||
printf("Address in module: 0x%p \n", (PVOID)((UINT64)moduleBase + (DWORD)pRuntimeFunctionTable[i].BeginAddress));
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
// TODO: Implement the rest after
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
printf("Function not found\n");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("\n Unwind Inspector v%f \n", VERSION);
|
||||
printf("\n Made with <3 by %s \n\n", AUTHOR);
|
||||
|
||||
printf(" Mandatory args: \n"
|
||||
" -m <module>: Target DLL\n"
|
||||
" -f <function>: Target Function\n"
|
||||
" -a <function-address>: Target Function Address\n"
|
||||
);
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t** argv)
|
||||
{
|
||||
LPCWSTR moduleName = NULL;
|
||||
LPCWSTR functionName = NULL;
|
||||
UINT64 functionAddress = NULL;
|
||||
char functionNameA[MAX_PATH] = {0};
|
||||
|
||||
HMODULE moduleBase = NULL;
|
||||
PVOID functionPtr = NULL;
|
||||
|
||||
PERF targetFp = NULL;
|
||||
|
||||
while ((argc > 1) && (argv[1][0] == '-'))
|
||||
{
|
||||
switch (argv[1][1])
|
||||
{
|
||||
case 'f':
|
||||
++argv;
|
||||
--argc;
|
||||
functionName = argv[1];
|
||||
if (wcslen(argv[1]) == 0) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
++argv;
|
||||
--argc;
|
||||
if (wcslen(argv[1]) == 0) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
functionAddress = (UINT64)wcstoll(argv[1], NULL, 16);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
++argv;
|
||||
--argc;
|
||||
if (wcslen(argv[1]) == 0) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
moduleName = argv[1];
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[-] Wrong Argument: %ls\n", argv[1]);
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
|
||||
if ((NULL == functionName && NULL == functionAddress) || NULL == moduleName) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
moduleBase = LoadLibraryW(moduleName);
|
||||
|
||||
if (NULL == moduleBase) {
|
||||
printf("[-] Module %ws not found. Aborting\n", moduleName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == functionAddress){
|
||||
size_t bytesCopied;
|
||||
wcstombs_s(&bytesCopied, (char*)functionNameA, MAX_PATH, (const wchar_t*)functionName, MAX_PATH - 1);
|
||||
|
||||
functionPtr = (PVOID)GetProcAddress(moduleBase, (LPCSTR)functionNameA);
|
||||
if (NULL == functionPtr) {
|
||||
printf("[-] Function %s not found. Aborting\n", (LPCSTR)functionNameA);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("[*] Using function address 0x%I64x\n", functionAddress);
|
||||
functionPtr = (PVOID)functionAddress;
|
||||
}
|
||||
|
||||
targetFp = RTFindFunctionByAddress((UINT64)moduleBase, (DWORD64)functionPtr - (DWORD64)moduleBase);
|
||||
|
||||
|
||||
|
||||
if (NULL == targetFp) {
|
||||
printf("[-] Function %s not found in Runtime Function Table. Aborting\n", (LPCSTR)functionNameA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PrintUnwindInfo(moduleBase, (PVOID)targetFp->UnwindData);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{e86abdaa-444c-409a-b466-9e034e859c80}</ProjectGuid>
|
||||
<RootNamespace>UnwindInspector</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UnwindInspector.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\AddressHunter.h" />
|
||||
<ClInclude Include="include\Common.h" />
|
||||
<ClInclude Include="include\Functions.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UnwindInspector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\AddressHunter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Functions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,356 @@
|
||||
// https://raw.githubusercontent.com/paranoidninja/PIC-Get-Privileges/main/addresshunter.h
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define DEREF( name )*(UINT_PTR *)(name)
|
||||
#define DEREF_64( name )*(DWORD64 *)(name)
|
||||
#define DEREF_32( name )*(DWORD *)(name)
|
||||
#define DEREF_16( name )*(WORD *)(name)
|
||||
#define DEREF_8( name )*(BYTE *)(name)
|
||||
|
||||
#define KERNELBASE_HASH 0xc42f2982
|
||||
#define KERNEL32DLL_HASH 0xbc5d4571
|
||||
#define MSVCRTDLL_HASH 0xc3222c90
|
||||
#define ADVAPI32DLL_HASH 0x8353484b
|
||||
#define NTDLL_HASH 0x4f576ca1
|
||||
|
||||
#define FH_RND_SEED 0xDC072B8A
|
||||
#define ROL8(v) (v << 8 | v >> 24)
|
||||
#define ROR8(v) (v >> 8 | v << 24)
|
||||
#define ROX8(v) ((FH_RND_SEED % 2) ? ROL8(v) : ROR8(v))
|
||||
|
||||
//redefine UNICODE_STR struct
|
||||
typedef struct _UNICODE_STR
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR pBuffer;
|
||||
} UNICODE_STR, * PUNICODE_STR;
|
||||
|
||||
//redefine PEB_LDR_DATA struct
|
||||
typedef struct _PEB_LDR_DATA
|
||||
{
|
||||
DWORD dwLength;
|
||||
DWORD dwInitialized;
|
||||
LPVOID lpSsHandle;
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
LPVOID lpEntryInProgress;
|
||||
} PEB_LDR_DATA, * PPEB_LDR_DATA;
|
||||
|
||||
//redefine LDR_DATA_TABLE_ENTRY struct
|
||||
typedef struct _LDR_DATA_TABLE_ENTRY
|
||||
{
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
PVOID DllBase;
|
||||
PVOID EntryPoint;
|
||||
ULONG SizeOfImage;
|
||||
UNICODE_STR FullDllName;
|
||||
UNICODE_STR BaseDllName;
|
||||
ULONG Flags;
|
||||
SHORT LoadCount;
|
||||
SHORT TlsIndex;
|
||||
LIST_ENTRY HashTableEntry;
|
||||
ULONG TimeDateStamp;
|
||||
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
|
||||
|
||||
//redefine PEB_FREE_BLOCK struct
|
||||
typedef struct _PEB_FREE_BLOCK
|
||||
{
|
||||
struct _PEB_FREE_BLOCK* pNext;
|
||||
DWORD dwSize;
|
||||
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
|
||||
|
||||
//redefine PEB struct
|
||||
typedef struct __PEB
|
||||
{
|
||||
BYTE bInheritedAddressSpace;
|
||||
BYTE bReadImageFileExecOptions;
|
||||
BYTE bBeingDebugged;
|
||||
BYTE bSpareBool;
|
||||
LPVOID lpMutant;
|
||||
LPVOID lpImageBaseAddress;
|
||||
PPEB_LDR_DATA pLdr;
|
||||
LPVOID lpProcessParameters;
|
||||
LPVOID lpSubSystemData;
|
||||
LPVOID lpProcessHeap;
|
||||
PRTL_CRITICAL_SECTION pFastPebLock;
|
||||
LPVOID lpFastPebLockRoutine;
|
||||
LPVOID lpFastPebUnlockRoutine;
|
||||
DWORD dwEnvironmentUpdateCount;
|
||||
LPVOID lpKernelCallbackTable;
|
||||
DWORD dwSystemReserved;
|
||||
DWORD dwAtlThunkSListPtr32;
|
||||
PPEB_FREE_BLOCK pFreeList;
|
||||
DWORD dwTlsExpansionCounter;
|
||||
LPVOID lpTlsBitmap;
|
||||
DWORD dwTlsBitmapBits[2];
|
||||
LPVOID lpReadOnlySharedMemoryBase;
|
||||
LPVOID lpReadOnlySharedMemoryHeap;
|
||||
LPVOID lpReadOnlyStaticServerData;
|
||||
LPVOID lpAnsiCodePageData;
|
||||
LPVOID lpOemCodePageData;
|
||||
LPVOID lpUnicodeCaseTableData;
|
||||
DWORD dwNumberOfProcessors;
|
||||
DWORD dwNtGlobalFlag;
|
||||
LARGE_INTEGER liCriticalSectionTimeout;
|
||||
DWORD dwHeapSegmentReserve;
|
||||
DWORD dwHeapSegmentCommit;
|
||||
DWORD dwHeapDeCommitTotalFreeThreshold;
|
||||
DWORD dwHeapDeCommitFreeBlockThreshold;
|
||||
DWORD dwNumberOfHeaps;
|
||||
DWORD dwMaximumNumberOfHeaps;
|
||||
LPVOID lpProcessHeaps;
|
||||
LPVOID lpGdiSharedHandleTable;
|
||||
LPVOID lpProcessStarterHelper;
|
||||
DWORD dwGdiDCAttributeList;
|
||||
LPVOID lpLoaderLock;
|
||||
DWORD dwOSMajorVersion;
|
||||
DWORD dwOSMinorVersion;
|
||||
WORD wOSBuildNumber;
|
||||
WORD wOSCSDVersion;
|
||||
DWORD dwOSPlatformId;
|
||||
DWORD dwImageSubsystem;
|
||||
DWORD dwImageSubsystemMajorVersion;
|
||||
DWORD dwImageSubsystemMinorVersion;
|
||||
DWORD dwImageProcessAffinityMask;
|
||||
DWORD dwGdiHandleBuffer[34];
|
||||
LPVOID lpPostProcessInitRoutine;
|
||||
LPVOID lpTlsExpansionBitmap;
|
||||
DWORD dwTlsExpansionBitmapBits[32];
|
||||
DWORD dwSessionId;
|
||||
ULARGE_INTEGER liAppCompatFlags;
|
||||
ULARGE_INTEGER liAppCompatFlagsUser;
|
||||
LPVOID lppShimData;
|
||||
LPVOID lpAppCompatInfo;
|
||||
UNICODE_STR usCSDVersion;
|
||||
LPVOID lpActivationContextData;
|
||||
LPVOID lpProcessAssemblyStorageMap;
|
||||
LPVOID lpSystemDefaultActivationContextData;
|
||||
LPVOID lpSystemAssemblyStorageMap;
|
||||
DWORD dwMinimumStackCommit;
|
||||
} _PEB, * _PPEB;
|
||||
|
||||
|
||||
DWORD HashModule(PCSTR ModuleName, size_t length)
|
||||
{
|
||||
DWORD i = 0;
|
||||
DWORD Hash = FH_RND_SEED;
|
||||
|
||||
while (i < length / 2)
|
||||
{
|
||||
WORD PartialName = *(WORD*)((ULONG64)ModuleName + i++) | 0x20202020;
|
||||
Hash ^= PartialName + ROR8(Hash);
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
|
||||
|
||||
// function to fetch the base address of a Mmodule from the Process Environment Block
|
||||
UINT64 GetModule(DWORD TargetHash) {
|
||||
ULONG_PTR dll, val1;
|
||||
PWSTR val2;
|
||||
USHORT usCounter;
|
||||
// We want to stop when we find this
|
||||
DWORD firstHash = 0;
|
||||
|
||||
// PEB is at 0x60 offset and __readgsqword is compiler intrinsic,
|
||||
// so we don't need to extract it's symbol
|
||||
dll = __readgsqword(0x60);
|
||||
|
||||
dll = (ULONG_PTR)((_PPEB)dll)->pLdr;
|
||||
val1 = (ULONG_PTR)((PPEB_LDR_DATA)dll)->InMemoryOrderModuleList.Flink;
|
||||
|
||||
while (NULL != val1) {
|
||||
val2 = (PWSTR)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.pBuffer;
|
||||
usCounter = (USHORT)((PLDR_DATA_TABLE_ENTRY)val1)->BaseDllName.Length;
|
||||
|
||||
//calculate the hash of kernel32.dll
|
||||
DWORD Hash = HashModule((PCSTR)val2, usCounter);
|
||||
if (firstHash == 0) {
|
||||
firstHash = Hash;
|
||||
}
|
||||
else if (firstHash == Hash) {
|
||||
break;
|
||||
}
|
||||
|
||||
//wprintf(L"%s: %u\n --> Hash: %x - Target: %x\n", (WCHAR*)val2, usCounter, Hash, TargetHash);
|
||||
|
||||
// compare the hash kernel32.dll
|
||||
if (Hash == TargetHash) {
|
||||
//return kernel32.dll if found
|
||||
dll = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)val1)->DllBase;
|
||||
return dll;
|
||||
}
|
||||
val1 = DEREF(val1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// custom strcmp function since this function will be called by GetSymbolAddress
|
||||
// which means we have to call strcmp before loading msvcrt.dll
|
||||
// so we are writing our own my_strcmp so that we don't have to play with egg or chicken dilemma
|
||||
int my_strcmp(const char* p1, const char* p2) {
|
||||
const unsigned char* s1 = (const unsigned char*)p1;
|
||||
const unsigned char* s2 = (const unsigned char*)p2;
|
||||
unsigned char c1, c2;
|
||||
do {
|
||||
c1 = (unsigned char)*s1++;
|
||||
c2 = (unsigned char)*s2++;
|
||||
if (c1 == '\0') {
|
||||
return c1 - c2;
|
||||
}
|
||||
} while (c1 == c2);
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
UINT64 GetSymbolAddress(HMODULE hModule, LPCSTR lpProcName) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0,
|
||||
exportedAddressTable = 0,
|
||||
namePointerTable = 0,
|
||||
ordinalTable = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions);
|
||||
namePointerTable = (dllAddress + exportDirectory->AddressOfNames);
|
||||
ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) {
|
||||
exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable));
|
||||
}
|
||||
else {
|
||||
DWORD dwCounter = exportDirectory->NumberOfNames;
|
||||
while (dwCounter--) {
|
||||
char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable));
|
||||
if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) {
|
||||
exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)(dllAddress + DEREF_32(exportedAddressTable));
|
||||
break;
|
||||
}
|
||||
namePointerTable += sizeof(DWORD);
|
||||
ordinalTable += sizeof(WORD);
|
||||
}
|
||||
}
|
||||
|
||||
return symbolAddress;
|
||||
}
|
||||
|
||||
|
||||
UINT64 GetSymbolOffset(HMODULE hModule, LPCSTR lpProcName) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0,
|
||||
exportedAddressTable = 0,
|
||||
namePointerTable = 0,
|
||||
ordinalTable = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
exportedAddressTable = (dllAddress + exportDirectory->AddressOfFunctions);
|
||||
namePointerTable = (dllAddress + exportDirectory->AddressOfNames);
|
||||
ordinalTable = (dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
if (((UINT64)lpProcName & 0xFFFF0000) == 0x00000000) {
|
||||
exportedAddressTable += ((IMAGE_ORDINAL((UINT64)lpProcName) - exportDirectory->Base) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)DEREF_32(exportedAddressTable);
|
||||
}
|
||||
else {
|
||||
DWORD dwCounter = exportDirectory->NumberOfNames;
|
||||
while (dwCounter--) {
|
||||
char* cpExportedFunctionName = (char*)(dllAddress + DEREF_32(namePointerTable));
|
||||
if (my_strcmp(cpExportedFunctionName, lpProcName) == 0) {
|
||||
exportedAddressTable += (DEREF_16(ordinalTable) * sizeof(DWORD));
|
||||
symbolAddress = (UINT64)DEREF_32(exportedAddressTable);
|
||||
break;
|
||||
}
|
||||
namePointerTable += sizeof(DWORD);
|
||||
ordinalTable += sizeof(WORD);
|
||||
}
|
||||
}
|
||||
|
||||
return symbolAddress;
|
||||
}
|
||||
|
||||
char* GetSymbolNameByOffset(HMODULE hModule, UINT64 offset) {
|
||||
UINT64 dllAddress = (UINT64)hModule,
|
||||
symbolAddress = 0;
|
||||
|
||||
if (hModule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = NULL;
|
||||
PIMAGE_DATA_DIRECTORY dataDirectory = NULL;
|
||||
PIMAGE_EXPORT_DIRECTORY exportDirectory = NULL;
|
||||
|
||||
ntHeaders = (PIMAGE_NT_HEADERS)(dllAddress + ((PIMAGE_DOS_HEADER)dllAddress)->e_lfanew);
|
||||
dataDirectory = (PIMAGE_DATA_DIRECTORY)&ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||
exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(dllAddress + dataDirectory->VirtualAddress);
|
||||
|
||||
LPDWORD exportedAddressTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfFunctions);
|
||||
LPDWORD namePointerTable = (LPDWORD)(dllAddress + exportDirectory->AddressOfNames);
|
||||
LPWORD ordinalTable = (LPWORD)(dllAddress + exportDirectory->AddressOfNameOrdinals);
|
||||
|
||||
char* currProcName;
|
||||
|
||||
for (SIZE_T i = 0; i < exportDirectory->NumberOfNames; i++) {
|
||||
// Get current function name
|
||||
currProcName = (LPSTR)((LPBYTE)hModule + namePointerTable[i]);
|
||||
|
||||
// Get current function address
|
||||
if (exportedAddressTable[ordinalTable[i]] == offset) {
|
||||
return currProcName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PVOID GetExceptionDirectoryAddress(HMODULE hModule, DWORD* tSize)
|
||||
{
|
||||
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew);
|
||||
DWORD64 exceptionDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[3].VirtualAddress;
|
||||
*tSize = ntHeader->OptionalHeader.DataDirectory[3].Size;
|
||||
DWORD64 imageExceptionDirectory = (DWORD64)((DWORD_PTR)hModule + exceptionDirectoryRVA);
|
||||
return (PVOID)imageExceptionDirectory;
|
||||
|
||||
}
|
||||
|
||||
PVOID GetExportDirectoryAddress(HMODULE hModule)
|
||||
{
|
||||
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
|
||||
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD64)hModule + dosHeader->e_lfanew);
|
||||
DWORD_PTR exportDirectoryRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
DWORD64 imageExportDirectory = (DWORD64)((DWORD_PTR)hModule + exportDirectoryRVA);
|
||||
|
||||
return (PVOID)imageExportDirectory;
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef COMMON_H_INCLUDED
|
||||
#define COMMON_H_INCLUDED
|
||||
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#include <dbghelp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "AddressHunter.h"
|
||||
|
||||
#define VERSION 0.1
|
||||
#define AUTHOR "KlezVirus"
|
||||
#define MAX_FRAMES 154
|
||||
// Remove if you have a self-made definition of memcmp
|
||||
#define MemCompare memcmp
|
||||
|
||||
// Removing malloc deps
|
||||
#undef malloc
|
||||
#define malloc(x) HeapAlloc(GetProcessHeap(), 0, x)
|
||||
|
||||
#undef realloc
|
||||
#define realloc(x,s) HeapReAlloc(GetProcessHeap(), 0, x, s)
|
||||
|
||||
#undef free
|
||||
#define free(x) HeapFree(GetProcessHeap(), 0, x)
|
||||
|
||||
// Removing memset deps
|
||||
void* custom_memset(void* dest, int c, size_t count);
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DPRINT(...) { printf(__VA_ARGS__); }
|
||||
#else
|
||||
#define DPRINT(...) {}
|
||||
#endif
|
||||
#define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF))
|
||||
|
||||
#define BitVal(data,y) ( (data>>y) & 1)
|
||||
|
||||
#define BitChainInfo(data) BitVal(data, 2)
|
||||
#define BitUHandler(data) BitVal(data, 1)
|
||||
#define BitEHandler(data) BitVal(data, 0)
|
||||
#define Version(data) BitVal(data, 4)*2 + BitVal(data, 3)
|
||||
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define B2BP BYTE_TO_BINARY_PATTERN
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
(byte & 0x80 ? '1' : '0'), \
|
||||
(byte & 0x40 ? '1' : '0'), \
|
||||
(byte & 0x20 ? '1' : '0'), \
|
||||
(byte & 0x10 ? '1' : '0'), \
|
||||
(byte & 0x08 ? '1' : '0'), \
|
||||
(byte & 0x04 ? '1' : '0'), \
|
||||
(byte & 0x02 ? '1' : '0'), \
|
||||
(byte & 0x01 ? '1' : '0')
|
||||
|
||||
|
||||
typedef UCHAR UBYTE;
|
||||
typedef PIMAGE_RUNTIME_FUNCTION_ENTRY PERF;
|
||||
|
||||
|
||||
typedef enum _REGISTERS {
|
||||
RAX = 0,
|
||||
RCX,
|
||||
RDX,
|
||||
RBX,
|
||||
RSP,
|
||||
RBP,
|
||||
RSI,
|
||||
RDI,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15
|
||||
} REGISTERS;
|
||||
|
||||
|
||||
typedef union _UNWIND_CODE {
|
||||
struct {
|
||||
UBYTE CodeOffset; // 0xFF00
|
||||
UBYTE UnwindOp : 4; // 0x000f OPCODE
|
||||
UBYTE OpInfo : 4; // 0x00f0
|
||||
};
|
||||
USHORT FrameOffset;
|
||||
} UNWIND_CODE, * PUNWIND_CODE;
|
||||
|
||||
typedef struct _UNWIND_INFO {
|
||||
UBYTE Version : 3;
|
||||
UBYTE Flags : 5; // 4 bytes
|
||||
UBYTE SizeOfProlog; // 4 bytes
|
||||
UBYTE CountOfCodes; // 4 bytes
|
||||
UBYTE FrameRegister : 4;
|
||||
UBYTE FrameOffset : 4; // 4bytes
|
||||
UNWIND_CODE UnwindCode[1];
|
||||
union {
|
||||
OPTIONAL ULONG ExceptionHandler;
|
||||
OPTIONAL ULONG FunctionEntry;
|
||||
};
|
||||
OPTIONAL ULONG ExceptionData[];
|
||||
} UNWIND_INFO, * PUNWIND_INFO;
|
||||
|
||||
#define GetUnwindCodeEntry(info, index) \
|
||||
((info)->UnwindCode[index])
|
||||
|
||||
#define GetLanguageSpecificDataPtr(info) \
|
||||
((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
|
||||
|
||||
#define GetExceptionHandler(base, info) \
|
||||
((PEXCEPTION_ROUTINE)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
|
||||
|
||||
#define GetChainedFunctionEntry(base, info) \
|
||||
((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
|
||||
|
||||
#define GetExceptionDataPtr(info) \
|
||||
((PVOID)((PULONG)GetLanguageSpecificDataPtr(info) + 1))
|
||||
|
||||
#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
|
||||
#define ADDRESS ADDRESS64
|
||||
#define LPADDRESS LPADDRESS64
|
||||
#else
|
||||
typedef struct _tagADDRESS {
|
||||
DWORD Offset;
|
||||
WORD Segment;
|
||||
ADDRESS_MODE Mode;
|
||||
} ADDRESS, * LPADDRESS;
|
||||
#endif
|
||||
|
||||
typedef struct _MIN_CTX {
|
||||
|
||||
DWORD64 Rax;
|
||||
DWORD64 Rcx;
|
||||
DWORD64 Rdx;
|
||||
DWORD64 Rbx;
|
||||
DWORD64 Rsp;
|
||||
DWORD64 Rbp;
|
||||
DWORD64 Rsi;
|
||||
DWORD64 Rdi;
|
||||
DWORD64 R8;
|
||||
DWORD64 R9;
|
||||
DWORD64 R10;
|
||||
DWORD64 R11;
|
||||
DWORD64 R12;
|
||||
DWORD64 R13;
|
||||
DWORD64 R14;
|
||||
DWORD64 R15;
|
||||
|
||||
DWORD64 Rip;
|
||||
DWORD64 Reserved;
|
||||
DWORD64 StackSize;
|
||||
|
||||
} MIN_CTX, *PMIN_CTX;
|
||||
|
||||
typedef enum _UNWIND_OP_CODES {
|
||||
// x86_64. https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
|
||||
UWOP_PUSH_NONVOL = 0,
|
||||
UWOP_ALLOC_LARGE, // 1
|
||||
UWOP_ALLOC_SMALL, // 2
|
||||
UWOP_SET_FPREG, // 3
|
||||
UWOP_SAVE_NONVOL, // 4
|
||||
UWOP_SAVE_NONVOL_BIG, // 5
|
||||
UWOP_EPILOG, // 6
|
||||
UWOP_SPARE_CODE, // 7
|
||||
UWOP_SAVE_XMM128, // 8
|
||||
UWOP_SAVE_XMM128BIG, // 9
|
||||
UWOP_PUSH_MACH_FRAME, // 10
|
||||
|
||||
// ARM64. https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
UWOP_ALLOC_MEDIUM,
|
||||
UWOP_SAVE_R19R20X,
|
||||
UWOP_SAVE_FPLRX,
|
||||
UWOP_SAVE_FPLR,
|
||||
UWOP_SAVE_REG,
|
||||
UWOP_SAVE_REGX,
|
||||
UWOP_SAVE_REGP,
|
||||
UWOP_SAVE_REGPX,
|
||||
UWOP_SAVE_LRPAIR,
|
||||
UWOP_SAVE_FREG,
|
||||
UWOP_SAVE_FREGX,
|
||||
UWOP_SAVE_FREGP,
|
||||
UWOP_SAVE_FREGPX,
|
||||
UWOP_SET_FP,
|
||||
UWOP_ADD_FP,
|
||||
UWOP_NOP,
|
||||
UWOP_END,
|
||||
UWOP_SAVE_NEXT,
|
||||
UWOP_TRAP_FRAME,
|
||||
UWOP_CONTEXT,
|
||||
UWOP_CLEAR_UNWOUND_TO_CALL,
|
||||
// ARM: https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
|
||||
|
||||
UWOP_ALLOC_HUGE,
|
||||
UWOP_WIDE_ALLOC_MEDIUM,
|
||||
UWOP_WIDE_ALLOC_LARGE,
|
||||
UWOP_WIDE_ALLOC_HUGE,
|
||||
|
||||
UWOP_WIDE_SAVE_REG_MASK,
|
||||
UWOP_WIDE_SAVE_SP,
|
||||
UWOP_SAVE_REGS_R4R7LR,
|
||||
UWOP_WIDE_SAVE_REGS_R4R11LR,
|
||||
UWOP_SAVE_FREG_D8D15,
|
||||
UWOP_SAVE_REG_MASK,
|
||||
UWOP_SAVE_LR,
|
||||
UWOP_SAVE_FREG_D0D15,
|
||||
UWOP_SAVE_FREG_D16D31,
|
||||
UWOP_WIDE_NOP, // UWOP_NOP
|
||||
UWOP_END_NOP, // UWOP_END
|
||||
UWOP_WIDE_END_NOP,
|
||||
// Custom implementation opcodes (implementation specific).
|
||||
UWOP_CUSTOM,
|
||||
} UNWIND_OP_CODES;
|
||||
|
||||
// Stack allocations use UOP_AllocSmall, UOP_AllocLarge from above, plus
|
||||
// the following. AllocSmall, AllocLarge and AllocHuge represent a 16 bit
|
||||
// instruction, while the WideAlloc* opcodes represent a 32 bit instruction.
|
||||
// Small can represent a stack offset of 0x7f*4 (252) bytes, Medium can
|
||||
// represent up to 0x3ff*4 (4092) bytes, Large up to 0xffff*4 (262140) bytes,
|
||||
// and Huge up to 0xffffff*4 (67108860) bytes.
|
||||
|
||||
|
||||
#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
|
||||
#define STACKFRAME STACKFRAME64
|
||||
#define LPSTACKFRAME LPSTACKFRAME64
|
||||
#else
|
||||
typedef struct _tagSTACKFRAME {
|
||||
ADDRESS AddrPC;
|
||||
ADDRESS AddrReturn;
|
||||
ADDRESS AddrFrame;
|
||||
ADDRESS AddrStack;
|
||||
PVOID FuncTableEntry;
|
||||
DWORD Params[4];
|
||||
BOOL Far;
|
||||
BOOL Virtual;
|
||||
DWORD Reserved[3];
|
||||
KDHELP KdHelp;
|
||||
ADDRESS AddrBStore;
|
||||
} STACKFRAME, * LPSTACKFRAME;
|
||||
#endif
|
||||
|
||||
|
||||
BYTE ExtractOpInfo(BYTE OpIC) {
|
||||
return OpIC >> 4;
|
||||
}
|
||||
|
||||
BYTE ExtractOpCode(BYTE OpIC) {
|
||||
return OpIC & 0x0F;
|
||||
}
|
||||
|
||||
char* GetOpInfo(int op) {
|
||||
char* reg = (char*)malloc(4);
|
||||
if (reg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
custom_memset(reg, 0, 4);
|
||||
|
||||
if(op == 0) {
|
||||
memcpy(reg, "RAX", 4);
|
||||
}
|
||||
else if(op == 1) {
|
||||
memcpy(reg, "RCX", 4);
|
||||
}
|
||||
else if(op == 2) {
|
||||
memcpy(reg, "RDX", 4);
|
||||
}
|
||||
else if(op == 3) {
|
||||
memcpy(reg, "RBX", 4);
|
||||
}
|
||||
else if(op == 4) {
|
||||
memcpy(reg, "RSP", 4);
|
||||
}
|
||||
else if(op == 5) {
|
||||
memcpy(reg, "RBP", 4);
|
||||
}
|
||||
else if(op == 6) {
|
||||
memcpy(reg, "RSI", 4);
|
||||
}
|
||||
else if(op == 7) {
|
||||
memcpy(reg, "RDI", 4);
|
||||
}
|
||||
else if(op == 8) {
|
||||
memcpy(reg, "R8\0", 4);
|
||||
}
|
||||
else if(op == 9) {
|
||||
memcpy(reg, "R9\0", 4);
|
||||
}
|
||||
else if(op == 10) {
|
||||
memcpy(reg, "R10", 4);
|
||||
}
|
||||
else if(op == 11) {
|
||||
memcpy(reg, "R11", 4);
|
||||
}
|
||||
else if(op == 12) {
|
||||
memcpy(reg, "R12", 4);
|
||||
}
|
||||
else if(op == 13) {
|
||||
memcpy(reg, "R13", 4);
|
||||
}
|
||||
else if(op == 14) {
|
||||
memcpy(reg, "R14", 4);
|
||||
}
|
||||
else if(op == 15) {
|
||||
memcpy(reg, "R15", 4);
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void* custom_memset(void* dest, int val, size_t len) {
|
||||
for (char* dst = (char*)dest; len != 0; len--) {
|
||||
*dst++ = val;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include "Windows.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DPRINTUNWINDCODE(x) { \
|
||||
printf("0x%x\t", x->CodeOffset); \
|
||||
printf("0x%x\t", x->OpInfo); \
|
||||
printf("0x%x\n", x->UnwindOp); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define DPRINTUNWINDCODE(x) {}
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
#ifdef _VERBOSE_DEBUG
|
||||
#define DPRINTCTX(x) { \
|
||||
printf("RAX: 0x%llx -", x.Rax); \
|
||||
printf("RBX :0x%llx -", x.Rbx); \
|
||||
printf("RCX: 0x%llx -", x.Rcx); \
|
||||
printf("RDX: 0x%llx -", x.Rdx); \
|
||||
printf("RDI: 0x%llx -", x.Rdi); \
|
||||
printf("RSI: 0x%llx -", x.Rsi); \
|
||||
printf("RBP: 0x%llx -", x.Rbp); \
|
||||
printf("RSP: 0x%llx -\n", x.Rsp); \
|
||||
printf("R8 : 0x%llx -", x.R8 ); \
|
||||
printf("R9 : 0x%llx -", x.R9 ); \
|
||||
printf("R10: 0x%llx -", x.R10); \
|
||||
printf("R11: 0x%llx -", x.R11); \
|
||||
printf("R12: 0x%llx -", x.R12); \
|
||||
printf("R13: 0x%llx -", x.R13); \
|
||||
printf("R14: 0x%llx -", x.R14); \
|
||||
printf("R15: 0x%llx \n", x.R15); \
|
||||
printf("RIP: 0x%llx \n", x.Rip); \
|
||||
}
|
||||
#else
|
||||
#define DPRINTCTX(x) {}
|
||||
#endif
|
||||
#else
|
||||
#define DPRINTCTX(x) {}
|
||||
#endif
|
||||
|
||||
typedef SIZE_T(WINAPI* VirtualQueryType)(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
|
||||
typedef HANDLE(WINAPI* OpenProcessType)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
typedef DWORD(WINAPI* GetCurrentProcessIdType)();
|
||||
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByAddress(UINT64, DWORD64);
|
||||
PIMAGE_RUNTIME_FUNCTION_ENTRY RTFindFunctionByIndex(UINT64, DWORD);
|
||||
DWORD GetStackFrameSize(HMODULE, PVOID, DWORD*);
|
||||
DWORD GetStackFrameSizeWhereRbpIsPushedOnStack(HMODULE, PVOID, DWORD*);
|
||||
DWORD GetStackFrameSizeIgnoringUwopSetFpreg(HMODULE, PVOID, DWORD*);
|
||||
void PrintUnwindInfo(HMODULE, PVOID);
|
||||
void LookupSymbolFromRTIndex(HMODULE, int, bool);
|
||||
void EnumAllRTFunctions(HMODULE);
|
||||
DWORD FindRTFunctionsUnwind(HMODULE, PVOID);
|
||||
|
||||
|
||||
VOID FindGadget(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, DWORD gadgetType);
|
||||
DWORD FindProlog(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset);
|
||||
DWORD FindPopRbp(HMODULE moduleBase, PERF pRuntimeFunctionTable, DWORD rtLastIndex, PDWORD stackSize, PDWORD prtSaveIndex, PDWORD skip, PDWORD64 rtTargetOffset);
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "Windows.h"
|
||||
|
||||
void TestLocateFunctionByAddress();
|
||||
void TestLookupByFrameOffset();
|
||||
void TestEnumAllRT(DWORD);
|
||||
void Test();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Reference in New Issue
Block a user