├── .gitattributes ├── .gitignore ├── LICENSE ├── LinuxDetours.sln ├── LinuxDetours ├── LinuxDetours.vcxproj ├── Makefile ├── barrier.cpp ├── detours.cpp ├── detours.h ├── disasm.cpp ├── limits.h ├── main.cpp ├── plthook.h ├── plthook_elf.cpp ├── readme │ ├── images │ │ ├── ArchOptions.gif │ │ ├── ChangeRemote.gif │ │ ├── ManageConnections.gif │ │ ├── OutputTypes.gif │ │ ├── debuggerexport.png │ │ ├── firstconnection.png │ │ ├── linker.png │ │ └── postbuild.png │ ├── readme.html │ └── stylesheet.css ├── trampoline_arm.cpp ├── trampoline_x86.cpp └── types.h └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thierry Bizimungu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinuxDetours.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LinuxDetours", "LinuxDetours\LinuxDetours.vcxproj", "{1F301A1B-7744-4378-833C-C4E27A096045}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Debug-Arm|ARM = Debug-Arm|ARM 15 | Debug-Arm|ARM64 = Debug-Arm|ARM64 16 | Debug-Arm|x64 = Debug-Arm|x64 17 | Debug-Arm|x86 = Debug-Arm|x86 18 | Debug-ARM64|ARM = Debug-ARM64|ARM 19 | Debug-ARM64|ARM64 = Debug-ARM64|ARM64 20 | Debug-ARM64|x64 = Debug-ARM64|x64 21 | Debug-ARM64|x86 = Debug-ARM64|x86 22 | Debug-Arm-Thumb|ARM = Debug-Arm-Thumb|ARM 23 | Debug-Arm-Thumb|ARM64 = Debug-Arm-Thumb|ARM64 24 | Debug-Arm-Thumb|x64 = Debug-Arm-Thumb|x64 25 | Debug-Arm-Thumb|x86 = Debug-Arm-Thumb|x86 26 | Release|ARM = Release|ARM 27 | Release|ARM64 = Release|ARM64 28 | Release|x64 = Release|x64 29 | Release|x86 = Release|x86 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|ARM.ActiveCfg = Debug|ARM 33 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|ARM64.ActiveCfg = Debug|ARM 34 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|x64.ActiveCfg = Debug|x64 35 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|x64.Build.0 = Debug|x64 36 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|x86.ActiveCfg = Debug|x86 37 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug|x86.Build.0 = Debug|x86 38 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|ARM.ActiveCfg = Debug-Arm|ARM 39 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|ARM.Build.0 = Debug-Arm|ARM 40 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|ARM64.ActiveCfg = Debug-Arm|x86 41 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|x64.ActiveCfg = Debug-Arm|x64 42 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|x86.ActiveCfg = Debug-Arm|x86 43 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm|x86.Build.0 = Debug-Arm|x86 44 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|ARM.ActiveCfg = Debug-ARM64|ARM 45 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|ARM64.ActiveCfg = Debug-ARM64|ARM64 46 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|ARM64.Build.0 = Debug-ARM64|ARM64 47 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|x64.ActiveCfg = Debug-ARM64|x64 48 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|x86.ActiveCfg = Debug-ARM64|x86 49 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-ARM64|x86.Build.0 = Debug-ARM64|x86 50 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|ARM.ActiveCfg = Debug-Arm-Thumb|ARM 51 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|ARM.Build.0 = Debug-Arm-Thumb|ARM 52 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|ARM64.ActiveCfg = Debug-Arm-Thumb|x86 53 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|x64.ActiveCfg = Debug-Arm-Thumb|x64 54 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|x86.ActiveCfg = Debug-Arm-Thumb|x86 55 | {1F301A1B-7744-4378-833C-C4E27A096045}.Debug-Arm-Thumb|x86.Build.0 = Debug-Arm-Thumb|x86 56 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|ARM.ActiveCfg = Release|ARM 57 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|ARM.Build.0 = Release|ARM 58 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|ARM64.ActiveCfg = Release|ARM 59 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|ARM64.Build.0 = Release|ARM 60 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|x64.ActiveCfg = Release|x64 61 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|x64.Build.0 = Release|x64 62 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|x86.ActiveCfg = Release|x86 63 | {1F301A1B-7744-4378-833C-C4E27A096045}.Release|x86.Build.0 = Release|x86 64 | EndGlobalSection 65 | GlobalSection(SolutionProperties) = preSolution 66 | HideSolutionNode = FALSE 67 | EndGlobalSection 68 | GlobalSection(ExtensibilityGlobals) = postSolution 69 | SolutionGuid = {CFDDA7EB-D2EF-4063-8F4F-2E7E2E886066} 70 | EndGlobalSection 71 | EndGlobal 72 | -------------------------------------------------------------------------------- /LinuxDetours/LinuxDetours.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug-Arm-Thumb 6 | ARM 7 | 8 | 9 | Debug-Arm-Thumb 10 | ARM64 11 | 12 | 13 | Debug-Arm-Thumb 14 | x64 15 | 16 | 17 | Debug-Arm-Thumb 18 | x86 19 | 20 | 21 | Debug-ARM64 22 | ARM 23 | 24 | 25 | Debug-ARM64 26 | ARM64 27 | 28 | 29 | Debug-ARM64 30 | x64 31 | 32 | 33 | Debug-ARM64 34 | x86 35 | 36 | 37 | Debug-Arm 38 | ARM 39 | 40 | 41 | Debug-Arm 42 | ARM64 43 | 44 | 45 | Debug-Arm 46 | x64 47 | 48 | 49 | Debug-Arm 50 | x86 51 | 52 | 53 | Debug 54 | ARM 55 | 56 | 57 | Debug 58 | ARM64 59 | 60 | 61 | Release 62 | ARM 63 | 64 | 65 | Debug 66 | x86 67 | 68 | 69 | Release 70 | ARM64 71 | 72 | 73 | Release 74 | x86 75 | 76 | 77 | Debug 78 | x64 79 | 80 | 81 | Release 82 | x64 83 | 84 | 85 | 86 | {1f301a1b-7744-4378-833c-c4e27a096045} 87 | Linux 88 | LinuxDetours 89 | 15.0 90 | Linux 91 | 1.0 92 | Generic 93 | {D51BCBC9-82E9-4017-911E-C93873C4EA2B} 94 | 95 | 96 | 97 | true 98 | 99 | 100 | true 101 | 102 | 103 | true 104 | 105 | 106 | true 107 | 108 | 109 | true 110 | 111 | 112 | true 113 | 114 | 115 | true 116 | 117 | 118 | true 119 | 120 | 121 | false 122 | 123 | 124 | false 125 | 126 | 127 | true 128 | 129 | 130 | true 131 | 132 | 133 | true 134 | 135 | 136 | true 137 | 138 | 139 | false 140 | 141 | 142 | true 143 | 144 | 145 | true 146 | 147 | 148 | true 149 | 150 | 151 | true 152 | 153 | 154 | false 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | clang++ 163 | clang++ 164 | clang++ 165 | 166 | 167 | clang++ 168 | clang++ 169 | clang++ 170 | 171 | 172 | clang++ 173 | clang++ 174 | clang++ 175 | 176 | 177 | clang++ 178 | clang++ 179 | clang++ 180 | 181 | 182 | clang++ 183 | clang++ 184 | clang++ 185 | 186 | 187 | clang++ 188 | clang++ 189 | clang++ 190 | 191 | 192 | clang++ 193 | clang++ 194 | clang++ 195 | $(IncludePath) 196 | $(LibraryPath) 197 | 198 | 199 | clang++ 200 | clang++ 201 | clang++ 202 | $(IncludePath) 203 | /usr/local/lib;$(LibraryPath) 204 | 205 | 206 | clang++ 207 | clang++ 208 | clang++ 209 | 210 | 211 | clang++ 212 | clang++ 213 | clang++ 214 | 215 | 216 | clang++ 217 | clang++ 218 | clang++ 219 | 220 | 221 | clang++ 222 | clang++ 223 | clang++ 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | _AMD64_;_UNIX64 243 | 244 | 245 | -lpthread -ldl -lglog %(AdditionalOptions) 246 | 247 | 248 | 249 | 250 | _AMD64_;DETOURS_64BIT;_WIN64 251 | 252 | 253 | -lpthread -ldl %(AdditionalOptions) 254 | 255 | 256 | 257 | 258 | _AMD64_;DETOURS_64BIT;_WIN64 259 | 260 | 261 | -lpthread -ldl %(AdditionalOptions) 262 | 263 | 264 | 265 | 266 | _AMD64_;DETOURS_64BIT;_WIN64 267 | 268 | 269 | -lpthread -ldl %(AdditionalOptions) 270 | 271 | 272 | 273 | 274 | -lpthread -ldl %(AdditionalOptions) 275 | 276 | 277 | _ARM64_ 278 | %(AdditionalOptions) 279 | 280 | 281 | 282 | 283 | -lpthread -ldl %(AdditionalOptions) 284 | 285 | 286 | _ARM64_ 287 | %(AdditionalOptions) 288 | 289 | 290 | 291 | 292 | -lpthread -ldl -lglog %(AdditionalOptions) 293 | 294 | 295 | _ARM_;_ARM32_ 296 | -mcpu=cortex-a5 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | -lpthread -ldl -lglog %(AdditionalOptions) 314 | 315 | 316 | _ARM_;_ARM32_ 317 | -v 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | -lpthread -ldl -lglog %(AdditionalOptions) 335 | 336 | 337 | _ARM64_;_UNIX64 338 | 339 | 340 | 341 | 342 | 343 | 344 | -lpthread -ldl -lglog %(AdditionalOptions) 345 | 346 | 347 | _ARM64_;_UNIX64 348 | 349 | 350 | 351 | 352 | 353 | 354 | -lpthread -ldl -lglog %(AdditionalOptions) 355 | 356 | 357 | _ARM_ 358 | -mthumb -mcpu=cortex-a5%(AdditionalOptions) 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /LinuxDetours/Makefile: -------------------------------------------------------------------------------- 1 | UNAME := $(shell uname) 2 | UNAME_M := $(shell uname -m) 3 | 4 | CXX = clang++ 5 | CXX_FLAGS = -Wall -Wno-null-conversion -std=c++11 -g -O0 -fno-omit-frame-pointer -fPIC -shared 6 | CXX_DEFINES = -lpthread -ldl -lglog 7 | 8 | SOURCES = barrier.cpp detours.cpp disasm.cpp plthook_elf.cpp 9 | 10 | TRAMPOLINE_ARM = trampoline_arm.cpp 11 | TRAMPOLINE_X86 = trampoline_x86.cpp 12 | 13 | LIB_NAME = libdetours 14 | 15 | .PHONY: linux_arm linux_arm64 linux_x64 macos_x64 16 | 17 | all: 18 | ifeq ($(UNAME),Darwin) 19 | $(MAKE) macos_x64 20 | else 21 | ifeq ($(UNAME_M),x86_64) 22 | $(MAKE) linux_x64 23 | else ifneq (,$(findstring arm,$(UNAME_M))) 24 | $(MAKE) linux_arm 25 | else 26 | $(MAKE) linux_arm64 27 | endif 28 | endif 29 | 30 | linux_x64: 31 | $(CXX) $(CXX_FLAGS) $(CXX_DEFINES) $(SOURCES) $(TRAMPOLINE_X86) -D_AMD64_ -D_UNIX64 -o $(LIB_NAME)64.so 32 | linux_arm: 33 | $(CXX) $(CXX_FLAGS) $(CXX_DEFINES) $(SOURCES) $(TRAMPOLINE_ARM) -mcpu=cortex-a5 -D_ARM_ -D_ARM32_ -o $(LIB_NAME)32.so 34 | linux_arm64: 35 | $(CXX) $(CXX_FLAGS) $(CXX_DEFINES) $(SOURCES) $(TRAMPOLINE_ARM) -D_ARM64_ -D_UNIX64 -o $(LIB_NAME)64.so 36 | macos_x64: 37 | $(CXX) $(CXX_FLAGS) $(CXX_DEFINES) $(SOURCES) $(TRAMPOLINE_X86) -D_AMD64_ -D_UNIX64 -o $(LIB_NAME)64.dylib 38 | 39 | clean: 40 | ifeq ($(UNAME),Darwin) 41 | rm -f $(LIB_NAME)64.dylib 42 | else 43 | ifneq (,$(findstring arm,$(UNAME_M))) 44 | rm -f $(LIB_NAME)32.so 45 | else 46 | rm -f $(LIB_NAME)64.so 47 | endif 48 | endif 49 | 50 | -------------------------------------------------------------------------------- /LinuxDetours/barrier.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 2 | 3 | 4 | #include "limits.h" 5 | #include "types.h" 6 | // #define DETOUR_DEBUG 1 7 | #define DETOURS_INTERNAL 8 | #include "detours.h" 9 | 10 | #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH 11 | #error detours.h version mismatch 12 | #endif 13 | 14 | // allocate at DLL Entry 15 | 16 | BARRIER_UNIT Unit; 17 | 18 | void RtlZeroMemory( 19 | PVOID InTarget, 20 | ULONG InByteCount) 21 | { 22 | ULONG Index; 23 | UCHAR* Target = (UCHAR*)InTarget; 24 | 25 | for (Index = 0; Index < InByteCount; Index++) 26 | { 27 | *Target = 0; 28 | 29 | Target++; 30 | } 31 | } 32 | void RtlInitializeLock(RTL_SPIN_LOCK* OutLock) 33 | { 34 | if (OutLock != NULL) { 35 | RtlZeroMemory(OutLock, sizeof(RTL_SPIN_LOCK)); 36 | 37 | //create mutex attribute variable 38 | pthread_mutexattr_t mAttr; 39 | 40 | // setup recursive mutex for mutex attribute 41 | pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_RECURSIVE); 42 | 43 | // Use the mutex attribute to create the mutex 44 | pthread_mutex_init(&OutLock->Lock, &mAttr); 45 | 46 | // Mutex attribute can be destroy after initializing the mutex variable 47 | pthread_mutexattr_destroy(&mAttr); 48 | } 49 | } 50 | 51 | void RtlAcquireLock(RTL_SPIN_LOCK* InLock) 52 | { 53 | if (InLock != NULL) { 54 | pthread_mutex_lock(&InLock->Lock); 55 | 56 | DETOUR_ASSERT(!InLock->IsOwned, L"barrier.cpp - !InLock->IsOwned"); 57 | 58 | InLock->IsOwned = TRUE; 59 | } 60 | } 61 | 62 | void RtlReleaseLock(RTL_SPIN_LOCK* InLock) 63 | { 64 | if (InLock != NULL) { 65 | DETOUR_ASSERT(InLock->IsOwned, L"barrier.cpp - InLock->IsOwned"); 66 | 67 | InLock->IsOwned = FALSE; 68 | 69 | pthread_mutex_unlock(&InLock->Lock); 70 | } 71 | } 72 | 73 | void RtlDeleteLock(RTL_SPIN_LOCK* InLock) 74 | { 75 | if (InLock != NULL) { 76 | DETOUR_ASSERT(!InLock->IsOwned, L"barrier.cpp - InLock->IsOwned"); 77 | 78 | pthread_mutex_destroy(&InLock->Lock); 79 | } 80 | } 81 | 82 | void RtlSleep(ULONG InTimeout) 83 | { 84 | sleep(InTimeout); 85 | } 86 | 87 | 88 | void RtlCopyMemory( 89 | PVOID InDest, 90 | PVOID InSource, 91 | ULONG InByteCount) 92 | { 93 | ULONG Index; 94 | UCHAR* Dest = (UCHAR*)InDest; 95 | UCHAR* Src = (UCHAR*)InSource; 96 | 97 | for (Index = 0; Index < InByteCount; Index++) 98 | { 99 | *Dest = *Src; 100 | 101 | Dest++; 102 | Src++; 103 | } 104 | } 105 | 106 | void* RtlAllocateMemory(BOOL InZeroMemory, ULONG InSize) 107 | { 108 | void* Result = malloc(InSize); 109 | 110 | if (InZeroMemory && (Result != NULL)) 111 | RtlZeroMemory(Result, InSize); 112 | 113 | return Result; 114 | } 115 | 116 | LONG RtlProtectMemory(void* InPointer, ULONG InSize, ULONG InNewProtection) 117 | { 118 | NTSTATUS NtStatus; 119 | 120 | if (mprotect(InPointer, (size_t)InSize, (int)InNewProtection)) 121 | THROW(-1, (PWCHAR)"Unable to make memory executable.") 122 | else 123 | RETURN; 124 | 125 | THROW_OUTRO: 126 | FINALLY_OUTRO: 127 | return NtStatus; 128 | } 129 | 130 | void RtlFreeMemory(void* InPointer) 131 | { 132 | DETOUR_ASSERT(InPointer != NULL, "barrier.cpp - InPointer != NULL"); 133 | 134 | #ifdef _DEBUG 135 | free(InPointer); 136 | #else 137 | free(InPointer); 138 | #endif 139 | } 140 | 141 | LONG RtlInterlockedIncrement(LONG* RefValue) 142 | { 143 | return __sync_fetch_and_add(RefValue, 1); 144 | } 145 | 146 | BOOL RtlIsValidPointer(PVOID InPtr, ULONG InSize) 147 | { 148 | if ((InPtr == NULL) || (InPtr == (PVOID)~0)) 149 | return FALSE; 150 | 151 | //DETOUR_ASSERT(!IsBadReadPtr(InPtr, InSize), "barrier.cpp - !IsBadReadPtr(InPtr, InSize)"); 152 | 153 | return TRUE; 154 | } 155 | 156 | static PWCHAR LastError = (PWCHAR)""; 157 | static ULONG LastErrorCode = 0; 158 | 159 | void RtlSetLastError(LONG InCode, LONG InNtStatus, WCHAR* InMessage) 160 | { 161 | LastErrorCode = InCode; 162 | 163 | if (InMessage == NULL) 164 | LastError = (PWCHAR)""; 165 | else 166 | { 167 | if (InNtStatus == 0) { 168 | 169 | } 170 | #if _DEBUG 171 | LastErrorCode = InNtStatus; 172 | #endif 173 | LastError = (PWCHAR)InMessage; 174 | } 175 | } 176 | void RtlAssert(BOOL InAssert, LPCWSTR lpMessageText) 177 | { 178 | if (InAssert) { 179 | return; 180 | } 181 | 182 | LOG(FATAL) << lpMessageText; 183 | } 184 | 185 | 186 | LONG DetourExport DetourSetGlobalInclusiveACL( 187 | ULONG* InThreadIdList, 188 | ULONG InThreadCount) 189 | { 190 | /* 191 | Description: 192 | 193 | Sets an inclusive global ACL based on the given thread ID list. 194 | 195 | Parameters: 196 | - InThreadIdList 197 | An array of thread IDs. If you specific zero for an entry in this array, 198 | it will be automatically replaced with the calling thread ID. 199 | 200 | - InThreadCount 201 | The count of entries listed in the thread ID list. This value must not exceed 202 | MAX_ACE_COUNT! 203 | */ 204 | return DetourSetACL(DetourBarrierGetAcl(), FALSE, InThreadIdList, InThreadCount); 205 | } 206 | 207 | LONG DetourExport DetourSetGlobalExclusiveACL( 208 | ULONG* InThreadIdList, 209 | ULONG InThreadCount) 210 | { 211 | /* 212 | Description: 213 | 214 | Sets an exclusive global ACL based on the given thread ID list. 215 | 216 | Parameters: 217 | - InThreadIdList 218 | An array of thread IDs. If you specific zero for an entry in this array, 219 | it will be automatically replaced with the calling thread ID. 220 | 221 | - InThreadCount 222 | The count of entries listed in the thread ID list. This value must not exceed 223 | MAX_ACE_COUNT! 224 | */ 225 | return DetourSetACL(DetourBarrierGetAcl(), TRUE, InThreadIdList, InThreadCount); 226 | } 227 | 228 | BOOL DetourIsValidHandle( 229 | TRACED_HOOK_HANDLE InTracedHandle, 230 | PLOCAL_HOOK_INFO* OutHandle) 231 | { 232 | /* 233 | Description: 234 | 235 | A handle is considered to be valid, if the whole structure 236 | points to valid memory AND the signature is valid AND the 237 | hook is installed! 238 | 239 | */ 240 | if (!IsValidPointer(InTracedHandle, sizeof(HOOK_TRACE_INFO))) 241 | return FALSE; 242 | 243 | if (OutHandle != NULL) 244 | *OutHandle = InTracedHandle->Link; 245 | 246 | return TRUE; 247 | } 248 | LONG DetourSetACL( 249 | HOOK_ACL* InAcl, 250 | BOOL InIsExclusive, 251 | ULONG* InThreadIdList, 252 | ULONG InThreadCount) 253 | { 254 | /* 255 | Description: 256 | 257 | This method is used internally to provide a generic interface to 258 | either the global or local hook ACLs. 259 | 260 | Parameters: 261 | - InAcl 262 | NULL if you want to set the global ACL. 263 | Any LOCAL_HOOK_INFO::LocalACL to set the hook specific ACL. 264 | 265 | - InIsExclusive 266 | TRUE if all listed thread shall be excluded from interception, 267 | FALSE otherwise 268 | 269 | - InThreadIdList 270 | An array of thread IDs. If you specific zero for an entry in this array, 271 | it will be automatically replaced with the calling thread ID. 272 | 273 | - InThreadCount 274 | The count of entries listed in the thread ID list. This value must not exceed 275 | MAX_ACE_COUNT! 276 | */ 277 | 278 | ULONG Index; 279 | 280 | DETOUR_ASSERT(IsValidPointer(InAcl, sizeof(HOOK_ACL)), "barrier.cpp - IsValidPointer(InAcl, sizeof(HOOK_ACL))"); 281 | 282 | if (InThreadCount > MAX_ACE_COUNT) 283 | return -2; 284 | 285 | if (!IsValidPointer(InThreadIdList, InThreadCount * sizeof(ULONG))) 286 | return -1; 287 | 288 | for (Index = 0; Index < InThreadCount; Index++) 289 | { 290 | if (InThreadIdList[Index] == 0) 291 | InThreadIdList[Index] = (ULONG)pthread_self(); 292 | } 293 | 294 | // set ACL... 295 | if (!mprotect(detour_get_page(InAcl), detour_get_page_size(), PAGE_READWRITE)) { 296 | InAcl->IsExclusive = InIsExclusive; 297 | InAcl->Count = InThreadCount; 298 | 299 | RtlCopyMemory(InAcl->Entries, InThreadIdList, InThreadCount * sizeof(ULONG)); 300 | if (mprotect(detour_get_page(InAcl), detour_get_page_size(), PAGE_EXECUTE_READ)) { 301 | 302 | return -3; 303 | } 304 | } 305 | return 0; 306 | } 307 | 308 | HOOK_ACL* DetourBarrierGetAcl() 309 | { 310 | return &Unit.GlobalACL; 311 | } 312 | 313 | LONG DetourExport DetourBarrierProcessAttach() 314 | { 315 | /* 316 | Description: 317 | 318 | Will be called on DLL load and initializes all barrier structures. 319 | */ 320 | RtlZeroMemory(&Unit, sizeof(Unit)); 321 | 322 | // globally accept all threads... 323 | Unit.GlobalACL.IsExclusive = TRUE; 324 | 325 | // allocate private heap 326 | RtlInitializeLock(&Unit.TLS.ThreadSafe); 327 | 328 | //Unit.IsInitialized = AuxUlibInitialize()?TRUE:FALSE; 329 | Unit.IsInitialized = TRUE; 330 | 331 | return STATUS_SUCCESS; 332 | } 333 | 334 | 335 | BOOL TlsGetCurrentValue( 336 | THREAD_LOCAL_STORAGE* InTls, 337 | THREAD_RUNTIME_INFO** OutValue) 338 | { 339 | /* 340 | Description: 341 | 342 | Queries the THREAD_RUNTIME_INFO for the calling thread. 343 | The caller shall previously be added to the storage by 344 | using TlsAddCurrentThread(). 345 | 346 | Parameters: 347 | 348 | - InTls 349 | 350 | The storage where the caller is registered. 351 | 352 | - OutValue 353 | 354 | Is filled with a pointer to the caller's private storage entry. 355 | 356 | Returns: 357 | 358 | FALSE if the caller was not registered in the storage, TRUE otherwise. 359 | */ 360 | ULONG CurrentId = (ULONG)pthread_self(); 361 | 362 | LONG Index; 363 | 364 | for (Index = 0; Index < MAX_THREAD_COUNT; Index++) 365 | { 366 | if (InTls->IdList[Index] == CurrentId) 367 | { 368 | *OutValue = &InTls->Entries[Index]; 369 | 370 | return TRUE; 371 | } 372 | } 373 | 374 | return FALSE; 375 | } 376 | BOOL TlsAddCurrentThread(THREAD_LOCAL_STORAGE* InTls) 377 | { 378 | /* 379 | Description: 380 | 381 | Tries to reserve a THREAD_RUNTIME_INFO entry for the calling thread. 382 | On success it may call TlsGetCurrentValue() to query a pointer to 383 | its private entry. 384 | 385 | This is a replacement for the Windows Thread Local Storage which seems 386 | to cause trouble when using it in Explorer.EXE for example. 387 | 388 | No parameter validation (for performance reasons). 389 | 390 | This method will raise an assertion if the thread was already added 391 | to the storage! 392 | 393 | Parameters: 394 | - InTls 395 | 396 | The thread local storage to allocate from. 397 | 398 | Returns: 399 | 400 | TRUE on success, FALSE otherwise. 401 | */ 402 | ULONG CurrentId = (ULONG)pthread_self(); 403 | 404 | LONG Index = -1; 405 | LONG i; 406 | 407 | RtlAcquireLock(&InTls->ThreadSafe); 408 | 409 | // select Index AND check whether thread is already registered. 410 | for (i = 0; i < MAX_THREAD_COUNT; i++) 411 | { 412 | if ((InTls->IdList[i] == 0) && (Index == -1)) 413 | Index = i; 414 | 415 | DETOUR_ASSERT(InTls->IdList[i] != CurrentId, "barrier.cpp - InTls->IdList[i] != CurrentId"); 416 | } 417 | 418 | if (Index == -1) 419 | { 420 | RtlReleaseLock(&InTls->ThreadSafe); 421 | 422 | return FALSE; 423 | } 424 | 425 | InTls->IdList[Index] = CurrentId; 426 | RtlZeroMemory(&InTls->Entries[Index], sizeof(THREAD_RUNTIME_INFO)); 427 | 428 | RtlReleaseLock(&InTls->ThreadSafe); 429 | 430 | return TRUE; 431 | } 432 | 433 | void TlsRemoveCurrentThread(THREAD_LOCAL_STORAGE* InTls) 434 | { 435 | /* 436 | Description: 437 | 438 | Removes the caller from the local storage. If the caller 439 | is already removed, the method will do nothing. 440 | 441 | Parameters: 442 | 443 | - InTls 444 | 445 | The storage from which the caller should be removed. 446 | */ 447 | ULONG CurrentId = (ULONG)pthread_self(); 448 | ULONG Index; 449 | 450 | RtlAcquireLock(&InTls->ThreadSafe); 451 | 452 | for (Index = 0; Index < MAX_THREAD_COUNT; Index++) 453 | { 454 | if (InTls->IdList[Index] == CurrentId) 455 | { 456 | InTls->IdList[Index] = 0; 457 | 458 | RtlZeroMemory(&InTls->Entries[Index], sizeof(THREAD_RUNTIME_INFO)); 459 | } 460 | } 461 | 462 | RtlReleaseLock(&InTls->ThreadSafe); 463 | } 464 | 465 | void DetourBarrierProcessDetach() 466 | { 467 | /* 468 | Description: 469 | 470 | Will be called on DLL unload. 471 | */ 472 | ULONG Index; 473 | 474 | RtlDeleteLock(&Unit.TLS.ThreadSafe); 475 | 476 | // release thread specific resources 477 | for (Index = 0; Index < MAX_THREAD_COUNT; Index++) 478 | { 479 | if (Unit.TLS.Entries[Index].Entries != NULL) 480 | RtlFreeMemory(Unit.TLS.Entries[Index].Entries); 481 | } 482 | 483 | RtlZeroMemory(&Unit, sizeof(Unit)); 484 | } 485 | 486 | void DetourExport DetourBarrierThreadDetach() 487 | { 488 | /* 489 | Description: 490 | 491 | Will be called on thread termination and cleans up the TLS. 492 | */ 493 | LPTHREAD_RUNTIME_INFO Info; 494 | 495 | if (TlsGetCurrentValue(&Unit.TLS, &Info)) 496 | { 497 | if (Info->Entries != NULL) 498 | RtlFreeMemory(Info->Entries); 499 | 500 | Info->Entries = NULL; 501 | } 502 | 503 | TlsRemoveCurrentThread(&Unit.TLS); 504 | } 505 | 506 | RTL_SPIN_LOCK GlobalHookLock; 507 | 508 | void DetourCriticalInitialize() 509 | { 510 | /* 511 | Description: 512 | 513 | Fail safe initialization of global hooking structures... 514 | */ 515 | 516 | RtlInitializeLock(&GlobalHookLock); 517 | } 518 | 519 | void DetourCriticalFinalize() 520 | { 521 | /* 522 | Description: 523 | 524 | Will be called in the DLL_PROCESS_DETACH event and just uninstalls 525 | all hooks. If it is possible also their memory is released. 526 | */ 527 | RtlDeleteLock(&GlobalHookLock); 528 | } 529 | 530 | BOOL IsLoaderLock() 531 | { 532 | /* 533 | Returns: 534 | 535 | TRUE if the current thread hols the OS loader lock, or the library was not initialized 536 | properly. In both cases a hook handler should not be executed! 537 | 538 | FALSE if it is safe to execute the hook handler. 539 | 540 | */ 541 | return FALSE; 542 | } 543 | 544 | 545 | BOOL AcquireSelfProtection() 546 | { 547 | /* 548 | Description: 549 | 550 | To provide more convenience for writing the TDB, this self protection 551 | will disable ALL hooks for the current thread until ReleaseSelfProtection() 552 | is called. This allows one to call any API during TDB initialization 553 | without being intercepted... 554 | 555 | Returns: 556 | 557 | TRUE if the caller's runtime info has been locked down. 558 | 559 | FALSE if the caller's runtime info already has been locked down 560 | or is not available. The hook handler should not be executed in 561 | this case! 562 | 563 | */ 564 | LPTHREAD_RUNTIME_INFO Runtime = NULL; 565 | 566 | if (!TlsGetCurrentValue(&Unit.TLS, &Runtime) || Runtime->IsProtected) 567 | return FALSE; 568 | 569 | Runtime->IsProtected = TRUE; 570 | 571 | return TRUE; 572 | } 573 | 574 | void DetourExport ReleaseSelfProtection() 575 | { 576 | /* 577 | Description: 578 | 579 | Exists the TDB self protection. Refer to AcquireSelfProtection() for more 580 | information. 581 | 582 | An assertion is raised if the caller has not owned the self protection. 583 | */ 584 | LPTHREAD_RUNTIME_INFO Runtime = NULL; 585 | 586 | DETOUR_ASSERT(TlsGetCurrentValue(&Unit.TLS, &Runtime) && Runtime->IsProtected, "barrier.cpp - TlsGetCurrentValue(&Unit.TLS, &Runtime) && Runtime->IsProtected"); 587 | 588 | Runtime->IsProtected = FALSE; 589 | } 590 | 591 | 592 | 593 | BOOL ACLContains( 594 | HOOK_ACL* InACL, 595 | ULONG InCheckID) 596 | { 597 | /* 598 | Returns: 599 | 600 | TRUE if the given ACL contains the given ID, FALSE otherwise. 601 | */ 602 | ULONG Index; 603 | 604 | for (Index = 0; Index < InACL->Count; Index++) 605 | { 606 | if (InACL->Entries[Index] == InCheckID) 607 | return TRUE; 608 | } 609 | 610 | return FALSE; 611 | } 612 | 613 | 614 | BOOL DetourExport IsThreadIntercepted( 615 | HOOK_ACL* LocalACL, 616 | ULONG InThreadID) 617 | { 618 | /* 619 | Description: 620 | 621 | Please refer to DetourIsThreadIntercepted() for more information. 622 | 623 | Returns: 624 | 625 | TRUE if the given thread is intercepted by the global AND local ACL, 626 | FALSE otherwise. 627 | */ 628 | ULONG CheckID; 629 | 630 | if (InThreadID == 0) 631 | CheckID = (ULONG)pthread_self(); 632 | else 633 | CheckID = InThreadID; 634 | 635 | if (ACLContains(&Unit.GlobalACL, CheckID)) 636 | { 637 | if (ACLContains(LocalACL, CheckID)) 638 | { 639 | if (LocalACL->IsExclusive) 640 | return FALSE; 641 | } 642 | else 643 | { 644 | if (!LocalACL->IsExclusive) 645 | return FALSE; 646 | } 647 | 648 | return !Unit.GlobalACL.IsExclusive; 649 | } 650 | else 651 | { 652 | if (ACLContains(LocalACL, CheckID)) 653 | { 654 | if (LocalACL->IsExclusive) 655 | return FALSE; 656 | } 657 | else 658 | { 659 | if (!LocalACL->IsExclusive) 660 | return FALSE; 661 | } 662 | 663 | return Unit.GlobalACL.IsExclusive; 664 | } 665 | } 666 | 667 | LONG DetourExport DetourBarrierGetCallback(PVOID* OutValue) 668 | { 669 | /* 670 | Description: 671 | 672 | Is expected to be called inside a hook handler. Otherwise it 673 | will fail with STATUS_NOT_SUPPORTED. The method retrieves 674 | the callback initially passed to the related DetourInstallHook() 675 | call. 676 | 677 | */ 678 | LONG NtStatus; 679 | LPTHREAD_RUNTIME_INFO Runtime; 680 | 681 | if (!IsValidPointer(OutValue, sizeof(PVOID))) 682 | THROW(STATUS_INVALID_PARAMETER, (PWCHAR)"Invalid result storage specified."); 683 | 684 | if (!TlsGetCurrentValue(&Unit.TLS, &Runtime)) 685 | THROW(-1, (PWCHAR)("The caller is not inside a hook handler.")); 686 | 687 | if (Runtime->Current != NULL) 688 | *OutValue = Runtime->Callback; 689 | else 690 | THROW(-1, (PWCHAR)"The caller is not inside a hook handler."); 691 | 692 | RETURN; 693 | 694 | THROW_OUTRO: 695 | FINALLY_OUTRO: 696 | return NtStatus; 697 | } 698 | 699 | PWCHAR DetourExport RtlGetLastErrorStringCopy() 700 | { 701 | ULONG len = (ULONG)(strlen(LastError) + 1) * sizeof(PWCHAR); 702 | PWCHAR pBuffer = (PWCHAR)malloc(len); 703 | CopyMemory(pBuffer, LastError, len); 704 | 705 | return pBuffer; 706 | } 707 | 708 | PWCHAR DetourExport RtlGetLastErrorString() 709 | { 710 | return LastError; 711 | } -------------------------------------------------------------------------------- /LinuxDetours/detours.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | ///////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Core Detours Functionality 5 | // 6 | // 7 | 8 | #ifndef _DETOURS_H_ 9 | #define _DETOURS_H_ 10 | 11 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 12 | 13 | ////////////////////////////////////////////////////////////////////////////// 14 | // 15 | #include "types.h" 16 | 17 | #undef DETOURS_X64 18 | #undef DETOURS_X86 19 | #undef DETOURS_IA64 20 | #undef DETOURS_ARM 21 | #undef DETOURS_ARM64 22 | #undef DETOURS_BITS 23 | #undef DETOURS_32BIT 24 | #undef DETOURS_64BIT 25 | 26 | #if defined(_X86_) 27 | #define DETOURS_X86 28 | #define DETOURS_OPTION_BITS 64 29 | 30 | #elif defined(_AMD64_) 31 | #define DETOURS_X64 32 | #define DETOURS_OPTION_BITS 32 33 | 34 | #elif defined(_IA64_) 35 | #define DETOURS_IA64 36 | #define DETOURS_OPTION_BITS 32 37 | 38 | #elif defined(_ARM_) 39 | #define DETOURS_ARM 40 | #if defined(_ARM32_) 41 | #define DETOURS_ARM32 42 | #endif 43 | #elif defined(_ARM64_) 44 | #define DETOURS_ARM64 45 | 46 | #else 47 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 48 | #endif 49 | 50 | #ifdef _UNIX64 51 | #undef DETOURS_32BIT 52 | #define DETOURS_64BIT 1 53 | #define DETOURS_BITS 64 54 | // If all 64bit kernels can run one and only one 32bit architecture. 55 | //#define DETOURS_OPTION_BITS 32 56 | #else 57 | #define DETOURS_32BIT 1 58 | #undef DETOURS_64BIT 59 | #define DETOURS_BITS 32 60 | // If all 64bit kernels can run one and only one 32bit architecture. 61 | //#define DETOURS_OPTION_BITS 32 62 | #endif 63 | 64 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 65 | #define DetourExport __attribute__((visibility("default"))) 66 | ////////////////////////////////////////////////////////////////////////////// 67 | // 68 | 69 | #if (_MSC_VER < 1299) 70 | typedef UINT64 LONG_PTR; 71 | typedef UINT64 ULONG_PTR; 72 | #endif 73 | #define ERROR_INVALID_OPERATION 4317L 74 | #define ERROR_DS_DRA_INVALID_PARAMETER 8437L 75 | #define ERROR_NOT_ENOUGH_MEMORY 8L // dderror 76 | #define ERROR_INVALID_BLOCK 9L 77 | #define ERROR_INVALID_HANDLE 6L 78 | #define ERROR_INVALID_PARAMETER 87L // dderror 79 | #define __debugbreak() 80 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 81 | // 82 | // These definitions are include so that Detours will build even if the 83 | // compiler doesn't have full SAL 2.0 support. 84 | // 85 | #ifndef DETOURS_DONT_REMOVE_SAL_20 86 | 87 | #ifdef DETOURS_TEST_REMOVE_SAL_20 88 | #undef _Analysis_assume_ 89 | #undef _Benign_race_begin_ 90 | #undef _Benign_race_end_ 91 | #undef _Field_range_ 92 | #undef _Field_size_ 93 | #undef _In_ 94 | #undef _In_bytecount_ 95 | #undef _In_count_ 96 | #undef _In_opt_ 97 | #undef _In_opt_bytecount_ 98 | #undef _In_opt_count_ 99 | #undef _In_opt_z_ 100 | #undef _In_range_ 101 | #undef _In_reads_ 102 | #undef _In_reads_bytes_ 103 | #undef _In_reads_opt_ 104 | #undef _In_reads_opt_bytes_ 105 | #undef _In_reads_or_z_ 106 | #undef _In_z_ 107 | #undef _Inout_ 108 | #undef _Inout_opt_ 109 | #undef _Inout_z_count_ 110 | #undef _Out_ 111 | #undef _Out_opt_ 112 | #undef _Out_writes_ 113 | #undef _Outptr_result_maybenull_ 114 | #undef _Readable_bytes_ 115 | #undef _Success_ 116 | #undef _Writable_bytes_ 117 | #undef _Pre_notnull_ 118 | #endif 119 | 120 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 121 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 122 | #endif 123 | 124 | #if defined(_In_count_) && !defined(_In_reads_) 125 | #define _In_reads_(x) _In_count_(x) 126 | #endif 127 | 128 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 129 | #define _In_reads_opt_(x) _In_opt_count_(x) 130 | #endif 131 | 132 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 133 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 134 | #endif 135 | 136 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 137 | #define _In_reads_bytes_(x) _In_bytecount_(x) 138 | #endif 139 | 140 | #ifndef _In_ 141 | #define _In_ 142 | #endif 143 | 144 | #ifndef _In_bytecount_ 145 | #define _In_bytecount_(x) 146 | #endif 147 | 148 | #ifndef _In_count_ 149 | #define _In_count_(x) 150 | #endif 151 | 152 | #ifndef _In_opt_ 153 | #define _In_opt_ 154 | #endif 155 | 156 | #ifndef _In_opt_bytecount_ 157 | #define _In_opt_bytecount_(x) 158 | #endif 159 | 160 | #ifndef _In_opt_count_ 161 | #define _In_opt_count_(x) 162 | #endif 163 | 164 | #ifndef _In_opt_z_ 165 | #define _In_opt_z_ 166 | #endif 167 | 168 | #ifndef _In_range_ 169 | #define _In_range_(x,y) 170 | #endif 171 | 172 | #ifndef _In_reads_ 173 | #define _In_reads_(x) 174 | #endif 175 | 176 | #ifndef _In_reads_bytes_ 177 | #define _In_reads_bytes_(x) 178 | #endif 179 | 180 | #ifndef _In_reads_opt_ 181 | #define _In_reads_opt_(x) 182 | #endif 183 | 184 | #ifndef _In_reads_opt_bytes_ 185 | #define _In_reads_opt_bytes_(x) 186 | #endif 187 | 188 | #ifndef _In_reads_or_z_ 189 | #define _In_reads_or_z_ 190 | #endif 191 | 192 | #ifndef _In_z_ 193 | #define _In_z_ 194 | #endif 195 | 196 | #ifndef _Inout_ 197 | #define _Inout_ 198 | #endif 199 | 200 | #ifndef _Inout_opt_ 201 | #define _Inout_opt_ 202 | #endif 203 | 204 | #ifndef _Inout_z_count_ 205 | #define _Inout_z_count_(x) 206 | #endif 207 | 208 | #ifndef _Out_ 209 | #define _Out_ 210 | #endif 211 | 212 | #ifndef _Out_opt_ 213 | #define _Out_opt_ 214 | #endif 215 | 216 | #ifndef _Out_writes_ 217 | #define _Out_writes_(x) 218 | #endif 219 | 220 | #ifndef _Outptr_result_maybenull_ 221 | #define _Outptr_result_maybenull_ 222 | #endif 223 | 224 | #ifndef _Writable_bytes_ 225 | #define _Writable_bytes_(x) 226 | #endif 227 | 228 | #ifndef _Readable_bytes_ 229 | #define _Readable_bytes_(x) 230 | #endif 231 | 232 | #ifndef _Success_ 233 | #define _Success_(x) 234 | #endif 235 | 236 | #ifndef _Pre_notnull_ 237 | #define _Pre_notnull_ 238 | #endif 239 | 240 | #ifdef DETOURS_INTERNAL 241 | 242 | #ifndef _Benign_race_begin_ 243 | #define _Benign_race_begin_ 244 | #endif 245 | 246 | #ifndef _Benign_race_end_ 247 | #define _Benign_race_end_ 248 | #endif 249 | 250 | #ifndef _Field_size_ 251 | #define _Field_size_(x) 252 | #endif 253 | 254 | #ifndef _Field_range_ 255 | #define _Field_range_(x,y) 256 | #endif 257 | 258 | #ifndef _Analysis_assume_ 259 | #define _Analysis_assume_(x) 260 | #endif 261 | 262 | #endif // DETOURS_INTERNAL 263 | #endif // DETOURS_DONT_REMOVE_SAL_20 264 | 265 | ////////////////////////////////////////////////////////////////////////////// 266 | // 267 | #ifndef GUID_DEFINED 268 | #define GUID_DEFINED 269 | typedef struct _GUID 270 | { 271 | DWORD Data1; 272 | WORD Data2; 273 | WORD Data3; 274 | BYTE Data4[8]; 275 | } GUID; 276 | 277 | #ifdef INITGUID 278 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 279 | const GUID name \ 280 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 281 | #else 282 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 283 | const GUID name 284 | #endif // INITGUID 285 | #endif // !GUID_DEFINED 286 | 287 | #if defined(__cplusplus) 288 | #ifndef _REFGUID_DEFINED 289 | #define _REFGUID_DEFINED 290 | #define REFGUID const GUID & 291 | #endif // !_REFGUID_DEFINED 292 | #else // !__cplusplus 293 | #ifndef _REFGUID_DEFINED 294 | #define _REFGUID_DEFINED 295 | #define REFGUID const GUID * const 296 | #endif // !_REFGUID_DEFINED 297 | #endif // !__cplusplus 298 | 299 | #ifndef ARRAYSIZE 300 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 301 | #endif 302 | 303 | // 304 | ////////////////////////////////////////////////////////////////////////////// 305 | 306 | #ifdef __cplusplus 307 | extern "C" { 308 | #endif // __cplusplus 309 | 310 | /////////////////////////////////////////////////// Instruction Target Macros. 311 | // 312 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 313 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 314 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 315 | 316 | extern const GUID DETOUR_EXE_RESTORE_GUID; 317 | extern const GUID DETOUR_EXE_HELPER_GUID; 318 | 319 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 320 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 321 | 322 | /////////////////////////////////////////////////////////// Binary Structures. 323 | // 324 | 325 | 326 | 327 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 328 | { \ 329 | sizeof(DETOUR_SECTION_HEADER),\ 330 | DETOUR_SECTION_HEADER_SIGNATURE,\ 331 | sizeof(DETOUR_SECTION_HEADER),\ 332 | (cbSectionSize),\ 333 | \ 334 | 0,\ 335 | 0,\ 336 | 0,\ 337 | 0,\ 338 | \ 339 | 0,\ 340 | 0,\ 341 | 0,\ 342 | 0,\ 343 | } 344 | 345 | /////////////////////////////////////////////////////////////// Helper Macros. 346 | // 347 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 348 | #define DETOURS_STRINGIFY_(x) #x 349 | 350 | ///////////////////////////////////////////////////////////// Binary Typedefs. 351 | // 352 | /* 353 | typedef BOOL(CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 354 | _In_opt_ PVOID pContext, 355 | _In_opt_ LPCSTR pszFile, 356 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 357 | 358 | typedef BOOL(CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 359 | _In_opt_ PVOID pContext, 360 | _In_ LPCSTR pszOrigFile, 361 | _In_ LPCSTR pszFile, 362 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 363 | 364 | typedef BOOL(CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 365 | _In_opt_ PVOID pContext, 366 | _In_ ULONG nOrigOrdinal, 367 | _In_ ULONG nOrdinal, 368 | _Out_ ULONG *pnOutOrdinal, 369 | _In_opt_ LPCSTR pszOrigSymbol, 370 | _In_opt_ LPCSTR pszSymbol, 371 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 372 | 373 | typedef BOOL(CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 374 | _In_opt_ PVOID pContext); 375 | 376 | typedef BOOL(CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 377 | _In_ ULONG nOrdinal, 378 | _In_opt_ LPCSTR pszName, 379 | _In_opt_ PVOID pCode); 380 | 381 | typedef BOOL(CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 382 | _In_opt_ HMODULE hModule, 383 | _In_opt_ LPCSTR pszFile); 384 | 385 | typedef BOOL(CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 386 | _In_ DWORD nOrdinal, 387 | _In_opt_ LPCSTR pszFunc, 388 | _In_opt_ PVOID pvFunc); 389 | 390 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 391 | typedef BOOL(CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 392 | _In_ DWORD nOrdinal, 393 | _In_opt_ LPCSTR pszFunc, 394 | _In_opt_ PVOID* ppvFunc);*/ 395 | 396 | typedef VOID * PDETOUR_BINARY; 397 | typedef VOID * PDETOUR_LOADED_BINARY; 398 | 399 | //////////////////////////////////////////////////////////// Transaction APIs. 400 | // 401 | LONG DetourTransactionBegin(VOID); 402 | LONG DetourTransactionAbort(VOID); 403 | LONG DetourTransactionCommit(VOID); 404 | 405 | 406 | ////////////////////////////////////////////////////////////////////////////// 407 | // 408 | // dotnet trampoline barrier definitions 409 | // 410 | #define MAX_HOOK_COUNT 1024 411 | #define MAX_ACE_COUNT 128 412 | #define MAX_THREAD_COUNT 128 413 | #define MAX_PASSTHRU_SIZE 1024 * 64 414 | 415 | #define DETOUR_ASSERT(expr, Msg) RtlAssert((BOOL)(expr),(LPCWSTR) Msg); 416 | #define THROW(code, Msg) { NtStatus = (code); RtlSetLastError(0, NtStatus, Msg); goto THROW_OUTRO; } 417 | 418 | #define RTL_SUCCESS(ntstatus) SUCCEEDED(ntstatus) 419 | 420 | #define STATUS_SUCCESS 0 421 | #define RETURN { RtlSetLastError(STATUS_SUCCESS, STATUS_SUCCESS, (PWCHAR)""); NtStatus = STATUS_SUCCESS; goto FINALLY_OUTRO; } 422 | #define FORCE(expr) { if(!RTL_SUCCESS(NtStatus = (expr))) goto THROW_OUTRO; } 423 | #define IsValidPointer RtlIsValidPointer 424 | 425 | #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) ) 426 | BOOL RtlIsValidPointer(PVOID InPtr, ULONG InSize); 427 | 428 | typedef struct _DETOUR_TRAMPOLINE * PLOCAL_HOOK_INFO; 429 | 430 | typedef struct _HOOK_ACL_ 431 | { 432 | ULONG Count; 433 | BOOL IsExclusive; 434 | ULONG Entries[MAX_ACE_COUNT]; 435 | }HOOK_ACL; 436 | 437 | typedef struct _HOOK_TRACE_INFO_ 438 | { 439 | PLOCAL_HOOK_INFO Link; 440 | }HOOK_TRACE_INFO, *TRACED_HOOK_HANDLE; 441 | 442 | /* 443 | Setup the ACLs after hook installation. Please note that every 444 | hook starts suspended. You will have to set a proper ACL to 445 | make it active! 446 | */ 447 | 448 | LONG DetourSetInclusiveACL( 449 | ULONG* InThreadIdList, 450 | ULONG InThreadCount, 451 | TRACED_HOOK_HANDLE InHandle); 452 | 453 | LONG DetourSetExclusiveACL( 454 | ULONG* InThreadIdList, 455 | ULONG InThreadCount, 456 | TRACED_HOOK_HANDLE InHandle); 457 | 458 | LONG DetourSetGlobalInclusiveACL( 459 | ULONG* InThreadIdList, 460 | ULONG InThreadCount); 461 | 462 | LONG DetourSetGlobalExclusiveACL( 463 | ULONG* InThreadIdList, 464 | ULONG InThreadCount); 465 | 466 | LONG DetourIsThreadIntercepted( 467 | TRACED_HOOK_HANDLE InHook, 468 | ULONG InThreadID, 469 | BOOL* OutResult); 470 | 471 | LONG DetourSetACL( 472 | HOOK_ACL* InAcl, 473 | BOOL InIsExclusive, 474 | ULONG* InThreadIdList, 475 | ULONG InThreadCount); 476 | 477 | HOOK_ACL* DetourBarrierGetAcl(); 478 | /* 479 | The following barrier methods are meant to be used in hook handlers only! 480 | 481 | They will all fail with STATUS_NOT_SUPPORTED if called outside a 482 | valid hook handler... 483 | */ 484 | LONG DetourBarrierGetCallback(PVOID* OutValue); 485 | 486 | LONG DetourBarrierGetReturnAddress(PVOID* OutValue); 487 | 488 | LONG DetourBarrierGetAddressOfReturnAddress(PVOID** OutValue); 489 | 490 | LONG DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 491 | 492 | LONG DetourUpdateThread(_In_ pthread_t hThread); 493 | 494 | LONG DetourAttach(_Inout_ PVOID *ppPointer, 495 | _In_ PVOID pDetour); 496 | 497 | LONG DetourAttachEx(_Inout_ PVOID *ppPointer, 498 | _In_ PVOID pDetour, 499 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 500 | _Out_opt_ PVOID *ppRealTarget, 501 | _Out_opt_ PVOID *ppRealDetour); 502 | 503 | LONG DetourDetach(_Inout_ PVOID *ppPointer, 504 | _In_ PVOID pDetour); 505 | 506 | BOOL DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 507 | BOOL DetourSetRetainRegions(_In_ BOOL fRetain); 508 | PVOID DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 509 | PVOID DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 510 | 511 | void DetourBarrierThreadDetach(); 512 | 513 | LONG DetourBarrierProcessAttach(); 514 | void DetourBarrierProcessDetach(); 515 | 516 | void DetourCriticalInitialize(); 517 | void DetourCriticalFinalize(); 518 | 519 | LONG DetourInstallHook( 520 | void* InEntryPoint, 521 | void* InHookProc, 522 | void* InCallback, 523 | TRACED_HOOK_HANDLE OutHandle); 524 | 525 | LONG DetourUninstallHook(TRACED_HOOK_HANDLE InHandle); 526 | 527 | 528 | ////////////////////////////////////////////////////////////// Code Functions. 529 | // 530 | PVOID DetourFindFunction(_In_ LPCSTR pszModule, 531 | _In_ LPCSTR pszFunction); 532 | PVOID DetourCodeFromPointer(_In_ PVOID pPointer, 533 | _Out_opt_ PVOID *ppGlobals); 534 | PVOID DetourCopyInstruction(_In_opt_ PVOID pDst, 535 | _Inout_opt_ PVOID *ppDstPool, 536 | _In_ PVOID pSrc, 537 | _Out_opt_ PVOID *ppTarget, 538 | _Out_opt_ LONG *plExtra); 539 | 540 | 541 | ///////////////////////////////////////////////////// Loaded Binary Functions. 542 | // 543 | HMODULE DetourGetContainingModule(_In_ PVOID pvAddr); 544 | HMODULE DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); 545 | PVOID DetourGetEntryPoint(_In_opt_ HMODULE hModule); 546 | ULONG DetourGetModuleSize(_In_opt_ HMODULE hModule); 547 | 548 | 549 | _Writable_bytes_(*pcbData) 550 | _Readable_bytes_(*pcbData) 551 | _Success_(return != NULL) 552 | PVOID DetourFindPayload(_In_opt_ HMODULE hModule, 553 | _In_ REFGUID rguid, 554 | _Out_ DWORD *pcbData); 555 | 556 | _Writable_bytes_(*pcbData) 557 | _Readable_bytes_(*pcbData) 558 | _Success_(return != NULL) 559 | PVOID DetourFindPayloadEx(_In_ REFGUID rguid, 560 | _Out_ DWORD * pcbData); 561 | 562 | DWORD DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); 563 | 564 | ///////////////////////////////////////////////// Persistent Binary Functions. 565 | // 566 | 567 | PDETOUR_BINARY DetourBinaryOpen(_In_ HANDLE hFile); 568 | 569 | _Writable_bytes_(*pcbData) 570 | _Readable_bytes_(*pcbData) 571 | _Success_(return != NULL) 572 | PVOID DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, 573 | _Out_opt_ GUID *pGuid, 574 | _Out_ DWORD *pcbData, 575 | _Inout_ DWORD *pnIterator); 576 | 577 | _Writable_bytes_(*pcbData) 578 | _Readable_bytes_(*pcbData) 579 | _Success_(return != NULL) 580 | PVOID DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, 581 | _In_ REFGUID rguid, 582 | _Out_ DWORD *pcbData); 583 | 584 | PVOID DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, 585 | _In_ REFGUID rguid, 586 | _In_reads_opt_(cbData) PVOID pData, 587 | _In_ DWORD cbData); 588 | 589 | 590 | /////////////////////////////////////////////////// Create Process & Load Dll. 591 | // 592 | 593 | 594 | 595 | // 596 | ////////////////////////////////////////////////////////////////////////////// 597 | #ifdef __cplusplus 598 | } 599 | #endif // __cplusplus 600 | 601 | //////////////////////////////////////////////// Detours Internal Definitions. 602 | // 603 | #ifdef __cplusplus 604 | #ifdef DETOURS_INTERNAL 605 | 606 | #define NOTHROW 607 | // #define NOTHROW (nothrow) 608 | 609 | ////////////////////////////////////////////////////////////////////////////// 610 | // 611 | #if (_MSC_VER < 1299) 612 | 613 | 614 | static inline 615 | LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) 616 | { 617 | return (LONG)__sync_val_compare_and_swap(ptr, oval, nval); 618 | } 619 | #else 620 | #include 621 | #endif 622 | 623 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 624 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 625 | #endif 626 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 627 | 628 | #ifndef DETOUR_TRACE 629 | #if DETOUR_DEBUG 630 | #define DETOUR_TRACE(x) printf x 631 | #define DETOUR_BREAK() __debugbreak() 632 | #include 633 | #include "limits.h" 634 | #else 635 | #include 636 | #include 637 | const char * ___DETOUR_TRACE(const char *format, ...); 638 | #define DETOUR_TRACE(x) LOG(INFO) << ___DETOUR_TRACE x 639 | #define DETOUR_BREAK() 640 | #endif 641 | #endif 642 | 643 | #if 1 || defined(DETOURS_IA64) 644 | 645 | 646 | #endif // DETOURS_IA64 647 | 648 | #ifdef DETOURS_ARM 649 | 650 | 651 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 652 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 653 | 654 | #endif // DETOURS_ARM 655 | 656 | ////////////////////////////////////////////////////////////////////////////// 657 | 658 | #ifdef __cplusplus 659 | extern "C" { 660 | #endif // __cplusplus 661 | 662 | #define DETOUR_OFFLINE_LIBRARY(x) \ 663 | PVOID DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 664 | _Inout_opt_ PVOID *ppDstPool, \ 665 | _In_ PVOID pSrc, \ 666 | _Out_opt_ PVOID *ppTarget, \ 667 | _Out_opt_ LONG *plExtra); \ 668 | \ 669 | BOOL DetourSetCodeModule##x(_In_ HMODULE hModule, \ 670 | _In_ BOOL fLimitReferencesToModule); \ 671 | 672 | DETOUR_OFFLINE_LIBRARY(X86) 673 | DETOUR_OFFLINE_LIBRARY(X64) 674 | DETOUR_OFFLINE_LIBRARY(ARM) 675 | DETOUR_OFFLINE_LIBRARY(ARM64) 676 | DETOUR_OFFLINE_LIBRARY(IA64) 677 | 678 | #undef DETOUR_OFFLINE_LIBRARY 679 | 680 | ////////////////////////////////////////////////////////////////////////////// 681 | // 682 | // Helpers for manipulating page protection. 683 | // 684 | 685 | _Success_(return != FALSE) 686 | BOOL DetourVirtualProtectSameExecuteEx(_In_ pid_t hProcess, 687 | _In_ PVOID pAddress, 688 | _In_ SIZE_T nSize, 689 | _In_ DWORD dwNewProtect, 690 | _Out_ PDWORD pdwOldProtect); 691 | 692 | _Success_(return != FALSE) 693 | BOOL DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 694 | _In_ SIZE_T nSize, 695 | _In_ DWORD dwNewProtect, 696 | _Out_ PDWORD pdwOldProtect); 697 | #ifdef __cplusplus 698 | } 699 | #endif // __cplusplus 700 | 701 | ////////////////////////////////////////////////////////////////////////////// 702 | 703 | #define MM_ALLOCATION_GRANULARITY 0x10000 704 | 705 | ////////////////////////////////////////////////////////////////////////////// 706 | 707 | 708 | //LONG DetourBarrierBeginStackTrace(PVOID* OutBackup); 709 | 710 | //LONG DetourBarrierEndStackTrace(PVOID InBackup); 711 | 712 | BOOL DetourIsValidHandle( 713 | TRACED_HOOK_HANDLE InTracedHandle, 714 | PLOCAL_HOOK_INFO* OutHandle); 715 | 716 | BOOL IsLoaderLock(); 717 | BOOL AcquireSelfProtection(); 718 | 719 | void RtlAssert(BOOL InAssert, LPCWSTR lpMessageText); 720 | void RtlSetLastError(LONG InCode, LONG InNtStatus, WCHAR* InMessage); 721 | 722 | typedef struct _RTL_SPIN_LOCK_ 723 | { 724 | pthread_mutex_t Lock; 725 | BOOL IsOwned; 726 | }RTL_SPIN_LOCK; 727 | 728 | void RtlInitializeLock(RTL_SPIN_LOCK* InLock); 729 | 730 | void RtlAcquireLock(RTL_SPIN_LOCK* InLock); 731 | 732 | void RtlReleaseLock(RTL_SPIN_LOCK* InLock); 733 | 734 | void RtlDeleteLock(RTL_SPIN_LOCK* InLock); 735 | 736 | void RtlSleep(ULONG InTimeout); 737 | 738 | 739 | PVOID detour_get_page(PVOID addr); 740 | int detour_get_page_size(); 741 | 742 | typedef struct _RUNTIME_INFO_ 743 | { 744 | // "true" if the current thread is within the related hook handler 745 | BOOL IsExecuting; 746 | // the hook this information entry belongs to... This allows a per thread and hook storage! 747 | DWORD HLSIdent; 748 | // the return address of the current thread's hook handler... 749 | void* RetAddress; 750 | // the address of the return address of the current thread's hook handler... 751 | void** AddrOfRetAddr; 752 | }RUNTIME_INFO; 753 | 754 | typedef struct _THREAD_RUNTIME_INFO_ 755 | { 756 | RUNTIME_INFO* Entries; 757 | RUNTIME_INFO* Current; 758 | void* Callback; 759 | BOOL IsProtected; 760 | }THREAD_RUNTIME_INFO, *LPTHREAD_RUNTIME_INFO; 761 | 762 | typedef struct _THREAD_LOCAL_STORAGE_ 763 | { 764 | THREAD_RUNTIME_INFO Entries[MAX_THREAD_COUNT]; 765 | DWORD IdList[MAX_THREAD_COUNT]; 766 | RTL_SPIN_LOCK ThreadSafe; 767 | }THREAD_LOCAL_STORAGE; 768 | 769 | typedef struct _BARRIER_UNIT_ 770 | { 771 | HOOK_ACL GlobalACL; 772 | BOOL IsInitialized; 773 | THREAD_LOCAL_STORAGE TLS; 774 | }BARRIER_UNIT; 775 | 776 | 777 | BOOL TlsGetCurrentValue( 778 | THREAD_LOCAL_STORAGE* InTls, 779 | THREAD_RUNTIME_INFO** OutValue); 780 | BOOL TlsAddCurrentThread(THREAD_LOCAL_STORAGE* InTls); 781 | 782 | void RtlFreeMemory(void* InPointer); 783 | 784 | void* RtlAllocateMemory( 785 | BOOL InZeroMemory, 786 | ULONG InSize); 787 | 788 | #undef RtlCopyMemory 789 | void RtlCopyMemory( 790 | PVOID InDest, 791 | PVOID InSource, 792 | ULONG InByteCount); 793 | 794 | #undef RtlZeroMemory 795 | void RtlZeroMemory( 796 | PVOID InTarget, 797 | ULONG InByteCount); 798 | 799 | BOOL IsThreadIntercepted( 800 | HOOK_ACL* LocalACL, 801 | ULONG InThreadID); 802 | void ReleaseSelfProtection(); 803 | 804 | extern BARRIER_UNIT Unit; 805 | extern RTL_SPIN_LOCK GlobalHookLock; 806 | 807 | 808 | #endif // DETOURS_INTERNAL 809 | #endif // __cplusplus 810 | 811 | #endif // _DETOURS_H_ 812 | // 813 | //////////////////////////////////////////////////////////////// End of File. 814 | -------------------------------------------------------------------------------- /LinuxDetours/limits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define CHAR_BIT 8 // number of bits in a char 3 | #define SCHAR_MIN (-128) // minimum signed char value 4 | #define SCHAR_MAX 127 // maximum signed char value 5 | #define UCHAR_MAX 0xff // maximum unsigned char value 6 | 7 | #ifndef _CHAR_UNSIGNED 8 | #define CHAR_MIN SCHAR_MIN // mimimum char value 9 | #define CHAR_MAX SCHAR_MAX // maximum char value 10 | #else 11 | #define CHAR_MIN 0 12 | #define CHAR_MAX UCHAR_MAX 13 | #endif 14 | 15 | #define MB_LEN_MAX 5 // max. # bytes in multibyte char 16 | #define SHRT_MIN (-32768) // minimum (signed) short value 17 | #define SHRT_MAX 32767 // maximum (signed) short value 18 | #define USHRT_MAX 0xffff // maximum unsigned short value 19 | #define INT_MIN (-2147483647 - 1) // minimum (signed) int value 20 | #define INT_MAX 2147483647 // maximum (signed) int value 21 | #define UINT_MAX 0xffffffff // maximum unsigned int value 22 | #define LONG_MIN (-2147483647L - 1) // minimum (signed) long value 23 | #define LONG_MAX 2147483647L // maximum (signed) long value 24 | #define ULONG_MAX 0xffffffffUL // maximum unsigned long value 25 | #define LLONG_MAX 9223372036854775807i64 // maximum signed long long int value 26 | #define LLONG_MIN (-9223372036854775807i64 - 1) // minimum signed long long int value 27 | #define ULLONG_MAX 0xffffffffffffffffui64 // maximum unsigned long long int value 28 | 29 | #define _I8_MIN (-127i8 - 1) // minimum signed 8 bit value 30 | #define _I8_MAX 127i8 // maximum signed 8 bit value 31 | #define _UI8_MAX 0xffui8 // maximum unsigned 8 bit value 32 | 33 | #define _I16_MIN (-32767i16 - 1) // minimum signed 16 bit value 34 | #define _I16_MAX 32767i16 // maximum signed 16 bit value 35 | #define _UI16_MAX 0xffffui16 // maximum unsigned 16 bit value 36 | 37 | #define _I32_MIN (-2147483647i32 - 1) // minimum signed 32 bit value 38 | #define _I32_MAX 2147483647i32 // maximum signed 32 bit value 39 | #define _UI32_MAX 0xffffffffui32 // maximum unsigned 32 bit value 40 | 41 | // minimum signed 64 bit value 42 | #define _I64_MIN (-9223372036854775807i64 - 1) 43 | // maximum signed 64 bit value 44 | #define _I64_MAX 9223372036854775807i64 45 | // maximum unsigned 64 bit value 46 | #define _UI64_MAX 0xffffffffffffffffui64 47 | 48 | #if _INTEGRAL_MAX_BITS >= 128 49 | // minimum signed 128 bit value 50 | #define _I128_MIN (-170141183460469231731687303715884105727i128 - 1) 51 | // maximum signed 128 bit value 52 | #define _I128_MAX 170141183460469231731687303715884105727i128 53 | // maximum unsigned 128 bit value 54 | #define _UI128_MAX 0xffffffffffffffffffffffffffffffffui128 55 | #endif 56 | 57 | #ifndef SIZE_MAX 58 | #ifdef _UNIX64 59 | #define SIZE_MAX _UI64_MAX 60 | #else 61 | #define SIZE_MAX UINT_MAX 62 | #endif 63 | #endif 64 | 65 | #if __STDC_WANT_SECURE_LIB__ 66 | #ifndef RSIZE_MAX 67 | #define RSIZE_MAX (SIZE_MAX >> 1) 68 | #endif 69 | #endif 70 | 71 | -------------------------------------------------------------------------------- /LinuxDetours/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "detours.h" 3 | #include 4 | 5 | unsigned int sleep_detour(unsigned int seconds) 6 | { 7 | LOG(INFO) << "detours_test: Called sleep_detour"; 8 | return sleep(seconds); 9 | } 10 | unsigned int test_detour_b(unsigned int seconds, unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e) 11 | { 12 | LOG(INFO) << "detours_test: Called test_detour_b"; 13 | return seconds + 1; 14 | } 15 | unsigned int test_detour_a(unsigned int seconds, unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e) 16 | { 17 | LOG(INFO) << "detours_test: Detoured function 'test_detour_b' -> function 'test_detour_a' with params: " 18 | << a << ", " << b << ", " << c << ", " << d << ", " << e; 19 | return test_detour_b(seconds + 2, a, b, c, d, e); 20 | } 21 | 22 | VOID* test_runner(void*) 23 | { 24 | LOG(INFO) << "detours_test: Function 'test_detour_b' returned " << test_detour_b(1, 2, 3, 4, 5, 6); 25 | 26 | LOG(INFO) << "detours_test: Calling sleep for 1 second"; 27 | sleep(1); 28 | LOG(INFO) << "detours_test: Calling sleep again for 2 seconds"; 29 | sleep(2); 30 | 31 | LOG(INFO) << "detours_test: Done sleeping\n"; 32 | 33 | return NULL; 34 | } 35 | 36 | int test_glog(char * argv) 37 | { 38 | google::InitGoogleLogging(argv); 39 | FLAGS_logtostderr = true; 40 | 41 | LOG(INFO) << "detours_test: Starting detours tests"; 42 | return 1; 43 | } 44 | 45 | int main(int argc, char * argv[]) 46 | { 47 | test_glog(argv[0]); 48 | 49 | DetourBarrierProcessAttach(); 50 | DetourCriticalInitialize(); 51 | 52 | LONG test_detour_callback = 0; 53 | LONG sleep_detour_callback = 0; 54 | TRACED_HOOK_HANDLE test_detour_handle = new HOOK_TRACE_INFO(); 55 | TRACED_HOOK_HANDLE sleep_detour_handle = new HOOK_TRACE_INFO(); 56 | 57 | DetourInstallHook((void*)test_detour_b, (void*)test_detour_a, &test_detour_callback, test_detour_handle); 58 | DetourInstallHook((void*)sleep, (void*)sleep_detour, &sleep_detour_callback, sleep_detour_handle); 59 | 60 | ULONG ret = DetourSetExclusiveACL(new ULONG(), 1, (TRACED_HOOK_HANDLE)test_detour_handle); 61 | ret = DetourSetExclusiveACL(new ULONG(), 1, (TRACED_HOOK_HANDLE)sleep_detour_handle); 62 | 63 | pthread_t t; 64 | pthread_create(&t, NULL, test_runner, NULL); 65 | pthread_join(t, NULL); 66 | 67 | DetourUninstallHook(test_detour_handle); 68 | DetourUninstallHook(sleep_detour_handle); 69 | 70 | delete test_detour_handle; 71 | delete sleep_detour_handle; 72 | 73 | sleep(1); 74 | 75 | DetourCriticalFinalize(); 76 | DetourBarrierProcessDetach(); 77 | 78 | return 0; 79 | } -------------------------------------------------------------------------------- /LinuxDetours/plthook.h: -------------------------------------------------------------------------------- 1 | /* -*- indent-tabs-mode: nil -*- 2 | * 3 | * plthook.h -- the header file of plthook 4 | * 5 | * URL: https://github.com/kubo/plthook 6 | * 7 | * ------------------------------------------------------ 8 | * 9 | * Copyright 2013-2014 Kubo Takehiro 10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, are 12 | * permitted provided that the following conditions are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright notice, this list of 15 | * conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 18 | * of conditions and the following disclaimer in the documentation and/or other materials 19 | * provided with the distribution. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 23 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR 24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | * The views and conclusions contained in the software and documentation are those of the 32 | * authors and should not be interpreted as representing official policies, either expressed 33 | * or implied, of the authors. 34 | * 35 | */ 36 | #ifndef PLTHOOK_H 37 | #define PLTHOOK_H 1 38 | 39 | #define PLTHOOK_SUCCESS 0 40 | #define PLTHOOK_FILE_NOT_FOUND 1 41 | #define PLTHOOK_INVALID_FILE_FORMAT 2 42 | #define PLTHOOK_FUNCTION_NOT_FOUND 3 43 | #define PLTHOOK_INVALID_ARGUMENT 4 44 | #define PLTHOOK_OUT_OF_MEMORY 5 45 | #define PLTHOOK_INTERNAL_ERROR 6 46 | #define PLTHOOK_NOT_IMPLEMENTED 7 47 | 48 | typedef struct plthook plthook_t; 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | int plthook_open(plthook_t **plthook_out, const char *filename); 55 | int plthook_open_by_handle(plthook_t **plthook_out, void *handle); 56 | int plthook_open_by_address(plthook_t **plthook_out, void *address); 57 | int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out); 58 | int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc); 59 | void plthook_close(plthook_t *plthook); 60 | const char *plthook_error(void); 61 | 62 | #ifdef __cplusplus 63 | }; /* extern "C" */ 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /LinuxDetours/plthook_elf.cpp: -------------------------------------------------------------------------------- 1 | /* -*- indent-tabs-mode: nil -*- 2 | * 3 | * plthook_elf.c -- implemention of plthook for ELF format 4 | * 5 | * URL: https://github.com/kubo/plthook 6 | * 7 | * ------------------------------------------------------ 8 | * 9 | * Copyright 2013-2016 Kubo Takehiro 10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, are 12 | * permitted provided that the following conditions are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright notice, this list of 15 | * conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 18 | * of conditions and the following disclaimer in the documentation and/or other materials 19 | * provided with the distribution. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED 22 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 23 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR 24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | * The views and conclusions contained in the software and documentation are those of the 32 | * authors and should not be interpreted as representing official policies, either expressed 33 | * or implied, of the authors. 34 | * 35 | */ 36 | #if defined(__sun) && defined(_XOPEN_SOURCE) && !defined(__EXTENSIONS__) 37 | #define __EXTENSIONS__ 38 | #endif 39 | #if defined(__linux__) && !defined(_GNU_SOURCE) 40 | #define _GNU_SOURCE 41 | #endif 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #ifdef __sun 52 | #include 53 | #define ELF_TARGET_ALL 54 | #endif /* __sun */ 55 | #ifdef __FreeBSD__ 56 | #include 57 | #include 58 | #include 59 | #endif 60 | #include 61 | #include 62 | #include "plthook.h" 63 | 64 | #ifndef __GNUC__ 65 | #define __attribute__(arg) 66 | #endif 67 | 68 | #if defined __FreeBSD__ && defined __i386__ && __ELF_WORD_SIZE == 64 69 | #error 32-bit application on 64-bit OS is not supported. 70 | #endif 71 | 72 | #if !defined(R_X86_64_JUMP_SLOT) && defined(R_X86_64_JMP_SLOT) 73 | #define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT 74 | #endif 75 | 76 | #if defined __x86_64__ || defined __x86_64 77 | #define R_JUMP_SLOT R_X86_64_JUMP_SLOT 78 | #define Elf_Plt_Rel Elf_Rela 79 | #define PLT_DT_REL DT_RELA 80 | #define R_GLOBAL_DATA R_X86_64_GLOB_DAT 81 | #elif defined __i386__ || defined __i386 82 | #define R_JUMP_SLOT R_386_JMP_SLOT 83 | #define Elf_Plt_Rel Elf_Rel 84 | #define PLT_DT_REL DT_REL 85 | #define R_GLOBAL_DATA R_386_GLOB_DAT 86 | #elif defined __arm__ || defined __arm 87 | #define R_JUMP_SLOT R_ARM_JUMP_SLOT 88 | #define Elf_Plt_Rel Elf_Rel 89 | #elif defined __aarch64__ || defined __aarch64 /* ARM64 */ 90 | #define R_JUMP_SLOT R_AARCH64_JUMP_SLOT 91 | #define Elf_Plt_Rel Elf_Rela 92 | #elif defined __powerpc64__ 93 | #define R_JUMP_SLOT R_PPC64_JMP_SLOT 94 | #define Elf_Plt_Rel Elf_Rela 95 | #elif defined __powerpc__ 96 | #define R_JUMP_SLOT R_PPC_JMP_SLOT 97 | #define Elf_Plt_Rel Elf_Rela 98 | #elif 0 /* disabled because not tested */ && (defined __sparcv9 || defined __sparc_v9__) 99 | #define R_JUMP_SLOT R_SPARC_JMP_SLOT 100 | #define Elf_Plt_Rel Elf_Rela 101 | #elif 0 /* disabled because not tested */ && (defined __sparc || defined __sparc__) 102 | #define R_JUMP_SLOT R_SPARC_JMP_SLOT 103 | #define Elf_Plt_Rel Elf_Rela 104 | #elif 0 /* disabled because not tested */ && (defined __ia64 || defined __ia64__) 105 | #define R_JUMP_SLOT R_IA64_IPLTMSB 106 | #define Elf_Plt_Rel Elf_Rela 107 | #else 108 | #error unsupported OS 109 | #endif 110 | 111 | #if defined __LP64__ 112 | #ifndef ELF_CLASS 113 | #define ELF_CLASS ELFCLASS64 114 | #endif 115 | #define SIZE_T_FMT "lu" 116 | #define ELF_WORD_FMT "u" 117 | #define ELF_XWORD_FMT "lu" 118 | #define ELF_SXWORD_FMT "ld" 119 | #define Elf_Half Elf64_Half 120 | #define Elf_Xword Elf64_Xword 121 | #define Elf_Sxword Elf64_Sxword 122 | #define Elf_Ehdr Elf64_Ehdr 123 | #define Elf_Phdr Elf64_Phdr 124 | #define Elf_Sym Elf64_Sym 125 | #define Elf_Dyn Elf64_Dyn 126 | #define Elf_Rel Elf64_Rel 127 | #define Elf_Rela Elf64_Rela 128 | #ifndef ELF_R_SYM 129 | #define ELF_R_SYM ELF64_R_SYM 130 | #endif 131 | #ifndef ELF_R_TYPE 132 | #define ELF_R_TYPE ELF64_R_TYPE 133 | #endif 134 | #else /* __LP64__ */ 135 | #ifndef ELF_CLASS 136 | #define ELF_CLASS ELFCLASS32 137 | #endif 138 | #define SIZE_T_FMT "u" 139 | #ifdef __sun 140 | #define ELF_WORD_FMT "lu" 141 | #define ELF_XWORD_FMT "lu" 142 | #define ELF_SXWORD_FMT "ld" 143 | #else 144 | #define ELF_WORD_FMT "u" 145 | #define ELF_XWORD_FMT "u" 146 | #define ELF_SXWORD_FMT "d" 147 | #endif 148 | #define Elf_Half Elf32_Half 149 | #define Elf_Xword Elf32_Word 150 | #define Elf_Sxword Elf32_Sword 151 | #define Elf_Ehdr Elf32_Ehdr 152 | #define Elf_Phdr Elf32_Phdr 153 | #define Elf_Sym Elf32_Sym 154 | #define Elf_Dyn Elf32_Dyn 155 | #define Elf_Rel Elf32_Rel 156 | #define Elf_Rela Elf32_Rela 157 | #ifndef ELF_R_SYM 158 | #define ELF_R_SYM ELF32_R_SYM 159 | #endif 160 | #ifndef ELF_R_TYPE 161 | #define ELF_R_TYPE ELF32_R_TYPE 162 | #endif 163 | #endif /* __LP64__ */ 164 | 165 | #if defined(PT_GNU_RELRO) && !defined(__sun) && !defined(__ANDROID__) 166 | #define SUPPORT_RELRO /* RELRO (RELocation Read-Only) */ 167 | #if !defined(DF_1_NOW) && defined(DF_1_BIND_NOW) 168 | #define DF_1_NOW DF_1_BIND_NOW 169 | #endif 170 | #endif 171 | 172 | struct plthook { 173 | const Elf_Sym *dynsym; 174 | const char *dynstr; 175 | size_t dynstr_size; 176 | const char *plt_addr_base; 177 | const Elf_Plt_Rel *plt; 178 | size_t plt_cnt; 179 | Elf_Xword r_type; 180 | #ifdef SUPPORT_RELRO 181 | const char *relro_start; 182 | const char *relro_end; 183 | #endif 184 | #if defined __ANDROID__ 185 | struct link_map *created_lmap; 186 | #endif 187 | }; 188 | 189 | static char errmsg[512]; 190 | 191 | #ifdef SUPPORT_RELRO 192 | static size_t page_size; 193 | #endif 194 | 195 | static int plthook_open_executable(plthook_t **plthook_out); 196 | static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename); 197 | static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag); 198 | #ifdef SUPPORT_RELRO 199 | static int set_relro_members(plthook_t *plthook, struct link_map *lmap); 200 | #endif 201 | static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap); 202 | #if defined __ANDROID__ 203 | static int plthook_open_owned(plthook_t **plthook_out, struct link_map *lmap); 204 | #endif 205 | static int check_elf_header(const Elf_Ehdr *ehdr); 206 | static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); 207 | 208 | #if defined __ANDROID__ 209 | static char* get_executable() { 210 | ssize_t size = 0; 211 | ssize_t bufsize = 8; 212 | char* linkname = NULL; 213 | 214 | while(1) { 215 | linkname = realloc(linkname, bufsize); 216 | size = readlink("/proc/self/exe", linkname, bufsize); 217 | if(size == -1) { 218 | free(linkname); 219 | return NULL; 220 | } 221 | if(size + 1 < bufsize) { 222 | break; 223 | } 224 | bufsize *= 2; 225 | } 226 | 227 | linkname[size] = 0; 228 | return linkname; 229 | } 230 | 231 | struct dh_iter { 232 | const char* fname; 233 | char* addr; 234 | struct link_map* lmap; 235 | }; 236 | 237 | static int dl_iterate_cb(struct dl_phdr_info *info, size_t size, void *data) { 238 | ElfW(Half) phdr_idx = 0; 239 | 240 | if (info->dlpi_name == NULL) { 241 | return 0; 242 | } 243 | 244 | struct dh_iter* iter = (struct dh_iter*)data; 245 | 246 | const char* dlpi_name_abs = strrchr(info->dlpi_name, '/'); 247 | if (dlpi_name_abs != NULL) { 248 | dlpi_name_abs++; 249 | } else { 250 | dlpi_name_abs = info->dlpi_name; 251 | } 252 | 253 | int match = 0; 254 | if (iter->fname) { 255 | match = strcmp(info->dlpi_name, iter->fname) == 0 || (strcmp(dlpi_name_abs, iter->fname) == 0); 256 | } else { 257 | for (phdr_idx = 0; !match && phdr_idx < info->dlpi_phnum; ++phdr_idx) { 258 | const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; 259 | char* base = (char*)info->dlpi_addr + phdr->p_vaddr; 260 | if (base <= iter->addr && base + phdr->p_memsz > iter->addr) { 261 | match = 1; 262 | } 263 | } 264 | } 265 | 266 | if (match) { 267 | struct link_map* prev = NULL; 268 | 269 | for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; ++phdr_idx) { 270 | const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; 271 | if (phdr->p_type == PT_DYNAMIC) { 272 | struct link_map* lmap = (struct link_map*)malloc(sizeof(struct link_map)); 273 | lmap->l_addr = info->dlpi_addr; 274 | lmap->l_name = strdup(dlpi_name_abs); 275 | lmap->l_ld = (Elf_Dyn*)(info->dlpi_addr + phdr->p_vaddr); 276 | lmap->l_next = NULL; 277 | lmap->l_prev = prev; 278 | if (prev != NULL) { 279 | prev->l_next = lmap; 280 | } 281 | prev = lmap; 282 | if (iter->lmap == NULL) { 283 | iter->lmap = lmap; 284 | } 285 | } 286 | } 287 | return 1; 288 | } 289 | return 0; 290 | } 291 | 292 | static struct link_map* create_link_map_fname(const char* fname) 293 | { 294 | struct dh_iter iter; 295 | iter.fname = fname; 296 | iter.addr = NULL; 297 | iter.lmap = NULL; 298 | 299 | dl_iterate_phdr(dl_iterate_cb, &iter); 300 | 301 | return iter.lmap; 302 | } 303 | 304 | static struct link_map* create_link_map_addr(void* addr) 305 | { 306 | struct dh_iter iter; 307 | iter.fname = NULL; 308 | iter.addr = (char*)addr; 309 | iter.lmap = NULL; 310 | 311 | dl_iterate_phdr(dl_iterate_cb, &iter); 312 | 313 | return iter.lmap; 314 | } 315 | 316 | static void delete_link_map(struct link_map* lmap) 317 | { 318 | while(lmap) { 319 | struct link_map* next = lmap->l_next; 320 | free(lmap->l_name); 321 | free(lmap); 322 | lmap = next; 323 | } 324 | } 325 | #endif 326 | 327 | int plthook_open(plthook_t **plthook_out, const char *filename) 328 | { 329 | *plthook_out = NULL; 330 | if (filename == NULL) { 331 | return plthook_open_executable(plthook_out); 332 | } else { 333 | return plthook_open_shared_library(plthook_out, filename); 334 | } 335 | } 336 | 337 | int plthook_open_by_handle(plthook_t **plthook_out, void *hndl) 338 | { 339 | #if defined __ANDROID__ 340 | return PLTHOOK_NOT_IMPLEMENTED; 341 | #else 342 | struct link_map *lmap = NULL; 343 | 344 | if (hndl == NULL) { 345 | set_errmsg("NULL handle"); 346 | return PLTHOOK_FILE_NOT_FOUND; 347 | } 348 | if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) { 349 | set_errmsg("dlinfo error"); 350 | return PLTHOOK_FILE_NOT_FOUND; 351 | } 352 | return plthook_open_real(plthook_out, lmap); 353 | #endif 354 | } 355 | 356 | int plthook_open_by_address(plthook_t **plthook_out, void *address) 357 | { 358 | #if defined __FreeBSD__ 359 | return PLTHOOK_NOT_IMPLEMENTED; 360 | #elif defined __ANDROID__ 361 | struct link_map *lmap = create_link_map_addr(address); 362 | if (lmap == NULL) { 363 | set_errmsg("create_link_map_addr unable to find address"); 364 | return PLTHOOK_INTERNAL_ERROR; 365 | } 366 | return plthook_open_owned(plthook_out, lmap); 367 | #else 368 | Dl_info info; 369 | struct link_map *lmap = NULL; 370 | 371 | *plthook_out = NULL; 372 | if (dladdr1(address, &info, (void**)&lmap, RTLD_DL_LINKMAP) == 0) { 373 | set_errmsg("dladdr error"); 374 | return PLTHOOK_FILE_NOT_FOUND; 375 | } 376 | return plthook_open_real(plthook_out, lmap); 377 | #endif 378 | } 379 | 380 | static int plthook_open_executable(plthook_t **plthook_out) 381 | { 382 | #if defined __linux__ 383 | #if defined __ANDROID__ 384 | char* exe = get_executable(); 385 | if (!exe) { 386 | set_errmsg("plthook_open_executable unable to get executable path"); 387 | return PLTHOOK_FILE_NOT_FOUND; 388 | } 389 | struct link_map *lmap = create_link_map_fname(exe); 390 | free(exe); 391 | if (lmap == NULL) { 392 | set_errmsg("create_link_map_fname unable to find executable"); 393 | return PLTHOOK_INTERNAL_ERROR; 394 | } 395 | return plthook_open_owned(plthook_out, lmap); 396 | #else 397 | return plthook_open_real(plthook_out, _r_debug.r_map); 398 | #endif 399 | #elif defined __sun 400 | const char *auxv_file = "/proc/self/auxv"; 401 | #define NUM_AUXV_CNT 10 402 | FILE *fp = fopen(auxv_file, "r"); 403 | auxv_t auxv; 404 | struct r_debug *r_debug = NULL; 405 | 406 | if (fp == NULL) { 407 | set_errmsg("Could not open %s: %s", auxv_file, 408 | strerror(errno)); 409 | return PLTHOOK_INTERNAL_ERROR; 410 | } 411 | while (fread(&auxv, sizeof(auxv_t), 1, fp) == 1) { 412 | if (auxv.a_type == AT_SUN_LDDATA) { 413 | r_debug = (struct r_debug *)auxv.a_un.a_ptr; 414 | break; 415 | } 416 | } 417 | fclose(fp); 418 | if (r_debug == NULL) { 419 | set_errmsg("Could not find r_debug"); 420 | return PLTHOOK_INTERNAL_ERROR; 421 | } 422 | return plthook_open_real(plthook_out, r_debug->r_map); 423 | #elif defined __FreeBSD__ 424 | return plthook_open_shared_library(plthook_out, NULL); 425 | #else 426 | set_errmsg("Opening the main program is not supported on this platform."); 427 | return PLTHOOK_NOT_IMPLEMENTED; 428 | #endif 429 | } 430 | 431 | static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename) 432 | { 433 | void *hndl = dlopen(filename, RTLD_LAZY | RTLD_NOLOAD); 434 | struct link_map *lmap = NULL; 435 | 436 | if (hndl == NULL) { 437 | set_errmsg("dlopen error: %s", dlerror()); 438 | return PLTHOOK_FILE_NOT_FOUND; 439 | } 440 | #ifdef __ANDROID__ 441 | lmap = create_link_map_fname(filename); 442 | if (lmap == NULL) { 443 | set_errmsg("create_link_map_fname error"); 444 | dlclose(hndl); 445 | return PLTHOOK_FILE_NOT_FOUND; 446 | } 447 | dlclose(hndl); 448 | return plthook_open_owned(plthook_out, lmap); 449 | #else 450 | if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) { 451 | set_errmsg("dlinfo error"); 452 | dlclose(hndl); 453 | return PLTHOOK_FILE_NOT_FOUND; 454 | } 455 | dlclose(hndl); 456 | return plthook_open_real(plthook_out, lmap); 457 | #endif 458 | } 459 | 460 | static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag) 461 | { 462 | while (dyn->d_tag != DT_NULL) { 463 | if (dyn->d_tag == tag) { 464 | return dyn; 465 | } 466 | dyn++; 467 | } 468 | return NULL; 469 | } 470 | 471 | #ifdef SUPPORT_RELRO 472 | #if defined __linux__ 473 | static const char *get_mapped_file(const void *address, char *buf, int *err) 474 | { 475 | unsigned long addr = (unsigned long)address; 476 | FILE *fp; 477 | 478 | fp = fopen("/proc/self/maps", "r"); 479 | if (fp == NULL) { 480 | set_errmsg("failed to open /proc/self/maps"); 481 | *err = PLTHOOK_INTERNAL_ERROR; 482 | return NULL; 483 | } 484 | while (fgets(buf, PATH_MAX, fp) != NULL) { 485 | unsigned long start, end; 486 | int offset = 0; 487 | 488 | sscanf(buf, "%lx-%lx %*s %*x %*x:%*x %*u %n", &start, &end, &offset); 489 | if (offset == 0) { 490 | continue; 491 | } 492 | if (start < addr && addr < end) { 493 | char *p = buf + offset; 494 | while (*p == ' ') { 495 | p++; 496 | } 497 | if (*p != '/') { 498 | continue; 499 | } 500 | p[strlen(p) - 1] = '\0'; /* remove '\n' */ 501 | fclose(fp); 502 | return p; 503 | } 504 | } 505 | fclose(fp); 506 | set_errmsg("Could not find a mapped file reagion containing %p", address); 507 | *err = PLTHOOK_INTERNAL_ERROR; 508 | return NULL; 509 | } 510 | #elif defined __FreeBSD__ 511 | static const char *get_mapped_file(const void *address, char *buf, int *err) 512 | { 513 | uint64_t addr = (uint64_t)address; 514 | struct kinfo_vmentry *top; 515 | int i, cnt; 516 | 517 | top = kinfo_getvmmap(getpid(), &cnt); 518 | if (top == NULL) { 519 | fprintf(stderr, "failed to call kinfo_getvmmap()\n"); 520 | *err = PLTHOOK_INTERNAL_ERROR; 521 | return NULL; 522 | } 523 | for (i = 0; i < cnt; i++) { 524 | struct kinfo_vmentry *kve = top + i; 525 | 526 | if (kve->kve_start < addr && addr < kve->kve_end) { 527 | strncpy(buf, kve->kve_path, PATH_MAX); 528 | free(top); 529 | return buf; 530 | } 531 | } 532 | free(top); 533 | set_errmsg("Could not find a mapped file reagion containing %p", address); 534 | *err = PLTHOOK_INTERNAL_ERROR; 535 | return NULL; 536 | } 537 | #else 538 | static const char *get_mapped_file(const void *address, char *buf, int *err) 539 | { 540 | set_errmsg("Could not find a mapped file reagion containing %p", address); 541 | *err = PLTHOOK_INTERNAL_ERROR; 542 | return NULL; 543 | } 544 | #endif 545 | 546 | static int set_relro_members(plthook_t *plthook, struct link_map *lmap) 547 | { 548 | char fnamebuf[PATH_MAX]; 549 | const char *fname; 550 | FILE *fp; 551 | Elf_Ehdr ehdr; 552 | Elf_Half idx; 553 | int rv; 554 | 555 | if (lmap->l_name[0] == '/') { 556 | fname = lmap->l_name; 557 | } else { 558 | int err; 559 | 560 | fname = get_mapped_file(plthook->dynstr, fnamebuf, &err); 561 | if (fname == NULL) { 562 | return err; 563 | } 564 | } 565 | fp = fopen(fname, "r"); 566 | if (fp == NULL) { 567 | set_errmsg("failed to open %s", fname); 568 | return PLTHOOK_INTERNAL_ERROR; 569 | } 570 | if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 571 | set_errmsg("failed to read the ELF header."); 572 | fclose(fp); 573 | return PLTHOOK_INVALID_FILE_FORMAT; 574 | } 575 | rv = check_elf_header(&ehdr); 576 | if (rv != 0) { 577 | fclose(fp); 578 | return rv; 579 | } 580 | 581 | fseek(fp, ehdr.e_phoff, SEEK_SET); 582 | 583 | for (idx = 0; idx < ehdr.e_phnum; idx++) { 584 | Elf_Phdr phdr; 585 | 586 | if (fread(&phdr, sizeof(phdr), 1, fp) != 1) { 587 | set_errmsg("failed to read the program header table."); 588 | fclose(fp); 589 | return PLTHOOK_INVALID_FILE_FORMAT; 590 | } 591 | if (phdr.p_type == PT_GNU_RELRO) { 592 | plthook->relro_start = plthook->plt_addr_base + phdr.p_vaddr; 593 | plthook->relro_end = plthook->relro_start + phdr.p_memsz; 594 | break; 595 | } 596 | } 597 | fclose(fp); 598 | return 0; 599 | } 600 | #endif 601 | 602 | static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap) 603 | { 604 | plthook_t plthook = {NULL,}; 605 | const Elf_Dyn *dyn; 606 | const char *dyn_addr_base = NULL; 607 | 608 | #if defined __linux__ 609 | plthook.plt_addr_base = (char*)lmap->l_addr; 610 | #if defined __ANDROID__ 611 | dyn_addr_base = (const char*)lmap->l_addr; 612 | #endif 613 | #elif defined __FreeBSD__ || defined __sun 614 | const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr; 615 | int rv = check_elf_header(ehdr); 616 | if (rv != 0) { 617 | return rv; 618 | } 619 | if (ehdr->e_type == ET_DYN) { 620 | dyn_addr_base = (const char*)lmap->l_addr; 621 | plthook.plt_addr_base = (const char*)lmap->l_addr; 622 | } 623 | #else 624 | #error unsupported OS 625 | #endif 626 | 627 | /* get .dynsym section */ 628 | dyn = find_dyn_by_tag(lmap->l_ld, DT_SYMTAB); 629 | if (dyn == NULL) { 630 | set_errmsg("failed to find DT_SYMTAB"); 631 | return PLTHOOK_INTERNAL_ERROR; 632 | } 633 | plthook.dynsym = (const Elf_Sym*)(dyn_addr_base + dyn->d_un.d_ptr); 634 | 635 | /* Check sizeof(Elf_Sym) */ 636 | dyn = find_dyn_by_tag(lmap->l_ld, DT_SYMENT); 637 | if (dyn == NULL) { 638 | set_errmsg("failed to find DT_SYMTAB"); 639 | return PLTHOOK_INTERNAL_ERROR; 640 | } 641 | if (dyn->d_un.d_val != sizeof(Elf_Sym)) { 642 | set_errmsg("DT_SYMENT size %" ELF_XWORD_FMT " != %" SIZE_T_FMT, dyn->d_un.d_val, sizeof(Elf_Sym)); 643 | return PLTHOOK_INTERNAL_ERROR; 644 | } 645 | 646 | /* get .dynstr section */ 647 | dyn = find_dyn_by_tag(lmap->l_ld, DT_STRTAB); 648 | if (dyn == NULL) { 649 | set_errmsg("failed to find DT_STRTAB"); 650 | return PLTHOOK_INTERNAL_ERROR; 651 | } 652 | plthook.dynstr = dyn_addr_base + dyn->d_un.d_ptr; 653 | 654 | /* get .dynstr size */ 655 | dyn = find_dyn_by_tag(lmap->l_ld, DT_STRSZ); 656 | if (dyn == NULL) { 657 | set_errmsg("failed to find DT_STRSZ"); 658 | return PLTHOOK_INTERNAL_ERROR; 659 | } 660 | plthook.dynstr_size = dyn->d_un.d_val; 661 | 662 | /* get .rela.plt or .rel.plt section */ 663 | dyn = find_dyn_by_tag(lmap->l_ld, DT_JMPREL); 664 | plthook.r_type = R_JUMP_SLOT; 665 | #ifdef PLT_DT_REL 666 | if (dyn == NULL) { 667 | /* get .rela.dyn or .rel.dyn section */ 668 | dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_REL); 669 | plthook.r_type = R_GLOBAL_DATA; 670 | } 671 | #endif 672 | if (dyn == NULL) { 673 | set_errmsg("failed to find DT_JMPREL"); 674 | return PLTHOOK_INTERNAL_ERROR; 675 | } 676 | plthook.plt = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr); 677 | 678 | if (plthook.r_type == R_JUMP_SLOT) { 679 | /* get total size of .rela.plt or .rel.plt */ 680 | dyn = find_dyn_by_tag(lmap->l_ld, DT_PLTRELSZ); 681 | if (dyn == NULL) { 682 | set_errmsg("failed to find DT_PLTRELSZ"); 683 | return PLTHOOK_INTERNAL_ERROR; 684 | } 685 | 686 | plthook.plt_cnt = dyn->d_un.d_val / sizeof(Elf_Plt_Rel); 687 | #ifdef PLT_DT_REL 688 | } else { 689 | int total_size_tag = PLT_DT_REL == DT_RELA ? DT_RELASZ : DT_RELSZ; 690 | int elem_size_tag = PLT_DT_REL == DT_RELA ? DT_RELAENT : DT_RELENT; 691 | size_t total_size, elem_size; 692 | 693 | dyn = find_dyn_by_tag(lmap->l_ld, total_size_tag); 694 | if (dyn == NULL) { 695 | set_errmsg("failed to find 0x%x", total_size_tag); 696 | return PLTHOOK_INTERNAL_ERROR; 697 | } 698 | total_size = dyn->d_un.d_ptr; 699 | 700 | dyn = find_dyn_by_tag(lmap->l_ld, elem_size_tag); 701 | if (dyn == NULL) { 702 | set_errmsg("failed to find 0x%x", elem_size_tag); 703 | return PLTHOOK_INTERNAL_ERROR; 704 | } 705 | elem_size = dyn->d_un.d_ptr; 706 | plthook.plt_cnt = total_size / elem_size; 707 | #endif 708 | } 709 | 710 | #ifdef SUPPORT_RELRO 711 | dyn = find_dyn_by_tag(lmap->l_ld, DT_FLAGS_1); 712 | if (dyn != NULL && (dyn->d_un.d_val & DF_1_NOW)) { 713 | int rv = set_relro_members(&plthook, lmap); 714 | if (rv != 0) { 715 | return rv; 716 | } 717 | if (page_size == 0) { 718 | page_size = sysconf(_SC_PAGESIZE); 719 | } 720 | } 721 | #endif 722 | 723 | *plthook_out = (plthook_t*)malloc(sizeof(plthook_t)); 724 | if (*plthook_out == NULL) { 725 | set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t)); 726 | return PLTHOOK_OUT_OF_MEMORY; 727 | } 728 | **plthook_out = plthook; 729 | return 0; 730 | } 731 | 732 | #if defined __ANDROID__ 733 | static int plthook_open_owned(plthook_t **plthook_out, struct link_map *lmap) 734 | { 735 | plthook_t* plthook = NULL; 736 | int result = plthook_open_real(&plthook, lmap); 737 | if (result != PLTHOOK_SUCCESS) { 738 | delete_link_map(lmap); 739 | } else { 740 | plthook->created_lmap = lmap; 741 | } 742 | *plthook_out = plthook; 743 | return result; 744 | } 745 | #endif 746 | 747 | 748 | static int check_elf_header(const Elf_Ehdr *ehdr) 749 | { 750 | static const unsigned short s = 1; 751 | /* Check endianness at runtime. */ 752 | unsigned char elfdata = (*(const char*)&s) ? ELFDATA2LSB : ELFDATA2MSB; 753 | 754 | if (ehdr == NULL) { 755 | set_errmsg("invalid elf header address: NULL"); 756 | return PLTHOOK_INTERNAL_ERROR; 757 | } 758 | 759 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { 760 | set_errmsg("invalid file signature: 0x%02x,0x%02x,0x%02x,0x%02x", 761 | ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]); 762 | return PLTHOOK_INVALID_FILE_FORMAT; 763 | } 764 | if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { 765 | set_errmsg("invalid elf class: 0x%02x", ehdr->e_ident[EI_CLASS]); 766 | return PLTHOOK_INVALID_FILE_FORMAT; 767 | } 768 | if (ehdr->e_ident[EI_DATA] != elfdata) { 769 | set_errmsg("invalid elf data: 0x%02x", ehdr->e_ident[EI_DATA]); 770 | return PLTHOOK_INVALID_FILE_FORMAT; 771 | } 772 | if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { 773 | set_errmsg("invalid elf version: 0x%02x", ehdr->e_ident[EI_VERSION]); 774 | return PLTHOOK_INVALID_FILE_FORMAT; 775 | } 776 | if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { 777 | set_errmsg("invalid file type: 0x%04x", ehdr->e_type); 778 | return PLTHOOK_INVALID_FILE_FORMAT; 779 | } 780 | if (ehdr->e_version != EV_CURRENT) { 781 | set_errmsg("invalid object file version: %" ELF_WORD_FMT, ehdr->e_version); 782 | return PLTHOOK_INVALID_FILE_FORMAT; 783 | } 784 | if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) { 785 | set_errmsg("invalid elf header size: %u", ehdr->e_ehsize); 786 | return PLTHOOK_INVALID_FILE_FORMAT; 787 | } 788 | if (ehdr->e_phentsize != sizeof(Elf_Phdr)) { 789 | set_errmsg("invalid program header table entry size: %u", ehdr->e_phentsize); 790 | return PLTHOOK_INVALID_FILE_FORMAT; 791 | } 792 | return 0; 793 | } 794 | 795 | int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out) 796 | { 797 | while (*pos < plthook->plt_cnt) { 798 | const Elf_Plt_Rel *plt = plthook->plt + *pos; 799 | if (ELF_R_TYPE(plt->r_info) == plthook->r_type) { 800 | size_t idx = ELF_R_SYM(plt->r_info); 801 | 802 | idx = plthook->dynsym[idx].st_name; 803 | if (idx + 1 > plthook->dynstr_size) { 804 | set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx); 805 | return PLTHOOK_INVALID_FILE_FORMAT; 806 | } 807 | *name_out = plthook->dynstr + idx; 808 | *addr_out = (void**)(plthook->plt_addr_base + plt->r_offset); 809 | (*pos)++; 810 | return 0; 811 | } 812 | (*pos)++; 813 | } 814 | *name_out = NULL; 815 | *addr_out = NULL; 816 | return EOF; 817 | } 818 | 819 | int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc) 820 | { 821 | size_t funcnamelen = strlen(funcname); 822 | unsigned int pos = 0; 823 | const char *name; 824 | void **addr; 825 | int rv; 826 | 827 | if (plthook == NULL) { 828 | set_errmsg("invalid argument: The first argument is null."); 829 | return PLTHOOK_INVALID_ARGUMENT; 830 | } 831 | while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) { 832 | if (strncmp(name, funcname, funcnamelen) == 0) { 833 | if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') { 834 | #ifdef SUPPORT_RELRO 835 | void *maddr = NULL; 836 | if (plthook->relro_start <= (char*)addr && (char*)addr < plthook->relro_end) { 837 | maddr = (void*)((size_t)addr & ~(page_size - 1)); 838 | if (mprotect(maddr, page_size, PROT_READ | PROT_WRITE) != 0) { 839 | set_errmsg("Could not change the process memory protection at %p: %s", 840 | maddr, strerror(errno)); 841 | return PLTHOOK_INTERNAL_ERROR; 842 | } 843 | } 844 | #endif 845 | if (oldfunc) { 846 | *oldfunc = *addr; 847 | } 848 | *addr = funcaddr; 849 | #ifdef SUPPORT_RELRO 850 | if (maddr != NULL) { 851 | mprotect(maddr, page_size, PROT_READ); 852 | } 853 | #endif 854 | return 0; 855 | } 856 | } 857 | } 858 | if (rv == EOF) { 859 | set_errmsg("no such function: %s", funcname); 860 | rv = PLTHOOK_FUNCTION_NOT_FOUND; 861 | } 862 | return rv; 863 | } 864 | 865 | void plthook_close(plthook_t *plthook) 866 | { 867 | if (plthook != NULL) { 868 | #if defined __ANDROID__ 869 | if (plthook->created_lmap != NULL) { 870 | delete_link_map(plthook->created_lmap); 871 | } 872 | #endif 873 | free(plthook); 874 | } 875 | } 876 | 877 | const char *plthook_error(void) 878 | { 879 | return errmsg; 880 | } 881 | 882 | static void set_errmsg(const char *fmt, ...) 883 | { 884 | va_list ap; 885 | va_start(ap, fmt); 886 | vsnprintf(errmsg, sizeof(errmsg) - 1, fmt, ap); 887 | va_end(ap); 888 | } 889 | -------------------------------------------------------------------------------- /LinuxDetours/readme/images/ArchOptions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/ArchOptions.gif -------------------------------------------------------------------------------- /LinuxDetours/readme/images/ChangeRemote.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/ChangeRemote.gif -------------------------------------------------------------------------------- /LinuxDetours/readme/images/ManageConnections.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/ManageConnections.gif -------------------------------------------------------------------------------- /LinuxDetours/readme/images/OutputTypes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/OutputTypes.gif -------------------------------------------------------------------------------- /LinuxDetours/readme/images/debuggerexport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/debuggerexport.png -------------------------------------------------------------------------------- /LinuxDetours/readme/images/firstconnection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/firstconnection.png -------------------------------------------------------------------------------- /LinuxDetours/readme/images/linker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/linker.png -------------------------------------------------------------------------------- /LinuxDetours/readme/images/postbuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unknownv2/LinuxDetours/6eb4bf90d5f11cedafe47fdb50e57b154da9a196/LinuxDetours/readme/images/postbuild.png -------------------------------------------------------------------------------- /LinuxDetours/readme/readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Getting Started 9 | 10 | 11 | 12 | 13 |
14 | 18 | 19 | 20 | 21 |
22 | 23 |
62 | 72 | 73 | 74 |
24 |
25 |

Setting up your project for Linux Development

26 | 27 |

With this workload you can author C++ code for Linux servers, desktops and devices. You can manage your connections to these machines from within VS. VS will automatically copy and remotely build your sources and can launch your application with the debugger. Our project system supports targeting specific architectures, including ARM.

28 | 29 | 30 |

Connecting to Linux

31 |

Prerequisites

32 |

Today we only support building remotely on the Linux target machine. We are not limited by specific Linux distros but we do have dependencies on the presence of some tools. Specifically, we need openssh-server, g++, gdb and gdbserver. Use your favorite package manager to install them, e.g. on Debian based systems: sudo apt-get install openssh-server g++ gdb gdbserver

33 | 34 |

First connection

35 |

The first time you target a Linux machine you will be prompted for connection information. This is triggered by building the project.

36 | 37 | 38 |

Adding and removing connections

39 |

To add a new connection, go to Tools > Options and search for Connection, Connection Manager will be under Cross Platform. From here you can add and remove connections.

40 | 41 | 42 |

To change which connection a project is using go to the project properties general settings and update the Remote Build Machine option.

43 | 44 | 45 |

Project Properties

46 |

All of the options necessary to control C++ compilation are exposed on the project properies pages. We'll cover a few specific to how things work for Linux. First under general settings, you will see the remote root is set to ~/projects/ by default and that we are setting the remote project directory to match our project name in that location.

47 | 48 | 49 |

Looking at the General settings for the project, you can see how our output and intermediate directories were configured. Additionally, you’ll see that this project was configured as an application – thus our executable is under bin/x64/Debug/ as ConsoleApplication1.out. Notice that for configuration types we also support static and dynamic libraries.

50 | 51 |

Add additional library dependencies on the Linker > Input property page.

52 | 53 | 54 |

You can pass additional pre launch commands to the debugger to do things like launch graphical apps on the remote linux machine.

55 | 56 | 57 |

You can also send post build events to control remote behavior, as in this example that exports a gpio pin for use without requiring the executable run as super user.

58 | 59 | 60 |
61 |
63 |
64 | 65 |

Resources

66 | 67 |

Check out the VC++ for Linux Development page where we will keep updates posted and provider more in depth details on usage.

68 |

Give us feedback

69 |

Use the send feedback function in Visual Studio or contact us directly at VC++ Linux Support

70 |
71 |
75 |
76 | 77 | 78 | -------------------------------------------------------------------------------- /LinuxDetours/readme/stylesheet.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | color: #1E1E1E; 6 | font-size: 13px; 7 | font-family: "Segoe UI", Helvetica, Arial, sans-serif; 8 | line-height: 1.45; 9 | word-wrap: break-word; 10 | } 11 | 12 | /* General & 'Reset' Stuff */ 13 | 14 | 15 | .container { 16 | width: 1100px; 17 | margin: 0 auto; 18 | } 19 | 20 | section { 21 | display: block; 22 | margin: 0; 23 | } 24 | 25 | h1, h2, h3, h4, h5, h6 { 26 | margin: 0; 27 | } 28 | 29 | table, tr { 30 | width: 1100px; 31 | padding: 0px; 32 | vertical-align: top; 33 | } 34 | 35 | /* Header,
36 | header - container 37 | h1 - project name 38 | h2 - project description 39 | */ 40 | 41 | #header { 42 | color: #FFF; 43 | background: #68217a; 44 | position:relative; 45 | } 46 | h1, h2 { 47 | font-family: "Segoe UI Light", "Segoe UI", Helvetica, Arial, sans-serif; 48 | line-height: 1; 49 | margin: 0 18px;; 50 | padding: 0; 51 | } 52 | #header h1 { 53 | font-size: 3.4em; 54 | padding-top: 18px; 55 | font-weight: normal; 56 | margin-left: 15px; 57 | } 58 | 59 | #header h2 { 60 | font-size: 1.5em; 61 | margin-top: 10px; 62 | padding-bottom: 18px; 63 | font-weight: normal; 64 | } 65 | 66 | #main_content { 67 | width: 100%; 68 | display: flex; 69 | flex-direction: row; 70 | } 71 | 72 | 73 | h1, h2, h3, h4, h5, h6 { 74 | font-weight: bolder; 75 | } 76 | 77 | #main_content h1 { 78 | font-size: 1.8em; 79 | margin-top: 34px; 80 | } 81 | 82 | #main_content h1:first-child { 83 | margin-top: 30px; 84 | } 85 | 86 | #main_content h2 { 87 | font-size: 1.8em; 88 | } 89 | p, ul { 90 | margin: 11px 18px; 91 | } 92 | 93 | #main_content a { 94 | color: #06C; 95 | text-decoration: none; 96 | } 97 | ul { 98 | margin-top: 13px; 99 | margin-left: 18px; 100 | padding-left: 0; 101 | } 102 | ul li { 103 | margin-left: 18px; 104 | padding-left: 0; 105 | } 106 | #lpanel { 107 | width: 870px; 108 | float: left; 109 | } 110 | #rpanel ul { 111 | list-style-type: none; 112 | } 113 | #rpanel ul li { 114 | line-height: 1.8em; 115 | } 116 | #rpanel { 117 | background: #e7e7e7; 118 | width: 230px; 119 | } 120 | -------------------------------------------------------------------------------- /LinuxDetours/trampoline_arm.cpp: -------------------------------------------------------------------------------- 1 | #include "detours.h" 2 | 3 | #if defined(DETOURS_ARM) 4 | __attribute__((naked)) 5 | void trampoline_template_arm_func() { 6 | asm( 7 | 8 | ".global trampoline_template_thumb;" 9 | ".global trampoline_template_arm;" 10 | ".global trampoline_data_arm;" 11 | ".global trampoline_data_thumb;" 12 | 13 | "NETIntro:" /* .NET Barrier Intro Function */ 14 | ".byte 0;" 15 | ".byte 0;" 16 | ".byte 0;" 17 | ".byte 0;" 18 | "OldProc:" /* Original Replaced Function */ 19 | ".byte 0;" 20 | ".byte 0;" 21 | ".byte 0;" 22 | ".byte 0;" 23 | "NewProc:" /* Detour Function */ 24 | ".byte 0;" 25 | ".byte 0;" 26 | ".byte 0;" 27 | ".byte 0;" 28 | "NETOutro:" /* .NET Barrier Outro Function */ 29 | ".byte 0;" 30 | ".byte 0;" 31 | ".byte 0;" 32 | ".byte 0;" 33 | "IsExecutedPtr:" /* Count of times trampoline was executed */ 34 | ".byte 0;" 35 | ".byte 0;" 36 | ".byte 0;" 37 | ".byte 0;" 38 | 39 | "start:" 40 | 41 | "trampoline_template_thumb:" 42 | #if not defined(DETOURS_ARM32) 43 | ".thumb_func;" 44 | "bx pc;" 45 | "mov r8, r8;" // padding since pc is set to (current_instruction + 4) in Thumb Mode 46 | #endif 47 | "trampoline_template_arm:" 48 | ".code 32;" 49 | 50 | "push {r0, r1, r2, r3, r4, lr};" 51 | "push {r5, r6, r7, r8, r9, r10};" 52 | "vpush {d0-d7};" 53 | "ldr r5, IsExecutedPtr;" 54 | "dmb ish;" 55 | "try_inc_lock:" 56 | "ldrex r0, [r5];" 57 | "add r0, r0, #1;" 58 | "strex r1, r0, [r5];" 59 | "cmp r1, #0;" 60 | "bne try_inc_lock;" 61 | "dmb ish;" 62 | "ldr r2, NewProc;" 63 | "cmpeq r2, #0;" 64 | "bne call_net_entry;" 65 | /* call original method */ 66 | "dmb ish;" 67 | "try_dec_lock:" 68 | "ldrex r0, [r5];" 69 | "add r0, r0, #-1;" 70 | "strex r1, r0, [r5];" 71 | "cmp r1, #0;" 72 | "bne try_dec_lock;" 73 | "dmb ish;" 74 | "ldr r5, OldProc;" 75 | "b trampoline_exit;" 76 | 77 | /* call hook handler or original method... */ 78 | "call_net_entry:" 79 | 80 | "adr r0, start;" /* Hook handle (only a position hint) */ 81 | "add r2, sp, #0x6c;" /* original sp (address of return address)*/ 82 | "ldr r1, [sp, #0x6c];" /* return address (value stored in original sp) */ 83 | "ldr r4, NETIntro;" /* call NET intro */ 84 | "blx r4;" /* Hook->NETIntro(Hook, RetAddr, InitialSP)*/ 85 | 86 | /* should call original method? */ 87 | "cmp r0, #0;" 88 | "bne call_hook_handler;" 89 | 90 | /* call original method */ 91 | "ldr r5, IsExecutedPtr;" 92 | "dmb ish;" 93 | 94 | "try_dec_lock2:" 95 | "ldrex r0, [r5];" 96 | "add r0, r0, #-1;" 97 | "strex r1, r0, [r5];" 98 | "cmp r1, #0;" 99 | "bne try_dec_lock2;" 100 | "dmb ish;" 101 | 102 | "ldr r5, OldProc;" 103 | "b trampoline_exit;" 104 | 105 | "call_hook_handler:" 106 | /* call hook handler */ 107 | "ldr r5, NewProc;" 108 | "adr r4, call_net_outro;" 109 | "str r4, [sp, #0x6c];" /* store outro return to stack after hook handler is called */ 110 | "b trampoline_exit;" 111 | /* this is where the handler returns... */ 112 | "call_net_outro:" 113 | "mov r5, #0;" 114 | "push {r0, r1, r2, r3, r4, r5};" /* save return handler */ 115 | "add r1, sp, #5*4;" 116 | "adr r0, start;" /* get address of next Hook struct pointer */ 117 | /* Param 2: Address of return address */ 118 | "ldr r5, NETOutro;" 119 | "blx r5;" /* Hook->NETOutro(Hook, InAddrOfRetAddr)*/ 120 | "ldr r5, IsExecutedPtr;" 121 | "dmb ish;" 122 | "try_dec_lock3:" 123 | "ldrex r0, [r5];" 124 | "add r0, r0, #-1;" 125 | "strex r1, r0, [r5];" 126 | "cmp r1, #0;" 127 | "bne try_dec_lock3;" 128 | "dmb ish;" 129 | "pop {r0, r1, r2, r3, r4, lr} /* restore return value of user handler... */;" 130 | /* finally return to saved return address - the caller of this trampoline... */ 131 | "bx lr;" 132 | 133 | "trampoline_exit:" 134 | "mov r12, r5;" 135 | "vpop {d0-d7};" 136 | "pop {r5, r6, r7, r8, r9, r10};" 137 | "pop {r0, r1, r2, r3, r4, lr};" 138 | "bx r12 ; mov pc, r12;" 139 | "trampoline_data_arm:" 140 | "trampoline_data_thumb:" 141 | ".word 0x12345678;" 142 | ); 143 | } 144 | #elif defined(DETOURS_ARM64) 145 | __attribute__((naked)) 146 | void trampoline_template_arm_64_func() { 147 | asm(R"( 148 | 149 | .global trampoline_template_arm64 150 | .global trampoline_data_arm_64 151 | 152 | NETIntro: /* .NET Barrier Intro Function */ 153 | .byte 0 154 | .byte 0 155 | .byte 0 156 | .byte 0 157 | .byte 0 158 | .byte 0 159 | .byte 0 160 | .byte 0 161 | OldProc: /* Original Replaced Function */ 162 | .byte 0 163 | .byte 0 164 | .byte 0 165 | .byte 0 166 | .byte 0 167 | .byte 0 168 | .byte 0 169 | .byte 0 170 | NewProc: /* Detour Function */ 171 | .byte 0 172 | .byte 0 173 | .byte 0 174 | .byte 0 175 | .byte 0 176 | .byte 0 177 | .byte 0 178 | .byte 0 179 | NETOutro: /* .NET Barrier Outro Function */ 180 | .byte 0 181 | .byte 0 182 | .byte 0 183 | .byte 0 184 | .byte 0 185 | .byte 0 186 | .byte 0 187 | .byte 0 188 | IsExecutedPtr: /* Count of times trampoline was executed */ 189 | .byte 0 190 | .byte 0 191 | .byte 0 192 | .byte 0 193 | .byte 0 194 | .byte 0 195 | .byte 0 196 | .byte 0 197 | 198 | trampoline_template_arm64: 199 | 200 | start: 201 | stp x29, x30, [sp, #-16]! 202 | mov x29, sp 203 | sub sp, sp, #(10*8 + 8*16) 204 | stp q0, q1, [sp, #(0*16)] 205 | stp q2, q3, [sp, #(2*16)] 206 | stp q4, q5, [sp, #(4*16)] 207 | stp q6, q7, [sp, #(6*16)] 208 | stp x0, x1, [sp, #(8*16+0*8)] 209 | stp x2, x3, [sp, #(8*16+2*8)] 210 | stp x4, x5, [sp, #(8*16+4*8)] 211 | stp x6, x7, [sp, #(8*16+6*8)] 212 | str x8, [sp, #(8*16+8*8)] 213 | 214 | ldr x10, IsExecutedPtr 215 | try_inc_lock: 216 | ldxr w0, [x10] 217 | add w0, w0, #1 218 | stxr w1, w0, [x10] 219 | cbnz w1, try_inc_lock 220 | ldr x1, NewProc 221 | cbnz x1, call_net_entry 222 | /* call original method */ 223 | try_dec_lock: 224 | ldxr w0, [x10] 225 | add w0, w0, #-1 226 | stxr w1, w0, [x10] 227 | cbnz x1, try_dec_lock 228 | ldr x10, OldProc 229 | b trampoline_exit 230 | /* call hook handler or original method... */ 231 | call_net_entry: 232 | adr x0, start /* call NET intro */ 233 | add x2, sp, #(10*8 + 8*16) + 8 /* original sp (address of return address)*/ 234 | ldr x1, [sp, #(10*8 + 8*16) + 8] /* return address (value stored in original sp) */ 235 | ldr x10, NETIntro 236 | blr x10 /* Hook->NETIntro(Hook, RetAddr, InitialSP)*/ 237 | /* should call original method? */ 238 | cbnz x0, call_hook_handler 239 | 240 | /* call original method */ 241 | ldr x10, IsExecutedPtr 242 | try_dec_lock2: 243 | ldxr w0, [x10] 244 | add w0, w0, #-1 245 | stxr w1, w0, [x10] 246 | cbnz w1, try_dec_lock2 247 | 248 | ldr x10, OldProc 249 | b trampoline_exit 250 | call_hook_handler: 251 | 252 | /* call hook handler */ 253 | ldr x10, NewProc 254 | adr x4, call_net_outro /*adjust return address */ 255 | str x4, [sp, #(10*8 + 8*16) + 8] /* store outro return to stack after hook handler is called */ 256 | b trampoline_exit 257 | /* this is where the handler returns... */ 258 | call_net_outro: 259 | mov x10, #0 260 | sub sp, sp, #(10*8 + 8*16) 261 | stp q0, q1, [sp, #(0*16)] 262 | stp q2, q3, [sp, #(2*16)] 263 | stp q4, q5, [sp, #(4*16)] 264 | stp q6, q7, [sp, #(6*16)] 265 | stp x0, x1, [sp, #(8*16+0*8)] 266 | stp x2, x3, [sp, #(8*16+2*8)] 267 | stp x4, x5, [sp, #(8*16+4*8)] 268 | stp x6, x7, [sp, #(8*16+6*8)] 269 | stp x8, x10,[sp, #(8*16+8*8)] /* save return handler */ 270 | 271 | add x1, sp, #(8*16+9*8) /* Param 2: Address of return address */ 272 | adr x0, start 273 | 274 | ldr x10, NETOutro 275 | blr x10 /* Hook->NETOutro(Hook, InAddrOfRetAddr)*/ 276 | 277 | ldr x10, IsExecutedPtr 278 | try_dec_lock3: 279 | ldxr w0, [x10] 280 | add w0, w0, #-1 281 | stxr w1, w0, [x10] 282 | cbnz w1, try_dec_lock3 283 | 284 | ldp q0, q1, [sp, #(0*16)] 285 | ldp q2, q3, [sp, #(2*16)] 286 | ldp q4, q5, [sp, #(4*16)] 287 | ldp q6, q7, [sp, #(6*16)] 288 | ldp x0, x1, [sp, #(8*16+0*8)] 289 | ldp x2, x3, [sp, #(8*16+2*8)] 290 | ldp x4, x5, [sp, #(8*16+4*8)] 291 | ldp x6, x7, [sp, #(8*16+6*8)] 292 | ldp x8, x30,[sp, #(8*16+8*8)] 293 | add sp, sp, #(10*8 + 8*16) 294 | 295 | /* finally return to saved return address - the caller of this trampoline... */ 296 | ret 297 | 298 | trampoline_exit: 299 | ldp q0, q1, [sp, #(0*16)] 300 | ldp q2, q3, [sp, #(2*16)] 301 | ldp q4, q5, [sp, #(4*16)] 302 | ldp q6, q7, [sp, #(6*16)] 303 | ldp x0, x1, [sp, #(8*16+0*8)] 304 | ldp x2, x3, [sp, #(8*16+2*8)] 305 | ldp x4, x5, [sp, #(8*16+4*8)] 306 | ldp x6, x7, [sp, #(8*16+6*8)] 307 | ldr x8, [sp, #(8*16+8*8)] 308 | mov sp, x29 309 | ldp x29, x30, [sp], #16 310 | br x10 311 | 312 | /* outro signature, to automatically determine code size */ 313 | trampoline_data_arm_64: 314 | .word 0x12345678 315 | )"); 316 | } 317 | #endif -------------------------------------------------------------------------------- /LinuxDetours/trampoline_x86.cpp: -------------------------------------------------------------------------------- 1 | #include "detours.h" 2 | 3 | #if defined(DETOURS_X64) 4 | __asm__ 5 | (R"(.intel_syntax 6 | .globl Trampoline_ASM_x64 7 | .globl trampoline_template_x64 8 | .globl trampoline_data_x64 9 | 10 | Trampoline_ASM_x64: 11 | 12 | NETIntro: 13 | .byte 0 14 | .byte 0 15 | .byte 0 16 | .byte 0 17 | .byte 0 18 | .byte 0 19 | .byte 0 20 | .byte 0 21 | OldProc: 22 | .byte 0 23 | .byte 0 24 | .byte 0 25 | .byte 0 26 | .byte 0 27 | .byte 0 28 | .byte 0 29 | .byte 0 30 | NewProc: 31 | .byte 0 32 | .byte 0 33 | .byte 0 34 | .byte 0 35 | .byte 0 36 | .byte 0 37 | .byte 0 38 | .byte 0 39 | NETOutro: 40 | .byte 0 41 | .byte 0 42 | .byte 0 43 | .byte 0 44 | .byte 0 45 | .byte 0 46 | .byte 0 47 | .byte 0 48 | IsExecutedPtr: 49 | .byte 0 50 | .byte 0 51 | .byte 0 52 | .byte 0 53 | .byte 0 54 | .byte 0 55 | .byte 0 56 | .byte 0 57 | 58 | trampoline_template_x64: 59 | 60 | push rsp 61 | push qword ptr [rsp] 62 | and rsp, 0xFFFFFFFFFFFFFFF0 63 | 64 | mov rax, rsp 65 | push rdi 66 | push rsi 67 | push rdx 68 | push rcx 69 | push r8 70 | push r9 71 | sub rsp, 8 * 16 ## space for SSE registers 72 | 73 | movups [rsp + 7 * 16], xmm0 74 | movups [rsp + 6 * 16], xmm1 75 | movups [rsp + 5 * 16], xmm2 76 | movups [rsp + 4 * 16], xmm3 77 | movups [rsp + 3 * 16], xmm4 78 | movups [rsp + 2 * 16], xmm5 79 | movups [rsp + 1 * 16], xmm6 80 | movups [rsp + 0 * 16], xmm7 81 | 82 | sub rsp, 32## shadow space for method calls 83 | 84 | lea rax, [rip + IsExecutedPtr] 85 | mov rax, [rax] 86 | .byte 0xF0 ## interlocked increment execution counter 87 | inc qword ptr [rax] 88 | 89 | ## is a user handler available? 90 | cmp qword ptr [rip + NewProc], 0 91 | 92 | .byte 0x3E ## branch usually taken 93 | jne call_net_entry 94 | 95 | ###################################################################################### call original method 96 | lea rax, [rip + IsExecutedPtr] 97 | mov rax, [rax] 98 | .byte 0xF0 ## interlocked decrement execution counter 99 | dec qword ptr [rax] 100 | 101 | lea rax, [rip + OldProc] 102 | jmp trampoline_exit 103 | 104 | ###################################################################################### call hook handler or original method... 105 | call_net_entry: 106 | 107 | 108 | ## call NET intro 109 | lea rdi, [rip + IsExecutedPtr + 8] ## Hook handle (only a position hint) 110 | ## Here we are under the alignment trick. 111 | mov rdx, [rsp + 32 + 8 * 16 + 6 * 8 + 8] ## rdx = original rsp (address of return address) 112 | mov rsi, [rdx] ## return address (value stored in original rsp) 113 | call qword ptr [rip + NETIntro] ## Hook->NETIntro(Hook, RetAddr, InitialRSP)## 114 | 115 | ## should call original method? 116 | test rax, rax 117 | 118 | .byte 0x3E ## branch usually taken 119 | jne call_hook_handler 120 | 121 | ## call original method 122 | lea rax, [rip + IsExecutedPtr] 123 | mov rax, [rax] 124 | .byte 0xF0 ## interlocked decrement execution counter 125 | dec qword ptr [rax] 126 | 127 | lea rax, [rip + OldProc] 128 | jmp trampoline_exit 129 | 130 | call_hook_handler: 131 | ## adjust return address 132 | lea rax, [rip + call_net_outro] 133 | ## Here we are under the alignment trick. 134 | mov r9, [rsp + 32 + 8 * 16 + 6 * 8 + 8] ## r9 = original rsp 135 | mov qword ptr [r9], rax 136 | 137 | ## call hook handler 138 | lea rax, [rip + NewProc] 139 | jmp trampoline_exit 140 | 141 | call_net_outro: ## this is where the handler returns... 142 | 143 | ## call NET outro 144 | ## Here we are NOT under the alignment trick. 145 | 146 | push 0 ## space for return address 147 | push rax 148 | 149 | sub rsp, 32 + 16## shadow space for method calls and SSE registers 150 | movups [rsp + 32], xmm0 151 | 152 | lea rdi, [rip + IsExecutedPtr + 8] ## Param 1: Hook handle hint 153 | lea rsi, [rsp + 56] ## Param 2: Address of return address 154 | call qword ptr [rip + NETOutro] ## Hook->NETOutro(Hook)## 155 | 156 | lea rax, [rip + IsExecutedPtr] 157 | mov rax, [rax] 158 | .byte 0xF0 ## interlocked decrement execution counter 159 | dec qword ptr [rax] 160 | 161 | add rsp, 32 + 16 162 | movups xmm0, [rsp - 16] 163 | 164 | pop rax ## restore return value of user handler... 165 | 166 | ## finally return to saved return address - the caller of this trampoline... 167 | ret 168 | 169 | ######################################################################################## generic outro for both cases... 170 | trampoline_exit: 171 | 172 | add rsp, 32 + 16 * 8 173 | movups xmm7, [rsp - 8 * 16] 174 | movups xmm6, [rsp - 7 * 16] 175 | movups xmm5, [rsp - 6 * 16] 176 | movups xmm4, [rsp - 5 * 16] 177 | movups xmm3, [rsp - 4 * 16] 178 | movups xmm2, [rsp - 3 * 16] 179 | movups xmm1, [rsp - 2 * 16] 180 | movups xmm0, [rsp - 1 * 16] 181 | 182 | pop r9 183 | pop r8 184 | pop rcx 185 | pop rdx 186 | pop rsi 187 | pop rdi 188 | 189 | ## Remove alignment trick: https://stackoverflow.com/a/9600102 190 | mov rsp, [rsp + 8] 191 | 192 | jmp qword ptr [rax] ## ATTENTION: In case of hook handler we will return to call_net_outro, otherwise to the caller... 193 | 194 | ## outro signature, to automatically determine code size 195 | 196 | trampoline_data_x64: 197 | .byte 0x78 198 | .byte 0x56 199 | .byte 0x34 200 | .byte 0x12 201 | 202 | )"); 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /LinuxDetours/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /** 3 | * types.h - These definitions are for linux/windows cross compiler compatibility 4 | * 5 | * author: Eric Young 01/22/2004 6 | */ 7 | 8 | 9 | #ifndef TYPES_H_ 10 | #define TYPES_H_ 11 | 12 | #define MIN(a,b) ((a < b) ? a : b) 13 | #define MAX(a,b) ((a > b) ? a : b) 14 | #define CLAMP(val,lower,upper) MAX(MIN(val,upper),lower) 15 | 16 | // These definitions are for linux 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #if defined(__linux) 35 | #include 36 | #endif 37 | #include 38 | #include 39 | 40 | // these are needed for Win32/Linux string comparisons 41 | #define genericStrICmp strcasecmp 42 | #define genericStrNICmp strncasecmp 43 | 44 | typedef char WCHAR; // wc, 16-bit UNICODE character 45 | 46 | #define CONST const 47 | typedef int BOOL; 48 | typedef long int LONG; 49 | typedef short int SHORT; 50 | typedef char CHAR; 51 | typedef int INT; 52 | typedef unsigned int DWORD; 53 | typedef unsigned short WORD; 54 | typedef unsigned char BYTE; 55 | typedef unsigned int UINT; 56 | 57 | typedef long long INT64; 58 | typedef unsigned long long UINT64; 59 | 60 | typedef int PT_FILEHANDLE; 61 | typedef void* DLL_HANDLE; 62 | 63 | typedef unsigned long* LPDWORD; 64 | typedef void* LPOVERLAPPED; 65 | typedef void* OVERLAPPED; 66 | typedef void* LPVOID; 67 | typedef void* PVOID; 68 | typedef void VOID; 69 | typedef int HANDLE; // note that handle here is assumed to be 70 | // a pointer to a file decriptor 71 | typedef int* PHANDLE; 72 | typedef int BOOL; 73 | 74 | typedef unsigned int UINT32; 75 | typedef unsigned int ULONG; 76 | typedef unsigned long long ULONG64; 77 | typedef unsigned long long ULONGLONG; 78 | typedef long long LONGLONG; 79 | 80 | typedef unsigned short USHORT; 81 | typedef unsigned char UCHAR; 82 | typedef long long INT64; 83 | typedef long long LARGE_INTEGER; 84 | typedef unsigned char BYTE; 85 | typedef BYTE* PBYTE; 86 | typedef int __int32; 87 | typedef short __int16; 88 | typedef unsigned char __int8; 89 | 90 | typedef int INT32; 91 | typedef LONG NTSTATUS; 92 | typedef BYTE BOOLEAN; 93 | typedef BOOLEAN *PBOOLEAN; 94 | typedef WCHAR *LPCWSTR, *PCWSTR; 95 | typedef WCHAR *PCHAR; 96 | typedef WCHAR *LPSTR, *PSTR; 97 | typedef WCHAR * PWCHAR, *UNICODE_STRING; 98 | typedef CHAR *PCHAR, *LPCH, *PCH; 99 | typedef CONST CHAR *LPCCH, *PCCH; 100 | 101 | typedef void * HMODULE; 102 | 103 | typedef CHAR *NPSTR, *LPSTR, *PSTR; 104 | typedef PSTR *PZPSTR; 105 | typedef CONST PSTR *PCZPSTR; 106 | typedef CONST CHAR *LPCSTR, *PCSTR; 107 | typedef PCSTR *PZPCSTR; 108 | typedef CONST PCSTR *PCZPCSTR; 109 | 110 | typedef CHAR *PZZSTR; 111 | typedef CONST CHAR *PCZZSTR; 112 | 113 | typedef CHAR *PNZCH; 114 | typedef CONST CHAR *PCNZCH; 115 | typedef DWORD *PDWORD; 116 | 117 | typedef size_t SIZE_T; 118 | 119 | //typedef unsigned long ULONG; 120 | typedef ULONG *PULONG; 121 | //typedef unsigned short USHORT; 122 | typedef USHORT *PUSHORT; 123 | //typedef unsigned char UCHAR; 124 | typedef UCHAR *PUCHAR; 125 | //typedef _Null_terminated_ char *PSZ; 126 | 127 | typedef signed char INT8, *PINT8; 128 | typedef signed short INT16, *PINT16; 129 | typedef signed int INT32, *PINT32; 130 | typedef unsigned char UINT8, *PUINT8; 131 | typedef unsigned short UINT16, *PUINT16; 132 | typedef unsigned int UINT32, *PUINT32; 133 | #if defined(_ARM64_) 134 | // 135 | // The following types are guaranteed to be signed and 64 bits wide. 136 | // 137 | 138 | typedef long long LONG64, *PLONG64; 139 | 140 | // 141 | // The following types are guaranteed to be unsigned and 64 bits wide. 142 | // 143 | 144 | typedef unsigned long long ULONG64, *PULONG64; 145 | typedef unsigned long long DWORD64, *PDWORD64; 146 | 147 | 148 | #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) 149 | #define ZeroMemory RtlZeroMemory 150 | #define NO_ERROR 0 151 | #define ERROR_INVALID_DATA 13L 152 | #if !defined(UNALIGNED) 153 | #define UNALIGNED 154 | #endif 155 | 156 | #define UNREFERENCED_PARAMETER(P) \ 157 | /*lint -save -e527 -e530 */ \ 158 | { \ 159 | (P) = (P); \ 160 | } \ 161 | 162 | #define CopyMemory memcpy 163 | 164 | #define _In_ 165 | 166 | #define CALLBACK __stdcall 167 | #define WINAPI 168 | #define WINAPIV __cdecl 169 | #define APIENTRY WINAPI 170 | #define APIPRIVATE __stdcall 171 | #define PASCAL __stdcall 172 | 173 | #define STATUS_SUCCESS 0 174 | #define STATUS_NOT_SUPPORTED 1 175 | #define STATUS_INVALID_PARAMETER_1 1 176 | #define STATUS_INVALID_PARAMETER_2 2 177 | #define STATUS_INVALID_PARAMETER_3 3 178 | #define STATUS_INVALID_PARAMETER_4 4 179 | #define STATUS_INTERNAL_ERROR 0 180 | #define STATUS_NO_MEMORY 0 181 | 182 | #define STATUS_TIMEOUT 1 183 | #define STATUS_INSUFFICIENT_RESOURCES 1 184 | #define STATUS_INVALID_PARAMETER ((DWORD)0xC000000DL) 185 | #define PAGE_EXECUTE_READWRITE PROT_EXEC | PROT_READ | PROT_WRITE 186 | #define PAGE_READONLY PROT_READ 187 | #define PAGE_READWRITE PROT_READ | PROT_WRITE 188 | #define PAGE_EXECUTE_READ PROT_EXEC | PROT_READ 189 | 190 | 191 | /* common constants */ 192 | #define SUCCESS 0 193 | #define FAILURE -1 194 | 195 | #define IOCTL_FAIL(status) (status < 0) 196 | 197 | /** unusual return codes */ 198 | #define UNIMPLEMENTED - 1001 199 | 200 | // create some equivalent constants in linux that windows have 201 | #define STATIC static 202 | 203 | #ifndef TRUE 204 | #define TRUE 1 205 | #endif 206 | 207 | #ifndef FALSE 208 | #define FALSE 0 209 | #endif 210 | 211 | #ifndef INVALID_HANDLE_VALUE 212 | #define INVALID_HANDLE_VALUE -1 213 | #endif 214 | 215 | /** sleep for x milliseconds */ 216 | //inline void nap(unsigned long msec) { usleep(msec*1000); } 217 | 218 | #define Sleep sleep 219 | #else 220 | 221 | #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) 222 | #define ZeroMemory RtlZeroMemory 223 | #define NO_ERROR 0 224 | #define ERROR_INVALID_DATA 13L 225 | #if !defined(UNALIGNED) 226 | #define UNALIGNED 227 | #endif 228 | 229 | #define UNREFERENCED_PARAMETER(P) \ 230 | /*lint -save -e527 -e530 */ \ 231 | { \ 232 | (P) = (P); \ 233 | } \ 234 | 235 | #define CopyMemory memcpy 236 | 237 | #define _In_ 238 | 239 | #define CALLBACK __stdcall 240 | #define WINAPI //__stdcall 241 | #define WINAPIV __cdecl 242 | #define APIENTRY WINAPI 243 | #define APIPRIVATE __stdcall 244 | #define PASCAL __stdcall 245 | 246 | #define STATUS_SUCCESS 0 247 | #define STATUS_NOT_SUPPORTED 1 248 | #define STATUS_INVALID_PARAMETER_1 1 249 | #define STATUS_INVALID_PARAMETER_2 2 250 | #define STATUS_INVALID_PARAMETER_3 3 251 | #define STATUS_INVALID_PARAMETER_4 4 252 | #define STATUS_INTERNAL_ERROR 0 253 | #define STATUS_NO_MEMORY 0 254 | 255 | #define STATUS_TIMEOUT 1 256 | #define STATUS_INSUFFICIENT_RESOURCES 1 257 | #define STATUS_INVALID_PARAMETER ((DWORD)0xC000000DL) 258 | #define PAGE_EXECUTE_READWRITE PROT_EXEC | PROT_READ | PROT_WRITE 259 | #define PAGE_READONLY PROT_READ 260 | #define PAGE_READWRITE PROT_READ | PROT_WRITE 261 | #define PAGE_EXECUTE_READ PROT_EXEC | PROT_READ 262 | /* These are defined so we can use TCHAR compatible string calls */ 263 | #define _TINT int 264 | #define _T(arg) arg 265 | #define TCHAR char 266 | #define tstrcpy strcpy 267 | #define tstrncpy strncpy 268 | #define _tcscat strcat 269 | #define _tcscpy(str1, str2) strcpy(str1, str2) 270 | #define _tcslen(str1) strlen(str1) 271 | #define _tfopen(filename, access) fopen(filename, access) 272 | #define _gettc getc 273 | #define _puttc putc 274 | #define _stscanf sscanf 275 | #define _stprintf sprintf 276 | #define _sntprintf snprintf 277 | #define _tprintf printf 278 | 279 | 280 | 281 | /* common constants */ 282 | #define SUCCESS 0 283 | #define FAILURE -1 284 | 285 | #define IOCTL_FAIL(status) (status < 0) 286 | 287 | /** unusual return codes */ 288 | #define UNIMPLEMENTED -1001 289 | 290 | // create some equivalent constants in linux that windows have 291 | #define STATIC static 292 | 293 | #ifndef TRUE 294 | #define TRUE 1 295 | #endif 296 | 297 | #ifndef FALSE 298 | #define FALSE 0 299 | #endif 300 | 301 | #ifndef INVALID_HANDLE_VALUE 302 | #define INVALID_HANDLE_VALUE -1 303 | #endif 304 | 305 | /** sleep for x milliseconds */ 306 | //inline void nap(unsigned long msec) { usleep(msec*1000); } 307 | 308 | #define Sleep sleep 309 | 310 | //typedef double VWTIME; 311 | /** returns the amount of time in seconds since some arbitrary moment. */ 312 | //inline VWTIME VWGetTime() { return 0.0; } 313 | 314 | 315 | #endif // end of the WIN32/Linux definitions 316 | 317 | 318 | // These are common declared types 319 | 320 | typedef unsigned char* PU8; 321 | typedef unsigned char U8; 322 | typedef unsigned short U16; 323 | typedef unsigned long U32; 324 | typedef signed char S8; 325 | typedef signed short S16; 326 | typedef signed long S32; 327 | 328 | 329 | #if defined(_DEBUG) 330 | #define dbgprint(string) { printf string; fflush(stdout); } 331 | #else 332 | #define dbgprint(string) 333 | #endif 334 | 335 | #include 336 | 337 | #endif // end of TYPES_H_ 338 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux Detours 2 | [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/unknownv2/LinuxDetours/blob/master/LICENSE) 3 | 4 | The [Microsoft Detours](https://github.com/Microsoft/Detours) library combined with the [EasyHook](https://github.com/EasyHook/EasyHook) C module thread barrier implementation and modified to work on Linux with support for X64, ARM (supports both ARM32 and Thumb instructions), and ARM64 architectures. 5 | 6 | 7 | ## Dependencies 8 | 9 | ### [Google Logging Module - glog](https://github.com/google/glog) 10 | 11 | You can install it by running: 12 | 13 | ``` 14 | sudo apt-get install libgoogle-glog-dev 15 | ``` 16 | 17 | ## Build 18 | 19 | ### LinuxDetours - Application 20 | You can use Visual Studio to build the `LinuxDetours` application after configuring the project to connect to your Linux system. 21 | 22 | ### libdetours - Shared Library (*.so, *.dylib) 23 | 24 | You can use the [`makefile`](LinuxDetours/Makefile) to build the shared library. The makefile outputs `libdetours32` for ARM and `libdetours64` for X64 and ARM64 in the `LinuxDetours` source directory. 25 | 26 | ``` 27 | git clone https://github.com/unknownv2/LinuxDetours.git 28 | cd LinuxDetours 29 | make -C LinuxDetours 30 | ``` --------------------------------------------------------------------------------