commit c661ae3c4601cb6ff79da5d04f2fea98809dfbf5 Author: Nick Landers Date: Tue Feb 18 14:03:51 2020 -0700 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..611428f --- /dev/null +++ b/.gitignore @@ -0,0 +1,353 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*[.json, .xml, .info] + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ diff --git a/Functions/Functions.vcxproj b/Functions/Functions.vcxproj new file mode 100644 index 0000000..624f33a --- /dev/null +++ b/Functions/Functions.vcxproj @@ -0,0 +1,87 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + + 15.0 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} + Win32Proj + Functions + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + + + + + + + + + + + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;FUNCTIONS_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;FUNCTIONS_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + + + \ No newline at end of file diff --git a/Functions/Functions.vcxproj.filters b/Functions/Functions.vcxproj.filters new file mode 100644 index 0000000..0d8d9e4 --- /dev/null +++ b/Functions/Functions.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Functions/main.cpp b/Functions/main.cpp new file mode 100644 index 0000000..694195f --- /dev/null +++ b/Functions/main.cpp @@ -0,0 +1,18 @@ +#include + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + return TRUE; +} + +// Return TRUE because this is the real DLL + +extern "C" __declspec(dllexport) BOOL Static() +{ + return TRUE; +}; + +extern "C" __declspec(dllexport) BOOL Dynamic() +{ + return TRUE; +}; \ No newline at end of file diff --git a/Harness/Harness.vcxproj b/Harness/Harness.vcxproj new file mode 100644 index 0000000..5fa352b --- /dev/null +++ b/Harness/Harness.vcxproj @@ -0,0 +1,93 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + + 15.0 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4} + Win32Proj + HijackMaker + 10.0 + Harness + + + + Application + true + v142 + Unicode + + + Application + true + v142 + Unicode + + + + + + + + + + + + + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + {2150d252-aa17-45c2-8981-a6dcf7055ca6} + + + + + + \ No newline at end of file diff --git a/Harness/Harness.vcxproj.filters b/Harness/Harness.vcxproj.filters new file mode 100644 index 0000000..0d8d9e4 --- /dev/null +++ b/Harness/Harness.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Harness/main.cpp b/Harness/main.cpp new file mode 100644 index 0000000..4015d2e --- /dev/null +++ b/Harness/main.cpp @@ -0,0 +1,31 @@ +#include + +extern "C" BOOL Static(); +typedef BOOL (WINAPI *DynExport)(); + +int main() { + + // Static Sink + if (Static()) { + MessageBox(0, L"[+] Static Sink: GOOD", L"Harness", 0); + } + else { + MessageBox(0, L"[!] Static Sink: BAD", L"Harness", 0); + } + + // Dynamic Sink + HMODULE module = LoadLibrary(L"Theif.dll"); + if (!module) return 1; + + DynExport Dynamic = (DynExport)GetProcAddress(module, "Mucklow"); + if (!Dynamic) return 1; + + if (Dynamic()) { + MessageBox(0, L"[+] Dynamic Sink: GOOD", L"Harness", 0); + } + else { + MessageBox(0, L"[!] Dynamic Sink: BAD", L"Harness", 0); + } + + return 0; +} \ No newline at end of file diff --git a/Koppeling.sln b/Koppeling.sln new file mode 100644 index 0000000..1fe36ef --- /dev/null +++ b/Koppeling.sln @@ -0,0 +1,124 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Functions", "Functions\Functions.vcxproj", "{DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Theif", "Theif\Theif.vcxproj", "{2150D252-AA17-45C2-8981-A6DCF7055CA6}" + ProjectSection(ProjectDependencies) = postProject + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} = {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260} = {62E3CCF4-07F3-496E-B77D-48D5AC0E6260} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Harness", "Harness\Harness.vcxproj", "{95BC2C38-1FBE-4AF1-967E-BC133250C4D4}" + ProjectSection(ProjectDependencies) = postProject + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} = {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{E956CB21-8B8B-4C10-BE6A-C560AAA097B0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cloners", "Cloners", "{AAF7506C-D305-4A6F-9761-CB8C2E6782CB}" +EndProject +Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PyClone", "PyClone\PyClone.pyproj", "{A2775E1E-C389-4DEB-B1C7-E46A210B1748}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetClone", "NetClone\NetClone.csproj", "{62E3CCF4-07F3-496E-B77D-48D5AC0E6260}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Dyn-NetClone|x64 = Dyn-NetClone|x64 + Dyn-NetClone|x86 = Dyn-NetClone|x86 + Dyn-PyClone|x64 = Dyn-PyClone|x64 + Dyn-PyClone|x86 = Dyn-PyClone|x86 + Dyn-Rebuild|x64 = Dyn-Rebuild|x64 + Dyn-Rebuild|x86 = Dyn-Rebuild|x86 + Stc-Forward|x64 = Stc-Forward|x64 + Stc-Forward|x86 = Stc-Forward|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-NetClone|x64.ActiveCfg = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-NetClone|x64.Build.0 = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-NetClone|x86.ActiveCfg = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-NetClone|x86.Build.0 = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-PyClone|x64.ActiveCfg = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-PyClone|x64.Build.0 = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-PyClone|x86.ActiveCfg = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-PyClone|x86.Build.0 = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-Rebuild|x64.ActiveCfg = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-Rebuild|x64.Build.0 = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-Rebuild|x86.ActiveCfg = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Dyn-Rebuild|x86.Build.0 = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Stc-Forward|x64.ActiveCfg = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Stc-Forward|x64.Build.0 = Debug|x64 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Stc-Forward|x86.ActiveCfg = Debug|Win32 + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717}.Stc-Forward|x86.Build.0 = Debug|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-NetClone|x64.ActiveCfg = Dyn-NetClone|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-NetClone|x64.Build.0 = Dyn-NetClone|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-NetClone|x86.ActiveCfg = Dyn-NetClone|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-NetClone|x86.Build.0 = Dyn-NetClone|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-PyClone|x64.ActiveCfg = Dyn-PyClone|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-PyClone|x64.Build.0 = Dyn-PyClone|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-PyClone|x86.ActiveCfg = Dyn-PyClone|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-PyClone|x86.Build.0 = Dyn-PyClone|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-Rebuild|x64.ActiveCfg = Dyn-Rebuild|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-Rebuild|x64.Build.0 = Dyn-Rebuild|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-Rebuild|x86.ActiveCfg = Dyn-Rebuild|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Dyn-Rebuild|x86.Build.0 = Dyn-Rebuild|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Stc-Forward|x64.ActiveCfg = Stc-Forward|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Stc-Forward|x64.Build.0 = Stc-Forward|x64 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Stc-Forward|x86.ActiveCfg = Stc-Forward|Win32 + {2150D252-AA17-45C2-8981-A6DCF7055CA6}.Stc-Forward|x86.Build.0 = Stc-Forward|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-NetClone|x64.ActiveCfg = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-NetClone|x64.Build.0 = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-NetClone|x86.ActiveCfg = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-NetClone|x86.Build.0 = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-PyClone|x64.ActiveCfg = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-PyClone|x64.Build.0 = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-PyClone|x86.ActiveCfg = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-PyClone|x86.Build.0 = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-Rebuild|x64.ActiveCfg = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-Rebuild|x64.Build.0 = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-Rebuild|x86.ActiveCfg = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Dyn-Rebuild|x86.Build.0 = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Stc-Forward|x64.ActiveCfg = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Stc-Forward|x64.Build.0 = Debug|x64 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Stc-Forward|x86.ActiveCfg = Debug|Win32 + {95BC2C38-1FBE-4AF1-967E-BC133250C4D4}.Stc-Forward|x86.Build.0 = Debug|Win32 + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-NetClone|x64.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-NetClone|x86.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-PyClone|x64.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-PyClone|x86.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-Rebuild|x64.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Dyn-Rebuild|x86.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Stc-Forward|x64.ActiveCfg = Debug|Any CPU + {A2775E1E-C389-4DEB-B1C7-E46A210B1748}.Stc-Forward|x86.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-NetClone|x64.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-NetClone|x64.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-NetClone|x86.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-NetClone|x86.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-PyClone|x64.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-PyClone|x64.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-PyClone|x86.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-PyClone|x86.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-Rebuild|x64.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-Rebuild|x64.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-Rebuild|x86.ActiveCfg = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Dyn-Rebuild|x86.Build.0 = Debug|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Stc-Forward|x64.ActiveCfg = Release|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Stc-Forward|x64.Build.0 = Release|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Stc-Forward|x86.ActiveCfg = Release|Any CPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260}.Stc-Forward|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DB8A345D-E19C-4C2A-9FDF-16BF4DD03717} = {E956CB21-8B8B-4C10-BE6A-C560AAA097B0} + {2150D252-AA17-45C2-8981-A6DCF7055CA6} = {E956CB21-8B8B-4C10-BE6A-C560AAA097B0} + {A2775E1E-C389-4DEB-B1C7-E46A210B1748} = {AAF7506C-D305-4A6F-9761-CB8C2E6782CB} + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260} = {AAF7506C-D305-4A6F-9761-CB8C2E6782CB} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7520776C-808A-4B77-B83A-FD5E08BA5803} + EndGlobalSection +EndGlobal diff --git a/NetClone/NetClone.csproj b/NetClone/NetClone.csproj new file mode 100644 index 0000000..06cb1b1 --- /dev/null +++ b/NetClone/NetClone.csproj @@ -0,0 +1,83 @@ + + + + + Debug + AnyCPU + {62E3CCF4-07F3-496E-B77D-48D5AC0E6260} + Exe + NetClone + NetClone + v4.7.2 + 512 + true + + + + AnyCPU + true + full + false + ..\Bin\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\CommandLineParser.2.7.82\lib\net461\CommandLine.dll + + + ..\packages\PeNet.1.5.3\lib\net461\PeNet.dll + + + ..\packages\PeNet.Asn1.1.3.3\lib\net461\PeNet.Asn1.dll + + + + + + ..\packages\System.Security.Cryptography.Pkcs.4.7.0\lib\net461\System.Security.Cryptography.Pkcs.dll + + + + + + + + ..\packages\Validation.2.4.18\lib\net45\Validation.dll + + + ..\packages\xunit.abstractions.2.0.2\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.extensibility.core.2.4.0\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.4.0\lib\net452\xunit.execution.desktop.dll + + + ..\packages\Xunit.SkippableFact.1.3.12\lib\net452\Xunit.SkippableFact.dll + + + + + + + + + + + + \ No newline at end of file diff --git a/NetClone/Program.cs b/NetClone/Program.cs new file mode 100644 index 0000000..4e0f4ca --- /dev/null +++ b/NetClone/Program.cs @@ -0,0 +1,207 @@ +using System; +using PeNet; +using PeNet.Structures; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using CommandLine; +using System.Reflection; +using PeNet.Utilities; + +namespace NetClone +{ + class Program + { + // Read_Only | Initialized_Data + const uint DEFAULT_CHARACTERISTICS = 0x40000040; + const uint SECTION_NAME = 8; + + static uint AlignUp(uint value, uint align = 0x1000) + { + uint t1 = (value + align - 1) & ~(align - 1); + return t1; + } + static uint GetOffset(AbstractStructure structure) + { + FieldInfo Offset = structure.GetType().GetField("Offset", BindingFlags.Instance | BindingFlags.NonPublic); + return (uint)Offset.GetValue(structure); + } + + static IMAGE_SECTION_HEADER AddSection(ref PeFile pe, string name, uint size, uint characteristics = DEFAULT_CHARACTERISTICS) + { + if (name.Length > SECTION_NAME) + { + throw new Exception("Section name is too long"); + } + + // sizeof(IMAGE_SECTION_HEADER); + const uint headerSize = 0x28; + uint headerOffset = GetOffset(pe.ImageSectionHeaders.Last()) + headerSize; + if (headerOffset + headerSize > pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders) + { + throw new Exception("Not enough room for additional SECTION_HEADER"); + } + + uint virtualSize = AlignUp(size, pe.ImageNtHeaders.OptionalHeader.SectionAlignment); + uint virtualAddress = AlignUp( + pe.ImageSectionHeaders.Last().VirtualAddress + pe.ImageSectionHeaders.Last().VirtualSize, + pe.ImageNtHeaders.OptionalHeader.SectionAlignment + ); + + uint rawSize = AlignUp(size, pe.ImageNtHeaders.OptionalHeader.FileAlignment); + uint rawPtr = AlignUp( + pe.ImageSectionHeaders.Last().PointerToRawData + pe.ImageSectionHeaders.Last().SizeOfRawData, + pe.ImageNtHeaders.OptionalHeader.FileAlignment + ); + + byte[] nullPadding = new byte[SECTION_NAME]; + + IMAGE_SECTION_HEADER section = new IMAGE_SECTION_HEADER( + pe.Buff, headerOffset, pe.ImageNtHeaders.OptionalHeader.ImageBase) + { + Name = Encoding.ASCII.GetBytes(name).Concat(nullPadding).ToArray(), + VirtualAddress = virtualAddress, + PointerToRawData = rawPtr, + VirtualSize = virtualSize, + SizeOfRawData = rawSize, + Characteristics = characteristics, + + PointerToRelocations = 0, + NumberOfRelocations = 0, + NumberOfLinenumbers = 0, + PointerToLinenumbers = 0, + }; + + pe.ImageNtHeaders.FileHeader.NumberOfSections += 1; + pe.ImageNtHeaders.OptionalHeader.SizeOfImage = virtualAddress + virtualSize; + + byte[] resizedBuffer = pe.Buff; + Array.Resize(ref resizedBuffer, pe.Buff.Length + (int)rawSize); + pe = new PeFile(resizedBuffer); + + return section; + } + static void CloneExports(ref PeFile target, PeFile reference, string referencePath, string sectionName) + { + IMAGE_DATA_DIRECTORY tgtExportDirectory = target.ImageNtHeaders.OptionalHeader.DataDirectory[0]; + IMAGE_DATA_DIRECTORY refExportDirectory = reference.ImageNtHeaders.OptionalHeader.DataDirectory[0]; + + if (!reference.HasValidExportDir) + { + throw new Exception("Reference DLL has no export directory"); + } + + List forwardNames = new List(); + foreach (ExportFunction export in reference.ExportedFunctions) + { + if (export.HasName) + { + forwardNames.Add(String.Format("{0}.{1}", referencePath, export.Name)); + } + else + { + forwardNames.Add(String.Format("{0}.#{1}", referencePath, export.Ordinal)); + } + } + + byte[] nullByte = new byte[1]; + byte[] forwardNameBlock = forwardNames.SelectMany( + s => Encoding.ASCII.GetBytes(s).Concat(nullByte) + ).ToArray(); + + // Add a new section to hold the new export table + uint newSectionSize = (uint)refExportDirectory.Size + (uint)forwardNameBlock.Length; + IMAGE_SECTION_HEADER newSection = AddSection(ref target, sectionName, newSectionSize); + uint delta = newSection.VirtualAddress - refExportDirectory.VirtualAddress; + uint forwardOffset = (uint)(newSection.VirtualAddress + refExportDirectory.Size); + + // Clear existing export table (optional) + // Array.Clear(target.Buff, (int)GetOffset(target.ImageExportDirectory), (int)tgtExportDirectory.Size); + + // Write our new export table into the section + Array.Copy( + reference.Buff, GetOffset(reference.ImageExportDirectory), + target.Buff, newSection.PointerToRawData, + refExportDirectory.Size + ); + + // Add in our forward name block + Array.Copy( + forwardNameBlock, 0, + target.Buff, newSection.PointerToRawData + refExportDirectory.Size, + forwardNameBlock.Length + ); + + IMAGE_EXPORT_DIRECTORY newExportDir = new IMAGE_EXPORT_DIRECTORY(target.Buff, newSection.PointerToRawData); + + newExportDir.AddressOfFunctions += (uint)delta; + newExportDir.AddressOfNames += (uint)delta; + newExportDir.AddressOfNameOrdinals += (uint)delta; + + + // Link function addresses to forward names + uint rawAddressOfFunctions = newExportDir.AddressOfFunctions.RVAtoFileMapping(target.ImageSectionHeaders); + for (int i = 0; i < newExportDir.NumberOfFunctions; i++) + { + string forwardName = forwardNames[i]; + uint offset = (uint)(rawAddressOfFunctions + 4 * i); + target.Buff.SetUInt32(offset, forwardOffset); + forwardOffset += (uint)forwardName.Length + 1; + } + + // Apply delta to export names + uint rawAddressOfNames = newExportDir.AddressOfNames.RVAtoFileMapping(target.ImageSectionHeaders); + for (int i = 0; i < newExportDir.NumberOfNames; i++) + { + uint offset = (uint)(rawAddressOfNames + 4 * i); + target.Buff.SetUInt32(offset, target.Buff.BytesToUInt32(offset) + delta); + } + + // Correct the image size + target.ImageNtHeaders.OptionalHeader.DataDirectory[0].VirtualAddress = newSection.VirtualAddress; + target.ImageNtHeaders.OptionalHeader.DataDirectory[0].Size = newSectionSize; + + return; + } + + public class Options + { + [Option("target", Required = true, HelpText = "Target DLL for modifications")] + public string Target { get; set; } + [Option("reference", Required = true, HelpText = "Reference DLL from which the exports will be cloned")] + public string Reference { get; set; } + [Option('o', "output", Required = false, HelpText = "Output file path (Default = .clone.dll)")] + public string Output { get; set; } + [Option('p', "reference-path", Required = false, HelpText = "Full path to reference DLL while being hijacked (if is not accurate)")] + public string ReferencePath { get; set; } + [Option('s', "section-path", Required = false, HelpText = "New section name", Default = ".rdata2")] + public string SectionPath { get; set; } + } + + static void Main(string[] args) + { + Parser.Default.ParseArguments(args) + .WithParsed(o => + { + if (String.IsNullOrEmpty(o.ReferencePath)) + { + o.ReferencePath = o.Reference; + } + + if (String.IsNullOrEmpty(o.Output)) + { + o.Output = o.Target + ".clone.dll"; + } + + PeFile targetPe = new PeFile(o.Target); + PeFile referencePe = new PeFile(o.Reference); + + CloneExports(ref targetPe, referencePe, o.ReferencePath, o.SectionPath); + + targetPe.SaveAs(o.Output); + + Console.WriteLine("[+] Done."); + }); + } + } +} diff --git a/NetClone/Properties/AssemblyInfo.cs b/NetClone/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3ead6e2 --- /dev/null +++ b/NetClone/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NetClone")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NetClone")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("62e3ccf4-07f3-496e-b77d-48d5ac0e6260")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NetClone/app.config b/NetClone/app.config new file mode 100644 index 0000000..312bb3f --- /dev/null +++ b/NetClone/app.config @@ -0,0 +1,3 @@ + + + diff --git a/NetClone/packages.config b/NetClone/packages.config new file mode 100644 index 0000000..5ab2362 --- /dev/null +++ b/NetClone/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/PyClone/PyClone.py b/PyClone/PyClone.py new file mode 100644 index 0000000..3770fca --- /dev/null +++ b/PyClone/PyClone.py @@ -0,0 +1,184 @@ +import sys, os +import argparse +import pefile +import copy + +# Read_Only | Initialized_Data +DEFAULT_CHARACTERISTICS = 0x40000040 +SECTION_NAME = 8 + +def align_up(value, align = 0x1000): + return (value + align - 1) & ~(align - 1) + +def add_section(pe, name, size, characteristics = DEFAULT_CHARACTERISTICS): + + # Sanity checks + + if len(name) > SECTION_NAME: + raise Exception('[!] Section name is too long') + + section_header_size = pefile.Structure(pefile.PE.__IMAGE_SECTION_HEADER_format__).sizeof() + section_header_off = pe.sections[-1].get_file_offset() + section_header_size + if section_header_off + section_header_size > pe.OPTIONAL_HEADER.SizeOfHeaders: + raise Exception('[!] Not enough room for another SECTION_HEADER') + + # Calculate/Align sizes + virtual_size = align_up(size, pe.OPTIONAL_HEADER.SectionAlignment) + virtual_addr = align_up( + pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize, + pe.OPTIONAL_HEADER.SectionAlignment + ) + + raw_size = align_up(size, pe.OPTIONAL_HEADER.FileAlignment) + raw_ptr = align_up( + pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData, + pe.OPTIONAL_HEADER.FileAlignment + ) + + # Configure section properties + section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__, pe=pe) + section.set_file_offset(section_header_off) + section.Name = name.encode().ljust(SECTION_NAME, b'\x00') + section.VirtualAddress = virtual_addr + section.PointerToRawData = raw_ptr + section.Misc = section.Misc_VirtualSize = virtual_size + section.SizeOfRawData = raw_size + section.Characteristics = characteristics + + section.PointerToRelocations = 0 + section.NumberOfRelocations = 0 + section.NumberOfLinenumbers = 0 + section.PointerToLinenumbers = 0 + + # Correct headers + pe.FILE_HEADER.NumberOfSections += 1 + pe.OPTIONAL_HEADER.SizeOfImage = virtual_addr + virtual_size + + # Add buffer padding + pe.__data__ += b'\x00' * raw_size + + # Append to ensure overwrite + pe.__structures__.append(section) + + # Recreate to save our changes + pe = pefile.PE(data = pe.write()) + + return pe, section + +def _clone_exports(tgt, ref, ref_path, new_section_name = '.rdata2'): + + ref = copy.deepcopy(ref) + tgt = copy.deepcopy(tgt) + + tgt_export_dir = tgt.OPTIONAL_HEADER.DATA_DIRECTORY[0] + ref_export_dir = ref.OPTIONAL_HEADER.DATA_DIRECTORY[0] + + if not ref_export_dir.Size: + raise Exception('Reference binary has no exports') + + exp_names = [ + ref_path.encode() + b'.' + e.name + if e.name else ref_path.encode() + b'.#' + e.ordinal + for e in ref.DIRECTORY_ENTRY_EXPORT.symbols + ] + exp_names_blob = b'\x00'.join(exp_names) + b'\x00' + + new_section_size = ref_export_dir.Size + len(exp_names_blob) + + tgt, section = add_section(tgt, new_section_name, new_section_size) + final_rva = section.VirtualAddress + + # Capture the reference export directory + export_dir = ref.__unpack_data__( + pefile.PE.__IMAGE_EXPORT_DIRECTORY_format__, + ref.get_data( + ref_export_dir.VirtualAddress, + pefile.Structure(pefile.PE.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() + ), + file_offset = 0 # we don't need this + ) + + # Calculate our delta + delta = final_rva - ref_export_dir.VirtualAddress + + # Apply RVA delta to export names + for i in range(export_dir.NumberOfNames): + ref.set_dword_at_rva( + export_dir.AddressOfNames + 4*i, + ref.get_dword_at_rva(export_dir.AddressOfNames + 4*i) + delta + ) + + assert export_dir.NumberOfFunctions == len(exp_names) + + # Link function addresses to forward names + forward_offset = ref_export_dir.VirtualAddress + ref_export_dir.Size + delta + for i in range(export_dir.NumberOfFunctions): + forward_name = exp_names[i] + ref.set_dword_at_rva( + export_dir.AddressOfFunctions + 4*i, + forward_offset + ) + forward_offset += len(forward_name) + 1 # +1 for null byte + + # Apply RVA delta to directory + export_dir.AddressOfFunctions += delta + export_dir.AddressOfNames += delta + export_dir.AddressOfNameOrdinals += delta + + # Write in our new export directory + tgt.set_bytes_at_rva( + final_rva, + ref.get_data(ref_export_dir.VirtualAddress, ref_export_dir.Size) + exp_names_blob + ) + tgt.set_bytes_at_rva( + final_rva, + export_dir.__pack__() + ) + + # Rebuild from bytes to save back + tgt = pefile.PE(data = tgt.__data__) + + # Update directory specs + tgt_export_dir = tgt.OPTIONAL_HEADER.DATA_DIRECTORY[0] + tgt_export_dir.VirtualAddress = section.VirtualAddress + tgt_export_dir.Size = new_section_size + tgt = pefile.PE(data = tgt.write()) + + return tgt + + +def main(arguments): + + parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('target', help="Target DLL for modifications") + parser.add_argument('reference', help="Reference DLL from which the exports will be cloned") + parser.add_argument('-o', '--out', help="Output file path (Default = .clone.dll)", default = None) + parser.add_argument('-p', '--path', help="Full path to reference DLL while being hijacked (if is not accurate)", default = None) + parser.add_argument('-s', '--section-name', help="New section name (Default = .rdata2)", default = ".rdata2") + args = parser.parse_args(arguments) + + if not args.path: + args.path = args.reference + + if not args.out: + args.out = args.target + '.clone.dll' + + target = open(args.target, 'rb').read() + reference = open(args.reference, 'rb').read() + + # I know we could target the paths directly, + # but I want to prove that we can do it in memory + target_pe = pefile.PE(data=target) + reference_pe = pefile.PE(data=reference) + + print('[+] Loaded files') + + cloned_pe = _clone_exports(target_pe, reference_pe, args.path, args.section_name) + + cloned_bytes = cloned_pe.write() + open(args.out, 'wb').write(cloned_bytes) + + print('\n[+] Done: {}'.format(args.out)) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) \ No newline at end of file diff --git a/PyClone/PyClone.pyproj b/PyClone/PyClone.pyproj new file mode 100644 index 0000000..fb418cd --- /dev/null +++ b/PyClone/PyClone.pyproj @@ -0,0 +1,33 @@ + + + Debug + 2.0 + a2775e1e-c389-4deb-b1c7-e46a210b1748 + . + PyClone.py + + + . + . + PyClone + PyClone + + + + + true + false + + + + + + + + + + + + \ No newline at end of file diff --git a/Theif/Theif.vcxproj b/Theif/Theif.vcxproj new file mode 100644 index 0000000..0a5820a --- /dev/null +++ b/Theif/Theif.vcxproj @@ -0,0 +1,343 @@ + + + + + Dyn-NetClone + Win32 + + + Dyn-NetClone + x64 + + + Dyn-PyClone + Win32 + + + Dyn-PyClone + x64 + + + Dyn-Rebuild + Win32 + + + Dyn-Rebuild + x64 + + + Stc-Forward + Win32 + + + Stc-Forward + x64 + + + + 15.0 + {2150D252-AA17-45C2-8981-A6DCF7055CA6} + Win32Proj + Theif + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + $(ProjectName) + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + true + $(SolutionDir)Bin\$(PlatformTarget)\ + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + $(SolutionDir)Bin\NetClone.exe --target "$(TargetPath)" --output "$(TargetPath)" --reference "$(TargetDir)Functions.dll" + + + + + + + + + Level3 + Disabled + _REBUILD;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + + + + + + + + + + + Level3 + Disabled + _FORWARD;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + + + + + + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + python "$(SolutionDir)PyClone\PyClone.py" "$(TargetPath)" "$(TargetDir)Functions.dll" -o "$(TargetPath)" + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + $(SolutionDir)Bin\NetClone.exe --target "$(TargetPath)" --output "$(TargetPath)" --reference "$(TargetDir)Functions.dll" + + + + + + + + + Level3 + Disabled + _REBUILD;WIN32;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + + + + + + + + + + + Level3 + Disabled + _FORWARD;WIN32;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;THEIF_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + + + + + + + python "$(SolutionDir)PyClone\PyClone.py" "$(TargetPath)" "$(TargetDir)Functions.dll" -o "$(TargetPath)" + + + + + + + + + + + \ No newline at end of file diff --git a/Theif/Theif.vcxproj.filters b/Theif/Theif.vcxproj.filters new file mode 100644 index 0000000..0d8d9e4 --- /dev/null +++ b/Theif/Theif.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Theif/main.cpp b/Theif/main.cpp new file mode 100644 index 0000000..0d77e12 --- /dev/null +++ b/Theif/main.cpp @@ -0,0 +1,327 @@ +#include +#include +#include +#include + +#ifdef _REBUILD +BOOL RebuildExportTable(PBYTE ourBase, PBYTE targetBase); +#endif + +#ifdef _FORWARD + +#pragma comment(linker,"/export:Static=Functions.dll.Static") +#pragma comment(linker,"/export:Dynamic=Functions.dll.Dynamic") + +#else + +// Return FALSE because this is the Theif DLL +// (we shouldn't hit these) + +extern "C" __declspec(dllexport) BOOL Static() +{ + return FALSE; +}; + +extern "C" __declspec(dllexport) BOOL Dynamic() +{ + return FALSE; +}; +#endif + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason != DLL_PROCESS_ATTACH) + return TRUE; + +#ifdef _REBUILD + HMODULE real_dll = LoadLibrary(L"Functions.dll"); + RebuildExportTable((PBYTE)hinstDLL, (PBYTE)real_dll); +#endif + + return (TRUE); +} + + +#ifdef _REBUILD + +PBYTE AllocateUsableMemory(PBYTE baseAddress, DWORD size, DWORD protection = PAGE_READWRITE) { + +#ifdef _WIN64 + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)baseAddress; + PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew); + PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader; + + // Create some breathing room + baseAddress = baseAddress + optionalHeader->SizeOfImage; + + for (PBYTE offset = baseAddress; offset < baseAddress + MAXDWORD; offset += 1024 * 8) { + PBYTE usuable = (PBYTE)VirtualAlloc( + offset, + size, + MEM_RESERVE | MEM_COMMIT, + protection); + + if (usuable) { + ZeroMemory(usuable, size); // Not sure if this is required + return usuable; + } + } +#else + // In x86 it doesn't matter where we allocate + + PBYTE usuable = (PBYTE)VirtualAlloc( + NULL, + size, + MEM_RESERVE | MEM_COMMIT, + protection); + + if (usuable) { + ZeroMemory(usuable, size); + return usuable; + } +#endif + return 0; +} + +typedef struct _UNICODE_STR +{ + USHORT Length; + USHORT MaximumLength; + PWSTR pBuffer; +} UNICODE_STR, * PUNICODE_STR; + +BOOL RebuildExportTable(PBYTE ourBase, PBYTE targetBase) +{ +#ifdef _WIN64 + BYTE jmpPrefix[] = { 0x48, 0xb8 }; + BYTE jmpRax[] = { 0xff, 0xe0 }; +#else + BYTE jmpPrefix[] = { 0x68 }; + BYTE jmpRax[] = { 0xc3 }; +#endif + + std::map exports; + + /// + // 1 - Get export directories for both DLLs. Perform sanity checks. + /// + + auto targetHeaders = (PIMAGE_NT_HEADERS)(targetBase + PIMAGE_DOS_HEADER(targetBase)->e_lfanew); + auto exportDataDir = &targetHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (exportDataDir->Size == 0) + return FALSE; // The real DLL doesn't have any exports + + // TODO - Consider mixed name/ordinal exports? (NumberOfNames != NumberOfFunctions) + auto targetExportDirectory = PIMAGE_EXPORT_DIRECTORY(targetBase + exportDataDir->VirtualAddress); + + auto nameOffsetList = PDWORD(targetBase + targetExportDirectory->AddressOfNames); + auto addressList = PDWORD(targetBase + targetExportDirectory->AddressOfFunctions); + auto ordinalList = PWORD(targetBase + targetExportDirectory->AddressOfNameOrdinals); + + auto ourHeaders = (PIMAGE_NT_HEADERS)(ourBase + PIMAGE_DOS_HEADER(ourBase)->e_lfanew); + auto ourExportDataDir = &ourHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (ourExportDataDir->Size == 0) + return FALSE; // Our DLLs doesn't have any exports + + auto ourExportDirectory = PIMAGE_EXPORT_DIRECTORY(ourBase + ourExportDataDir->VirtualAddress); + + /// + // 2 - Add all of the target DLL export names and code addresses to a map + /// + + for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++) { + std::string functionName = LPSTR(targetBase + nameOffsetList[i]); + if (functionName.empty()) continue; + PBYTE code = PBYTE(targetBase + addressList[ordinalList[i]]); + exports.insert(std::pair(functionName, code)); + } + + /// + // 3 - Loop all loaded modules and patch existing IATs + /// + +#if defined(_WIN64) + auto peb = PPEB(__readgsqword(0x60)); +#else + auto peb = PPEB(__readfsdword(0x30)); +#endif + + auto ldr = peb->Ldr; + auto lpHead = &ldr->InMemoryOrderModuleList, lpCurrent = lpHead; + + while ((lpCurrent = lpCurrent->Flink) != lpHead) + { + PLDR_DATA_TABLE_ENTRY dataTable = CONTAINING_RECORD(lpCurrent, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + + auto base = PBYTE(dataTable->DllBase); + auto ntHeaders = PIMAGE_NT_HEADERS(PBYTE(dataTable->DllBase) + PIMAGE_DOS_HEADER(dataTable->DllBase)->e_lfanew); + auto iatDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]; + auto importDirectory = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; + + if (iatDirectory->Size == 0 || importDirectory->Size == 0) + continue; + + auto importList = PIMAGE_IMPORT_DESCRIPTOR(base + importDirectory->VirtualAddress); + auto iatList = PIMAGE_THUNK_DATA(base + iatDirectory->VirtualAddress); + + // Un-Protect the IAT for the module + DWORD oldProtect = 0; + if (!VirtualProtect( + iatList, + iatDirectory->Size, + PAGE_READWRITE, + &oldProtect)) { + return FALSE; + } + + CHAR ourPath[MAX_PATH]; + LPSTR ourName = ourPath; + GetModuleFileNameA((HMODULE)ourBase, ourPath, MAX_PATH); + + for (DWORD i = 0; ourPath[i] != NULL; i++) { + if (ourPath[i] == '\\' || ourPath[i] == '/') + ourName = &ourPath[i + 1]; + } + + for (; importList->OriginalFirstThunk != 0; importList++) + { + auto moduleName = LPSTR(base + importList->Name); + if (_stricmp(ourName, moduleName) != 0) + continue; + + auto thunkData = PIMAGE_THUNK_DATA(base + importList->FirstThunk); + auto originalThunkData = PIMAGE_THUNK_DATA(base + importList->OriginalFirstThunk); + + for (; originalThunkData->u1.AddressOfData != 0; originalThunkData++, thunkData++) { + if (originalThunkData->u1.AddressOfData & IMAGE_ORDINAL_FLAG) { + OutputDebugString(L"[!!] Ordinal import\n"); + continue; // Skip anything loaded by ordinal + } + + PIMAGE_IMPORT_BY_NAME importByName = PIMAGE_IMPORT_BY_NAME(base + originalThunkData->u1.AddressOfData); + std::map::const_iterator pos = exports.find(std::string(importByName->Name)); + if (pos == exports.end()) + continue; + + OutputDebugString(L"[++] Patching IAT for: "); + OutputDebugStringA(importByName->Name); + + // If the name matches, patch the address to point to the real DLL + + thunkData->u1.AddressOfData = ULONGLONG(pos->second); + } + + break; + } + + // Re-Protect the IAT for the module + if (!VirtualProtect( + iatList, + iatDirectory->Size, + oldProtect, + &oldProtect)) { + return FALSE; + } + } + + /// + // 4 - Clone our export table to match the target DLL (for GetProcAddress) + /// + + // Make current header data RW for redirections + DWORD oldProtect = 0; + if (!VirtualProtect( + ourExportDirectory, + 64, PAGE_READWRITE, + &oldProtect)) { + return FALSE; + } + + DWORD totalAllocationSize = 0; + + // Add the size of jumps + totalAllocationSize += targetExportDirectory->NumberOfFunctions * (sizeof(jmpPrefix) + sizeof(jmpRax) + sizeof(LPVOID)); + + // Add the size of function table + totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(INT); + + // Add total size of names + PINT targetAddressOfNames = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfNames); + for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++) + totalAllocationSize += (DWORD)strlen(((LPCSTR)((PBYTE)targetBase + targetAddressOfNames[i]))) + 1; + + // Add size of name table + totalAllocationSize += targetExportDirectory->NumberOfNames * sizeof(INT); + + // Add the size of ordinals: + totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(USHORT); + + // Allocate usuable memory for rebuilt export data + PBYTE exportData = AllocateUsableMemory((PBYTE)ourBase, totalAllocationSize, PAGE_READWRITE); + if (!exportData) + return FALSE; + + PBYTE sideAllocation = exportData; // Used for VirtualProtect later + + // Copy Function Table + PINT newFunctionTable = (PINT)exportData; + CopyMemory(newFunctionTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfFunctions * sizeof(INT)); + exportData += targetExportDirectory->NumberOfFunctions * sizeof(INT); + ourExportDirectory->AddressOfFunctions = DWORD((PBYTE)newFunctionTable - (PBYTE)ourBase); + + // Write JMPs and update RVAs in the new function table + PINT targetAddressOfFunctions = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfFunctions); + for (DWORD i = 0; i < targetExportDirectory->NumberOfFunctions; i++) { + newFunctionTable[i] = DWORD((exportData - (PBYTE)ourBase)); + + CopyMemory(exportData, jmpPrefix, sizeof(jmpPrefix)); + exportData += sizeof(jmpPrefix); + + PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfFunctions[i]); + CopyMemory(exportData, &realAddress, sizeof(LPVOID)); + exportData += sizeof(LPVOID); + + CopyMemory(exportData, jmpRax, sizeof(jmpRax)); + exportData += sizeof(jmpRax); + } + + // Copy Name RVA Table + PINT newNameTable = (PINT)exportData; + CopyMemory(newNameTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfNames * sizeof(DWORD)); + exportData += targetExportDirectory->NumberOfNames * sizeof(DWORD); + ourExportDirectory->AddressOfNames = DWORD(((PBYTE)newNameTable - (PBYTE)ourBase)); + + // Copy names and apply delta to all the RVAs in the new name table + for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++) { + PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfNames[i]); + DWORD length = (DWORD)strlen((LPCSTR)realAddress); + CopyMemory(exportData, realAddress, length); + newNameTable[i] = DWORD((PBYTE)exportData - (PBYTE)ourBase); + exportData += (ULONG_PTR)length + 1; + } + + // Copy Ordinal Table + PINT newOrdinalTable = (PINT)exportData; + CopyMemory(newOrdinalTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNameOrdinals, targetExportDirectory->NumberOfFunctions * sizeof(USHORT)); + exportData += targetExportDirectory->NumberOfFunctions * sizeof(USHORT); + ourExportDirectory->AddressOfNameOrdinals = DWORD((PBYTE)newOrdinalTable - (PBYTE)ourBase); + + if (!VirtualProtect( + ourExportDirectory, + 64, oldProtect, + &oldProtect)) { + return FALSE; + } + + if (!VirtualProtect( + sideAllocation, + totalAllocationSize, + PAGE_EXECUTE_READ, + &oldProtect)) { + return FALSE; + } + + return TRUE; +} + +#endif \ No newline at end of file