├── .gitignore ├── .gitmodules ├── COPYING ├── PawnIO.sln ├── PawnIO ├── PawnIO.filters ├── PawnIO.inf ├── PawnIO.vcxproj ├── amx_loader.h ├── arch_detect.h ├── driver.cpp ├── ioctl.h ├── msrmrs.cpp ├── natives_impl.h ├── natives_impl_windows.cpp ├── signature.cpp ├── vm.cpp ├── vm.h └── x64.asm ├── README.md ├── cab.ddf └── gencab.bat /.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]eleaseUnrestricted/ 18 | [Rr]eleases/ 19 | bld/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | [Ll]og/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | project.fragment.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | #*.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.jfm 192 | *.pfx 193 | *.publishsettings 194 | node_modules/ 195 | orleans.codegen.cs 196 | 197 | # Since there are multiple workflows, uncomment next line to ignore bower_components 198 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 199 | #bower_components/ 200 | 201 | # RIA/Silverlight projects 202 | Generated_Code/ 203 | 204 | # Backup & report files from converting an old project file 205 | # to a newer Visual Studio version. Backup files are not needed, 206 | # because we have git ;-) 207 | _UpgradeReport_Files/ 208 | Backup*/ 209 | UpgradeLog*.XML 210 | UpgradeLog*.htm 211 | 212 | # SQL Server files 213 | *.mdf 214 | *.ldf 215 | 216 | # Business Intelligence projects 217 | *.rdl.data 218 | *.bim.layout 219 | *.bim_*.settings 220 | 221 | # Microsoft Fakes 222 | FakesAssemblies/ 223 | 224 | # GhostDoc plugin setting file 225 | *.GhostDoc.xml 226 | 227 | # Node.js Tools for Visual Studio 228 | .ntvs_analysis.dat 229 | 230 | # Visual Studio 6 build log 231 | *.plg 232 | 233 | # Visual Studio 6 workspace options file 234 | *.opt 235 | 236 | # Visual Studio LightSwitch build output 237 | **/*.HTMLClient/GeneratedArtifacts 238 | **/*.DesktopClient/GeneratedArtifacts 239 | **/*.DesktopClient/ModelManifest.xml 240 | **/*.Server/GeneratedArtifacts 241 | **/*.Server/ModelManifest.xml 242 | _Pvt_Extensions 243 | 244 | # Paket dependency manager 245 | .paket/paket.exe 246 | paket-files/ 247 | 248 | # FAKE - F# Make 249 | .fake/ 250 | 251 | # JetBrains Rider 252 | .idea/ 253 | *.sln.iml 254 | 255 | # CodeRush 256 | .cr/ 257 | 258 | # Python Tools for Visual Studio (PTVS) 259 | __pycache__/ 260 | *.pyc 261 | 262 | cabs 263 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "PawnPP"] 2 | path = PawnPP 3 | url = https://github.com/namazso/PawnPP 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /PawnIO.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32922.545 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PawnIO", "PawnIO\PawnIO.vcxproj", "{81038770-5789-48B5-8355-68B1FCCE4912}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|x64 = Debug|x64 12 | Release|ARM64 = Release|ARM64 13 | Release|x64 = Release|x64 14 | ReleaseUnrestricted|ARM64 = ReleaseUnrestricted|ARM64 15 | ReleaseUnrestricted|x64 = ReleaseUnrestricted|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|ARM64.ActiveCfg = Debug|ARM64 19 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|ARM64.Build.0 = Debug|ARM64 20 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|ARM64.Deploy.0 = Debug|ARM64 21 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|x64.ActiveCfg = Debug|x64 22 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|x64.Build.0 = Debug|x64 23 | {81038770-5789-48B5-8355-68B1FCCE4912}.Debug|x64.Deploy.0 = Debug|x64 24 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|ARM64.ActiveCfg = Release|ARM64 25 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|ARM64.Build.0 = Release|ARM64 26 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|ARM64.Deploy.0 = Release|ARM64 27 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|x64.ActiveCfg = Release|x64 28 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|x64.Build.0 = Release|x64 29 | {81038770-5789-48B5-8355-68B1FCCE4912}.Release|x64.Deploy.0 = Release|x64 30 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|ARM64.ActiveCfg = ReleaseUnrestricted|ARM64 31 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|ARM64.Build.0 = ReleaseUnrestricted|ARM64 32 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|ARM64.Deploy.0 = ReleaseUnrestricted|ARM64 33 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|x64.ActiveCfg = ReleaseUnrestricted|x64 34 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|x64.Build.0 = ReleaseUnrestricted|x64 35 | {81038770-5789-48B5-8355-68B1FCCE4912}.ReleaseUnrestricted|x64.Deploy.0 = ReleaseUnrestricted|x64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {B6A3B930-A3BD-4F20-8532-E89DCEAE08B8} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /PawnIO/PawnIO.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {8E41214B-6785-4CFE-B992-037D68949A14} 14 | inf;inv;inx;mof;mc; 15 | 16 | 17 | {927cd96a-d27f-4c5f-b064-bc6b11c5c2d9} 18 | 19 | 20 | 21 | 22 | Driver Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | Native Calls 34 | 35 | 36 | Header Files 37 | 38 | 39 | 40 | 41 | Source Files 42 | 43 | 44 | Native Calls 45 | 46 | 47 | Native Calls 48 | 49 | 50 | Source Files 51 | 52 | 53 | Source Files 54 | 55 | 56 | 57 | 58 | Native Calls 59 | 60 | 61 | -------------------------------------------------------------------------------- /PawnIO/PawnIO.inf: -------------------------------------------------------------------------------- 1 | ; PawnIO - Input-output driver 2 | ; Copyright (C) 2023 namazso 3 | ; 4 | ; This program is free software; you can redistribute it and/or modify 5 | ; it under the terms of the GNU General Public License as published by 6 | ; the Free Software Foundation; either version 2 of the License, or 7 | ; (at your option) any later version. 8 | ; 9 | ; This program is distributed in the hope that it will be useful, 10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ; GNU General Public License for more details. 13 | ; 14 | ; You should have received a copy of the GNU General Public License along 15 | ; with this program; if not, write to the Free Software Foundation, Inc., 16 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | ; 18 | ; Linking PawnIO statically or dynamically with other modules is making a 19 | ; combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | ; General Public License cover the whole combination. 21 | ; 22 | ; In addition, as a special exception, the copyright holders of PawnIO give 23 | ; you permission to combine PawnIO program with free software programs or 24 | ; libraries that are released under the GNU LGPL and with independent modules 25 | ; that communicate with PawnIO solely through the device IO control 26 | ; interface. You may copy and distribute such a system following the terms of 27 | ; the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | ; provided that you include the source code of that other code when and as 29 | ; the GNU GPL requires distribution of source code. 30 | ; 31 | ; Note that this exception does not include programs that communicate with 32 | ; PawnIO over the Pawn interface. This means that all modules loaded into 33 | ; PawnIO must be compatible with this licence, including the earlier 34 | ; exception clause. We recommend using the GNU Lesser General Public License 35 | ; version 2.1 to fulfill this requirement. 36 | ; 37 | ; For alternative licensing options, please contact the copyright holder at 38 | ; admin@namazso.eu. 39 | ; 40 | ; Note that people who make modified versions of PawnIO are not obligated to 41 | ; grant this special exception for their modified versions; it is their 42 | ; choice whether to do so. The GNU General Public License gives permission 43 | ; to release a modified version without this exception; this exception also 44 | ; makes it possible to release a modified version which carries forward this 45 | ; exception. 46 | 47 | [Version] 48 | Signature = "$WINDOWS NT$" 49 | Class = PawnIO_Class 50 | ClassGuid = {7c619961-f266-4c1b-8472-8d0047d6d47a} 51 | Provider = %ManufacturerName% 52 | CatalogFile = PawnIO.cat 53 | DriverVer = 09/01/2022,1.0.0.0 54 | PnpLockdown = 1 55 | 56 | [DestinationDirs] 57 | DefaultDestDir = 13 58 | 59 | ; ================= Class section ===================== 60 | 61 | [ClassInstall32] 62 | Addreg = PawnIOClassReg 63 | 64 | [PawnIOClassReg] 65 | HKR,,,0,%ClassName% 66 | HKR,,Icon,,-5 67 | 68 | [SourceDisksNames] 69 | 1 = %DiskName%,,,"" 70 | 71 | [SourceDisksFiles] 72 | PawnIO.sys = 1,, 73 | 74 | ;***************************************** 75 | ; Install Section 76 | ;***************************************** 77 | 78 | [DefaultInstall.NT$ARCH$] 79 | CopyFiles = Drivers_Dir 80 | 81 | [Drivers_Dir] 82 | PawnIO.sys 83 | 84 | ;-------------- Service installation 85 | [DefaultInstall.NT$ARCH$.Services] 86 | AddService = PawnIO,, PawnIO_Service_Inst 87 | 88 | ; -------------- PawnIO driver install sections 89 | [PawnIO_Service_Inst] 90 | DisplayName = %PawnIO.SVCDESC% 91 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 92 | StartType = 1 ; SERVICE_SYSTEM_START 93 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 94 | ServiceBinary = %13%\PawnIO.sys 95 | 96 | [Strings] 97 | ManufacturerName = "namazso" 98 | ClassName = "PawnIO_Class" 99 | DiskName = "PawnIO Installation Disk" 100 | PawnIO.DeviceDesc = "PawnIO Device" 101 | PawnIO.SVCDESC = "PawnIO Service" 102 | -------------------------------------------------------------------------------- /PawnIO/PawnIO.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | ReleaseUnrestricted 10 | ARM64 11 | 12 | 13 | ReleaseUnrestricted 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM64 23 | 24 | 25 | Release 26 | ARM64 27 | 28 | 29 | 30 | 31 | 32 | true 33 | true 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {81038770-5789-48B5-8355-68B1FCCE4912} 52 | {497e31cb-056b-4f31-abb8-447fd55ee5a5} 53 | v4.5 54 | 12.0 55 | Debug 56 | PawnIO 57 | $(LatestTargetPlatformVersion) 58 | 59 | 60 | 61 | Windows10 62 | true 63 | WindowsKernelModeDriver10.0 64 | Driver 65 | KMDF 66 | Windows Driver 67 | Spectre 68 | 69 | 70 | Windows10 71 | false 72 | WindowsKernelModeDriver10.0 73 | Driver 74 | KMDF 75 | Windows Driver 76 | Spectre 77 | 78 | 79 | Windows10 80 | false 81 | WindowsKernelModeDriver10.0 82 | Driver 83 | KMDF 84 | Windows Driver 85 | Spectre 86 | 87 | 88 | Windows10 89 | true 90 | WindowsKernelModeDriver10.0 91 | Driver 92 | KMDF 93 | Windows Driver 94 | Spectre 95 | 96 | 97 | Windows10 98 | false 99 | WindowsKernelModeDriver10.0 100 | Driver 101 | KMDF 102 | Windows Driver 103 | Spectre 104 | 105 | 106 | Windows10 107 | false 108 | WindowsKernelModeDriver10.0 109 | Driver 110 | KMDF 111 | Windows Driver 112 | Spectre 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | DbgengKernelDebugger 122 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 123 | 124 | 125 | DbgengKernelDebugger 126 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 127 | 128 | 129 | DbgengKernelDebugger 130 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 131 | 132 | 133 | DbgengKernelDebugger 134 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 135 | 136 | 137 | DbgengKernelDebugger 138 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 139 | 140 | 141 | DbgengKernelDebugger 142 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) 143 | 144 | 145 | 146 | false 147 | true 148 | trace.h 149 | true 150 | stdcpp17 151 | /Brepro %(AdditionalOptions) 152 | true 153 | false 154 | 155 | 156 | 157 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 158 | /Brepro /nocoffgrpinfo %(AdditionalOptions) 159 | true 160 | 161 | 162 | sha256 163 | 164 | 165 | false 166 | 167 | 168 | false 169 | 170 | 171 | 172 | 173 | false 174 | true 175 | trace.h 176 | true 177 | stdcpp17 178 | /Brepro %(AdditionalOptions) 179 | true 180 | false 181 | 182 | 183 | 184 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 185 | /Brepro /nocoffgrpinfo /PDBALTPATH:%_PDB% %(AdditionalOptions) 186 | true 187 | 188 | 189 | sha256 190 | 191 | 192 | false 193 | 194 | 195 | false 196 | 197 | 198 | 199 | 200 | false 201 | true 202 | trace.h 203 | true 204 | stdcpp17 205 | /Brepro %(AdditionalOptions) 206 | true 207 | false 208 | PAWNIO_UNRESTRICTED=1;%(PreprocessorDefinitions) 209 | 210 | 211 | 212 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 213 | /Brepro /nocoffgrpinfo /PDBALTPATH:%_PDB% %(AdditionalOptions) 214 | true 215 | 216 | 217 | sha256 218 | 219 | 220 | false 221 | 222 | 223 | false 224 | 225 | 226 | 227 | 228 | false 229 | true 230 | trace.h 231 | true 232 | stdcpp17 233 | /Brepro %(AdditionalOptions) 234 | true 235 | false 236 | 237 | 238 | 239 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 240 | /Brepro /nocoffgrpinfo /PDBALTPATH:%_PDB% %(AdditionalOptions) 241 | 242 | 243 | false 244 | 245 | 246 | false 247 | 248 | 249 | 250 | 251 | false 252 | true 253 | trace.h 254 | true 255 | stdcpp17 256 | /Brepro %(AdditionalOptions) 257 | true 258 | false 259 | PAWNIO_UNRESTRICTED=1;%(PreprocessorDefinitions) 260 | 261 | 262 | 263 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 264 | /Brepro /nocoffgrpinfo /PDBALTPATH:%_PDB% %(AdditionalOptions) 265 | 266 | 267 | false 268 | 269 | 270 | false 271 | 272 | 273 | 274 | 275 | false 276 | true 277 | trace.h 278 | true 279 | stdcpp17 280 | /Brepro %(AdditionalOptions) 281 | true 282 | false 283 | 284 | 285 | 286 | $(DDK_LIB_PATH)ksecdd.lib;$(DDK_LIB_PATH)Wdmsec.lib;%(AdditionalDependencies) 287 | /Brepro /nocoffgrpinfo %(AdditionalOptions) 288 | 289 | 290 | false 291 | 292 | 293 | false 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | true 302 | true 303 | true 304 | 305 | 306 | 307 | -------------------------------------------------------------------------------- /PawnIO/amx_loader.h: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #pragma once 48 | #include "../PawnPP/amx.h" 49 | #include 50 | 51 | namespace amx 52 | { 53 | enum class loader_error 54 | { 55 | success, 56 | invalid_file, 57 | unsupported_file_version, 58 | unsupported_amx_version, 59 | feature_not_supported, 60 | wrong_cell_size, 61 | native_not_resolved, 62 | unknown 63 | }; 64 | 65 | namespace detail 66 | { 67 | template 68 | static T byteswap(T t) 69 | { 70 | for (size_t i = 0; i < sizeof(t) / 2; ++i) 71 | std::swap(*(((char*)&t) + i), *((char*)&t + sizeof(t) - 1 - i)); 72 | return t; 73 | } 74 | 75 | template 76 | static T from_le(T t) 77 | { 78 | #if defined(BIG_ENDIAN) 79 | return byteswap(t); 80 | #elif defined(LITTLE_ENDIAN) 81 | return t; 82 | #else 83 | #error Define either BIG_ENDIAN or LITTLE_ENDIAN 84 | #endif 85 | } 86 | 87 | template 88 | static T read_le(const uint8_t* p) 89 | { 90 | T t{}; 91 | memcpy(&t, p, sizeof(t)); 92 | t = from_le(t); 93 | return t; 94 | } 95 | 96 | template 97 | static T align_up(T value, size_t align) 98 | { 99 | return (T)((value + align - 1) / align * align); 100 | } 101 | 102 | template 103 | static bool iter_valarray( 104 | const uint8_t* buf, 105 | size_t buf_size, 106 | size_t begin_offset, 107 | size_t end_offset, 108 | size_t entry_size, 109 | Fn fn = {} 110 | ) 111 | { 112 | const auto begin = buf + begin_offset; 113 | const auto end = buf + end_offset; 114 | const auto size = (size_t)(end - begin); 115 | const auto buf_end = buf + buf_size; 116 | 117 | if (begin < buf || begin > buf_end) 118 | return false; 119 | if (end < buf || end > buf_end) 120 | return false; 121 | if (begin > end || size % entry_size != 0) 122 | return false; 123 | 124 | for (size_t i = 0; i < size / entry_size; ++i) 125 | if (!fn(begin + i * entry_size)) 126 | return false; 127 | return true; 128 | } 129 | 130 | static bool count_valarray( 131 | const uint8_t* buf, 132 | size_t buf_size, 133 | size_t begin_offset, 134 | size_t end_offset, 135 | size_t entry_size, 136 | size_t& count 137 | ) 138 | { 139 | // local to help the compiler optimize 140 | size_t count_local{}; 141 | const auto ret = iter_valarray(buf, buf_size, begin_offset, end_offset, entry_size, [&count_local](const uint8_t*) 142 | { 143 | ++count_local; 144 | return true; 145 | }); 146 | count = count_local; 147 | return ret; 148 | } 149 | 150 | template 151 | static void alloc_from_buffer_aligned( 152 | uint8_t*& buf, 153 | T*& alloc_out_buf, 154 | size_t& alloc_out_count, 155 | size_t alloc_count 156 | ) 157 | { 158 | alloc_out_buf = (T*)buf; 159 | alloc_out_count = alloc_count; 160 | buf += align_up(alloc_count * sizeof(*alloc_out_buf), MEMORY_ALLOCATION_ALIGNMENT); 161 | } 162 | } 163 | 164 | template 165 | class loader 166 | { 167 | public: 168 | using amx_t = Amx; 169 | 170 | using cell = typename amx_t::cell; 171 | using scell = typename amx_t::scell; 172 | constexpr static size_t cell_bits = amx_t::cell_bits; 173 | 174 | private: 175 | constexpr static uint16_t expected_magic = 176 | cell_bits == 32 ? 0xF1E0 : 177 | cell_bits == 64 ? 0xF1E1 : 178 | cell_bits == 16 ? 0xF1E2 : 179 | 0; 180 | 181 | enum : uint32_t 182 | { 183 | flag_overlay = 1 << 0, 184 | flag_debug = 1 << 1, 185 | flag_nochecks = 1 << 2, 186 | flag_sleep = 1 << 3, 187 | flag_dseg_init = 1 << 5, 188 | }; 189 | 190 | cell* _code_ptr{}; 191 | size_t _code_count{}; 192 | cell* _data_ptr{}; 193 | size_t _data_count{}; 194 | 195 | public: 196 | amx_t amx{ &amx_callback_wrapper, this }; 197 | 198 | using native_fn = error(*)(amx_t* amx, loader* loader, void* user, cell argc, cell argv, cell& retval); 199 | using single_step_fn = error(*)(amx_t* amx, loader* loader, void* user); 200 | using break_fn = error(*)(amx_t* amx, loader* loader, void* user); 201 | 202 | struct native_arg 203 | { 204 | const char* name; 205 | native_fn callback; 206 | }; 207 | struct callbacks_arg 208 | { 209 | const native_arg* natives; 210 | size_t natives_count; 211 | single_step_fn on_single_step; 212 | break_fn on_break; 213 | void* user_data; 214 | }; 215 | 216 | private: 217 | single_step_fn _on_single_step{}; 218 | break_fn _on_break{}; 219 | void* _callback_user_data{}; 220 | 221 | native_fn* _natives_ptr{}; 222 | size_t _natives_count{}; 223 | 224 | std::pair* _publics_ptr{}; 225 | size_t _publics_count{}; 226 | 227 | std::pair* _pubvars_ptr{}; 228 | size_t _pubvars_count{}; 229 | 230 | cell _main{}; 231 | 232 | void* _alloc{}; 233 | 234 | public: 235 | cell get_public(const char* v) 236 | { 237 | const auto begin = _publics_ptr; 238 | const auto end = begin + _publics_count; 239 | const auto result = std::find_if(begin, end, [v](std::pair& a) 240 | { 241 | return 0 == strcmp(v, a.first); 242 | }); 243 | 244 | return result == end ? 0 : result->second; 245 | } 246 | cell get_pubvar(const char* v) 247 | { 248 | const auto begin = _pubvars_ptr; 249 | const auto end = begin + _pubvars_count; 250 | const auto result = std::find_if(begin, end, [v](std::pair& a) 251 | { 252 | return 0 == strcmp(v, a.first); 253 | }); 254 | 255 | return result == end ? 0 : result->second; 256 | } 257 | cell get_main() { return _main; } 258 | 259 | private: 260 | error amx_callback(cell index, cell stk, cell& pri) 261 | { 262 | if (index == amx_t::cbid_single_step) 263 | return _on_single_step ? _on_single_step(&amx, this, _callback_user_data) : error::success; 264 | if (index == amx_t::cbid_break) 265 | return _on_break ? _on_break(&amx, this, _callback_user_data) : error::success; 266 | if (index >= _natives_count) 267 | return error::invalid_operand; 268 | const auto pargc = amx.data_v2p(stk); 269 | if (!pargc) 270 | return error::access_violation; 271 | return _natives_ptr[(size_t)index](&amx, this, _callback_user_data, (*pargc / sizeof(cell)), stk + sizeof(cell), pri); 272 | } 273 | 274 | static error amx_callback_wrapper(amx_t*, void* user_data, cell index, cell stk, cell& pri) 275 | { 276 | return ((loader*)user_data)->amx_callback(index, stk, pri); 277 | } 278 | 279 | public: 280 | loader_error init(const uint8_t* buf, size_t buf_size, const callbacks_arg& callbacks) 281 | { 282 | static_assert(expected_magic != 0, "unsupported cell size"); 283 | using namespace detail; 284 | 285 | _on_single_step = callbacks.on_single_step; 286 | _on_break = callbacks.on_break; 287 | _callback_user_data = callbacks.user_data; 288 | 289 | if (buf_size < 60) 290 | return loader_error::invalid_file; 291 | 292 | const auto size = read_le(buf); 293 | const auto magic = read_le(buf + 4); 294 | const auto file_version = *(buf + 6); 295 | const auto amx_version = *(buf + 7); 296 | const auto flags = read_le(buf + 8); 297 | const auto defsize = read_le(buf + 10); 298 | const auto cod = read_le(buf + 12); 299 | const auto dat = read_le(buf + 16); 300 | const auto hea = read_le(buf + 20); 301 | const auto stp = read_le(buf + 24); 302 | const auto cip = read_le(buf + 28); 303 | const auto publics = read_le(buf + 32); 304 | const auto natives = read_le(buf + 36); 305 | const auto libraries = read_le(buf + 40); 306 | const auto pubvars = read_le(buf + 44); 307 | const auto tags = read_le(buf + 48); 308 | //const auto nametable = read_le(buf + 52); 309 | //const auto overlays = read_le(buf + 56); 310 | if (magic != expected_magic) 311 | { 312 | switch (magic) 313 | { 314 | case 0xF1E0: 315 | case 0xF1E1: 316 | case 0xF1E2: 317 | return loader_error::wrong_cell_size; 318 | default: 319 | return loader_error::invalid_file; 320 | } 321 | } 322 | if (size > buf_size) 323 | return loader_error::invalid_file; 324 | if (file_version != 11) 325 | return loader_error::unsupported_file_version; 326 | if (amx_version > amx_t::version) 327 | return loader_error::unsupported_amx_version; 328 | if (flags & flag_overlay || flags & flag_sleep) 329 | return loader_error::feature_not_supported; 330 | if (defsize < 8) 331 | return loader_error::invalid_file; 332 | 333 | size_t code_count{}; 334 | if (!count_valarray(buf, buf_size, cod, dat, sizeof(cell), code_count)) 335 | return loader_error::invalid_file; 336 | 337 | size_t data_count{}; 338 | if (!count_valarray(buf, buf_size, dat, hea, sizeof(cell), data_count)) 339 | return loader_error::invalid_file; 340 | 341 | const auto extra_size = (stp - hea) + sizeof(cell) - 1; 342 | const auto data_alloc_count = data_count + extra_size / sizeof(cell); 343 | 344 | _main = (cip == (uint32_t)-1 ? 0 : cip); 345 | 346 | size_t string_buffer_size{}; 347 | 348 | size_t publics_count{}; 349 | 350 | auto success = iter_valarray( 351 | buf, 352 | buf_size, 353 | publics, 354 | natives, 355 | defsize, 356 | [&](const uint8_t* p) 357 | { 358 | //const auto address = read_le(p); 359 | const auto nameofs = read_le(p + 4); 360 | auto nameend = nameofs; 361 | for (; nameend < buf_size; ++nameend) 362 | if (!buf[nameend]) 363 | break; 364 | if (nameend >= buf_size) 365 | return false; 366 | const auto begin = (const char*)buf + nameofs; 367 | const auto end = (const char*)buf + nameend; 368 | ++publics_count; 369 | string_buffer_size += end - begin + 1; 370 | //std::string name{ begin, end }; 371 | //this->_publics[name] = address; 372 | return true; 373 | } 374 | ); 375 | 376 | if (!success) 377 | return loader_error::invalid_file; 378 | 379 | size_t natives_count{}; 380 | bool native_not_found = false; 381 | success = iter_valarray( 382 | buf, 383 | buf_size, 384 | natives, 385 | libraries, 386 | defsize, 387 | [&](const uint8_t* p) 388 | { 389 | const auto nameofs = read_le(p + 4); 390 | auto nameend = nameofs; 391 | for (; nameend < buf_size; ++nameend) 392 | if (!buf[nameend]) 393 | break; 394 | if (nameend >= buf_size) 395 | return false; 396 | const auto begin = (const char*)buf + nameofs; 397 | //const auto end = (const char*)buf + nameend; 398 | 399 | const auto callbacks_natives_end = callbacks.natives + callbacks.natives_count; 400 | const auto result = std::find_if( 401 | callbacks.natives, 402 | callbacks_natives_end, 403 | [&begin](const native_arg& current) { return 0 == strcmp(begin, current.name); } 404 | ); 405 | if (result == callbacks_natives_end) 406 | { 407 | native_not_found = true; 408 | return false; 409 | } 410 | ++natives_count; 411 | //this->_natives.push_back(result->callback); 412 | return true; 413 | } 414 | ); 415 | 416 | if (!success) 417 | return native_not_found ? loader_error::native_not_resolved : loader_error::invalid_file; 418 | 419 | if (libraries != pubvars) 420 | return loader_error::feature_not_supported; 421 | 422 | size_t pubvars_count{}; 423 | success = iter_valarray( 424 | buf, 425 | buf_size, 426 | pubvars, 427 | tags, 428 | defsize, 429 | [&](const uint8_t* p) 430 | { 431 | //const auto address = read_le(p); 432 | const auto nameofs = read_le(p + 4); 433 | auto nameend = nameofs; 434 | for (; nameend < buf_size; ++nameend) 435 | if (!buf[nameend]) 436 | break; 437 | if (nameend >= buf_size) 438 | return false; 439 | const auto begin = (const char*)buf + nameofs; 440 | const auto end = (const char*)buf + nameend; 441 | ++pubvars_count; 442 | string_buffer_size += end - begin + 1; 443 | //std::string name{ begin, end }; 444 | //this->_pubvars[name] = address; 445 | return true; 446 | } 447 | ); 448 | 449 | if (!success) 450 | return loader_error::invalid_file; 451 | 452 | const size_t alloc_size = 0 453 | + align_up(code_count * sizeof(cell), MEMORY_ALLOCATION_ALIGNMENT) 454 | + align_up(data_alloc_count * sizeof(cell), MEMORY_ALLOCATION_ALIGNMENT) 455 | + align_up(publics_count * sizeof(*_publics_ptr), MEMORY_ALLOCATION_ALIGNMENT) 456 | + align_up(pubvars_count * sizeof(*_publics_ptr), MEMORY_ALLOCATION_ALIGNMENT) 457 | + align_up(natives_count * sizeof(*_publics_ptr), MEMORY_ALLOCATION_ALIGNMENT) 458 | + string_buffer_size; 459 | 460 | const auto alloc = ExAllocatePoolZero(NonPagedPoolNxCacheAligned, alloc_size, 'LxmA'); 461 | if (!alloc) 462 | return loader_error::unknown; 463 | 464 | memset(alloc, 0, alloc_size); 465 | 466 | _alloc = alloc; 467 | 468 | auto alloc_it = (uint8_t*)alloc; 469 | 470 | alloc_from_buffer_aligned(alloc_it, _code_ptr, _code_count, code_count); 471 | alloc_from_buffer_aligned(alloc_it, _data_ptr, _data_count, data_alloc_count); 472 | alloc_from_buffer_aligned(alloc_it, _publics_ptr, _publics_count, publics_count); 473 | alloc_from_buffer_aligned(alloc_it, _pubvars_ptr, _pubvars_count, pubvars_count); 474 | alloc_from_buffer_aligned(alloc_it, _natives_ptr, _natives_count, natives_count); 475 | 476 | auto string_buffer = (char*)alloc_it; 477 | 478 | // safe since it was checked when counting 479 | memcpy(_code_ptr, buf + cod, dat - cod); 480 | for (size_t i = 0; i < _code_count; ++i) 481 | _code_ptr[i] = from_le(_code_ptr[i]); 482 | 483 | // safe since it was checked when counting 484 | memcpy(_data_ptr, buf + dat, hea - dat); 485 | for (size_t i = 0; i < _code_count; ++i) 486 | _data_ptr[i] = from_le(_data_ptr[i]); 487 | 488 | cell code_base{}; 489 | bool result = amx.mem.code().map(_code_ptr, _code_count, code_base); 490 | if (!result) 491 | return loader_error::unknown; 492 | 493 | cell data_base{}; 494 | result = amx.mem.data().map(_data_ptr, _data_count, data_base); 495 | if (!result) 496 | return loader_error::unknown; 497 | 498 | // safe since it was checked when counting 499 | size_t publics_counter{}; 500 | iter_valarray( 501 | buf, 502 | buf_size, 503 | publics, 504 | natives, 505 | defsize, 506 | [&](const uint8_t* p) 507 | { 508 | const auto address = read_le(p); 509 | const auto nameofs = read_le(p + 4); 510 | auto nameend = nameofs; 511 | for (; nameend < buf_size; ++nameend) 512 | if (!buf[nameend]) 513 | break; 514 | if (nameend >= buf_size) 515 | return false; 516 | const auto begin = (const char*)buf + nameofs; 517 | const auto end = (const char*)buf + nameend; 518 | 519 | char* name = string_buffer; 520 | string_buffer += end - begin + 1; 521 | memcpy(name, begin, end - begin); 522 | 523 | this->_publics_ptr[publics_counter++] = { name, address }; 524 | return true; 525 | } 526 | ); 527 | 528 | // safe since it was checked when counting 529 | size_t natives_counter{}; 530 | iter_valarray( 531 | buf, 532 | buf_size, 533 | natives, 534 | libraries, 535 | defsize, 536 | [&](const uint8_t* p) 537 | { 538 | const auto nameofs = read_le(p + 4); 539 | auto nameend = nameofs; 540 | for (; nameend < buf_size; ++nameend) 541 | if (!buf[nameend]) 542 | break; 543 | if (nameend >= buf_size) 544 | return false; 545 | const auto begin = (const char*)buf + nameofs; 546 | //const auto end = (const char*)buf + nameend; 547 | 548 | const auto callbacks_natives_end = callbacks.natives + callbacks.natives_count; 549 | const auto result_it = std::find_if( 550 | callbacks.natives, 551 | callbacks_natives_end, 552 | [&begin](const native_arg& current) { return 0 == strcmp(begin, current.name); } 553 | ); 554 | if (result_it == callbacks_natives_end) 555 | { 556 | native_not_found = true; 557 | return false; 558 | } 559 | this->_natives_ptr[natives_counter++] = result_it->callback; 560 | return true; 561 | } 562 | ); 563 | 564 | // safe since it was checked when counting 565 | size_t pubvars_counter{}; 566 | iter_valarray( 567 | buf, 568 | buf_size, 569 | pubvars, 570 | tags, 571 | defsize, 572 | [&](const uint8_t* p) 573 | { 574 | const auto address = read_le(p); 575 | const auto nameofs = read_le(p + 4); 576 | auto nameend = nameofs; 577 | for (; nameend < buf_size; ++nameend) 578 | if (!buf[nameend]) 579 | break; 580 | if (nameend >= buf_size) 581 | return false; 582 | const auto begin = (const char*)buf + nameofs; 583 | const auto end = (const char*)buf + nameend; 584 | ++pubvars_count; 585 | string_buffer_size += end - begin + 1; 586 | 587 | char* name = string_buffer; 588 | string_buffer += end - begin + 1; 589 | memcpy(name, begin, end - begin); 590 | 591 | this->_pubvars_ptr[pubvars_counter++] = { name, address }; 592 | return true; 593 | } 594 | ); 595 | 596 | // something went very very wrong 597 | if (string_buffer >= (char*)alloc + alloc_size) 598 | return loader_error::unknown; 599 | 600 | amx.COD = code_base; 601 | amx.DAT = data_base; 602 | 603 | amx.STK = amx.STP = (cell)((_data_count - 1) * sizeof(cell)); 604 | amx.HEA = (cell)(data_count * sizeof(cell)); 605 | 606 | return loader_error::success; 607 | } 608 | 609 | loader() = default; 610 | loader(const uint8_t* buf, size_t buf_size, const callbacks_arg& callbacks) 611 | { 612 | init(buf, buf_size, callbacks); 613 | } 614 | 615 | ~loader() 616 | { 617 | if (_alloc) 618 | ExFreePool(_alloc); 619 | } 620 | 621 | loader(const loader&) = delete; 622 | loader(loader&&) = delete; 623 | 624 | loader& operator=(const loader&) = delete; 625 | loader& operator=(loader&&) = delete; 626 | }; 627 | } -------------------------------------------------------------------------------- /PawnIO/arch_detect.h: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #pragma once 48 | 49 | #if defined(_M_AMD64) || defined(__amd64__) 50 | #define ARCH_X64 1 51 | #define ARCH 1 52 | #elif defined(_M_ARM64) || defined(__aarch64__) 53 | #define ARCH_A64 1 54 | #define ARCH 2 55 | #else 56 | #error "Unsupported architecture" 57 | #endif 58 | -------------------------------------------------------------------------------- /PawnIO/driver.cpp: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #include "ioctl.h" 52 | #include "vm.h" 53 | 54 | static std::atomic g_refs = -1; 55 | 56 | NTSTATUS dispatch_irp(PDEVICE_OBJECT device_object, PIRP irp); 57 | 58 | void driver_unload(PDRIVER_OBJECT driver_object) 59 | { 60 | const auto device_object = driver_object->DeviceObject; 61 | UNICODE_STRING device_dospath = RTL_CONSTANT_STRING(k_device_dospath); 62 | 63 | IoDeleteSymbolicLink(&device_dospath); 64 | 65 | if (device_object) 66 | IoDeleteDevice(device_object); 67 | } 68 | 69 | const GUID k_device_class = { 0x7c619961, 0xf266, 0x4c1b, { 0x84, 0x72, 0x8d, 0x00, 0x47, 0xd6, 0xd4, 0x7a } }; 70 | 71 | EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path) 72 | { 73 | UNREFERENCED_PARAMETER(registry_path); 74 | 75 | UNICODE_STRING device_path = RTL_CONSTANT_STRING(k_device_path); 76 | PDEVICE_OBJECT device_object = nullptr; 77 | auto status = IoCreateDeviceSecure( 78 | driver_object, 79 | 0, 80 | &device_path, 81 | k_device_type, 82 | 0, 83 | FALSE, 84 | &SDDL_DEVOBJ_SYS_ALL_ADM_ALL, 85 | &k_device_class, 86 | &device_object 87 | ); 88 | 89 | if (!NT_SUCCESS(status)) 90 | { 91 | return status; 92 | } 93 | 94 | driver_object->DriverUnload = driver_unload; 95 | 96 | driver_object->MajorFunction[IRP_MJ_CREATE] = dispatch_irp; 97 | driver_object->MajorFunction[IRP_MJ_CLOSE] = dispatch_irp; 98 | driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dispatch_irp; 99 | 100 | UNICODE_STRING device_dospath = RTL_CONSTANT_STRING(k_device_dospath); 101 | status = IoCreateSymbolicLink(&device_dospath, &device_path); 102 | 103 | if (!NT_SUCCESS(status)) 104 | { 105 | IoDeleteDevice(device_object); 106 | return status; 107 | } 108 | 109 | driver_object->Flags &= ~DO_DEVICE_INITIALIZING; 110 | 111 | g_refs = 0; 112 | 113 | return status; 114 | } 115 | 116 | NTSTATUS dispatch_irp(PDEVICE_OBJECT device_object, PIRP irp) 117 | { 118 | UNREFERENCED_PARAMETER(device_object); 119 | 120 | irp->IoStatus.Information = 0; // written 121 | 122 | const auto irp_stack = IoGetCurrentIrpStackLocation(irp); 123 | 124 | auto status = STATUS_NOT_IMPLEMENTED; 125 | 126 | switch (irp_stack->MajorFunction) 127 | { 128 | case IRP_MJ_CREATE: 129 | ++g_refs; 130 | status = STATUS_SUCCESS; 131 | break; 132 | 133 | case IRP_MJ_CLOSE: 134 | if (irp_stack->FileObject->FsContext) 135 | vm_destroy(irp_stack->FileObject->FsContext); 136 | --g_refs; 137 | status = STATUS_SUCCESS; 138 | break; 139 | 140 | case IRP_MJ_DEVICE_CONTROL: 141 | switch (irp_stack->Parameters.DeviceIoControl.IoControlCode) 142 | { 143 | case IOCTL_PIO_GET_REFCOUNT: 144 | if(irp_stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(LONG)) 145 | { 146 | *(PLONG)irp->AssociatedIrp.SystemBuffer = g_refs; 147 | irp->IoStatus.Information = sizeof(g_refs); 148 | status = STATUS_SUCCESS; 149 | } 150 | else 151 | { 152 | status = STATUS_BUFFER_OVERFLOW; 153 | } 154 | break; 155 | 156 | case IOCTL_PIO_LOAD_BINARY: 157 | if (irp_stack->FileObject->FsContext) 158 | { 159 | status = STATUS_ALREADY_INITIALIZED; 160 | } 161 | else 162 | { 163 | status = vm_load_binary( 164 | irp_stack->FileObject->FsContext, 165 | irp->AssociatedIrp.SystemBuffer, 166 | irp_stack->Parameters.DeviceIoControl.InputBufferLength 167 | ); 168 | } 169 | break; 170 | 171 | case IOCTL_PIO_EXECUTE_FN: 172 | if (!irp_stack->FileObject->FsContext) 173 | { 174 | status = STATUS_INVALID_PARAMETER; 175 | } 176 | else 177 | { 178 | status = vm_execute_function( 179 | irp_stack->FileObject->FsContext, 180 | irp->AssociatedIrp.SystemBuffer, 181 | irp_stack->Parameters.DeviceIoControl.InputBufferLength, 182 | irp->AssociatedIrp.SystemBuffer, 183 | irp_stack->Parameters.DeviceIoControl.OutputBufferLength 184 | ); 185 | if (NT_SUCCESS(status)) 186 | irp->IoStatus.Information = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; 187 | } 188 | break; 189 | 190 | default: 191 | break; 192 | } 193 | break; 194 | 195 | default: 196 | break; 197 | } 198 | 199 | irp->IoStatus.Status = status; 200 | 201 | IoCompleteRequest(irp, IO_NO_INCREMENT); 202 | 203 | return status; 204 | } 205 | -------------------------------------------------------------------------------- /PawnIO/ioctl.h: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #pragma once 48 | 49 | constexpr static ULONG k_device_type = 41394; 50 | constexpr static wchar_t k_device_path[] = L"\\Device\\PawnIO"; 51 | constexpr static wchar_t k_device_dospath[] = L"\\DosDevices\\PawnIO"; 52 | constexpr static wchar_t k_device_win32path[] = L"\\\\.\\PawnIO"; 53 | 54 | enum IoCtls : ULONG 55 | { 56 | IOCTL_PIO_GET_REFCOUNT = CTL_CODE(k_device_type, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS), 57 | IOCTL_PIO_LOAD_BINARY = CTL_CODE(k_device_type, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS), 58 | IOCTL_PIO_EXECUTE_FN = CTL_CODE(k_device_type, 0x841, METHOD_BUFFERED, FILE_ANY_ACCESS) 59 | }; 60 | -------------------------------------------------------------------------------- /PawnIO/msrmrs.cpp: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #include 48 | #include 49 | 50 | // the msr and mrs instructions only allow immediates for selecting the architecture specific registers to act on so in 51 | // order to provide arbitrary register access to the VM without metamorphism (which is disallowed by HVCI) we simply 52 | // generate stubs for all possible registers into an array, and shove them into an executable section. Note that this 53 | // must be constexpr so that it can go into a read-only section because W^X is enforced 54 | // 55 | // arguments to (mrs|msr) instruction: 56 | // 57 | // [ 0: 4] (x0 for us) 58 | // [ 5: 7] op2 59 | // [ 8:11] crm 60 | // [12:15] crn 61 | // [16:18] op1 62 | // [19:19] op0 63 | // 64 | // so we need to iterate over all possible values in [5:19], meaning 0x8000 functions for both instruction 65 | 66 | template 67 | constexpr std::array generate_msrmrs() 68 | { 69 | constexpr auto mrs = 0xD5300000; // mrs x0, 70 | constexpr auto msr = 0xD5100000; // msr , x0 71 | 72 | constexpr auto ret = 0xD65F03C0; 73 | 74 | constexpr auto magic = (Mrs ? mrs : msr) | ((uint64_t)ret << 32); 75 | 76 | std::array arr{}; 77 | for (auto i = 0u; i < 0x8000; ++i) 78 | arr[i] = magic | (i << 5); 79 | return arr; 80 | } 81 | 82 | #pragma section (".msrmrs", read, execute) 83 | 84 | __declspec(allocate(".msrmrs")) constexpr auto k_mrsfn = generate_msrmrs(); 85 | __declspec(allocate(".msrmrs")) constexpr auto k_msrfn = generate_msrmrs(); 86 | 87 | // convenience functions where you only need to pass the assembled instruction 88 | 89 | unsigned arm_mrs(unsigned instruction) 90 | { 91 | return ((uint32_t(*)())&k_mrsfn[(instruction >> 5) & 0x7FFF])(); 92 | } 93 | 94 | void arm_msr(unsigned instruction, unsigned v) 95 | { 96 | ((void(*)(uint32_t))&k_msrfn[(instruction >> 5) & 0x7FFF])(v); 97 | } 98 | -------------------------------------------------------------------------------- /PawnIO/natives_impl.h: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #pragma once 48 | #include 49 | 50 | #include "arch_detect.h" 51 | 52 | using cell = unsigned long long; 53 | using scell = long long; 54 | 55 | static_assert(sizeof(cell) == sizeof(void*)); 56 | 57 | cell get_arch(); 58 | 59 | cell cpu_count(); 60 | cell cpu_set_affinity(cell which, std::array& old); 61 | cell cpu_restore_affinity(std::array old); 62 | 63 | cell msr_read(cell msr, cell& value); 64 | cell msr_write(cell msr, cell value); 65 | 66 | void interrupts_disable(); 67 | void interrupts_enable(); 68 | 69 | cell physical_read_byte(cell pa, cell& value); 70 | cell physical_read_word(cell pa, cell& value); 71 | cell physical_read_dword(cell pa, cell& value); 72 | cell physical_read_qword(cell pa, cell& value); 73 | 74 | cell physical_write_byte(cell pa, cell value); 75 | cell physical_write_word(cell pa, cell value); 76 | cell physical_write_dword(cell pa, cell value); 77 | cell physical_write_qword(cell pa, cell value); 78 | 79 | cell io_space_map(cell pa, cell size); 80 | void io_space_unmap(cell va, cell size); 81 | 82 | cell virtual_read_byte(cell va, cell& value); 83 | cell virtual_read_word(cell va, cell& value); 84 | cell virtual_read_dword(cell va, cell& value); 85 | cell virtual_read_qword(cell va, cell& value); 86 | 87 | cell virtual_write_byte(cell va, cell value); 88 | cell virtual_write_word(cell va, cell value); 89 | cell virtual_write_dword(cell va, cell value); 90 | cell virtual_write_qword(cell va, cell value); 91 | 92 | cell virtual_cmpxchg_byte(cell va, cell exchange, cell comparand); 93 | cell virtual_cmpxchg_word(cell va, cell exchange, cell comparand); 94 | cell virtual_cmpxchg_dword(cell va, cell exchange, cell comparand); 95 | cell virtual_cmpxchg_qword(cell va, cell exchange, cell comparand); 96 | 97 | cell virtual_alloc(cell size); 98 | void virtual_free(cell va); 99 | 100 | cell pci_config_read_byte(cell bus, cell device, cell function, cell offset, cell& value); 101 | cell pci_config_read_word(cell bus, cell device, cell function, cell offset, cell& value); 102 | cell pci_config_read_dword(cell bus, cell device, cell function, cell offset, cell& value); 103 | cell pci_config_read_qword(cell bus, cell device, cell function, cell offset, cell& value); 104 | 105 | cell pci_config_write_byte(cell bus, cell device, cell function, cell offset, cell value); 106 | cell pci_config_write_word(cell bus, cell device, cell function, cell offset, cell value); 107 | cell pci_config_write_dword(cell bus, cell device, cell function, cell offset, cell value); 108 | cell pci_config_write_qword(cell bus, cell device, cell function, cell offset, cell value); 109 | 110 | cell get_proc_address(const char* name); 111 | 112 | cell invoke( 113 | cell address, 114 | cell& retval, 115 | cell a0, 116 | cell a1, 117 | cell a2, 118 | cell a3, 119 | cell a4, 120 | cell a5, 121 | cell a6, 122 | cell a7, 123 | cell a8, 124 | cell a9, 125 | cell a10, 126 | cell a11, 127 | cell a12, 128 | cell a13, 129 | cell a14, 130 | cell a15 131 | ); 132 | 133 | cell microsleep(cell us); 134 | 135 | #if defined(ARCH_A64) 136 | 137 | #elif defined(ARCH_X64) 138 | 139 | // order: eax ecx edx ebx esi edi 140 | cell query_dell_smm(std::array in, std::array& out); 141 | 142 | void io_out_byte(cell port, cell value); 143 | void io_out_word(cell port, cell value); 144 | void io_out_dword(cell port, cell value); 145 | 146 | cell io_in_byte(cell port); 147 | cell io_in_word(cell port); 148 | cell io_in_dword(cell port); 149 | 150 | void llwpcb(cell addr); 151 | cell slwpcb(); 152 | 153 | // order: eax ebx ecx edx 154 | void cpuid(cell leaf, cell subleaf, std::array& out); 155 | 156 | cell cr_read(cell cr); 157 | void cr_write(cell cr, cell value); 158 | 159 | cell dr_read(cell dr); 160 | void dr_write(cell dr, cell value); 161 | 162 | cell xcr_read(cell xcr, cell& value); 163 | cell xcr_write(cell xcr, cell value); 164 | 165 | void invlpg(cell va); 166 | void invpcid(cell type, cell descriptor); 167 | 168 | cell readpmc(cell pmc, cell& value); 169 | 170 | cell rdtsc(); 171 | cell rdtscp(cell& pid); 172 | 173 | cell rdrand(cell& v); 174 | cell rdseed(cell& v); 175 | 176 | void lidt(cell limit, cell base); 177 | void sidt(cell& limit, cell& base); 178 | 179 | void lgdt(cell limit, cell base); 180 | void sgdt(cell& limit, cell& base); 181 | 182 | cell mxcsr_read(); 183 | void mxcsr_write(cell v); 184 | 185 | void stac(); 186 | void clac(); 187 | 188 | void halt(); 189 | 190 | void ud2(); 191 | 192 | void int3(); 193 | 194 | void int2c(); 195 | 196 | void wbinvd(); 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /PawnIO/natives_impl_windows.cpp: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #include 48 | #include 49 | #include "natives_impl.h" 50 | 51 | #pragma warning(disable: 4309) 52 | 53 | cell get_arch() 54 | { 55 | return ARCH; 56 | } 57 | 58 | cell cpu_count() 59 | { 60 | return KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); 61 | } 62 | 63 | cell cpu_set_affinity(cell which, std::array& old) 64 | { 65 | PROCESSOR_NUMBER pnum{}; 66 | const auto status = KeGetProcessorNumberFromIndex((ULONG)which, &pnum); 67 | if (!NT_SUCCESS(status)) 68 | return (cell)(scell)status; 69 | 70 | GROUP_AFFINITY ga{}, old_ga{}; 71 | ga.Group = pnum.Group; 72 | ga.Mask = 1ull << pnum.Number; 73 | KeSetSystemGroupAffinityThread(&ga, &old_ga); 74 | static_assert(sizeof(old_ga) == sizeof(cell[2]), "!!!"); 75 | memcpy(old.data(), &old_ga, sizeof(old_ga)); 76 | return (cell)(scell)(old_ga.Group == 0 && old_ga.Mask == 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS); 77 | } 78 | 79 | cell cpu_restore_affinity(std::array old) 80 | { 81 | GROUP_AFFINITY ga{}; 82 | static_assert(sizeof(ga) == sizeof(cell[2]), "!!!"); 83 | memcpy(&ga, old.data(), sizeof(ga)); 84 | if (ga.Group == 0 && ga.Mask == 0) 85 | return (cell)(scell)STATUS_UNSUCCESSFUL; // some idiot passed in the output of a failed cpu_set_affinity 86 | KeRevertToUserGroupAffinityThread(&ga); 87 | return (cell)(scell)STATUS_SUCCESS; 88 | } 89 | 90 | void interrupts_disable() { _disable(); } 91 | void interrupts_enable() { _enable(); } 92 | 93 | template 94 | cell physical_read(cell pa, cell& v) 95 | { 96 | PHYSICAL_ADDRESS phys{}; 97 | phys.QuadPart = (LONGLONG)pa; 98 | const auto va = MmGetVirtualForPhysical(phys); 99 | if (!va) 100 | return (cell)(scell)STATUS_UNSUCCESSFUL; 101 | __try 102 | { 103 | v = (cell)*(T*)va; 104 | return (cell)(scell)STATUS_SUCCESS; 105 | } 106 | __except (EXCEPTION_EXECUTE_HANDLER) 107 | { 108 | return (cell)(scell)GetExceptionCode(); 109 | } 110 | } 111 | 112 | template 113 | cell physical_write(cell pa, cell v) 114 | { 115 | PHYSICAL_ADDRESS phys{}; 116 | phys.QuadPart = (LONGLONG)pa; 117 | const auto va = MmGetVirtualForPhysical(phys); 118 | if (!va) 119 | return (cell)(scell)STATUS_UNSUCCESSFUL; 120 | __try 121 | { 122 | *(T*)va = (T)v; 123 | return (cell)(scell)STATUS_SUCCESS; 124 | } 125 | __except (EXCEPTION_EXECUTE_HANDLER) 126 | { 127 | return (cell)(scell)GetExceptionCode(); 128 | } 129 | } 130 | 131 | cell physical_read_byte(cell pa, cell& value) { return physical_read(pa, value); } 132 | cell physical_read_word(cell pa, cell& value) { return physical_read(pa, value); } 133 | cell physical_read_dword(cell pa, cell& value) { return physical_read(pa, value); } 134 | cell physical_read_qword(cell pa, cell& value) { return physical_read(pa, value); } 135 | 136 | cell physical_write_byte(cell pa, cell value) { return physical_write(pa, value); } 137 | cell physical_write_word(cell pa, cell value) { return physical_write(pa, value); } 138 | cell physical_write_dword(cell pa, cell value) { return physical_write(pa, value); } 139 | cell physical_write_qword(cell pa, cell value) { return physical_write(pa, value); } 140 | 141 | cell io_space_map(cell pa, cell size) 142 | { 143 | PHYSICAL_ADDRESS physical; 144 | physical.QuadPart = pa; 145 | return (cell)MmMapIoSpace(physical, size, MmNonCached); 146 | } 147 | 148 | void io_space_unmap(cell va, cell size) 149 | { 150 | MmUnmapIoSpace((PVOID)va, size); 151 | } 152 | 153 | template 154 | cell virtual_read(cell va, cell& v) 155 | { 156 | __try 157 | { 158 | v = (cell)*(T*)va; 159 | return (cell)(scell)STATUS_SUCCESS; 160 | } 161 | __except (EXCEPTION_EXECUTE_HANDLER) 162 | { 163 | return (cell)(scell)GetExceptionCode(); 164 | } 165 | } 166 | 167 | template 168 | cell virtual_write(cell va, cell v) 169 | { 170 | __try 171 | { 172 | *(T*)va = (T)v; 173 | return (cell)(scell)STATUS_SUCCESS; 174 | } 175 | __except (EXCEPTION_EXECUTE_HANDLER) 176 | { 177 | return (cell)(scell)GetExceptionCode(); 178 | } 179 | } 180 | 181 | template 182 | cell virtual_cmpxchg(cell va, cell exchange, cell comparand) 183 | { 184 | __try 185 | { 186 | switch (sizeof(T)) 187 | { 188 | case 1: 189 | _InterlockedCompareExchange8((char volatile*)va, (char)exchange, (char)comparand); 190 | break; 191 | case 2: 192 | _InterlockedCompareExchange16((short volatile*)va, (short)exchange, (short)comparand); 193 | break; 194 | case 4: 195 | _InterlockedCompareExchange((long volatile*)va, (long)exchange, (long)comparand); 196 | break; 197 | case 8: 198 | _InterlockedCompareExchange64((int64_t volatile*)va, (int64_t)exchange, (int64_t)comparand); 199 | break; 200 | } 201 | return (cell)(scell)STATUS_SUCCESS; 202 | } 203 | __except (EXCEPTION_EXECUTE_HANDLER) 204 | { 205 | return (cell)(scell)GetExceptionCode(); 206 | } 207 | } 208 | 209 | cell virtual_read_byte(cell va, cell& value) { return virtual_read(va, value); } 210 | cell virtual_read_word(cell va, cell& value) { return virtual_read(va, value); } 211 | cell virtual_read_dword(cell va, cell& value) { return virtual_read(va, value); } 212 | cell virtual_read_qword(cell va, cell& value) { return virtual_read(va, value); } 213 | 214 | cell virtual_write_byte(cell va, cell value) { return virtual_write(va, value); } 215 | cell virtual_write_word(cell va, cell value) { return virtual_write(va, value); } 216 | cell virtual_write_dword(cell va, cell value) { return virtual_write(va, value); } 217 | cell virtual_write_qword(cell va, cell value) { return virtual_write(va, value); } 218 | 219 | cell virtual_cmpxchg_byte(cell va, cell exchange, cell comparand) { return virtual_cmpxchg(va, exchange, comparand); } 220 | cell virtual_cmpxchg_word(cell va, cell exchange, cell comparand) { return virtual_cmpxchg(va, exchange, comparand); } 221 | cell virtual_cmpxchg_dword(cell va, cell exchange, cell comparand) { return virtual_cmpxchg(va, exchange, comparand); } 222 | cell virtual_cmpxchg_qword(cell va, cell exchange, cell comparand) { return virtual_cmpxchg(va, exchange, comparand); } 223 | 224 | cell virtual_alloc(cell size) 225 | { 226 | return (cell)ExAllocatePoolZero(NonPagedPoolNx, size, 'nwaP'); 227 | } 228 | 229 | void virtual_free(cell va) 230 | { 231 | ExFreePoolWithTag((PVOID)va, 'nwaP'); 232 | } 233 | 234 | #pragma warning(push) 235 | #pragma warning(disable: 4996) 236 | 237 | NTSTATUS pci_config_read_raw(ULONG bus, ULONG device, ULONG function, ULONG offset, PVOID buffer, ULONG length) 238 | { 239 | if (length == 0) 240 | return (cell)(scell)STATUS_INVALID_PARAMETER; 241 | 242 | PCI_SLOT_NUMBER slot{}; 243 | slot.u.bits.DeviceNumber = device; 244 | slot.u.bits.FunctionNumber = function; 245 | 246 | USHORT vendor_id{}; 247 | auto result = HalGetBusDataByOffset( 248 | PCIConfiguration, 249 | bus, 250 | slot.u.AsULONG, 251 | &vendor_id, 252 | 0, 253 | sizeof(vendor_id) 254 | ); 255 | 256 | if (result == 0) 257 | return (cell)(scell)STATUS_NOT_FOUND; 258 | 259 | if (result == 2 && vendor_id == PCI_INVALID_VENDORID) 260 | return (cell)(scell)STATUS_DEVICE_DOES_NOT_EXIST; 261 | 262 | result = HalGetBusDataByOffset( 263 | PCIConfiguration, 264 | bus, 265 | slot.u.AsULONG, 266 | buffer, 267 | offset, 268 | length 269 | ); 270 | 271 | if (result == 0) 272 | return (cell)(scell)STATUS_NOT_FOUND; 273 | 274 | if (result == 2 && length != 2) 275 | return (cell)(scell)STATUS_DEVICE_DOES_NOT_EXIST; 276 | 277 | if (result != length) 278 | return (cell)(scell)STATUS_UNSUCCESSFUL; 279 | 280 | return (cell)(scell)STATUS_SUCCESS; 281 | } 282 | 283 | NTSTATUS pci_config_write_raw(ULONG bus, ULONG device, ULONG function, ULONG offset, PVOID buffer, ULONG length) 284 | { 285 | if (length == 0) 286 | return (cell)(scell)STATUS_INVALID_PARAMETER; 287 | 288 | PCI_SLOT_NUMBER slot{}; 289 | slot.u.bits.DeviceNumber = device; 290 | slot.u.bits.FunctionNumber = function; 291 | 292 | USHORT vendor_id{}; 293 | auto result = HalGetBusDataByOffset( 294 | PCIConfiguration, 295 | bus, 296 | slot.u.AsULONG, 297 | &vendor_id, 298 | 0, 299 | sizeof(vendor_id) 300 | ); 301 | 302 | if (result == 0) 303 | return (cell)(scell)STATUS_NOT_FOUND; 304 | 305 | if (result == 2 && vendor_id == PCI_INVALID_VENDORID) 306 | return (cell)(scell)STATUS_DEVICE_DOES_NOT_EXIST; 307 | 308 | result = HalSetBusDataByOffset( 309 | PCIConfiguration, 310 | bus, 311 | slot.u.AsULONG, 312 | buffer, 313 | offset, 314 | length 315 | ); 316 | 317 | if (result != length) 318 | return (cell)(scell)STATUS_UNSUCCESSFUL; 319 | 320 | return (cell)(scell)STATUS_SUCCESS; 321 | } 322 | 323 | #pragma warning(pop) 324 | 325 | template 326 | cell pci_config_read(cell bus, cell device, cell function, cell offset, cell& value) 327 | { 328 | T t{}; 329 | const auto status = pci_config_read_raw((ULONG)bus, (ULONG)device, (ULONG)function, (ULONG)offset, &t, sizeof(t)); 330 | value = t; 331 | return status; 332 | } 333 | 334 | template 335 | cell pci_config_write(cell bus, cell device, cell function, cell offset, cell value) 336 | { 337 | T t{(T)value}; 338 | return pci_config_write_raw((ULONG)bus, (ULONG)device, (ULONG)function, (ULONG)offset, &t, sizeof(t)); 339 | } 340 | 341 | cell pci_config_read_byte(cell bus, cell device, cell function, cell offset, cell& value) { return pci_config_read(bus, device, function, offset, value); } 342 | cell pci_config_read_word(cell bus, cell device, cell function, cell offset, cell& value) { return pci_config_read(bus, device, function, offset, value); } 343 | cell pci_config_read_dword(cell bus, cell device, cell function, cell offset, cell& value) { return pci_config_read(bus, device, function, offset, value); } 344 | cell pci_config_read_qword(cell bus, cell device, cell function, cell offset, cell& value) { return pci_config_read(bus, device, function, offset, value); } 345 | 346 | cell pci_config_write_byte(cell bus, cell device, cell function, cell offset, cell value) { return pci_config_write(bus, device, function, offset, value); } 347 | cell pci_config_write_word(cell bus, cell device, cell function, cell offset, cell value) { return pci_config_write(bus, device, function, offset, value); } 348 | cell pci_config_write_dword(cell bus, cell device, cell function, cell offset, cell value) { return pci_config_write(bus, device, function, offset, value); } 349 | cell pci_config_write_qword(cell bus, cell device, cell function, cell offset, cell value) { return pci_config_write(bus, device, function, offset, value); } 350 | 351 | cell get_proc_address(const char* name) 352 | { 353 | const auto len = strlen(name); 354 | wchar_t name_w[1024]{}; 355 | const auto maxlen = min(len, std::size(name_w) - 1); 356 | for (size_t i = 0; i < maxlen; ++i) 357 | name_w[i] = name[i]; 358 | UNICODE_STRING ustr; 359 | RtlInitUnicodeString(&ustr, name_w); 360 | return (cell)MmGetSystemRoutineAddress(&ustr); 361 | } 362 | 363 | cell invoke( 364 | cell address, 365 | cell& retval, 366 | cell a0, 367 | cell a1, 368 | cell a2, 369 | cell a3, 370 | cell a4, 371 | cell a5, 372 | cell a6, 373 | cell a7, 374 | cell a8, 375 | cell a9, 376 | cell a10, 377 | cell a11, 378 | cell a12, 379 | cell a13, 380 | cell a14, 381 | cell a15 382 | ) 383 | { 384 | const auto p = (uintptr_t(*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t))address; 385 | __try 386 | { 387 | retval = p(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); 388 | return (cell)(scell)STATUS_SUCCESS; 389 | } 390 | __except (EXCEPTION_EXECUTE_HANDLER) 391 | { 392 | return (cell)(scell)GetExceptionCode(); 393 | } 394 | } 395 | 396 | cell microsleep(cell us) 397 | { 398 | LARGE_INTEGER li{}; 399 | li.QuadPart = (scell)us * -10; 400 | return (cell)(scell)KeDelayExecutionThread(KernelMode, FALSE, &li); 401 | } 402 | 403 | #if defined(ARCH_A64) 404 | 405 | unsigned arm_mrs(unsigned instruction); 406 | void arm_msr(unsigned instruction, unsigned v); 407 | 408 | cell msr_read(cell msr, cell& value) 409 | { 410 | value = 0; 411 | if ((msr & 0xFFFFFFFFFFF00000) != 0xD5300000) 412 | { 413 | return (cell)(scell)STATUS_INVALID_PARAMETER; 414 | } 415 | __try 416 | { 417 | value = (cell)arm_mrs((ULONG)msr); 418 | return (cell)(scell)STATUS_SUCCESS; 419 | } 420 | __except (EXCEPTION_EXECUTE_HANDLER) 421 | { 422 | return (cell)(scell)GetExceptionCode(); 423 | } 424 | } 425 | 426 | cell msr_write(cell msr, cell value) 427 | { 428 | if ((msr & 0xFFFFFFFFFFF00000) != 0xD5300000) 429 | { 430 | return (cell)(scell)STATUS_INVALID_PARAMETER; 431 | } 432 | 433 | __try 434 | { 435 | arm_msr((ULONG)msr, (ULONG)value); 436 | return (cell)(scell)STATUS_SUCCESS; 437 | } 438 | __except (EXCEPTION_EXECUTE_HANDLER) 439 | { 440 | return (cell)(scell)GetExceptionCode(); 441 | } 442 | } 443 | 444 | #endif 445 | 446 | #if defined(ARCH_X64) 447 | 448 | extern "C" ULONG __fastcall _dell(ULONG* smm); 449 | 450 | cell query_dell_smm(std::array in, std::array& out) 451 | { 452 | ULONG regs[6]; 453 | for (auto i = 0; i < 6; ++i) 454 | regs[i] = (ULONG)in[i]; 455 | const auto result = _dell(regs); 456 | for (auto i = 0; i < 6; ++i) 457 | out[i] = regs[i]; 458 | return (result != 0 || (regs[0] & 0xFFFF) == 0xFFFF || regs[0] == (ULONG)in[0]) ? false : true; 459 | } 460 | 461 | void io_out_byte(cell port, cell value) { __outbyte((USHORT)port, (UCHAR)value); } 462 | void io_out_word(cell port, cell value) { __outword((USHORT)port, (USHORT)value); } 463 | void io_out_dword(cell port, cell value) { __outdword((USHORT)port, (ULONG)value); } 464 | 465 | cell io_in_byte(cell port) { return __inbyte((USHORT)port); } 466 | cell io_in_word(cell port) { return __inword((USHORT)port); } 467 | cell io_in_dword(cell port) { return __indword((USHORT)port); } 468 | 469 | void llwpcb(cell addr) { __llwpcb((void*)addr); } 470 | cell slwpcb() { return (cell)__slwpcb(); } 471 | 472 | cell msr_read(cell msr, cell& value) 473 | { 474 | // clamp 475 | msr = (ULONG)msr; 476 | 477 | value = 0; 478 | __try 479 | { 480 | value = __readmsr((ULONG)msr); 481 | return (cell)(scell)STATUS_SUCCESS; 482 | } 483 | __except (EXCEPTION_EXECUTE_HANDLER) 484 | { 485 | return (cell)(scell)GetExceptionCode(); 486 | } 487 | } 488 | 489 | cell msr_write(cell msr, cell value) 490 | { 491 | // clamp 492 | msr = (ULONG)msr; 493 | 494 | __try 495 | { 496 | __writemsr((ULONG)msr, value); 497 | return (cell)(scell)STATUS_SUCCESS; 498 | } 499 | __except (EXCEPTION_EXECUTE_HANDLER) 500 | { 501 | return (cell)(scell)GetExceptionCode(); 502 | } 503 | } 504 | 505 | void cpuid(cell leaf, cell subleaf, std::array& out) 506 | { 507 | int out32[4]; 508 | __cpuidex(out32, (int)leaf, (int)subleaf); 509 | for (size_t i = 0; i < 4; ++i) 510 | out[i] = out32[i]; 511 | } 512 | 513 | extern "C" cell _crdr(cell id, cell v); 514 | 515 | cell crdr_wrap(cell v, cell idx, bool is_cr, bool is_wr) 516 | { 517 | return _crdr((idx & 0xF) << 3 | (cell)is_cr << 7 | (cell)is_wr << 8, v); 518 | } 519 | 520 | cell cr_read(cell cr) { return crdr_wrap(0, cr, true, false); } 521 | void cr_write(cell cr, cell value) { crdr_wrap(value, cr, true, true); } 522 | 523 | cell dr_read(cell dr) { return crdr_wrap(0, dr, false, false); } 524 | void dr_write(cell dr, cell value) { crdr_wrap(value, dr, false, true); } 525 | 526 | cell xcr_read(cell xcr, cell& value) 527 | { 528 | value = 0; 529 | __try 530 | { 531 | value = _xgetbv((ULONG)xcr); 532 | return (cell)(scell)STATUS_SUCCESS; 533 | } 534 | __except (EXCEPTION_EXECUTE_HANDLER) 535 | { 536 | return (cell)(scell)GetExceptionCode(); 537 | } 538 | } 539 | 540 | cell xcr_write(cell xcr, cell value) 541 | { 542 | __try 543 | { 544 | _xsetbv((ULONG)xcr, value); 545 | return (cell)(scell)STATUS_SUCCESS; 546 | } 547 | __except (EXCEPTION_EXECUTE_HANDLER) 548 | { 549 | return (cell)(scell)GetExceptionCode(); 550 | } 551 | } 552 | 553 | void invlpg(cell va) { __invlpg((void*)va); } 554 | void invpcid(cell type, cell descriptor) { _invpcid((unsigned)type, (void*)descriptor); } 555 | 556 | cell readpmc(cell pmc, cell& value) 557 | { 558 | value = 0; 559 | __try 560 | { 561 | value = __readpmc((ULONG)pmc); 562 | return (cell)(scell)STATUS_SUCCESS; 563 | } 564 | __except (EXCEPTION_EXECUTE_HANDLER) 565 | { 566 | return (cell)(scell)GetExceptionCode(); 567 | } 568 | } 569 | 570 | cell rdtsc() { return __rdtsc(); } 571 | 572 | cell rdtscp(cell& pid) 573 | { 574 | unsigned _pid{}; 575 | const auto res = __rdtscp(&_pid); 576 | pid = _pid; 577 | return res; 578 | } 579 | 580 | cell rdrand(cell& v) { return _rdrand64_step(&v); } 581 | cell rdseed(cell& v) { return _rdseed64_step(&v); } 582 | 583 | #include 584 | struct idtrgdtr 585 | { 586 | uint16_t limit; 587 | uintptr_t base; 588 | }; 589 | #include 590 | 591 | void lidt(cell limit, cell base) 592 | { 593 | idtrgdtr v{}; 594 | v.limit = (uint16_t)limit; 595 | v.base = base; 596 | __lidt(&v); 597 | } 598 | 599 | void sidt(cell& limit, cell& base) 600 | { 601 | idtrgdtr v{}; 602 | __sidt(&v); 603 | limit = v.limit; 604 | base = v.base; 605 | } 606 | 607 | void lgdt(cell limit, cell base) 608 | { 609 | idtrgdtr v{}; 610 | v.limit = (uint16_t)limit; 611 | v.base = base; 612 | _lgdt(&v); 613 | } 614 | 615 | void sgdt(cell& limit, cell& base) 616 | { 617 | idtrgdtr v{}; 618 | _sgdt(&v); 619 | limit = v.limit; 620 | base = v.base; 621 | } 622 | 623 | cell mxcsr_read() { return _mm_getcsr(); } 624 | void mxcsr_write(cell v) { _mm_setcsr((unsigned)v); } 625 | 626 | void stac() { _stac(); } 627 | void clac() { _clac(); } 628 | 629 | void halt() { __halt(); } 630 | 631 | void ud2() { __ud2(); } 632 | 633 | void int3() { __debugbreak(); } 634 | 635 | void int2c() { __int2c(); } 636 | 637 | void wbinvd() { __wbinvd(); } 638 | 639 | #endif 640 | -------------------------------------------------------------------------------- /PawnIO/signature.cpp: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #define SHA256_LEN (32) 53 | 54 | static NTSTATUS calculate_sha256(const void* data, size_t size, uint8_t* sha256) 55 | { 56 | BCRYPT_ALG_HANDLE alg_handle{}; 57 | auto status = BCryptOpenAlgorithmProvider( 58 | &alg_handle, 59 | BCRYPT_SHA256_ALGORITHM, 60 | nullptr, 61 | 0 62 | ); 63 | 64 | if (NT_SUCCESS(status)) 65 | { 66 | ULONG len = 0, rlen = 0; 67 | status = BCryptGetProperty( 68 | alg_handle, 69 | BCRYPT_OBJECT_LENGTH, 70 | (PUCHAR)&len, 71 | sizeof(len), 72 | &rlen, 73 | 0 74 | ); 75 | 76 | if(NT_SUCCESS(status) && rlen == sizeof(len)) 77 | { 78 | const auto hash_obj = _alloca(len); 79 | 80 | BCRYPT_HASH_HANDLE hash_handle{}; 81 | status = BCryptCreateHash( 82 | alg_handle, 83 | &hash_handle, 84 | (PUCHAR)hash_obj, 85 | len, 86 | nullptr, 87 | 0, 88 | 0 89 | ); 90 | 91 | if (NT_SUCCESS(status)) 92 | { 93 | status = BCryptHashData( 94 | hash_handle, 95 | (PUCHAR)const_cast(data), 96 | (ULONG)size, 97 | 0 98 | ); 99 | 100 | if (NT_SUCCESS(status)) 101 | { 102 | status = BCryptFinishHash(hash_handle, sha256, SHA256_LEN, 0); 103 | } 104 | 105 | BCryptDestroyHash(hash_handle); 106 | } 107 | } 108 | 109 | BCryptCloseAlgorithmProvider(alg_handle, 0); 110 | } 111 | 112 | return status; 113 | } 114 | 115 | static NTSTATUS verify_rsa(const uint8_t* sha256, const uint8_t* sig, size_t sig_len, const uint8_t* pubkey, size_t pubkey_len) 116 | { 117 | BCRYPT_ALG_HANDLE alg_handle{}; 118 | auto status = BCryptOpenAlgorithmProvider( 119 | &alg_handle, 120 | BCRYPT_RSA_ALGORITHM, 121 | nullptr, 122 | 0 123 | ); 124 | 125 | if (NT_SUCCESS(status)) 126 | { 127 | BCRYPT_KEY_HANDLE pubkey_handle{}; 128 | 129 | status = BCryptImportKeyPair( 130 | alg_handle, 131 | nullptr, 132 | BCRYPT_RSAPUBLIC_BLOB, 133 | &pubkey_handle, 134 | const_cast(pubkey), 135 | (ULONG)pubkey_len, 136 | 0 137 | ); 138 | 139 | 140 | if (NT_SUCCESS(status)) 141 | { 142 | BCRYPT_PKCS1_PADDING_INFO padding; 143 | padding.pszAlgId = BCRYPT_SHA256_ALGORITHM; 144 | 145 | status = BCryptVerifySignature( 146 | pubkey_handle, 147 | &padding, 148 | const_cast(sha256), 149 | SHA256_LEN, 150 | const_cast(sig), 151 | (ULONG)sig_len, 152 | BCRYPT_PAD_PKCS1 153 | ); 154 | 155 | BCryptDestroyKey(pubkey_handle); 156 | } 157 | 158 | BCryptCloseAlgorithmProvider(alg_handle, 0); 159 | } 160 | 161 | return status; 162 | } 163 | 164 | constexpr static uint8_t k_pubkey[] = { 0x52, 0x53, 0x41, 0x31, 0x00, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xB5, 0x45, 0xB8, 0x15, 0xF0, 0x2A, 0xEB, 0xCA, 0xC9, 0x35, 0x8F, 0x54, 0x15, 0x83, 0x12, 0x2C, 0xC3, 0xF3, 0x5E, 0x1E, 0xE7, 0xFB, 0xD3, 0xE1, 0x68, 0x73, 0x3B, 0x36, 0xC0, 0x5C, 0x6F, 0xD3, 0xBA, 0xF4, 0xD0, 0xA9, 0x9B, 0x6E, 0x9C, 0x66, 0x43, 0x2F, 0xC9, 0xB2, 0x82, 0xDF, 0x24, 0x6D, 0x8F, 0x5F, 0x45, 0xAF, 0x02, 0xDD, 0x6A, 0xEF, 0x04, 0x01, 0x74, 0x69, 0xC3, 0x20, 0x70, 0xDB, 0x3F, 0x05, 0x97, 0x9E, 0xE6, 0x01, 0x6B, 0x9E, 0x28, 0x53, 0x03, 0x59, 0x02, 0x98, 0x4C, 0x41, 0xAB, 0xB2, 0x56, 0x5F, 0xD6, 0x24, 0x98, 0xD1, 0xB3, 0xF9, 0xF8, 0x46, 0xC7, 0x21, 0x4B, 0xDF, 0xFD, 0xF2, 0x88, 0x2A, 0xCE, 0xDC, 0x75, 0x36, 0x40, 0xC2, 0x5E, 0x0B, 0x26, 0x17, 0x7A, 0x3D, 0xD6, 0x34, 0xD7, 0x47, 0xD6, 0x61, 0xE1, 0x33, 0xD7, 0x7A, 0x00, 0x7E, 0x9F, 0xEB, 0x92, 0x33, 0x52, 0x65, 0x8E, 0xF8, 0x7C, 0x49, 0xD4, 0x22, 0xB8, 0x22, 0xBD, 0x59, 0x56, 0xBC, 0xD5, 0x1B, 0x64, 0x4C, 0x91, 0x50, 0xAB, 0x1F, 0x67, 0x9F, 0x84, 0xDD, 0x8B, 0x4F, 0xFC, 0x28, 0x26, 0x52, 0x36, 0x49, 0x67, 0x0D, 0x6C, 0xA4, 0xA1, 0xAA, 0xEC, 0x2B, 0xB0, 0x05, 0x09, 0x08, 0x20, 0x38, 0x82, 0xAE, 0x47, 0xB9, 0x3C, 0xAE, 0x50, 0xBF, 0x93, 0x69, 0x94, 0xB5, 0x98, 0x7C, 0xA8, 0x2E, 0xA9, 0x8E, 0x7B, 0xC2, 0xB2, 0x12, 0xB9, 0xB1, 0x62, 0x46, 0x3C, 0xED, 0x24, 0x9C, 0x89, 0xE0, 0xB8, 0x46, 0x26, 0x1A, 0x5A, 0x08, 0xD6, 0xF0, 0x2A, 0xA3, 0x28, 0xB6, 0x73, 0x60, 0xAE, 0xC3, 0x2D, 0x4C, 0x5A, 0x24, 0xF1, 0x58, 0x4C, 0x51, 0xD2, 0x66, 0xE9, 0xD9, 0x61, 0x98, 0x4D, 0xDE, 0x94, 0xD8, 0x44, 0x1F, 0x62, 0xF6, 0x4E, 0xF9, 0x73, 0x44, 0xA4, 0x7A, 0x2C, 0x2D, 0xC1, 0xDB, 0x4F, 0x58, 0xD6, 0x70, 0xB2, 0x6E, 0xE8, 0xD9, 0x50, 0x01, 0x35, 0x4F, 0x39, 0x49, 0x2E, 0x09, 0x76, 0x47, 0x9C, 0x3C, 0x7E, 0x72, 0x33, 0xCA, 0x13, 0xD7, 0x29, 0x82, 0xFB, 0x14, 0xAD, 0x4E, 0xC3, 0xA6, 0xC6, 0x4C, 0x18, 0x84, 0xB5, 0x83, 0x7A, 0xF0, 0x99, 0xBA, 0x1D, 0x56, 0xD2, 0xA2, 0xDF, 0x14, 0x34, 0x01, 0x6F, 0x83, 0x8D, 0xB8, 0xA0, 0x16, 0x2C, 0x36, 0x90, 0x0F, 0x96, 0x2D, 0x3B, 0x80, 0x58, 0x5C, 0xE7, 0x9D, 0x0D, 0x73, 0x38, 0xCA, 0xEE, 0x43, 0xF7, 0xC0, 0x37, 0xA4, 0xEA, 0xDD, 0x76, 0xCC, 0xA2, 0xF3, 0x54, 0xC8, 0x45, 0xC9, 0xBE, 0x3F, 0xCE, 0xAA, 0x98, 0x2F, 0x4C, 0x97, 0x87, 0x56, 0x00, 0x81, 0x6A, 0x7A, 0x41, 0x52, 0xF7, 0xF9, 0x0D, 0xEE, 0x5D, 0xB6, 0x05, 0x1F, 0x40, 0x9F, 0xDE, 0x75, 0x97, 0xD5, 0x8F, 0x28, 0x04, 0xDA, 0x57, 0xA2, 0x76, 0x52, 0x49, 0x35, 0xAC, 0x54, 0xF3, 0x09, 0xA6, 0x68, 0xEC, 0x84, 0xB8, 0x87, 0xD9, 0xBE, 0x26, 0xED, 0xFD, 0x75, 0x7D, 0x2A, 0x1B, 0x55, 0x18, 0x31, 0xA7, 0xA0, 0x44, 0xC5, 0x4A, 0x05, 0xD2, 0x55, 0x44, 0x70, 0x1D, 0x35, 0xE4, 0x61, 0x03, 0x5D, 0x82, 0x3C, 0x48, 0x40, 0x5F, 0x58, 0x64, 0x4E, 0xFF, 0xA6, 0xA1, 0x24, 0x7A, 0xAC, 0xF0, 0xF8, 0x3F, 0x9E, 0x9B, 0xE0, 0x53, 0x04, 0x55, 0xB1, 0xED, 0xDC, 0xC0, 0xC9, 0x9E, 0x5E, 0x31, 0x46, 0x09, 0x83, 0x51, 0x41, 0xBD, 0x41, 0x73, 0xC0, 0xD8, 0x36, 0x23, 0xAE, 0x0B, 0xDF, 0x89, 0x67, 0x2A, 0xC7, 0x56, 0x36, 0xA8, 0xE2, 0x76, 0xB8, 0xCB, 0x75, 0xA1, 0xF0, 0x7C, 0xAC, 0x4D, 0xCD, 0x56, 0xBB, 0x6A, 0x03, 0xCA, 0x7A, 0x89, 0xD2, 0x06, 0xE9, 0x02, 0x48, 0x17, 0x2F, 0xCF, 0xBC, 0xC1, 0xB6, 0xF7, 0xBF, 0x8A, 0xC1, 0xA7, 0x9B }; 165 | 166 | NTSTATUS check_signature(const void* mem, size_t len, const uint8_t* sig, size_t sig_len) 167 | { 168 | uint8_t sha256[SHA256_LEN]; 169 | const auto status = calculate_sha256(mem, len, sha256); 170 | if (!NT_SUCCESS(status)) 171 | return status; 172 | 173 | return verify_rsa(sha256, sig, sig_len, k_pubkey, sizeof(k_pubkey)); 174 | } 175 | -------------------------------------------------------------------------------- /PawnIO/vm.cpp: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #define LITTLE_ENDIAN 52 | #include "amx_loader.h" 53 | #include "natives_impl.h" 54 | 55 | #include "vm.h" 56 | 57 | using amx64 = amx::amx>>; 58 | using amx64_loader = amx::loader; 59 | 60 | static_assert(std::is_same_v, "cell mismatch"); 61 | 62 | template 63 | class arg_wrapper{}; 64 | 65 | template 66 | class arg_wrapper 67 | { 68 | cell* p{}; 69 | public: 70 | arg_wrapper() = default; 71 | amx::error init(amx64* amx, cell, cell argv) 72 | { 73 | p = amx->data_v2p(argv + Index * sizeof(cell)); 74 | if (!p) 75 | return amx::error::access_violation; 76 | p = amx->mem.data().translate(*p); 77 | if (!p) 78 | return amx::error::access_violation; 79 | return amx::error::success; 80 | } 81 | cell value{}; 82 | ~arg_wrapper() 83 | { 84 | if (p) 85 | *p = value; 86 | } 87 | }; 88 | 89 | template 90 | class arg_wrapper 91 | { 92 | public: 93 | arg_wrapper() = default; 94 | amx::error init(amx64* amx, cell, cell argv) 95 | { 96 | const auto p = amx->data_v2p(argv + Index * sizeof(cell)); 97 | if (!p) 98 | return amx::error::access_violation; 99 | value = *p; 100 | return amx::error::success; 101 | } 102 | cell value{}; 103 | ~arg_wrapper() = default; 104 | }; 105 | 106 | template 107 | class arg_wrapper&, Index> 108 | { 109 | std::array ps{}; 110 | public: 111 | arg_wrapper() = default; 112 | amx::error init(amx64* amx, cell, cell argv) 113 | { 114 | const auto p = amx->data_v2p(argv + Index * sizeof(cell)); 115 | if (!p) 116 | return amx::error::access_violation; 117 | const auto arr_base = *p; 118 | for (size_t i = 0; i < N; ++i) 119 | { 120 | const auto elem = amx->mem.data().translate(arr_base + i * sizeof(cell)); 121 | if (!elem) 122 | { 123 | ps = {}; 124 | return amx::error::access_violation; 125 | } 126 | ps[i] = elem; 127 | value[i] = *elem; 128 | } 129 | return amx::error::success; 130 | } 131 | std::array value{}; 132 | ~arg_wrapper() 133 | { 134 | for (size_t i = 0; i < N; ++i) 135 | *(ps[i]) = value[i]; 136 | } 137 | }; 138 | 139 | template 140 | class arg_wrapper, Index> 141 | { 142 | public: 143 | arg_wrapper() = default; 144 | amx::error init(amx64* amx, cell, cell argv) 145 | { 146 | const auto p = amx->data_v2p(argv + Index * sizeof(cell)); 147 | if (!p) 148 | return amx::error::access_violation; 149 | const auto arr_base = *p; 150 | for (size_t i = 0; i < N; ++i) 151 | { 152 | const auto elem = amx->mem.data().translate(arr_base + i * sizeof(cell)); 153 | if (!elem) 154 | return amx::error::access_violation; 155 | value[i] = *elem; 156 | } 157 | return amx::error::success; 158 | } 159 | std::array value{}; 160 | ~arg_wrapper() = default; 161 | }; 162 | 163 | // Implement wrapped tuple type. 164 | // 165 | namespace impl 166 | { 167 | template 168 | struct wtuple; 169 | template 170 | struct wtuple> { 171 | using type = std::tuple, Ix>...>; 172 | }; 173 | template 174 | using wtuple_t = typename wtuple, std::make_index_sequence>::type; 175 | 176 | template 177 | __forceinline amx::error init_wtuple(amx64* amx, cell argc, cell argv, T& tuple) 178 | { 179 | if constexpr (N == std::tuple_size_v) { 180 | return {}; 181 | } 182 | else { 183 | auto& wrapper = std::get(tuple); 184 | if (auto err = wrapper.init(amx, argc, argv); err != amx::error::success) 185 | return err; 186 | else 187 | return init_wtuple(amx, argc, argv, tuple); 188 | } 189 | } 190 | 191 | template 192 | __forceinline std::pair, amx::error> init_wtuple(amx64* amx, cell argc, cell argv) 193 | { 194 | std::pair, amx::error> result = {}; 195 | result.second = init_wtuple<0>(amx, argc, argv, result.first); 196 | return result; 197 | } 198 | }; 199 | 200 | template 201 | __forceinline amx::error native_callback_wrapper2( 202 | amx64* amx, 203 | amx64_loader* loader, 204 | void* user, 205 | cell argc, 206 | cell argv, 207 | cell& retval, 208 | Ret(*)(Args...) 209 | ) 210 | { 211 | UNREFERENCED_PARAMETER(loader); 212 | UNREFERENCED_PARAMETER(user); 213 | 214 | if (argc != sizeof...(Args)) 215 | return amx::error::invalid_operand; 216 | 217 | auto&& [wtuple, err] = impl::init_wtuple(amx, argc, argv); 218 | 219 | if (err != amx::error::success) 220 | return err; 221 | 222 | if constexpr (std::is_same_v) 223 | { 224 | retval = 0; 225 | std::apply( 226 | [&](auto&... wr) -> void 227 | { 228 | Fn(wr.value...); 229 | }, 230 | wtuple 231 | ); 232 | } 233 | else 234 | { 235 | retval = std::apply( 236 | [&](auto&... wr) -> Ret 237 | { 238 | return Fn(wr.value...); 239 | }, 240 | wtuple 241 | ); 242 | } 243 | 244 | // rest of the bullshit 245 | return amx::error::success; 246 | } 247 | 248 | template 249 | amx::error native_callback_wrapper(amx64* amx, amx64_loader* loader, void* user, cell argc, cell argv, cell& retval) 250 | { 251 | return native_callback_wrapper2(amx, loader, user, argc, argv, retval, Fn); 252 | } 253 | 254 | amx::error debug_print(amx64* amx, amx64_loader* loader, void* user, cell argc, cell argv, cell& retval) 255 | { 256 | UNREFERENCED_PARAMETER(loader); 257 | UNREFERENCED_PARAMETER(user); 258 | 259 | retval = 0; 260 | 261 | if (argc == 0) 262 | return amx::error::invalid_operand; 263 | char message[1024] = "[PawnIO] debug_print: "; 264 | cell args[64]{}; 265 | const auto pvfmt = amx->data_v2p(argv); 266 | if (!pvfmt) 267 | return amx::error::access_violation; 268 | const auto vfmt = *pvfmt; 269 | const auto last = std::begin(message) + std::size(message); 270 | auto it = message + strlen(message); 271 | auto vit = vfmt; 272 | size_t arg_count = 0; 273 | bool in_escape = false; 274 | while (true) 275 | { 276 | const auto pc = amx->mem.data().translate(vit); 277 | vit += sizeof(cell); 278 | if (!pc) 279 | return amx::error::access_violation; 280 | const auto c = (char)*pc; 281 | char to_cat[10]{}; 282 | if (in_escape) 283 | switch (c) 284 | { 285 | case '%': 286 | to_cat[0] = '%'; 287 | to_cat[1] = '%'; 288 | in_escape = false; 289 | break; 290 | case 'd': 291 | case 'i': 292 | case 'u': 293 | case 'o': 294 | case 'x': 295 | case 'X': 296 | to_cat[0] = '%'; 297 | to_cat[1] = 'l'; 298 | to_cat[2] = 'l'; 299 | to_cat[3] = c; 300 | ++arg_count; 301 | in_escape = false; 302 | break; 303 | default: 304 | return amx::error::invalid_operand; 305 | } 306 | else 307 | switch (c) 308 | { 309 | case '%': 310 | in_escape = true; 311 | break; 312 | case 0: 313 | goto leave; 314 | default: 315 | to_cat[0] = c; 316 | break; 317 | } 318 | 319 | const auto len = strlen(to_cat); 320 | if (it + len >= last) 321 | break; // just truncate 322 | 323 | memcpy(it, to_cat, len); 324 | it[len] = 0; 325 | it += len; 326 | 327 | continue; 328 | 329 | leave: 330 | break; 331 | } 332 | 333 | if (arg_count > argc - 1) 334 | return amx::error::invalid_operand; 335 | 336 | if (arg_count > std::size(args)) 337 | return amx::error::invalid_operand; 338 | 339 | for (size_t i = 0; i < arg_count; ++i) 340 | { 341 | const auto pparg = amx->data_v2p(argv + (i + 1) * sizeof(cell)); 342 | if (!pparg) 343 | return amx::error::invalid_operand; 344 | const auto parg = amx->mem.data().translate(*pparg); 345 | if (!parg) 346 | return amx::error::invalid_operand; 347 | args[i] = *parg; 348 | } 349 | 350 | vDbgPrintEx(DPFLTR_DEFAULT_ID, 3, message, (va_list)args); 351 | return amx::error::success; 352 | } 353 | 354 | amx::error get_proc_address_wrap(amx64* amx, amx64_loader* loader, void* user, cell argc, cell argv, cell& retval) 355 | { 356 | UNREFERENCED_PARAMETER(loader); 357 | UNREFERENCED_PARAMETER(user); 358 | 359 | retval = 0; 360 | 361 | char func_name[1024]{}; 362 | size_t idx = 0; 363 | 364 | if (argc == 0) 365 | return amx::error::invalid_operand; 366 | const auto pvfmt = amx->data_v2p(argv); 367 | if (!pvfmt) 368 | return amx::error::access_violation; 369 | const auto vfmt = *pvfmt; 370 | auto vit = vfmt; 371 | while (true) 372 | { 373 | const auto pc = amx->mem.data().translate(vit); 374 | vit += sizeof(cell); 375 | if (!pc) 376 | return amx::error::access_violation; 377 | const auto c = (char)*pc; 378 | 379 | func_name[idx++] = c; 380 | 381 | if (!c) 382 | break; 383 | 384 | if (idx == std::size(func_name)) 385 | return amx::error::access_violation; 386 | } 387 | 388 | retval = get_proc_address(func_name); 389 | 390 | return amx::error::success; 391 | } 392 | 393 | const static amx64_loader::native_arg NATIVES[] = 394 | { 395 | { "debug_print", &debug_print }, 396 | { "get_proc_address", &get_proc_address_wrap }, 397 | 398 | #define DEFINE_NATIVE(name) { #name, &native_callback_wrapper<&name> } 399 | 400 | DEFINE_NATIVE(get_arch), 401 | 402 | DEFINE_NATIVE(cpu_count), 403 | DEFINE_NATIVE(cpu_set_affinity), 404 | DEFINE_NATIVE(cpu_restore_affinity), 405 | 406 | DEFINE_NATIVE(msr_read), 407 | DEFINE_NATIVE(msr_write), 408 | 409 | DEFINE_NATIVE(interrupts_disable), 410 | DEFINE_NATIVE(interrupts_enable), 411 | 412 | DEFINE_NATIVE(physical_read_byte), 413 | DEFINE_NATIVE(physical_read_word), 414 | DEFINE_NATIVE(physical_read_dword), 415 | DEFINE_NATIVE(physical_read_qword), 416 | 417 | DEFINE_NATIVE(physical_write_byte), 418 | DEFINE_NATIVE(physical_write_word), 419 | DEFINE_NATIVE(physical_write_dword), 420 | DEFINE_NATIVE(physical_write_qword), 421 | 422 | DEFINE_NATIVE(io_space_map), 423 | DEFINE_NATIVE(io_space_unmap), 424 | 425 | DEFINE_NATIVE(virtual_read_byte), 426 | DEFINE_NATIVE(virtual_read_word), 427 | DEFINE_NATIVE(virtual_read_dword), 428 | DEFINE_NATIVE(virtual_read_qword), 429 | 430 | DEFINE_NATIVE(virtual_write_byte), 431 | DEFINE_NATIVE(virtual_write_word), 432 | DEFINE_NATIVE(virtual_write_dword), 433 | DEFINE_NATIVE(virtual_write_qword), 434 | 435 | DEFINE_NATIVE(virtual_cmpxchg_byte), 436 | DEFINE_NATIVE(virtual_cmpxchg_word), 437 | DEFINE_NATIVE(virtual_cmpxchg_dword), 438 | DEFINE_NATIVE(virtual_cmpxchg_qword), 439 | 440 | DEFINE_NATIVE(virtual_alloc), 441 | DEFINE_NATIVE(virtual_free), 442 | 443 | DEFINE_NATIVE(pci_config_read_byte), 444 | DEFINE_NATIVE(pci_config_read_word), 445 | DEFINE_NATIVE(pci_config_read_dword), 446 | DEFINE_NATIVE(pci_config_read_qword), 447 | 448 | DEFINE_NATIVE(pci_config_write_byte), 449 | DEFINE_NATIVE(pci_config_write_word), 450 | DEFINE_NATIVE(pci_config_write_dword), 451 | DEFINE_NATIVE(pci_config_write_qword), 452 | 453 | DEFINE_NATIVE(invoke), 454 | 455 | DEFINE_NATIVE(microsleep), 456 | 457 | #if defined(ARCH_A64) 458 | 459 | #elif defined(ARCH_X64) 460 | 461 | DEFINE_NATIVE(query_dell_smm), 462 | 463 | DEFINE_NATIVE(io_out_byte), 464 | DEFINE_NATIVE(io_out_word), 465 | DEFINE_NATIVE(io_out_dword), 466 | 467 | DEFINE_NATIVE(io_in_byte), 468 | DEFINE_NATIVE(io_in_word), 469 | DEFINE_NATIVE(io_in_dword), 470 | 471 | DEFINE_NATIVE(llwpcb), 472 | DEFINE_NATIVE(slwpcb), 473 | 474 | DEFINE_NATIVE(cpuid), 475 | 476 | DEFINE_NATIVE(cr_read), 477 | DEFINE_NATIVE(cr_write), 478 | 479 | DEFINE_NATIVE(dr_read), 480 | DEFINE_NATIVE(dr_write), 481 | 482 | DEFINE_NATIVE(xcr_read), 483 | DEFINE_NATIVE(xcr_write), 484 | 485 | DEFINE_NATIVE(invlpg), 486 | DEFINE_NATIVE(invpcid), 487 | 488 | DEFINE_NATIVE(readpmc), 489 | 490 | DEFINE_NATIVE(rdtsc), 491 | DEFINE_NATIVE(rdtscp), 492 | 493 | DEFINE_NATIVE(rdrand), 494 | DEFINE_NATIVE(rdseed), 495 | 496 | DEFINE_NATIVE(lidt), 497 | DEFINE_NATIVE(sidt), 498 | 499 | DEFINE_NATIVE(lgdt), 500 | DEFINE_NATIVE(sgdt), 501 | 502 | DEFINE_NATIVE(mxcsr_read), 503 | DEFINE_NATIVE(mxcsr_write), 504 | 505 | DEFINE_NATIVE(stac), 506 | DEFINE_NATIVE(clac), 507 | 508 | DEFINE_NATIVE(halt), 509 | 510 | DEFINE_NATIVE(ud2), 511 | 512 | DEFINE_NATIVE(int3), 513 | 514 | DEFINE_NATIVE(int2c), 515 | 516 | DEFINE_NATIVE(wbinvd), 517 | 518 | #endif 519 | 520 | #undef DEFINE_NATIVE 521 | }; 522 | 523 | void __cdecl operator delete(void*, size_t) 524 | { 525 | __debugbreak(); 526 | } 527 | 528 | struct context 529 | { 530 | std::aligned_storage_t loader_storage; 531 | amx64_loader* loader; 532 | FAST_MUTEX mutex; 533 | }; 534 | 535 | NTSTATUS check_signature(const void* mem, size_t len, const uint8_t* sig, size_t sig_len); 536 | 537 | NTSTATUS vm_load_binary(PVOID& ctx, PVOID buffer, SIZE_T size) 538 | { 539 | if (size < 4) 540 | return STATUS_INVALID_PARAMETER; 541 | const auto sig_len = *(PULONG)buffer; 542 | if (sig_len > (size - 4)) 543 | return STATUS_INVALID_PARAMETER; 544 | 545 | const auto mem = (uint8_t*)buffer + 4 + sig_len; 546 | const auto len = size - 4 - sig_len; 547 | 548 | auto status = check_signature(mem, len, (uint8_t*)buffer + 4, sig_len); 549 | 550 | #ifdef PAWNIO_UNRESTRICTED 551 | DbgPrint("[PawnIO] Signature check result: %X\n", status); 552 | status = STATUS_SUCCESS; 553 | #endif 554 | 555 | if (!NT_SUCCESS(status)) 556 | return status; 557 | 558 | // load 559 | const auto my_ctx = (context*)ExAllocatePoolZero(NonPagedPoolNxCacheAligned, sizeof(context), 'OIwP'); 560 | if (!my_ctx) 561 | return STATUS_NO_MEMORY; 562 | 563 | const auto loader = new (&my_ctx->loader_storage) amx64_loader(); 564 | my_ctx->loader = loader; 565 | 566 | const amx64_loader::callbacks_arg callbacks 567 | { 568 | NATIVES, 569 | std::size(NATIVES), 570 | nullptr, 571 | nullptr, 572 | nullptr 573 | }; 574 | 575 | const auto result = loader->init(mem, len, callbacks); 576 | 577 | if (result != amx::loader_error::success) 578 | { 579 | loader->~amx64_loader(); 580 | ExFreePool(my_ctx); 581 | return STATUS_UNSUCCESSFUL; 582 | } 583 | 584 | const auto main = loader->get_main(); 585 | if (main) 586 | { 587 | cell ret{}; 588 | const auto res = loader->amx.call(main, ret); 589 | 590 | if (res != amx::error::success) 591 | status = STATUS_UNSUCCESSFUL; 592 | else 593 | status = (NTSTATUS)ret; 594 | 595 | if (!NT_SUCCESS(status)) 596 | { 597 | loader->~amx64_loader(); 598 | ExFreePool(my_ctx); 599 | return status; 600 | } 601 | } 602 | 603 | ExInitializeFastMutex(&my_ctx->mutex); 604 | 605 | ctx = (PVOID)my_ctx; 606 | return STATUS_SUCCESS; 607 | } 608 | 609 | NTSTATUS vm_execute_function(PVOID ctx, PVOID in_buffer, SIZE_T in_size, PVOID out_buffer, SIZE_T out_size) 610 | { 611 | if (in_size < 32) 612 | return STATUS_INVALID_PARAMETER; 613 | char arr[33]; 614 | arr[32] = 0; 615 | memcpy(arr, in_buffer, 32); 616 | if (strlen(arr) == 32) 617 | return STATUS_INVALID_PARAMETER; 618 | 619 | if (strncmp(arr, "ioctl_", 6) != 0) 620 | return STATUS_INVALID_PARAMETER; 621 | 622 | if (!ctx) 623 | return STATUS_DEVICE_NOT_READY; 624 | 625 | // call function 626 | const auto my_ctx = (context*)ctx; 627 | const auto loader = my_ctx->loader; 628 | const auto fn = loader->get_public(arr); 629 | if (!fn) 630 | return STATUS_OBJECT_NAME_NOT_FOUND; 631 | 632 | auto& amx = loader->amx; 633 | 634 | const auto cell_in_buffer = (cell*)in_buffer + 4; 635 | const auto cell_in_count = in_size / sizeof(cell) - 4; 636 | cell cell_in_va{}; 637 | 638 | const auto cell_out_buffer = (cell*)out_buffer; 639 | const auto cell_out_count = out_size / sizeof(cell); 640 | cell cell_out_va{}; 641 | 642 | NTSTATUS status = STATUS_SUCCESS; 643 | 644 | ExAcquireFastMutex(&my_ctx->mutex); 645 | 646 | if (amx.mem.data().map(cell_in_buffer, cell_in_count, cell_in_va)) 647 | { 648 | if (amx.mem.data().map(cell_out_buffer, cell_out_count, cell_out_va)) 649 | { 650 | amx64::cell out{}; 651 | const auto DAT = loader->amx.DAT; 652 | const auto ret = loader->amx.call(fn, out, { cell_in_va - DAT, cell_in_count, cell_out_va - DAT, cell_out_count }); 653 | if (ret != amx::error::success) 654 | { 655 | DbgPrint("[PawnIO] Call to %s failed: %X\n", arr, ret); 656 | status = STATUS_UNSUCCESSFUL; 657 | } 658 | else 659 | status = (NTSTATUS)out; 660 | 661 | amx.mem.data().unmap(cell_out_va, cell_out_count); 662 | } 663 | else 664 | { 665 | status = STATUS_UNSUCCESSFUL; 666 | } 667 | amx.mem.data().unmap(cell_in_va, cell_in_count); 668 | } 669 | else 670 | { 671 | status = STATUS_UNSUCCESSFUL; 672 | } 673 | 674 | ExReleaseFastMutex(&my_ctx->mutex); 675 | 676 | return status; 677 | } 678 | 679 | NTSTATUS vm_destroy(PVOID ctx) 680 | { 681 | if (ctx) 682 | { 683 | const auto my_ctx = (context*)ctx; 684 | const auto loader = my_ctx->loader; 685 | const auto fn = loader->get_public("unload"); 686 | if (fn) { 687 | cell ret{}; 688 | loader->amx.call(fn, ret); 689 | } 690 | loader->~amx64_loader(); 691 | ExFreePool(my_ctx); 692 | } 693 | 694 | return STATUS_SUCCESS; 695 | } 696 | -------------------------------------------------------------------------------- /PawnIO/vm.h: -------------------------------------------------------------------------------- 1 | // PawnIO - Input-output driver 2 | // Copyright (C) 2023 namazso 3 | // 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License along 15 | // with this program; if not, write to the Free Software Foundation, Inc., 16 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | // 18 | // Linking PawnIO statically or dynamically with other modules is making a 19 | // combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | // General Public License cover the whole combination. 21 | // 22 | // In addition, as a special exception, the copyright holders of PawnIO give 23 | // you permission to combine PawnIO program with free software programs or 24 | // libraries that are released under the GNU LGPL and with independent modules 25 | // that communicate with PawnIO solely through the device IO control 26 | // interface. You may copy and distribute such a system following the terms of 27 | // the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | // provided that you include the source code of that other code when and as 29 | // the GNU GPL requires distribution of source code. 30 | // 31 | // Note that this exception does not include programs that communicate with 32 | // PawnIO over the Pawn interface. This means that all modules loaded into 33 | // PawnIO must be compatible with this licence, including the earlier 34 | // exception clause. We recommend using the GNU Lesser General Public License 35 | // version 2.1 to fulfill this requirement. 36 | // 37 | // For alternative licensing options, please contact the copyright holder at 38 | // admin@namazso.eu. 39 | // 40 | // Note that people who make modified versions of PawnIO are not obligated to 41 | // grant this special exception for their modified versions; it is their 42 | // choice whether to do so. The GNU General Public License gives permission 43 | // to release a modified version without this exception; this exception also 44 | // makes it possible to release a modified version which carries forward this 45 | // exception. 46 | 47 | #pragma once 48 | 49 | NTSTATUS vm_load_binary(PVOID& ctx, PVOID buffer, SIZE_T size); 50 | NTSTATUS vm_execute_function(PVOID ctx, PVOID in_buffer, SIZE_T in_size, PVOID out_buffer, SIZE_T out_size); 51 | NTSTATUS vm_destroy(PVOID ctx); 52 | -------------------------------------------------------------------------------- /PawnIO/x64.asm: -------------------------------------------------------------------------------- 1 | ; PawnIO - Input-output driver 2 | ; Copyright (C) 2023 namazso 3 | ; 4 | ; This program is free software; you can redistribute it and/or modify 5 | ; it under the terms of the GNU General Public License as published by 6 | ; the Free Software Foundation; either version 2 of the License, or 7 | ; (at your option) any later version. 8 | ; 9 | ; This program is distributed in the hope that it will be useful, 10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ; GNU General Public License for more details. 13 | ; 14 | ; You should have received a copy of the GNU General Public License along 15 | ; with this program; if not, write to the Free Software Foundation, Inc., 16 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | ; 18 | ; Linking PawnIO statically or dynamically with other modules is making a 19 | ; combined work based on PawnIO. Thus, the terms and conditions of the GNU 20 | ; General Public License cover the whole combination. 21 | ; 22 | ; In addition, as a special exception, the copyright holders of PawnIO give 23 | ; you permission to combine PawnIO program with free software programs or 24 | ; libraries that are released under the GNU LGPL and with independent modules 25 | ; that communicate with PawnIO solely through the device IO control 26 | ; interface. You may copy and distribute such a system following the terms of 27 | ; the GNU GPL for PawnIO and the licenses of the other code concerned, 28 | ; provided that you include the source code of that other code when and as 29 | ; the GNU GPL requires distribution of source code. 30 | ; 31 | ; Note that this exception does not include programs that communicate with 32 | ; PawnIO over the Pawn interface. This means that all modules loaded into 33 | ; PawnIO must be compatible with this licence, including the earlier 34 | ; exception clause. We recommend using the GNU Lesser General Public License 35 | ; version 2.1 to fulfill this requirement. 36 | ; 37 | ; For alternative licensing options, please contact the copyright holder at 38 | ; admin@namazso.eu. 39 | ; 40 | ; Note that people who make modified versions of PawnIO are not obligated to 41 | ; grant this special exception for their modified versions; it is their 42 | ; choice whether to do so. The GNU General Public License gives permission 43 | ; to release a modified version without this exception; this exception also 44 | ; makes it possible to release a modified version which carries forward this 45 | ; exception. 46 | 47 | .code 48 | 49 | PUBLIC _dell 50 | 51 | _dell PROC FRAME 52 | push rbx 53 | .pushreg rbx 54 | push rsi 55 | .pushreg rsi 56 | push rdi 57 | .pushreg rdi 58 | .endprolog 59 | 60 | mov r8, rcx 61 | 62 | mov eax, [r8] 63 | mov ecx, [r8+4] 64 | mov edx, [r8+8] 65 | mov ebx, [r8+12] 66 | mov esi, [r8+16] 67 | mov edi, [r8+20] 68 | 69 | out 0b2h, al 70 | out 084h, al 71 | 72 | mov [r8], eax 73 | mov [r8+4], ecx 74 | mov [r8+8], edx 75 | mov [r8+12], ebx 76 | mov [r8+16], esi 77 | mov [r8+20], edi 78 | 79 | pop rdi 80 | pop rsi 81 | pop rbx 82 | 83 | setb al 84 | movzx eax, al 85 | 86 | ret 87 | _dell ENDP 88 | 89 | _crdr PROC 90 | lea rax, begin 91 | add rax, rcx 92 | jmp rax 93 | ALIGN 8 94 | begin: 95 | ; mov rax, dr[0-7] 96 | DB 0fh, 21h, 0c0h 97 | ret 98 | ALIGN 8 99 | DB 0fh, 21h, 0c8h 100 | ret 101 | ALIGN 8 102 | DB 0fh, 21h, 0d0h 103 | ret 104 | ALIGN 8 105 | DB 0fh, 21h, 0d8h 106 | ret 107 | ALIGN 8 108 | DB 0fh, 21h, 0e0h 109 | ret 110 | ALIGN 8 111 | DB 0fh, 21h, 0e8h 112 | ret 113 | ALIGN 8 114 | DB 0fh, 21h, 0f0h 115 | ret 116 | ALIGN 8 117 | DB 0fh, 21h, 0f8h 118 | ret 119 | ALIGN 8 120 | 121 | ; mov rax, dr[8-15] 122 | DB 44h, 0fh, 21h, 0c0h 123 | ret 124 | ALIGN 8 125 | DB 44h, 0fh, 21h, 0c8h 126 | ret 127 | ALIGN 8 128 | DB 44h, 0fh, 21h, 0d0h 129 | ret 130 | ALIGN 8 131 | DB 44h, 0fh, 21h, 0d8h 132 | ret 133 | ALIGN 8 134 | DB 44h, 0fh, 21h, 0e0h 135 | ret 136 | ALIGN 8 137 | DB 44h, 0fh, 21h, 0e8h 138 | ret 139 | ALIGN 8 140 | DB 44h, 0fh, 21h, 0f0h 141 | ret 142 | ALIGN 8 143 | DB 44h, 0fh, 21h, 0f8h 144 | ret 145 | ALIGN 8 146 | 147 | ; mov rax, cr[0-7] 148 | DB 0fh, 20h, 0c0h 149 | ret 150 | ALIGN 8 151 | DB 0fh, 20h, 0c8h 152 | ret 153 | ALIGN 8 154 | DB 0fh, 20h, 0d0h 155 | ret 156 | ALIGN 8 157 | DB 0fh, 20h, 0d8h 158 | ret 159 | ALIGN 8 160 | DB 0fh, 20h, 0e0h 161 | ret 162 | ALIGN 8 163 | DB 0fh, 20h, 0e8h 164 | ret 165 | ALIGN 8 166 | DB 0fh, 20h, 0f0h 167 | ret 168 | ALIGN 8 169 | DB 0fh, 20h, 0f8h 170 | ret 171 | ALIGN 8 172 | 173 | ; mov rax, cr[8-15] 174 | DB 44h, 0fh, 20h, 0c0h 175 | ret 176 | ALIGN 8 177 | DB 44h, 0fh, 20h, 0c8h 178 | ret 179 | ALIGN 8 180 | DB 44h, 0fh, 20h, 0d0h 181 | ret 182 | ALIGN 8 183 | DB 44h, 0fh, 20h, 0d8h 184 | ret 185 | ALIGN 8 186 | DB 44h, 0fh, 20h, 0e0h 187 | ret 188 | ALIGN 8 189 | DB 44h, 0fh, 20h, 0e8h 190 | ret 191 | ALIGN 8 192 | DB 44h, 0fh, 20h, 0f0h 193 | ret 194 | ALIGN 8 195 | DB 44h, 0fh, 20h, 0f8h 196 | ret 197 | ALIGN 8 198 | 199 | ; mov dr[0-7], rdx 200 | DB 0fh, 23h, 0c2h 201 | ret 202 | ALIGN 8 203 | DB 0fh, 23h, 0cah 204 | ret 205 | ALIGN 8 206 | DB 0fh, 23h, 0d2h 207 | ret 208 | ALIGN 8 209 | DB 0fh, 23h, 0dah 210 | ret 211 | ALIGN 8 212 | DB 0fh, 23h, 0e2h 213 | ret 214 | ALIGN 8 215 | DB 0fh, 23h, 0eah 216 | ret 217 | ALIGN 8 218 | DB 0fh, 23h, 0f2h 219 | ret 220 | ALIGN 8 221 | DB 0fh, 23h, 0fah 222 | ret 223 | ALIGN 8 224 | 225 | ; mov dr[8-15], rdx 226 | DB 44h, 0fh, 23h, 0c2h 227 | ret 228 | ALIGN 8 229 | DB 44h, 0fh, 23h, 0cah 230 | ret 231 | ALIGN 8 232 | DB 44h, 0fh, 23h, 0d2h 233 | ret 234 | ALIGN 8 235 | DB 44h, 0fh, 23h, 0dah 236 | ret 237 | ALIGN 8 238 | DB 44h, 0fh, 23h, 0e2h 239 | ret 240 | ALIGN 8 241 | DB 44h, 0fh, 23h, 0eah 242 | ret 243 | ALIGN 8 244 | DB 44h, 0fh, 23h, 0f2h 245 | ret 246 | ALIGN 8 247 | DB 44h, 0fh, 23h, 0fah 248 | ret 249 | ALIGN 8 250 | 251 | ; mov cr[0-7], rdx 252 | DB 0fh, 22h, 0c2h 253 | ret 254 | ALIGN 8 255 | DB 0fh, 22h, 0cah 256 | ret 257 | ALIGN 8 258 | DB 0fh, 22h, 0d2h 259 | ret 260 | ALIGN 8 261 | DB 0fh, 22h, 0dah 262 | ret 263 | ALIGN 8 264 | DB 0fh, 22h, 0e2h 265 | ret 266 | ALIGN 8 267 | DB 0fh, 22h, 0eah 268 | ret 269 | ALIGN 8 270 | DB 0fh, 22h, 0f2h 271 | ret 272 | ALIGN 8 273 | DB 0fh, 22h, 0fah 274 | ret 275 | ALIGN 8 276 | 277 | ; mov cr[8-15], rdx 278 | DB 44h, 0fh, 22h, 0c2h 279 | ret 280 | ALIGN 8 281 | DB 44h, 0fh, 22h, 0cah 282 | ret 283 | ALIGN 8 284 | DB 44h, 0fh, 22h, 0d2h 285 | ret 286 | ALIGN 8 287 | DB 44h, 0fh, 22h, 0dah 288 | ret 289 | ALIGN 8 290 | DB 44h, 0fh, 22h, 0e2h 291 | ret 292 | ALIGN 8 293 | DB 44h, 0fh, 22h, 0eah 294 | ret 295 | ALIGN 8 296 | DB 44h, 0fh, 22h, 0f2h 297 | ret 298 | ALIGN 8 299 | DB 44h, 0fh, 22h, 0fah 300 | ret 301 | ALIGN 8 302 | _crdr ENDP 303 | 304 | END -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PawnIO 2 | 3 | Driver source. For downloads please see [pawnio.eu](https://pawnio.eu). 4 | 5 | ## License 6 | 7 | PawnIO - Input-output driver 8 | Copyright (C) 2023 namazso 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License along 21 | with this program; if not, write to the Free Software Foundation, Inc., 22 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | 24 | Linking PawnIO statically or dynamically with other modules is making a 25 | combined work based on PawnIO. Thus, the terms and conditions of the GNU 26 | General Public License cover the whole combination. 27 | 28 | In addition, as a special exception, the copyright holders of PawnIO give 29 | you permission to combine PawnIO program with free software programs or 30 | libraries that are released under the GNU LGPL and with independent modules 31 | that communicate with PawnIO solely through the device IO control 32 | interface. You may copy and distribute such a system following the terms of 33 | the GNU GPL for PawnIO and the licenses of the other code concerned, 34 | provided that you include the source code of that other code when and as 35 | the GNU GPL requires distribution of source code. 36 | 37 | Note that this exception does not include programs that communicate with 38 | PawnIO over the Pawn interface. This means that all modules loaded into 39 | PawnIO must be compatible with this licence, including the earlier 40 | exception clause. We recommend using the GNU Lesser General Public License 41 | version 2.1 to fulfill this requirement. 42 | 43 | For alternative licensing options, please contact the copyright holder at 44 | admin@namazso.eu. 45 | 46 | Note that people who make modified versions of PawnIO are not obligated to 47 | grant this special exception for their modified versions; it is their 48 | choice whether to do so. The GNU General Public License gives permission 49 | to release a modified version without this exception; this exception also 50 | makes it possible to release a modified version which carries forward this 51 | exception. 52 | -------------------------------------------------------------------------------- /cab.ddf: -------------------------------------------------------------------------------- 1 | .OPTION EXPLICIT 2 | .Set CabinetFileCountThreshold=0 3 | .Set FolderFileCountThreshold=0 4 | .Set FolderSizeThreshold=0 5 | .Set MaxCabinetSize=0 6 | .Set MaxDiskFileCount=0 7 | .Set MaxDiskSize=0 8 | .Set CompressionType=MSZIP 9 | .Set Cabinet=on 10 | .Set Compress=on 11 | .Set DestinationDir=PawnIO 12 | PawnIO\PawnIO.inf 13 | PawnIO\PawnIO.sys 14 | PawnIO\PawnIO.cat 15 | PawnIO.pdb 16 | -------------------------------------------------------------------------------- /gencab.bat: -------------------------------------------------------------------------------- 1 | makecab /D RptFileName=cabs/PawnIO_ARM64.rpt /D InfFileName=cabs/PawnIO_ARM64.inf /D CabinetNameTemplate=PawnIO_ARM64.cab /D DiskDirectory1=cabs /D SourceDir=ARM64\Release /f cab.ddf 2 | makecab /D RptFileName=cabs/PawnIO_x64.rpt /D InfFileName=cabs/PawnIO_x64.inf /D CabinetNameTemplate=PawnIO_x64.cab /D DiskDirectory1=cabs /D SourceDir=x64\Release /f cab.ddf 3 | --------------------------------------------------------------------------------